| #! /bin/bash |
| # SPDX-License-Identifier: GPL-2.0 |
| # Copyright (C) 2021 Facebook, Inc. All Rights Reserved. |
| # |
| # FS QA Test 291 |
| # |
| # Test btrfs consistency after each FUA while enabling verity on a file |
| # This test works by following the pattern in log-writes/replay-individual.sh: |
| # 1. run a workload (verity + sync) while logging to the log device |
| # 2. replay an entry to the replay device |
| # 3. snapshot the replay device to the snapshot device |
| # 4. run destructive tests on the snapshot device (e.g. mount with orphans) |
| # 5. goto 2 |
| # |
| . ./common/preamble |
| _begin_fstest auto verity recoveryloop |
| |
| # Override the default cleanup function. |
| _cleanup() |
| { |
| cd / |
| _log_writes_cleanup &> /dev/null |
| $LVM_PROG vgremove -f -y $vgname >>$seqres.full 2>&1 |
| losetup -d $loop_dev >>$seqres.full 2>&1 |
| rm -f $img |
| _restore_fsverity_signatures |
| } |
| |
| . ./common/filter |
| . ./common/attr |
| . ./common/dmlogwrites |
| . ./common/verity |
| |
| |
| _require_scratch |
| _require_test |
| _require_loop |
| _require_log_writes |
| _require_dm_target snapshot |
| _require_command $LVM_PROG lvm |
| _require_scratch_verity |
| _require_btrfs_command inspect-internal dump-tree |
| _require_test_program "log-writes/replay-log" |
| _disable_fsverity_signatures |
| |
| sync_loop() { |
| i=$1 |
| [ -z "$i" ] && _fail "sync loop needs a number of iterations" |
| while [ $i -gt 0 ] |
| do |
| $XFS_IO_PROG -c sync $SCRATCH_MNT |
| let i-=1 |
| done |
| } |
| |
| dump_tree() { |
| local dev=$1 |
| $BTRFS_UTIL_PROG inspect-internal dump-tree $dev |
| } |
| |
| count_item() { |
| local dev=$1 |
| local item=$2 |
| dump_tree $dev | grep -c "$item" |
| } |
| |
| count_merkle_items() { |
| local dev=$1 |
| count_item $dev 'VERITY_\(DESC\|MERKLE\)_ITEM' |
| } |
| |
| _log_writes_init $SCRATCH_DEV |
| _log_writes_mkfs |
| _log_writes_mount |
| |
| f=$SCRATCH_MNT/fsv |
| MB=$((1024 * 1024)) |
| img=$TEST_DIR/$$.img |
| $XFS_IO_PROG -fc "pwrite -q 0 $((10 * $MB))" $f |
| $XFS_IO_PROG -c sync $SCRATCH_MNT |
| sync_loop 10 & |
| sync_proc=$! |
| _fsv_enable $f |
| $XFS_IO_PROG -c sync $SCRATCH_MNT |
| wait $sync_proc |
| |
| _log_writes_unmount |
| _log_writes_remove |
| |
| # the snapshot and the replay will each be the size of the log writes dev |
| # so we create a loop device of size 2 * logwrites and then split it into |
| # replay and snapshot with lvm. |
| log_writes_blocks=$(blockdev --getsz $LOGWRITES_DEV) |
| replay_bytes=$((512 * $log_writes_blocks)) |
| img_bytes=$((2 * $replay_bytes)) |
| |
| $XFS_IO_PROG -fc "pwrite -q -S 0 $img_bytes $MB" $img >>$seqres.full 2>&1 || \ |
| _fail "failed to create image for loop device" |
| loop_dev=$(losetup -f --show $img) |
| vgname=vg_replay |
| lvname=lv_replay |
| replay_dev=/dev/mapper/vg_replay-lv_replay |
| snapname=lv_snap |
| snap_dev=/dev/mapper/vg_replay-$snapname |
| |
| $LVM_PROG vgcreate -f $vgname $loop_dev >>$seqres.full 2>&1 || _fail "failed to vgcreate $vgname" |
| $LVM_PROG lvcreate -L "$replay_bytes"B -n $lvname $vgname -y >>$seqres.full 2>&1 || \ |
| _fail "failed to lvcreate $lvname" |
| $UDEV_SETTLE_PROG >>$seqres.full 2>&1 |
| |
| replay_log_prog=$here/src/log-writes/replay-log |
| num_entries=$($replay_log_prog --log $LOGWRITES_DEV --num-entries) |
| entry=$($replay_log_prog --log $LOGWRITES_DEV --replay $replay_dev --find --end-mark mkfs | cut -d@ -f1) |
| prev=$(_log_writes_mark_to_entry_number mkfs) |
| [ -z "$prev" ] && _fail "failed to locate entry mark 'mkfs'" |
| cur=$(_log_writes_find_next_fua $prev) |
| |
| # state = 0: verity hasn't started |
| # state = 1: verity underway |
| # state = 2: verity done |
| state=0 |
| while [ ! -z "$cur" ]; |
| do |
| _log_writes_replay_log_range $cur $replay_dev >> $seqres.full |
| |
| $LVM_PROG lvcreate -s -L 4M -n $snapname $vgname/$lvname >>$seqres.full 2>&1 || \ |
| _fail "Failed to create snapshot" |
| $UDEV_SETTLE_PROG >>$seqres.full 2>&1 |
| |
| orphan=$(count_item $snap_dev ORPHAN) |
| [ $state -eq 0 ] && [ $orphan -gt 0 ] && state=1 |
| |
| pre_mount=$(count_merkle_items $snap_dev) |
| _mount $snap_dev $SCRATCH_MNT || _fail "mount failed at entry $cur" |
| fsverity measure $SCRATCH_MNT/fsv >>$seqres.full 2>&1 |
| measured=$? |
| umount $SCRATCH_MNT |
| [ $state -eq 1 ] && [ $measured -eq 0 ] && state=2 |
| [ $state -eq 2 ] && ([ $measured -eq 0 ] || _fail "verity done, but measurement failed at entry $cur") |
| post_mount=$(count_merkle_items $snap_dev) |
| |
| echo "entry: $cur, state: $state, orphan: $orphan, pre_mount: $pre_mount, post_mount: $post_mount" >> $seqres.full |
| |
| if [ $state -eq 1 ]; then |
| [ $post_mount -eq 0 ] || \ |
| _fail "mount failed to clear under-construction merkle items pre: $pre_mount, post: $post_mount at entry $cur"; |
| fi |
| if [ $state -eq 2 ]; then |
| [ $pre_mount -gt 0 ] || \ |
| _fail "expected to have verity items before mount at entry $cur" |
| [ $pre_mount -eq $post_mount ] || \ |
| _fail "mount cleared merkle items after verity was enabled $pre_mount vs $post_mount at entry $cur"; |
| fi |
| |
| $LVM_PROG lvremove $vgname/$snapname -y >>$seqres.full |
| |
| prev=$cur |
| cur=$(_log_writes_find_next_fua $(($cur + 1))) |
| done |
| |
| [ $state -eq 2 ] || _fail "expected to reach verity done state" |
| |
| echo "Silence is golden" |
| |
| # success, all done |
| status=0 |
| exit |