| 1 | #!/usr/bin/env bash |
| 2 | # group: rw auto aio quick |
| 3 | # |
| 4 | # Test concurrent cluster allocations |
| 5 | # |
| 6 | # Copyright (C) 2012 Red Hat, Inc. |
| 7 | # |
| 8 | # This program is free software; you can redistribute it and/or modify |
| 9 | # it under the terms of the GNU General Public License as published by |
| 10 | # the Free Software Foundation; either version 2 of the License, or |
| 11 | # (at your option) any later version. |
| 12 | # |
| 13 | # This program is distributed in the hope that it will be useful, |
| 14 | # but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 16 | # GNU General Public License for more details. |
| 17 | # |
| 18 | # You should have received a copy of the GNU General Public License |
| 19 | # along with this program. If not, see <http://www.gnu.org/licenses/>. |
| 20 | # |
| 21 | |
| 22 | # creator |
| 23 | owner=kwolf@redhat.com |
| 24 | |
| 25 | seq=`basename $0` |
| 26 | echo "QA output created by $seq" |
| 27 | |
| 28 | status=1 # failure is the default! |
| 29 | |
| 30 | _cleanup() |
| 31 | { |
| 32 | _cleanup_test_img |
| 33 | } |
| 34 | trap "_cleanup; exit \$status" 0 1 2 3 15 |
| 35 | |
| 36 | # get standard environment, filters and checks |
| 37 | . ./common.rc |
| 38 | . ./common.filter |
| 39 | |
| 40 | _supported_fmt qcow2 |
| 41 | _supported_proto file fuse |
| 42 | # data_file does not support compressed clusters |
| 43 | _unsupported_imgopts data_file |
| 44 | |
| 45 | CLUSTER_SIZE=64k |
| 46 | size=128M |
| 47 | |
| 48 | echo |
| 49 | echo "== creating backing file for COW tests ==" |
| 50 | |
| 51 | TEST_IMG_SAVE=$TEST_IMG |
| 52 | TEST_IMG="$TEST_IMG.base" |
| 53 | _make_test_img $size |
| 54 | |
| 55 | backing_io() |
| 56 | { |
| 57 | local offset=$1 |
| 58 | local sectors=$2 |
| 59 | local op=$3 |
| 60 | local pattern=0 |
| 61 | local cur_sec=0 |
| 62 | |
| 63 | for ((i=0;i<=$((sectors - 1));i++)); do |
| 64 | cur_sec=$((offset / 65536 + i)) |
| 65 | pattern=$(( ( (cur_sec % 128) + (cur_sec / 128)) % 128 )) |
| 66 | |
| 67 | echo "$op -P $pattern $((cur_sec * 64))k 64k" |
| 68 | done |
| 69 | } |
| 70 | |
| 71 | backing_io 0 32 write | $QEMU_IO "$TEST_IMG" | _filter_qemu_io |
| 72 | |
| 73 | TEST_IMG=$TEST_IMG_SAVE |
| 74 | _make_test_img -b "$TEST_IMG.base" -F $IMGFMT 6G |
| 75 | |
| 76 | echo |
| 77 | echo "== Some concurrent requests touching the same cluster ==" |
| 78 | |
| 79 | overlay_io() |
| 80 | { |
| 81 | # Allocate middle of cluster 1, then write to somewhere before and after it |
| 82 | cat <<EOF |
| 83 | break write_aio A |
| 84 | aio_write -P 10 0x18000 0x2000 |
| 85 | wait_break A |
| 86 | |
| 87 | aio_write -P 11 0x12000 0x2000 |
| 88 | aio_write -P 12 0x1c000 0x2000 |
| 89 | |
| 90 | resume A |
| 91 | aio_flush |
| 92 | EOF |
| 93 | |
| 94 | # Sequential write case: Alloc middle of cluster 2, then write overlapping |
| 95 | # to next cluster |
| 96 | cat <<EOF |
| 97 | break write_aio A |
| 98 | aio_write -P 20 0x28000 0x2000 |
| 99 | wait_break A |
| 100 | aio_write -P 21 0x2a000 0x10000 |
| 101 | resume A |
| 102 | aio_flush |
| 103 | EOF |
| 104 | |
| 105 | # The same with a gap between both requests |
| 106 | cat <<EOF |
| 107 | break write_aio A |
| 108 | aio_write -P 40 0x48000 0x2000 |
| 109 | wait_break A |
| 110 | aio_write -P 41 0x4c000 0x10000 |
| 111 | resume A |
| 112 | aio_flush |
| 113 | EOF |
| 114 | |
| 115 | # Sequential write, but the next cluster is already allocated |
| 116 | cat <<EOF |
| 117 | write -P 70 0x76000 0x8000 |
| 118 | aio_flush |
| 119 | break write_aio A |
| 120 | aio_write -P 60 0x66000 0x2000 |
| 121 | wait_break A |
| 122 | aio_write -P 61 0x6a000 0xe000 |
| 123 | resume A |
| 124 | aio_flush |
| 125 | EOF |
| 126 | |
| 127 | # Sequential write, but the next cluster is already allocated |
| 128 | # and physically in the right position |
| 129 | cat <<EOF |
| 130 | write -P 89 0x80000 0x1000 |
| 131 | write -P 90 0x96000 0x8000 |
| 132 | aio_flush |
| 133 | discard 0x80000 0x10000 |
| 134 | aio_flush |
| 135 | break write_aio A |
| 136 | aio_write -P 80 0x86000 0x2000 |
| 137 | wait_break A |
| 138 | aio_write -P 81 0x8a000 0xe000 |
| 139 | resume A |
| 140 | aio_flush |
| 141 | EOF |
| 142 | |
| 143 | # Sequential write, and the next cluster is compressed |
| 144 | cat <<EOF |
| 145 | write -P 109 0xa0000 0x1000 |
| 146 | write -c -P 110 0xb0000 0x10000 |
| 147 | aio_flush |
| 148 | discard 0xa0000 0x10000 |
| 149 | aio_flush |
| 150 | break write_aio A |
| 151 | aio_write -P 100 0xa6000 0x2000 |
| 152 | wait_break A |
| 153 | aio_write -P 101 0xaa000 0xe000 |
| 154 | resume A |
| 155 | aio_flush |
| 156 | EOF |
| 157 | |
| 158 | # Reverse sequential write |
| 159 | cat <<EOF |
| 160 | break write_aio A |
| 161 | aio_write -P 121 0xdc000 0x2000 |
| 162 | wait_break A |
| 163 | aio_write -P 120 0xc4000 0x18000 |
| 164 | resume A |
| 165 | aio_flush |
| 166 | EOF |
| 167 | |
| 168 | # Reverse sequential write with a gap |
| 169 | cat <<EOF |
| 170 | break write_aio A |
| 171 | aio_write -P 141 0xfc000 0x2000 |
| 172 | wait_break A |
| 173 | aio_write -P 140 0xe4000 0x14000 |
| 174 | resume A |
| 175 | aio_flush |
| 176 | EOF |
| 177 | |
| 178 | # Allocate an area in the middle and then overwrite with a larger request |
| 179 | cat <<EOF |
| 180 | break write_aio A |
| 181 | aio_write -P 161 0x10c000 0x8000 |
| 182 | wait_break A |
| 183 | aio_write -P 160 0x104000 0x18000 |
| 184 | resume A |
| 185 | aio_flush |
| 186 | EOF |
| 187 | |
| 188 | # Create a pre-allocated zero cluster, then start a write on it and discard it |
| 189 | # before the L2 update is made |
| 190 | cat <<EOF |
| 191 | write -P 181 0x120000 0x10000 |
| 192 | write -z 0x120000 0x10000 |
| 193 | |
| 194 | break write_aio A |
| 195 | aio_write -P 180 0x120000 0x10000 |
| 196 | wait_break A |
| 197 | aio_discard 0x120000 0x10000 |
| 198 | resume A |
| 199 | aio_flush |
| 200 | EOF |
| 201 | |
| 202 | # Create a pre-allocated zero cluster, then start a write on it and a |
| 203 | # concurrent zero write with MAY_UNMAP before the L2 update is made |
| 204 | cat <<EOF |
| 205 | write -P 181 0x130000 0x10000 |
| 206 | write -z 0x130000 0x10000 |
| 207 | |
| 208 | break write_aio A |
| 209 | aio_write -P 180 0x130000 0x10000 |
| 210 | wait_break A |
| 211 | aio_write -z -u 0x130000 0x10000 |
| 212 | resume A |
| 213 | aio_flush |
| 214 | EOF |
| 215 | |
| 216 | # Create a pre-allocated zero cluster, then start a write on it and a |
| 217 | # concurrent zero write without MAY_UNMAP before the L2 update is made |
| 218 | cat <<EOF |
| 219 | write -P 181 0x140000 0x10000 |
| 220 | write -z 0x140000 0x10000 |
| 221 | |
| 222 | break write_aio A |
| 223 | aio_write -P 180 0x140000 0x10000 |
| 224 | wait_break A |
| 225 | aio_write -z 0x140000 0x10000 |
| 226 | resume A |
| 227 | aio_flush |
| 228 | EOF |
| 229 | |
| 230 | # Start an allocating write to a previously unallocated cluster and, before |
| 231 | # its L2 update is linked, issue a concurrent sub-cluster zero write with |
| 232 | # MAY_UNMAP that targets a disjoint range within the same cluster. The zero |
| 233 | # write's head/tail are zero (cluster is unallocated), so qcow2_co_pwrite_zeroes |
| 234 | # would expand it to the full subcluster. Without waiting for dependencies |
| 235 | # before the zero write's "unallocated" type check, that check passes, |
| 236 | # qcow2_subcluster_zeroize then yields in wait_for_dependencies, the allocating |
| 237 | # write links its L2 entry, and the resumed zeroize unmaps the cluster - |
| 238 | # silently discarding the just-written data. Waiting first makes the zero write |
| 239 | # fall back to a bounce-buffered real write, which only touches its own |
| 240 | # subrange. |
| 241 | cat <<EOF |
| 242 | break write_aio A |
| 243 | aio_write -P 180 0x200000 0x4000 |
| 244 | wait_break A |
| 245 | aio_write -z -u 0x204000 0x4000 |
| 246 | resume A |
| 247 | aio_flush |
| 248 | EOF |
| 249 | } |
| 250 | |
| 251 | overlay_io | $QEMU_IO blkdebug::"$TEST_IMG" | _filter_qemu_io |\ |
| 252 | sed -e 's/[0-9]*\/[0-9]* bytes at offset [0-9]*/XXX\/XXX bytes at offset XXX/g' \ |
| 253 | -e 's/^[0-9]* KiB/XXX KiB/g' |
| 254 | |
| 255 | echo |
| 256 | echo "== Verify image content ==" |
| 257 | |
| 258 | verify_io() |
| 259 | { |
| 260 | if ($QEMU_IMG info -U -f "$IMGFMT" "$TEST_IMG" | grep "compat: 0.10" > /dev/null); then |
| 261 | # In v2 images clusters are not discarded when there is a backing file. |
| 262 | # Keep the variable empty so that the previous value can be used as |
| 263 | # the default below |
| 264 | discarded= |
| 265 | else |
| 266 | # Discarded clusters are zeroed for v3 or later |
| 267 | discarded=0 |
| 268 | fi |
| 269 | |
| 270 | echo read -P 0 0 0x10000 |
| 271 | |
| 272 | echo read -P 1 0x10000 0x2000 |
| 273 | echo read -P 11 0x12000 0x2000 |
| 274 | echo read -P 1 0x14000 0x4000 |
| 275 | echo read -P 10 0x18000 0x2000 |
| 276 | echo read -P 1 0x1a000 0x2000 |
| 277 | echo read -P 12 0x1c000 0x2000 |
| 278 | echo read -P 1 0x1e000 0x2000 |
| 279 | |
| 280 | echo read -P 2 0x20000 0x8000 |
| 281 | echo read -P 20 0x28000 0x2000 |
| 282 | echo read -P 21 0x2a000 0x10000 |
| 283 | echo read -P 3 0x3a000 0x6000 |
| 284 | |
| 285 | echo read -P 4 0x40000 0x8000 |
| 286 | echo read -P 40 0x48000 0x2000 |
| 287 | echo read -P 4 0x4a000 0x2000 |
| 288 | echo read -P 41 0x4c000 0x10000 |
| 289 | echo read -P 5 0x5c000 0x4000 |
| 290 | |
| 291 | echo read -P 6 0x60000 0x6000 |
| 292 | echo read -P 60 0x66000 0x2000 |
| 293 | echo read -P 6 0x68000 0x2000 |
| 294 | echo read -P 61 0x6a000 0xe000 |
| 295 | echo read -P 70 0x78000 0x6000 |
| 296 | echo read -P 7 0x7e000 0x2000 |
| 297 | |
| 298 | echo read -P ${discarded:-89} 0x80000 0x1000 |
| 299 | echo read -P ${discarded:-8} 0x81000 0x5000 |
| 300 | echo read -P 80 0x86000 0x2000 |
| 301 | echo read -P ${discarded:-8} 0x88000 0x2000 |
| 302 | echo read -P 81 0x8a000 0xe000 |
| 303 | echo read -P 90 0x98000 0x6000 |
| 304 | echo read -P 9 0x9e000 0x2000 |
| 305 | |
| 306 | echo read -P ${discarded:-109} 0xa0000 0x1000 |
| 307 | echo read -P ${discarded:-10} 0xa1000 0x5000 |
| 308 | echo read -P 100 0xa6000 0x2000 |
| 309 | echo read -P ${discarded:-10} 0xa8000 0x2000 |
| 310 | echo read -P 101 0xaa000 0xe000 |
| 311 | echo read -P 110 0xb8000 0x8000 |
| 312 | |
| 313 | echo read -P 12 0xc0000 0x4000 |
| 314 | echo read -P 120 0xc4000 0x18000 |
| 315 | echo read -P 121 0xdc000 0x2000 |
| 316 | echo read -P 13 0xde000 0x2000 |
| 317 | |
| 318 | echo read -P 14 0xe0000 0x4000 |
| 319 | echo read -P 140 0xe4000 0x14000 |
| 320 | echo read -P 15 0xf8000 0x4000 |
| 321 | echo read -P 141 0xfc000 0x2000 |
| 322 | echo read -P 15 0xfe000 0x2000 |
| 323 | |
| 324 | echo read -P 16 0x100000 0x4000 |
| 325 | echo read -P 160 0x104000 0x8000 |
| 326 | # Undefined content for 0x10c000 0x8000 |
| 327 | echo read -P 160 0x114000 0x8000 |
| 328 | echo read -P 17 0x11c000 0x4000 |
| 329 | |
| 330 | echo read -P 0 0x120000 0x10000 |
| 331 | echo read -P 0 0x130000 0x10000 |
| 332 | echo read -P 0 0x140000 0x10000 |
| 333 | |
| 334 | echo read -P 180 0x200000 0x4000 |
| 335 | echo read -P 0 0x204000 0xc000 |
| 336 | } |
| 337 | |
| 338 | verify_io | $QEMU_IO "$TEST_IMG" | _filter_qemu_io |
| 339 | |
| 340 | _check_test_img |
| 341 | |
| 342 | # success, all done |
| 343 | echo "*** done" |
| 344 | rm -f $seq.full |
| 345 | status=0 |