]>
Commit | Line | Data |
---|---|---|
11fdf7f2 | 1 | #!/usr/bin/env bash |
7c673cae FG |
2 | |
3 | # Copyright (C) 2013 Inktank Storage, Inc. | |
4 | # | |
5 | # This is free software; see the source for copying conditions. | |
6 | # There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR | |
7 | # A PARTICULAR PURPOSE. | |
8 | # | |
9 | # This is free software; you can redistribute it and/or modify it | |
10 | # under the terms of the GNU General Public License as | |
11 | # published by the Free Software Foundation version 2. | |
12 | ||
13 | # Alex Elder <elder@inktank.com> | |
14 | # April 10, 2013 | |
15 | ||
16 | ################################################################ | |
17 | ||
18 | # The purpose of this test is to validate that data read from a | |
19 | # mapped rbd image is what it's expected to be. | |
20 | # | |
21 | # By default it creates an image and fills it with some data. It | |
22 | # then reads back the data at a series of offsets known to cover | |
23 | # various situations (such as reading the beginning, end, or the | |
24 | # entirety of an object, or doing a read that spans multiple | |
25 | # objects), and stashes the results in a set of local files. | |
26 | # | |
27 | # It also creates and maps a snapshot of the original image after | |
28 | # it's been filled, and reads back the same ranges of data from the | |
29 | # snapshot. It then compares the data read back with what was read | |
30 | # back from the original image, verifying they match. | |
31 | # | |
32 | # Clone functionality is tested as well, in which case a clone is | |
33 | # made of the snapshot, and the same ranges of data are again read | |
34 | # and compared with the original. In addition, a snapshot of that | |
35 | # clone is created, and a clone of *that* snapshot is put through | |
36 | # the same set of tests. (Clone testing can be optionally skipped.) | |
37 | ||
38 | ################################################################ | |
39 | ||
40 | # Default parameter values. Environment variables, if set, will | |
41 | # supercede these defaults. Such variables have names that begin | |
42 | # with "IMAGE_READ_", for e.g. use IMAGE_READ_PAGE_SIZE=65536 | |
43 | # to use 65536 as the page size. | |
11fdf7f2 | 44 | set -e |
7c673cae FG |
45 | |
46 | DEFAULT_VERBOSE=true | |
47 | DEFAULT_TEST_CLONES=true | |
48 | DEFAULT_LOCAL_FILES=false | |
49 | DEFAULT_FORMAT=2 | |
50 | DEFAULT_DOUBLE_ORDER=true | |
51 | DEFAULT_HALF_ORDER=false | |
52 | DEFAULT_PAGE_SIZE=4096 | |
53 | DEFAULT_OBJECT_ORDER=22 | |
54 | MIN_OBJECT_ORDER=12 # technically 9, but the rbd CLI enforces 12 | |
55 | MAX_OBJECT_ORDER=32 | |
56 | ||
11fdf7f2 TL |
57 | RBD_FORCE_ALLOW_V1=1 |
58 | ||
7c673cae FG |
59 | PROGNAME=$(basename $0) |
60 | ||
61 | ORIGINAL=original-$$ | |
62 | SNAP1=snap1-$$ | |
63 | CLONE1=clone1-$$ | |
64 | SNAP2=snap2-$$ | |
65 | CLONE2=clone2-$$ | |
66 | ||
67 | function err() { | |
68 | if [ $# -gt 0 ]; then | |
69 | echo "${PROGNAME}: $@" >&2 | |
70 | fi | |
71 | exit 2 | |
72 | } | |
73 | ||
74 | function usage() { | |
75 | if [ $# -gt 0 ]; then | |
76 | echo "" >&2 | |
77 | echo "${PROGNAME}: $@" >&2 | |
78 | fi | |
79 | echo "" >&2 | |
80 | echo "Usage: ${PROGNAME} [<options>]" >&2 | |
81 | echo "" >&2 | |
82 | echo "options are:" >&2 | |
83 | echo " -o object_order" >&2 | |
84 | echo " must be ${MIN_OBJECT_ORDER}..${MAX_OBJECT_ORDER}" >&2 | |
85 | echo " -p page_size (in bytes)" >&2 | |
86 | echo " note: there must be at least 4 pages per object" >&2 | |
87 | echo " -1" >&2 | |
88 | echo " test using format 1 rbd images (default)" >&2 | |
89 | echo " -2" >&2 | |
90 | echo " test using format 2 rbd images" >&2 | |
91 | echo " -c" >&2 | |
92 | echo " also test rbd clone images (implies format 2)" >&2 | |
93 | echo " -d" >&2 | |
94 | echo " clone object order double its parent's (format 2)" >&2 | |
95 | echo " -h" >&2 | |
96 | echo " clone object order half of its parent's (format 2)" >&2 | |
97 | echo " -l" >&2 | |
98 | echo " use local files rather than rbd images" >&2 | |
99 | echo " -v" >&2 | |
100 | echo " disable reporting of what's going on" >&2 | |
101 | echo "" >&2 | |
102 | exit 1 | |
103 | } | |
104 | ||
105 | function verbose() { | |
106 | [ "${VERBOSE}" = true ] && echo "$@" | |
107 | true # Don't let the verbose test spoil our return value | |
108 | } | |
109 | ||
110 | function quiet() { | |
111 | "$@" 2> /dev/null | |
112 | } | |
113 | ||
114 | function boolean_toggle() { | |
115 | [ $# -eq 1 ] || exit 99 | |
116 | test "$1" = "true" && echo false || echo true | |
117 | } | |
118 | ||
119 | function parseargs() { | |
120 | local opts="o:p:12clv" | |
121 | local lopts="order:,page_size:,local,clone,verbose" | |
122 | local parsed | |
123 | local clone_order_msg | |
124 | ||
125 | # use values from environment if available | |
126 | VERBOSE="${IMAGE_READ_VERBOSE:-${DEFAULT_VERBOSE}}" | |
127 | TEST_CLONES="${IMAGE_READ_TEST_CLONES:-${DEFAULT_TEST_CLONES}}" | |
128 | LOCAL_FILES="${IMAGE_READ_LOCAL_FILES:-${DEFAULT_LOCAL_FILES}}" | |
129 | DOUBLE_ORDER="${IMAGE_READ_DOUBLE_ORDER:-${DEFAULT_DOUBLE_ORDER}}" | |
130 | HALF_ORDER="${IMAGE_READ_HALF_ORDER:-${DEFAULT_HALF_ORDER}}" | |
131 | FORMAT="${IMAGE_READ_FORMAT:-${DEFAULT_FORMAT}}" | |
132 | PAGE_SIZE="${IMAGE_READ_PAGE_SIZE:-${DEFAULT_PAGE_SIZE}}" | |
133 | OBJECT_ORDER="${IMAGE_READ_OBJECT_ORDER:-${DEFAULT_OBJECT_ORDER}}" | |
134 | ||
135 | parsed=$(getopt -o "${opts}" -l "${lopts}" -n "${PROGNAME}" -- "$@") || | |
136 | usage | |
137 | eval set -- "${parsed}" | |
138 | while true; do | |
139 | case "$1" in | |
140 | -v|--verbose) | |
141 | VERBOSE=$(boolean_toggle "${VERBOSE}");; | |
142 | -c|--clone) | |
143 | TEST_CLONES=$(boolean_toggle "${TEST_CLONES}");; | |
144 | -d|--double) | |
145 | DOUBLE_ORDER=$(boolean_toggle "${DOUBLE_ORDER}");; | |
146 | -h|--half) | |
147 | HALF_ORDER=$(boolean_toggle "${HALF_ORDER}");; | |
148 | -l|--local) | |
149 | LOCAL_FILES=$(boolean_toggle "${LOCAL_FILES}");; | |
150 | -1|-2) | |
151 | FORMAT="${1:1}";; | |
152 | -p|--page_size) | |
153 | PAGE_SIZE="$2"; shift;; | |
154 | -o|--order) | |
155 | OBJECT_ORDER="$2"; shift;; | |
156 | --) | |
157 | shift; break;; | |
158 | *) | |
159 | err "getopt internal error" | |
160 | esac | |
161 | shift | |
162 | done | |
163 | [ $# -gt 0 ] && usage "excess arguments ($*)" | |
164 | ||
165 | if [ "${TEST_CLONES}" = true ]; then | |
166 | # If we're using different object orders for clones, | |
167 | # make sure the limits are updated accordingly. If | |
168 | # both "half" and "double" are specified, just | |
169 | # ignore them both. | |
170 | if [ "${DOUBLE_ORDER}" = true ]; then | |
171 | if [ "${HALF_ORDER}" = true ]; then | |
172 | DOUBLE_ORDER=false | |
173 | HALF_ORDER=false | |
174 | else | |
175 | ((MAX_OBJECT_ORDER -= 2)) | |
176 | fi | |
177 | elif [ "${HALF_ORDER}" = true ]; then | |
178 | ((MIN_OBJECT_ORDER += 2)) | |
179 | fi | |
180 | fi | |
181 | ||
182 | [ "${OBJECT_ORDER}" -lt "${MIN_OBJECT_ORDER}" ] && | |
183 | usage "object order (${OBJECT_ORDER}) must be" \ | |
184 | "at least ${MIN_OBJECT_ORDER}" | |
185 | [ "${OBJECT_ORDER}" -gt "${MAX_OBJECT_ORDER}" ] && | |
186 | usage "object order (${OBJECT_ORDER}) must be" \ | |
187 | "at most ${MAX_OBJECT_ORDER}" | |
188 | ||
189 | if [ "${TEST_CLONES}" = true ]; then | |
190 | if [ "${DOUBLE_ORDER}" = true ]; then | |
191 | ((CLONE1_ORDER = OBJECT_ORDER + 1)) | |
192 | ((CLONE2_ORDER = OBJECT_ORDER + 2)) | |
193 | clone_order_msg="double" | |
194 | elif [ "${HALF_ORDER}" = true ]; then | |
195 | ((CLONE1_ORDER = OBJECT_ORDER - 1)) | |
196 | ((CLONE2_ORDER = OBJECT_ORDER - 2)) | |
197 | clone_order_msg="half of" | |
198 | else | |
199 | CLONE1_ORDER="${OBJECT_ORDER}" | |
200 | CLONE2_ORDER="${OBJECT_ORDER}" | |
201 | clone_order_msg="the same as" | |
202 | fi | |
203 | fi | |
204 | ||
205 | [ "${TEST_CLONES}" != true ] || FORMAT=2 | |
206 | ||
207 | OBJECT_SIZE=$(echo "2 ^ ${OBJECT_ORDER}" | bc) | |
208 | OBJECT_PAGES=$(echo "${OBJECT_SIZE} / ${PAGE_SIZE}" | bc) | |
209 | IMAGE_SIZE=$((2 * 16 * OBJECT_SIZE / (1024 * 1024))) | |
210 | [ "${IMAGE_SIZE}" -lt 1 ] && IMAGE_SIZE=1 | |
211 | IMAGE_OBJECTS=$((IMAGE_SIZE * (1024 * 1024) / OBJECT_SIZE)) | |
212 | ||
213 | [ "${OBJECT_PAGES}" -lt 4 ] && | |
214 | usage "object size (${OBJECT_SIZE}) must be" \ | |
215 | "at least 4 * page size (${PAGE_SIZE})" | |
216 | ||
217 | echo "parameters for this run:" | |
218 | echo " format ${FORMAT} images will be tested" | |
219 | echo " object order is ${OBJECT_ORDER}, so" \ | |
220 | "objects are ${OBJECT_SIZE} bytes" | |
221 | echo " page size is ${PAGE_SIZE} bytes, so" \ | |
222 | "there are are ${OBJECT_PAGES} pages in an object" | |
223 | echo " derived image size is ${IMAGE_SIZE} MB, so" \ | |
224 | "there are ${IMAGE_OBJECTS} objects in an image" | |
225 | if [ "${TEST_CLONES}" = true ]; then | |
226 | echo " clone functionality will be tested" | |
227 | echo " object size for a clone will be ${clone_order_msg}" | |
228 | echo " the object size of its parent image" | |
229 | fi | |
230 | ||
231 | true # Don't let the clones test spoil our return value | |
232 | } | |
233 | ||
234 | function image_dev_path() { | |
235 | [ $# -eq 1 ] || exit 99 | |
236 | local image_name="$1" | |
237 | ||
238 | if [ "${LOCAL_FILES}" = true ]; then | |
239 | echo "${TEMP}/${image_name}" | |
240 | return | |
241 | fi | |
242 | ||
243 | echo "/dev/rbd/rbd/${image_name}" | |
244 | } | |
245 | ||
246 | function out_data_dir() { | |
247 | [ $# -lt 2 ] || exit 99 | |
248 | local out_data="${TEMP}/data" | |
249 | local image_name | |
250 | ||
251 | if [ $# -eq 1 ]; then | |
252 | image_name="$1" | |
253 | echo "${out_data}/${image_name}" | |
254 | else | |
255 | echo "${out_data}" | |
256 | fi | |
257 | } | |
258 | ||
259 | function setup() { | |
260 | verbose "===== setting up =====" | |
261 | TEMP=$(mktemp -d /tmp/rbd_image_read.XXXXX) | |
262 | mkdir -p $(out_data_dir) | |
263 | ||
264 | # create and fill the original image with some data | |
265 | create_image "${ORIGINAL}" | |
266 | map_image "${ORIGINAL}" | |
267 | fill_original | |
268 | ||
269 | # create a snapshot of the original | |
270 | create_image_snap "${ORIGINAL}" "${SNAP1}" | |
271 | map_image_snap "${ORIGINAL}" "${SNAP1}" | |
272 | ||
273 | if [ "${TEST_CLONES}" = true ]; then | |
274 | # create a clone of the original snapshot | |
275 | create_snap_clone "${ORIGINAL}" "${SNAP1}" \ | |
276 | "${CLONE1}" "${CLONE1_ORDER}" | |
277 | map_image "${CLONE1}" | |
278 | ||
279 | # create a snapshot of that clone | |
280 | create_image_snap "${CLONE1}" "${SNAP2}" | |
281 | map_image_snap "${CLONE1}" "${SNAP2}" | |
282 | ||
283 | # create a clone of that clone's snapshot | |
284 | create_snap_clone "${CLONE1}" "${SNAP2}" \ | |
285 | "${CLONE2}" "${CLONE2_ORDER}" | |
286 | map_image "${CLONE2}" | |
287 | fi | |
288 | } | |
289 | ||
290 | function teardown() { | |
291 | verbose "===== cleaning up =====" | |
292 | if [ "${TEST_CLONES}" = true ]; then | |
293 | unmap_image "${CLONE2}" || true | |
294 | destroy_snap_clone "${CLONE1}" "${SNAP2}" "${CLONE2}" || true | |
295 | ||
296 | unmap_image_snap "${CLONE1}" "${SNAP2}" || true | |
297 | destroy_image_snap "${CLONE1}" "${SNAP2}" || true | |
298 | ||
299 | unmap_image "${CLONE1}" || true | |
300 | destroy_snap_clone "${ORIGINAL}" "${SNAP1}" "${CLONE1}" || true | |
301 | fi | |
302 | unmap_image_snap "${ORIGINAL}" "${SNAP1}" || true | |
303 | destroy_image_snap "${ORIGINAL}" "${SNAP1}" || true | |
304 | unmap_image "${ORIGINAL}" || true | |
305 | destroy_image "${ORIGINAL}" || true | |
306 | ||
307 | rm -rf $(out_data_dir) | |
308 | rmdir "${TEMP}" | |
309 | } | |
310 | ||
311 | function create_image() { | |
312 | [ $# -eq 1 ] || exit 99 | |
313 | local image_name="$1" | |
314 | local image_path | |
315 | local bytes | |
316 | ||
317 | verbose "creating image \"${image_name}\"" | |
318 | if [ "${LOCAL_FILES}" = true ]; then | |
319 | image_path=$(image_dev_path "${image_name}") | |
320 | bytes=$(echo "${IMAGE_SIZE} * 1024 * 1024 - 1" | bc) | |
321 | quiet dd if=/dev/zero bs=1 count=1 seek="${bytes}" \ | |
322 | of="${image_path}" | |
323 | return | |
324 | fi | |
325 | ||
326 | rbd create "${image_name}" --image-format "${FORMAT}" \ | |
327 | --size "${IMAGE_SIZE}" --order "${OBJECT_ORDER}" \ | |
328 | --image-shared | |
329 | } | |
330 | ||
331 | function destroy_image() { | |
332 | [ $# -eq 1 ] || exit 99 | |
333 | local image_name="$1" | |
334 | local image_path | |
335 | ||
336 | verbose "destroying image \"${image_name}\"" | |
337 | if [ "${LOCAL_FILES}" = true ]; then | |
338 | image_path=$(image_dev_path "${image_name}") | |
339 | rm -f "${image_path}" | |
340 | return | |
341 | fi | |
342 | ||
343 | rbd rm "${image_name}" | |
344 | } | |
345 | ||
346 | function map_image() { | |
347 | [ $# -eq 1 ] || exit 99 | |
348 | local image_name="$1" # can be image@snap too | |
349 | ||
350 | if [ "${LOCAL_FILES}" = true ]; then | |
351 | return | |
352 | fi | |
353 | ||
354 | sudo rbd map "${image_name}" | |
355 | } | |
356 | ||
357 | function unmap_image() { | |
358 | [ $# -eq 1 ] || exit 99 | |
359 | local image_name="$1" # can be image@snap too | |
360 | local image_path | |
361 | ||
362 | if [ "${LOCAL_FILES}" = true ]; then | |
363 | return | |
364 | fi | |
365 | image_path=$(image_dev_path "${image_name}") | |
366 | ||
367 | if [ -e "${image_path}" ]; then | |
368 | sudo rbd unmap "${image_path}" | |
369 | fi | |
370 | } | |
371 | ||
372 | function map_image_snap() { | |
373 | [ $# -eq 2 ] || exit 99 | |
374 | local image_name="$1" | |
375 | local snap_name="$2" | |
376 | local image_snap | |
377 | ||
378 | if [ "${LOCAL_FILES}" = true ]; then | |
379 | return | |
380 | fi | |
381 | ||
382 | image_snap="${image_name}@${snap_name}" | |
383 | map_image "${image_snap}" | |
384 | } | |
385 | ||
386 | function unmap_image_snap() { | |
387 | [ $# -eq 2 ] || exit 99 | |
388 | local image_name="$1" | |
389 | local snap_name="$2" | |
390 | local image_snap | |
391 | ||
392 | if [ "${LOCAL_FILES}" = true ]; then | |
393 | return | |
394 | fi | |
395 | ||
396 | image_snap="${image_name}@${snap_name}" | |
397 | unmap_image "${image_snap}" | |
398 | } | |
399 | ||
400 | function create_image_snap() { | |
401 | [ $# -eq 2 ] || exit 99 | |
402 | local image_name="$1" | |
403 | local snap_name="$2" | |
404 | local image_snap="${image_name}@${snap_name}" | |
405 | local image_path | |
406 | local snap_path | |
407 | ||
408 | verbose "creating snapshot \"${snap_name}\"" \ | |
409 | "of image \"${image_name}\"" | |
410 | if [ "${LOCAL_FILES}" = true ]; then | |
411 | image_path=$(image_dev_path "${image_name}") | |
412 | snap_path=$(image_dev_path "${image_snap}") | |
413 | ||
414 | cp "${image_path}" "${snap_path}" | |
415 | return | |
416 | fi | |
417 | ||
418 | rbd snap create "${image_snap}" | |
419 | } | |
420 | ||
421 | function destroy_image_snap() { | |
422 | [ $# -eq 2 ] || exit 99 | |
423 | local image_name="$1" | |
424 | local snap_name="$2" | |
425 | local image_snap="${image_name}@${snap_name}" | |
426 | local snap_path | |
427 | ||
428 | verbose "destroying snapshot \"${snap_name}\"" \ | |
429 | "of image \"${image_name}\"" | |
430 | if [ "${LOCAL_FILES}" = true ]; then | |
431 | snap_path=$(image_dev_path "${image_snap}") | |
432 | rm -rf "${snap_path}" | |
433 | return | |
434 | fi | |
435 | ||
436 | rbd snap rm "${image_snap}" | |
437 | } | |
438 | ||
439 | function create_snap_clone() { | |
440 | [ $# -eq 4 ] || exit 99 | |
441 | local image_name="$1" | |
442 | local snap_name="$2" | |
443 | local clone_name="$3" | |
444 | local clone_order="$4" | |
445 | local image_snap="${image_name}@${snap_name}" | |
446 | local snap_path | |
447 | local clone_path | |
448 | ||
449 | verbose "creating clone image \"${clone_name}\"" \ | |
450 | "of image snapshot \"${image_name}@${snap_name}\"" | |
451 | if [ "${LOCAL_FILES}" = true ]; then | |
452 | snap_path=$(image_dev_path "${image_name}@${snap_name}") | |
453 | clone_path=$(image_dev_path "${clone_name}") | |
454 | ||
455 | cp "${snap_path}" "${clone_path}" | |
456 | return | |
457 | fi | |
458 | ||
459 | rbd snap protect "${image_snap}" | |
460 | rbd clone --order "${clone_order}" --image-shared \ | |
461 | "${image_snap}" "${clone_name}" | |
462 | } | |
463 | ||
464 | function destroy_snap_clone() { | |
465 | [ $# -eq 3 ] || exit 99 | |
466 | local image_name="$1" | |
467 | local snap_name="$2" | |
468 | local clone_name="$3" | |
469 | local image_snap="${image_name}@${snap_name}" | |
470 | local clone_path | |
471 | ||
472 | verbose "destroying clone image \"${clone_name}\"" | |
473 | if [ "${LOCAL_FILES}" = true ]; then | |
474 | clone_path=$(image_dev_path "${clone_name}") | |
475 | ||
476 | rm -rf "${clone_path}" | |
477 | return | |
478 | fi | |
479 | ||
480 | rbd rm "${clone_name}" | |
481 | rbd snap unprotect "${image_snap}" | |
482 | } | |
483 | ||
484 | # function that produces "random" data with which to fill the image | |
485 | function source_data() { | |
486 | while quiet dd if=/bin/bash skip=$(($$ % 199)) bs="${PAGE_SIZE}"; do | |
487 | : # Just do the dd | |
488 | done | |
489 | } | |
490 | ||
491 | function fill_original() { | |
492 | local image_path=$(image_dev_path "${ORIGINAL}") | |
493 | ||
494 | verbose "filling original image" | |
495 | # Fill 16 objects worth of "random" data | |
496 | source_data | | |
497 | quiet dd bs="${PAGE_SIZE}" count=$((16 * OBJECT_PAGES)) \ | |
498 | of="${image_path}" | |
499 | } | |
500 | ||
501 | function do_read() { | |
502 | [ $# -eq 3 -o $# -eq 4 ] || exit 99 | |
503 | local image_name="$1" | |
504 | local offset="$2" | |
505 | local length="$3" | |
506 | [ "${length}" -gt 0 ] || err "do_read: length must be non-zero" | |
507 | local image_path=$(image_dev_path "${image_name}") | |
508 | local out_data=$(out_data_dir "${image_name}") | |
509 | local range=$(printf "%06u~%04u" "${offset}" "${length}") | |
510 | local out_file | |
511 | ||
512 | [ $# -eq 4 ] && offset=$((offset + 16 * OBJECT_PAGES)) | |
513 | ||
514 | verbose "reading \"${image_name}\" pages ${range}" | |
515 | ||
516 | out_file="${out_data}/pages_${range}" | |
517 | ||
518 | quiet dd bs="${PAGE_SIZE}" skip="${offset}" count="${length}" \ | |
519 | if="${image_path}" of="${out_file}" | |
520 | } | |
521 | ||
522 | function one_pass() { | |
523 | [ $# -eq 1 -o $# -eq 2 ] || exit 99 | |
524 | local image_name="$1" | |
525 | local extended | |
526 | [ $# -eq 2 ] && extended="true" | |
527 | local offset | |
528 | local length | |
529 | ||
530 | offset=0 | |
531 | ||
532 | # +-----------+-----------+--- | |
533 | # |X:X:X...X:X| : : ... : | : | |
534 | # +-----------+-----------+--- | |
535 | length="${OBJECT_PAGES}" | |
536 | do_read "${image_name}" "${offset}" "${length}" ${extended} | |
537 | offset=$((offset + length)) | |
538 | ||
539 | # ---+-----------+--- | |
540 | # : |X: : ... : | : | |
541 | # ---+-----------+--- | |
542 | length=1 | |
543 | do_read "${image_name}" "${offset}" "${length}" ${extended} | |
544 | offset=$((offset + length)) | |
545 | ||
546 | # ---+-----------+--- | |
547 | # : | :X: ... : | : | |
548 | # ---+-----------+--- | |
549 | length=1 | |
550 | do_read "${image_name}" "${offset}" "${length}" ${extended} | |
551 | offset=$((offset + length)) | |
552 | ||
553 | # ---+-----------+--- | |
554 | # : | : :X...X: | : | |
555 | # ---+-----------+--- | |
556 | length=$((OBJECT_PAGES - 3)) | |
557 | do_read "${image_name}" "${offset}" "${length}" ${extended} | |
558 | offset=$((offset + length)) | |
559 | ||
560 | # ---+-----------+--- | |
561 | # : | : : ... :X| : | |
562 | # ---+-----------+--- | |
563 | length=1 | |
564 | do_read "${image_name}" "${offset}" "${length}" ${extended} | |
565 | offset=$((offset + length)) | |
566 | ||
567 | # ---+-----------+--- | |
568 | # : |X:X:X...X:X| : | |
569 | # ---+-----------+--- | |
570 | length="${OBJECT_PAGES}" | |
571 | do_read "${image_name}" "${offset}" "${length}" ${extended} | |
572 | offset=$((offset + length)) | |
573 | ||
574 | offset=$((offset + 1)) # skip 1 | |
575 | ||
576 | # ---+-----------+--- | |
577 | # : | :X:X...X:X| : | |
578 | # ---+-----------+--- | |
579 | length=$((OBJECT_PAGES - 1)) | |
580 | do_read "${image_name}" "${offset}" "${length}" ${extended} | |
581 | offset=$((offset + length)) | |
582 | ||
583 | # ---+-----------+-----------+--- | |
584 | # : |X:X:X...X:X|X: : ... : | : | |
585 | # ---+-----------+-----------+--- | |
586 | length=$((OBJECT_PAGES + 1)) | |
587 | do_read "${image_name}" "${offset}" "${length}" ${extended} | |
588 | offset=$((offset + length)) | |
589 | ||
590 | # ---+-----------+-----------+--- | |
591 | # : | :X:X...X:X|X: : ... : | : | |
592 | # ---+-----------+-----------+--- | |
593 | length="${OBJECT_PAGES}" | |
594 | do_read "${image_name}" "${offset}" "${length}" ${extended} | |
595 | offset=$((offset + length)) | |
596 | ||
597 | # ---+-----------+-----------+--- | |
598 | # : | :X:X...X:X|X:X: ... : | : | |
599 | # ---+-----------+-----------+--- | |
600 | length=$((OBJECT_PAGES + 1)) | |
601 | do_read "${image_name}" "${offset}" "${length}" ${extended} | |
602 | offset=$((offset + length)) | |
603 | ||
604 | # ---+-----------+-----------+--- | |
605 | # : | : :X...X:X|X:X:X...X:X| : | |
606 | # ---+-----------+-----------+--- | |
607 | length=$((2 * OBJECT_PAGES + 2)) | |
608 | do_read "${image_name}" "${offset}" "${length}" ${extended} | |
609 | offset=$((offset + length)) | |
610 | ||
611 | offset=$((offset + 1)) # skip 1 | |
612 | ||
613 | # ---+-----------+-----------+----- | |
614 | # : | :X:X...X:X|X:X:X...X:X|X: : | |
615 | # ---+-----------+-----------+----- | |
616 | length=$((2 * OBJECT_PAGES)) | |
617 | do_read "${image_name}" "${offset}" "${length}" ${extended} | |
618 | offset=$((offset + length)) | |
619 | ||
620 | # --+-----------+-----------+-------- | |
621 | # : | :X:X...X:X|X:X:X...X:X|X:X: : | |
622 | # --+-----------+-----------+-------- | |
623 | length=2049 | |
624 | length=$((2 * OBJECT_PAGES + 1)) | |
625 | do_read "${image_name}" "${offset}" "${length}" ${extended} | |
626 | # offset=$((offset + length)) | |
627 | } | |
628 | ||
629 | function run_using() { | |
630 | [ $# -eq 1 ] || exit 99 | |
631 | local image_name="$1" | |
632 | local out_data=$(out_data_dir "${image_name}") | |
633 | ||
634 | verbose "===== running using \"${image_name}\" =====" | |
635 | mkdir -p "${out_data}" | |
636 | one_pass "${image_name}" | |
637 | one_pass "${image_name}" extended | |
638 | } | |
639 | ||
640 | function compare() { | |
641 | [ $# -eq 1 ] || exit 99 | |
642 | local image_name="$1" | |
643 | local out_data=$(out_data_dir "${image_name}") | |
644 | local original=$(out_data_dir "${ORIGINAL}") | |
645 | ||
646 | verbose "===== comparing \"${image_name}\" =====" | |
647 | for i in $(ls "${original}"); do | |
648 | verbose compare "\"${image_name}\" \"${i}\"" | |
649 | cmp "${original}/${i}" "${out_data}/${i}" | |
650 | done | |
651 | [ "${image_name}" = "${ORIGINAL}" ] || rm -rf "${out_data}" | |
652 | } | |
653 | ||
654 | function doit() { | |
655 | [ $# -eq 1 ] || exit 99 | |
656 | local image_name="$1" | |
657 | ||
658 | run_using "${image_name}" | |
659 | compare "${image_name}" | |
660 | } | |
661 | ||
662 | ########## Start | |
663 | ||
664 | parseargs "$@" | |
665 | ||
666 | trap teardown EXIT HUP INT | |
667 | setup | |
668 | ||
669 | run_using "${ORIGINAL}" | |
670 | doit "${ORIGINAL}@${SNAP1}" | |
671 | if [ "${TEST_CLONES}" = true ]; then | |
672 | doit "${CLONE1}" | |
673 | doit "${CLONE1}@${SNAP2}" | |
674 | doit "${CLONE2}" | |
675 | fi | |
676 | rm -rf $(out_data_dir "${ORIGINAL}") | |
677 | ||
678 | echo "Success!" | |
679 | ||
680 | exit 0 |