60b3eb231de2dae742b15351491a7d153d8290ed
[platform/upstream/multipath-tools.git] / kpartx / test-kpartx
1 #! /bin/bash
2
3 # This is a unit test program for kpartx, in particular for deleting partitions.
4 #
5 # The rationale is the following:
6 #
7 #  1) kpartx should delete all mappings it created beforehand.
8 #  2) kpartx should handle partitions on dm devices and other devices
9 #     (e.g. loop devices) equally well.
10 #  3) kpartx should only delete "partitions", which are single-target
11 #     linear mappings into a block device. Other maps should not be touched.
12 #  4) kpartx should only delete mappings it created itself beforehand.
13 #     In particular, it shouldn't delete LVM LVs, even if they are fully
14 #     contained in the block device at hand and thus look like partitions
15 #     in the first place. (For historical compatibility reasons, we allow
16 #     such mappings to be deleted with the -f/--force flag).
17 #  5) DM map names may be changed, thus kpartx shouldn't rely on them to
18 #     check whether a mapping is a partition of a particular device. It is
19 #     legal for a partition of /dev/loop0 to be named "loop0".
20
21 # Note: This program tries hard to clean up, but if tests fail,
22 # stale DM or loop devices may keep lurking around.
23
24 # Set WORKDIR in environment to existing dir to for persistence
25 # WARNING:  exisiting files will be truncated.
26 # If empty, test will be done in temporary dir
27 : ${WORKDIR:=}
28 # Set this environment variable to test an alternative kpartx executable
29 : ${KPARTX:=}
30 # Options to pass to kpartx always
31 : ${KPARTX_OPTS:=-s}
32 # Time to wait for device nodes to appear (microseconds)
33 # Waiting is only needed if "s" is not in $KPARTX_OPTS
34 : ${WAIT_US:=0}
35
36 # IMPORTANT: The ERR trap is essential for this program to work correctly!
37 trap 'LINE=$LINENO; trap - ERR; echo "== error in $BASH_COMMAND on line $LINE ==" >&2; exit 1' ERR
38 trap 'cleanup' 0
39
40 CLEANUP=:
41 cleanup() {
42     trap - ERR
43     trap - 0
44     if [[ $OK ]]; then
45         echo == all tests completed successfully == >&2
46     else
47         echo == step $STEP failed == >&2
48     fi
49     eval "$CLEANUP" &>/dev/null
50 }
51
52 push_cleanup() {
53     CLEANUP="$@;$CLEANUP"
54 }
55
56 pop_cleanup() {
57     # CAUTION: simplistic
58     CLEANUP=${CLEANUP#*;}
59 }
60
61 step() {
62     STEP="$@"
63     echo == Test step: $STEP == >&2
64 }
65
66 mk_partitions() {
67     parted -s $1 mklabel msdos
68     parted -s -- $1 mkpart prim ext2 1MiB -1s
69 }
70
71 wipe_ptable() {
72     dd if=/dev/zero of=$1 bs=1b count=1
73 }
74
75 step preparation
76
77 [[ $UID -eq 0 ]]
78 [[ $KPARTX ]] || {
79     if [[ -x $PWD/kpartx/kpartx ]]; then
80         KPARTX=$PWD/kpartx/kpartx
81     else
82         KPARTX=$(which kpartx)
83     fi
84 }
85 [[ $KPARTX ]]
86
87 FILE1=kpartx1
88 FILE2=kpartx2
89 FILE3=kpartx3
90 SIZE=$((1024*1024*1024))  # use bytes as units here
91 SECTSIZ=512
92 OFFS=32                # offset of linear mapping into dev, sectors
93 VG=kpvg  # volume group name
94 LV=kplv  # logical vol name
95 LVMCONF='devices { filter = [ "a|/dev/loop.*|", r".*" ] }'
96
97 OK=
98
99 [[ $WORKDIR ]] || {
100     WORKDIR=$(mktemp -d /tmp/kpartx-XXXXXX)
101     push_cleanup 'rm -rf $WORKDIR'
102 }
103
104 push_cleanup "cd $PWD"
105 cd "$WORKDIR"
106
107 step "create loop devices"
108 truncate -s $SIZE $FILE1
109 truncate -s $SIZE $FILE2
110 truncate -s $SIZE $FILE3
111
112 LO1=$(losetup -f $FILE1 --show)
113 push_cleanup 'losetup -d $LO1'
114 LO2=$(losetup -f $FILE2 --show)
115 push_cleanup 'losetup -d $LO2'
116 LO3=$(losetup -f $FILE3 --show)
117 push_cleanup 'losetup -d $LO3'
118
119 [[ $LO1 && $LO2 && $LO3 && -b $LO1 && -b $LO2 && -b $LO3 ]]
120 DEV1=$(stat -c "%t:%T" $LO1)
121 DEV2=$(stat -c "%t:%T" $LO2)
122 DEV3=$(stat -c "%t:%T" $LO3)
123
124 usleep $WAIT_US
125
126 step "create DM devices (spans)"
127 # Create two linear mappings spanning two loopdevs.
128 # One of them gets a pathological name colliding with
129 # the loop device name.
130 # These mappings must not be removed by kpartx.
131 # They also serve as DM devices to test partition removal on those.
132
133 TABLE="\
134 0 $((SIZE/SECTSIZ-OFFS)) linear $DEV1 $OFFS
135 $((SIZE/SECTSIZ-OFFS)) $((SIZE/SECTSIZ-OFFS)) linear $DEV2 $OFFS"
136
137 SPAN1=kpt
138 SPAN2=$(basename $LO2)
139 dmsetup create $SPAN1 <<<"$TABLE"
140 push_cleanup 'dmsetup remove -f $SPAN1'
141
142 dmsetup create $SPAN2 <<<"$TABLE"
143 push_cleanup 'dmsetup remove -f $SPAN2'
144
145 usleep $WAIT_US
146 [[ -b /dev/mapper/$SPAN1 ]]
147 [[ -b /dev/mapper/$SPAN2 ]]
148
149 step "create vg on $LO3"
150 # On the 3rd loop device, we create a VG and an LV
151 # The LV should not be removed by kpartx.
152 pvcreate --config "$LVMCONF" -f $LO3
153 vgcreate --config "$LVMCONF" $VG $LO3
154 push_cleanup 'vgremove --config "$LVMCONF" -f $VG'
155 lvcreate --config "$LVMCONF" -L $((SIZE/2))B -n $LV $VG
156 push_cleanup 'lvremove --config "$LVMCONF" -f $VG/$LV'
157 usleep $WAIT_US
158
159 [[ -b /dev/mapper/$VG-$LV ]]
160
161 # dmsetup table /dev/mapper/$VG-$LV
162 # dmsetup info /dev/mapper/$VG-$LV
163
164 step "create partitions on loop devices"
165
166 mk_partitions $LO1
167 mk_partitions $LO2
168
169 # Test invocation of kpartx with regular file here
170 LO2P1=/dev/mapper/$(basename $LO2)-foo1
171 $KPARTX $KPARTX_OPTS -a -p -foo $FILE2
172 [[ -b $LO2P1 ]]
173 push_cleanup 'dmsetup remove -f $(basename $LO2P1)'
174
175 step "remove partitions with deleted ptable"
176 wipe_ptable $LO2
177 $KPARTX $KPARTX_OPTS -d $LO2
178 [[ ! -b $LO2P1 ]]
179
180 mk_partitions $LO2
181 $KPARTX $KPARTX_OPTS -a -p -foo $FILE2
182 [[ -b $LO2P1 ]]
183
184 LO1P1=/dev/mapper/$(basename $LO1)-eggs1
185 $KPARTX $KPARTX_OPTS -a -p -eggs $LO1
186 push_cleanup 'dmsetup remove -f $(basename $LO1P1)'
187
188 usleep $WAIT_US
189 [[ -b $LO1P1 ]]
190 [[ -b $LO2P1 ]]
191
192 # dmsetup info $LO2P1
193
194 # Set pathological name for partition on $LO1 (same as loop device itself)
195 dmsetup rename $(basename $LO1P1) $(basename $LO1)
196 LO1P1=/dev/mapper/$(basename $LO1)
197 pop_cleanup
198 push_cleanup 'dmsetup remove -f $(basename $LO1P1)'
199
200 # dmsetup info $LO1P1
201
202 step "create partitions on DM devices"
203 mk_partitions /dev/mapper/$SPAN2
204
205 $KPARTX $KPARTX_OPTS -a -p -bar /dev/mapper/$SPAN2
206 SPAN2P1=/dev/mapper/${SPAN2}-bar1
207
208 # udev rules may have created partition mappings without UUIDs
209 # which aren't removed by default (if system standard kpartx doesn't
210 # set the UUID). Remove them using -f
211 push_cleanup '$KPARTX $KPARTX_OPTS -f -d /dev/mapper/$SPAN2'
212 push_cleanup 'dmsetup remove -f $(basename $SPAN2P1)'
213
214 $KPARTX $KPARTX_OPTS -a -p -spam /dev/mapper/$SPAN1
215 SPAN1P1=/dev/mapper/${SPAN1}-spam1
216 # see above
217 push_cleanup '$KPARTX $KPARTX_OPTS -f -d /dev/mapper/$SPAN1'
218 push_cleanup 'dmsetup remove -f $(basename $SPAN1P1)'
219
220 usleep $WAIT_US
221 [[ -b $SPAN2P1 ]]
222 [[ -b $SPAN1P1 ]]
223
224 step "rename partitions on DM device to default"
225 $KPARTX $KPARTX_OPTS -u /dev/mapper/$SPAN1
226 [[ ! -b ${SPAN1P1} ]]
227 # This assumes that $SPAN1 ends in a non-digit
228 [[ -b ${SPAN1P1//-spam/} ]]
229
230 step "rename partitions on DM device back from default"
231 $KPARTX $KPARTX_OPTS -u -p -spam /dev/mapper/$SPAN1
232 [[ -b ${SPAN1P1} ]]
233 [[ ! -b ${SPANP1//-foo/} ]]
234
235 step "delete partitions on DM devices"
236 $KPARTX $KPARTX_OPTS -d /dev/mapper/$SPAN1 >&2
237 usleep $WAIT_US
238
239 [[ -b $SPAN2P1 ]]
240 [[ -b $LO1P1 ]]
241 [[ -b $LO2P1 ]]
242 [[ ! -b $SPAN1P1 ]]
243
244 $KPARTX $KPARTX_OPTS -d /dev/mapper/$SPAN2
245 usleep $WAIT_US
246
247 [[ -b $LO1P1 ]]
248 [[ -b $LO2P1 ]]
249 [[ ! -b $SPAN2P1 ]]
250
251 step "rename partitions on loop device"
252 $KPARTX $KPARTX_OPTS -u -p -spam $LO2
253 [[ ! -b ${LO2P1} ]]
254 [[ -b ${LO2P1//-foo/-spam} ]]
255
256 step "rename partitions on loop device back"
257 $KPARTX $KPARTX_OPTS -u -p -foo $LO2
258 [[ -b ${LO2P1} ]]
259 [[ ! -b ${LO2P1//-foo/-spam} ]]
260
261 step "rename partitions on loop device to default"
262 $KPARTX $KPARTX_OPTS -u $LO2
263 #read a
264 [[ ! -b ${LO2P1} ]]
265 # $LO1 ends in a digit
266 [[ -b ${LO2P1//-foo/p} ]]
267
268 step "rename partitions on loop device back from default"
269 $KPARTX $KPARTX_OPTS -u -p -foo $LO2
270 [[ -b ${LO2P1} ]]
271 [[ ! -b ${LO2P1//-foo/p} ]]
272
273 step "rename partitions on loop devices"
274 $KPARTX $KPARTX_OPTS -u -p spam $LO2
275
276 step "delete partitions on loop devices"
277
278 $KPARTX $KPARTX_OPTS -d $LO3
279
280 # This will also delete the loop device
281 $KPARTX $KPARTX_OPTS -d $FILE2
282 $KPARTX $KPARTX_OPTS -d $LO1
283 usleep $WAIT_US
284
285 # ls -l /dev/mapper
286 [[ ! -b $LO1P1 ]]
287 pop_cleanup
288 [[ ! -b $LO2P1 ]]
289 pop_cleanup
290 # spans should not have been removed
291 [[ -b /dev/mapper/$SPAN1 ]]
292 [[ -b /dev/mapper/$SPAN2 ]]
293 # LVs neither
294 [[ -b /dev/mapper/$VG-$LV ]]
295
296 step "delete partitions on $LO3 with -f"
297
298 $KPARTX $KPARTX_OPTS -f -d $LO3
299 # -d -f should delete the LV, too
300 [[ ! -b /dev/mapper/$VG-$LV ]]
301 [[ -b /dev/mapper/$SPAN1 ]]
302 [[ -b /dev/mapper/$SPAN2 ]]
303
304 OK=yes