#!/bin/bash

set -e

LOOP1=/dev/loop1
LOOP2=/dev/loop2
MD=/dev/md1

# BITMAP=none works fine, BITMAP=internal corrupts the data.
BITMAP=internal

# Misc helpers
log() {
    echo === $@
}

error() {
    echo === ERROR === $@
    false
}

mb_to_sector() {
    echo $(($1 * 2048))
}

mb_to_byte() {
    echo $(($1 * 1048576))
}

check_md5sum() {
    sum=$(dd if=$MD iflag=direct | md5sum | cut -d ' ' -f 1)
    [ $sum == $1 ] || error "Data corrupted: got $sum, wanted $1"
    log "OK $sum"
}

CLEANUP=()
cleanup() {
    set +e
    for (( idx=${#CLEANUP[@]}-1 ; idx>=0 ; idx-- )) ; do
        log "cleanup: ${CLEANUP[idx]}"
        eval "${CLEANUP[idx]}"
    done
}
trap "cleanup" 0 1 2 15

log "Create 20 MiB disk1, partitioned as:"
log "disk1p1: 1 MiB"
log "disk1p2: 18 MiB"
dd if=/dev/zero of=disk1 bs=1M count=20
sfdisk --quiet --force disk1 <<EOF
unit: sectors
disk1p1: start=$(mb_to_sector 1), size=$(mb_to_sector 1), Id=fd
disk1p2: start=$(mb_to_sector 2), size=$(mb_to_sector 18), Id=fd
EOF

log "Create 30 MiB disk2, partitioned as:"
log "disk2p1: 1 MiB"
log "disk2p2: 28 MiB"
dd if=/dev/zero of=disk2 bs=1M count=30
sfdisk --quiet --force disk2 <<EOF
unit: sectors
disk2p1: start=$(mb_to_sector 1), size=$(mb_to_sector 1), Id=fd
disk2p2: start=$(mb_to_sector 2), size=$(mb_to_sector 28), Id=fd
EOF

log "Create loop devices for the big partitions"
losetup -o $(mb_to_byte 2) --sizelimit $(mb_to_byte 18) $LOOP1 disk1
CLEANUP+=("losetup -d $LOOP1")
losetup -o $(mb_to_byte 2) --sizelimit $(mb_to_byte 28) $LOOP2 disk2
CLEANUP+=("losetup -d $LOOP2")

log "Create MD device with just disk1"
mdadm -C $MD -e 0.90 -n 2 -l 1 --bitmap=$BITMAP --bitmap-chunk=1M $LOOP1 missing
CLEANUP+=("mdadm --stop $MD")
cat /proc/mdstat

log "Add disk2 and wait for sync"
mdadm --add $MD $LOOP2
mdadm --wait $MD
cat /proc/mdstat

MDSIZE=$(blockdev --getsize64 $MD)

log "Write some data"
yes 'aaaaa' | tr -d '\n' | head --bytes=$((MDSIZE)) > $MD
sync

log "Check md5sum"
check_md5sum 3e6cfeb0f93be97da0886768395264d2

log "Remove disk2"
mdadm --fail $MD $LOOP2
mdadm --remove $MD $LOOP2

log "Now change the first half of the data"
yes 'bbbbb' | tr -d '\n' | head --bytes=$((MDSIZE / 2)) > $MD
sync

log "Repartition disk2 as:"
log "disk2p1: 1 MiB"
log "disk2p2: 1 MiB"
log "disk2p3: 27 MiB"
losetup -d $LOOP2
sfdisk --quiet --force disk2 <<EOF
unit: sectors
disk2p1: start=$(mb_to_sector 1), size=$(mb_to_sector 1), Id=fd
disk2p2: start=$(mb_to_sector 2), size=$(mb_to_sector 1), Id=fd
disk2p3: start=$(mb_to_sector 3), size=$(mb_to_sector 27), Id=fd
EOF
losetup -o $(mb_to_byte 3) --sizelimit $(mb_to_byte 27) $LOOP2 disk2

log "Check md5sum with only disk1 in the array"
check_md5sum 0dd300d45a0290dbf5e4cc91f2024da5

hd $MD || true

log "Re-add disk2 to the array and wait for it to sync up"
mdadm --add $MD $LOOP2
cat /proc/mdstat
mdadm --wait $MD
cat /proc/mdstat

log "Remove disk1"
mdadm --fail $MD $LOOP1
mdadm --remove $MD $LOOP1

hd $MD || true

log "Check md5sum with only disk2 in the array"
check_md5sum 0dd300d45a0290dbf5e4cc91f2024da5

echo "OK!"
