tools: add a dm-logwrites replay tool
[xfstests-dev.git] / tools / dm-logwrite-replay
1 #!/bin/bash
2 # SPDX-License-Identifier: GPL-2.0 Copyright (c) 2021 Red Hat, Inc.  All Rights
3 # Reserved.
4 #
5 # dm-logwrite-replay utility.
6 #
7 # This is used to replay failures that result from generic/482. Modify the
8 # cleanup function in g/482 to the version that does not tear down the dm-thin
9 # volume and grab the thin volume name from the the 482.full output file.  Then
10 # you can replay the log writes manually with this tool so that the changes
11 # between a good replay and a bad replay can be isolated. The 482.full output
12 # file has all the FUA write locations recorded - these are what you pass the
13 # tool as "PREV_FUA" and "END_FUA".
14 #
15 # The tool uses the fstests infrastructure and scripts, so it needs to be run
16 # from the base fstests directory similar to the check script. RESULT_DIR is
17 # pointed at the current directory, which means that debug output from the tool
18 # placed in $seqres.full points ends up in ./dm-logwrite-replay.full.
19 #
20 # For example:
21 #       - device name /dev/mapper/thin-vol
22 #       - last good replay @ write 124
23 #       - first bad replay @ write 125
24 #
25 # Replay from start to 124:
26 #
27 # cd src/fstests
28 # tools/dm-logwrite-replay --dev /dev/mapper/thin-vol --end 124
29 # <take image of filesystem /dev/mapper/thin-vol>
30 #
31 # Replay from 124 to 125:
32 #
33 # tools/dm-logwrite-replay --dev /dev/mapper/thin-vol --start 124 --end 125
34 # <take image of filesystem from /dev/mapper/thin-vol>
35 #
36 # Now compare images of the filesystem to see the differences and analyse the
37 # failure.
38 #
39 # Often with log recovery failures, you need to see the pre-recovery state of
40 # the filesystem. To do this, use the --no-recovery option in conjunction with
41 # the above commands.  This allows you to determine if recovery is doing the
42 # wrong thing or not.
43 #
44 # Once finished, teardown the logwrites/thin vol with
45 #
46 # tools/dm-logwrite-replay --dev /dev/mapper/thin-vol --cleanup
47 #
48
49 DMTHIN_VOL_DEV=""
50 PREV_FUA=""
51 END_FUA=""
52 CLEANUP=""
53 DO_RECOVERY="y"
54
55 while [ $# -gt 0 ]; do
56         case "$1" in
57         --dev) DMTHIN_VOL_DEV="$2" ; shift ;;
58         --start) PREV_FUA="$2" ; shift ;;
59         --end) END_FUA="$2" ; shift ;;
60         --cleanup) CLEANUP=y ;;
61         --no-recovery) DO_RECOVERY="" ;;
62         esac
63         shift
64 done
65
66 [ -z "$DMTHIN_VOL_DEV" ] && _fail "not dmthin vol defined"
67
68 RESULT_DIR=`pwd`
69
70 . ./common/preamble
71 _begin_fstest replay
72
73 MOUNT_OPTIONS="-o dax=never"
74
75 # Import common functions.
76 . ./common/filter
77 . ./common/dmthin
78 . ./common/dmlogwrites
79
80 LOGWRITES_NAME=logwrites-test
81 LOGWRITES_DMDEV=/dev/mapper/$LOGWRITES_NAME
82
83 if [ -n "$CLEANUP" ]; then
84         _log_writes_cleanup &> /dev/null
85         _dmthin_cleanup
86         exit;
87 fi
88
89 if [ -z "$PREV_FUA" ]; then
90         prev=$(_log_writes_mark_to_entry_number mkfs)
91         [ -z "$prev" ] && _fail "failed to locate entry mark 'mkfs'"
92 else
93         prev="$((PREV_FUA + 1))"
94 fi
95 cur=$(_log_writes_find_next_fua $prev)
96 [ -z "$cur" ] && _fail "failed to locate next FUA write"
97
98 while [ ! -z "$cur" ]; do
99         echo "Replay writes from $prev to $cur"
100         _log_writes_replay_log_range $cur $DMTHIN_VOL_DEV
101
102         if [ -n "$DO_RECOVERY" ]; then
103                 _dmthin_mount
104                 _dmthin_check_fs
105         fi
106
107         [ -n "$END_FUA" -a "$END_FUA" -eq "$cur" ] && break;
108
109         prev=$cur
110         cur=$(_log_writes_find_next_fua $(($cur + 1)))
111         [ -z "$cur" ] && break
112 done
113