xref: /xnu-8020.121.3/bsd/dev/vn/shadow.c (revision fdd8201d7b966f0c3ea610489d29bd841d358941)
1 /*
2  * Copyright (c) 2001-2006 Apple Computer, Inc. All rights reserved.
3  *
4  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5  *
6  * This file contains Original Code and/or Modifications of Original Code
7  * as defined in and that are subject to the Apple Public Source License
8  * Version 2.0 (the 'License'). You may not use this file except in
9  * compliance with the License. The rights granted to you under the License
10  * may not be used to create, or enable the creation or redistribution of,
11  * unlawful or unlicensed copies of an Apple operating system, or to
12  * circumvent, violate, or enable the circumvention or violation of, any
13  * terms of an Apple operating system software license agreement.
14  *
15  * Please obtain a copy of the License at
16  * http://www.opensource.apple.com/apsl/ and read it before using this file.
17  *
18  * The Original Code and all software distributed under the License are
19  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23  * Please see the License for the specific language governing rights and
24  * limitations under the License.
25  *
26  * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27  */
28 
29 /*
30  * shadow.c
31  *
32  * Implement copy-on-write shadow map to allow a disk image to be
33  * mounted read-only, yet be writable by transferring writes to a
34  * "shadow" file.  Subsequent reads from blocks that have been
35  * written will then go the "shadow" file.
36  *
37  * The map has two parts:
38  * 1) a bit map to track which blocks have been written
39  * 2) a band map to map a "band" within the original file to a corresponding
40  *    "band" in the shadow file.  Each band has the same size.
41  *
42  * The band map is used to ensure that blocks that are contiguous in the
43  * original file will remain contiguous in the shadow file.
44  *
45  * For debugging purposes, this file can be compiled standalone using:
46  * cc -o shadow shadow.c -DTEST_SHADOW
47  */
48 
49 /*
50  * Modification History
51  *
52  * December 21, 2001    Dieter Siegmund ([email protected])
53  * - initial revision
54  */
55 #include <sys/param.h>
56 #include <sys/types.h>
57 #include <mach/boolean.h>
58 
59 #include <string.h>
60 
61 #ifdef TEST_SHADOW
62 #include <unistd.h>
63 #include <stdlib.h>
64 #else /* !TEST_SHADOW */
65 #include <sys/malloc.h>
66 #include <libkern/libkern.h>
67 #endif /* TEST_SHADOW */
68 
69 #include "shadow.h"
70 
71 #define UINT32_ALL_ONES                 ((uint32_t)(-1))
72 #define USHORT_ALL_ONES                 ((u_short)(-1))
73 #define UCHAR_ALL_ONES                  ((u_char)(-1))
74 
75 #define my_trunc(value, divisor)        ((value) / (divisor) * (divisor))
76 
77 /* a band size of 128K can represent a file up to 8GB */
78 #define BAND_SIZE_DEFAULT_POWER_2       17
79 #define BAND_SIZE_DEFAULT               (1 << BAND_SIZE_DEFAULT_POWER_2)
80 
81 typedef u_short band_number_t;
82 #define BAND_ZERO                       ((band_number_t)0)
83 #define BAND_MAX                        ((band_number_t)65535)
84 
85 struct shadow_map {
86 	uint32_t            blocks_per_band;/* size in blocks */
87 	uint32_t            block_size;
88 	u_char *            block_bitmap;       /* 1 bit per block; 1=written */
89 	band_number_t *     bands;              /* band map array */
90 	uint32_t            file_size_blocks;   /* size of file in bands */
91 	uint32_t            shadow_size_bands;  /* size of shadow in bands */
92 	uint32_t            next_band;          /* next free band */
93 	uint32_t            zeroth_band;        /* special-case 0th band */
94 };
95 
96 
97 typedef struct {
98 	uint64_t    byte;
99 	uint32_t    bit;
100 } bitmap_offset_t;
101 
102 static __inline__ u_char
bit(int b)103 bit(int b)
104 {
105 	return (u_char)(1 << b);
106 }
107 
108 /*
109  * Function: bits_lower
110  * Purpose:
111  *   Return a byte value in which bits numbered lower than 'b' are set.
112  */
113 static __inline__ u_char
bits_lower(int b)114 bits_lower(int b)
115 {
116 	return (u_char)(bit(b) - 1);
117 }
118 
119 /*
120  * Function: byte_set_bits
121  * Purpose:
122  *   Set the given range of bits within a byte.
123  */
124 static __inline__ u_char
byte_set_bits(int start,int end)125 byte_set_bits(int start, int end)
126 {
127 	return (u_char)((~bits_lower(start)) & (bits_lower(end) | bit(end)));
128 }
129 
130 static __inline__ bitmap_offset_t
bitmap_offset(off_t where)131 bitmap_offset(off_t where)
132 {
133 	bitmap_offset_t     b;
134 
135 	b.byte = where / NBBY;
136 	b.bit = where % NBBY;
137 	return b;
138 }
139 
140 /*
141  * Function: bitmap_set
142  *
143  * Purpose:
144  *   Set the given range of bits.
145  *
146  *   This algorithm tries to set the extents using the biggest
147  *   units, using longs, then a short, then a byte, then bits.
148  */
149 static void
bitmap_set(u_char * map,off_t start_bit,size_t bit_count)150 bitmap_set(u_char * map, off_t start_bit, size_t bit_count)
151 {
152 	bitmap_offset_t     start;
153 	bitmap_offset_t     end;
154 
155 	start = bitmap_offset(start_bit);
156 	end = bitmap_offset(start_bit + bit_count);
157 	if (start.byte < end.byte) {
158 		uint64_t n_bytes;
159 
160 		if (start.bit) {
161 			map[start.byte] |= byte_set_bits(start.bit, NBBY - 1);
162 			start.bit = 0;
163 			start.byte++;
164 			if (start.byte == end.byte) {
165 				goto end;
166 			}
167 		}
168 
169 		n_bytes = end.byte - start.byte;
170 
171 		while (n_bytes >= (sizeof(uint32_t))) {
172 			*((uint32_t *)(map + start.byte)) = UINT32_ALL_ONES;
173 			start.byte += sizeof(uint32_t);
174 			n_bytes -= sizeof(uint32_t);
175 		}
176 		if (n_bytes >= sizeof(u_short)) {
177 			*((u_short *)(map + start.byte)) = USHORT_ALL_ONES;
178 			start.byte += sizeof(u_short);
179 			n_bytes -= sizeof(u_short);
180 		}
181 		if (n_bytes == 1) {
182 			map[start.byte] = UCHAR_ALL_ONES;
183 			start.byte++;
184 			n_bytes = 0;
185 		}
186 	}
187 
188 end:
189 	if (end.bit > start.bit) {
190 		map[start.byte] |= byte_set_bits(start.bit, end.bit - 1);
191 	}
192 
193 	return;
194 }
195 
196 /*
197  * Function: bitmap_get
198  *
199  * Purpose:
200  *   Return the number of bits in the range that are the same e.g.
201  *   11101 returns 3 because the first 3 bits are the same (1's), whereas
202  *   001100 returns 2 because the first 2 bits are the same.
203  *   This algorithm tries to count things in as big a chunk as possible,
204  *   first aligning to a byte offset, then trying to count longs, a short,
205  *   a byte, then any remaining bits to find the bit that is different.
206  */
207 
208 static uint32_t
bitmap_get(u_char * map,off_t start_bit,size_t bit_count,boolean_t * ret_is_set)209 bitmap_get(u_char * map, off_t start_bit, size_t bit_count,
210     boolean_t * ret_is_set)
211 {
212 	uint32_t            count;
213 	int                 i;
214 	boolean_t           is_set;
215 	bitmap_offset_t     start;
216 	bitmap_offset_t     end;
217 
218 	start = bitmap_offset(start_bit);
219 	end = bitmap_offset(start_bit + bit_count);
220 
221 	is_set = (map[start.byte] & bit(start.bit)) ? TRUE : FALSE;
222 	count = 0;
223 
224 	if (start.byte < end.byte) {
225 		uint64_t n_bytes;
226 
227 		if (start.bit) { /* try to align to a byte */
228 			for (i = start.bit; i < NBBY; i++) {
229 				boolean_t       this_is_set;
230 
231 				this_is_set = (map[start.byte] & bit(i)) ? TRUE : FALSE;
232 				if (this_is_set != is_set) {
233 					goto done; /* found bit that was different, we're done */
234 				}
235 				count++;
236 			}
237 			start.bit = 0; /* made it to the next byte */
238 			start.byte++;
239 			if (start.byte == end.byte) {
240 				goto end; /* no more bytes, check for any leftover bits */
241 			}
242 		}
243 		/* calculate how many bytes are left in the range */
244 		n_bytes = end.byte - start.byte;
245 
246 		/* check for 4 bytes of the same bits */
247 		while (n_bytes >= sizeof(uint32_t)) {
248 			uint32_t * valPtr = (uint32_t *)(map + start.byte);
249 			if ((is_set && *valPtr == UINT32_ALL_ONES)
250 			    || (!is_set && *valPtr == 0)) {
251 				count += sizeof(*valPtr) * NBBY;
252 				start.byte += sizeof(*valPtr);
253 				n_bytes -= sizeof(*valPtr);
254 			} else {
255 				break; /* bits differ */
256 			}
257 		}
258 		/* check for 2 bytes of the same bits */
259 		if (n_bytes >= sizeof(u_short)) {
260 			u_short * valPtr = (u_short *)(map + start.byte);
261 
262 			if ((is_set && *valPtr == USHORT_ALL_ONES)
263 			    || (!is_set && (*valPtr == 0))) {
264 				count += sizeof(*valPtr) * NBBY;
265 				start.byte += sizeof(*valPtr);
266 				n_bytes -= sizeof(*valPtr);
267 			}
268 		}
269 
270 		/* check for 1 byte of the same bits */
271 		if (n_bytes) {
272 			if ((is_set && map[start.byte] == UCHAR_ALL_ONES)
273 			    || (!is_set && map[start.byte] == 0)) {
274 				count += NBBY;
275 				start.byte++;
276 				n_bytes--;
277 			}
278 			/* we found bits that were different, find the first one */
279 			if (n_bytes) {
280 				for (i = 0; i < NBBY; i++) {
281 					boolean_t   this_is_set;
282 
283 					this_is_set = (map[start.byte] & bit(i)) ? TRUE : FALSE;
284 					if (this_is_set != is_set) {
285 						break;
286 					}
287 					count++;
288 				}
289 				goto done;
290 			}
291 		}
292 	}
293 
294 end:
295 	for (i = start.bit; i < (int)end.bit; i++) {
296 		boolean_t this_is_set = (map[start.byte] & bit(i)) ? TRUE : FALSE;
297 
298 		if (this_is_set != is_set) {
299 			break;
300 		}
301 		count++;
302 	}
303 
304 done:
305 	*ret_is_set = is_set;
306 	return count;
307 }
308 
309 static __inline__ band_number_t
shadow_map_block_to_band(shadow_map_t * map,off_t block)310 shadow_map_block_to_band(shadow_map_t * map, off_t block)
311 {
312 	return (band_number_t)(block / map->blocks_per_band);
313 }
314 
315 /*
316  * Function: shadow_map_mapped_band
317  * Purpose:
318  *   Return the mapped band for the given band.
319  *   If map_it is FALSE, and the band is not mapped, return FALSE.
320  *   If map_it is TRUE, then this function will always return TRUE.
321  */
322 static boolean_t
shadow_map_mapped_band(shadow_map_t * map,band_number_t band,boolean_t map_it,band_number_t * mapped_band)323 shadow_map_mapped_band(shadow_map_t * map, band_number_t band,
324     boolean_t map_it, band_number_t * mapped_band)
325 {
326 	boolean_t           is_mapped = FALSE;
327 
328 	if (band == map->zeroth_band) {
329 		*mapped_band = BAND_ZERO;
330 		is_mapped = TRUE;
331 	} else {
332 		*mapped_band = map->bands[band];
333 		if (*mapped_band == BAND_ZERO) {
334 			if (map_it) {
335 				/* grow the file */
336 				if (map->next_band == 0) {
337 					/* remember the zero'th band */
338 					map->zeroth_band = band;
339 				}
340 				*mapped_band = map->bands[band] = (band_number_t)map->next_band++;
341 				is_mapped = TRUE;
342 			}
343 		} else {
344 			is_mapped = TRUE;
345 		}
346 	}
347 	return is_mapped;
348 }
349 
350 /*
351  * Function: shadow_map_contiguous
352  *
353  * Purpose:
354  *   Return the first offset within the range position..(position + count)
355  *   that is not a contiguous mapped band.
356  *
357  *   If called with is_write = TRUE, this function will map bands as it goes.
358  */
359 static off_t
shadow_map_contiguous(shadow_map_t * map,off_t start_block,size_t num_blocks,boolean_t is_write)360 shadow_map_contiguous(shadow_map_t * map, off_t start_block,
361     size_t num_blocks, boolean_t is_write)
362 {
363 	band_number_t       band = shadow_map_block_to_band(map, start_block);
364 	off_t               end_block = start_block + num_blocks;
365 	boolean_t           is_mapped;
366 	band_number_t       mapped_band;
367 	off_t               ret_end_block = end_block;
368 	off_t               p;
369 
370 	is_mapped = shadow_map_mapped_band(map, band, is_write, &mapped_band);
371 	if (is_write == FALSE && is_mapped == FALSE) {
372 		static int happened = 0;
373 		/* this can't happen */
374 		if (happened == 0) {
375 			printf("shadow_map_contiguous: this can't happen!\n");
376 			happened = 1;
377 		}
378 		return start_block;
379 	}
380 	for (p = my_trunc(start_block + map->blocks_per_band,
381 	    map->blocks_per_band);
382 	    p < end_block; p += map->blocks_per_band) {
383 		band_number_t   next_mapped_band;
384 
385 		band++;
386 		is_mapped = shadow_map_mapped_band(map, band, is_write,
387 		    &next_mapped_band);
388 		if (is_write == FALSE && is_mapped == FALSE) {
389 			return p;
390 		}
391 		if ((mapped_band + 1) != next_mapped_band) {
392 			/* not contiguous */
393 			ret_end_block = p;
394 			break;
395 		}
396 		mapped_band = next_mapped_band;
397 	}
398 	return ret_end_block;
399 }
400 
401 
402 /*
403  * Function: block_bitmap_size
404  * Purpose:
405  *   The number of bytes required in a block bitmap to represent a file of size
406  *   file_size.
407  *
408  *   The bytes required is the number of blocks in the file,
409  *   divided by the number of bits per byte.
410  * Note:
411  *   An 8GB file requires (assuming 512 byte block):
412  *   2^33 / 2^9 / 2^3 = 2^21 = 2MB
413  *   of bitmap space.  This is a non-trival amount of memory,
414  *   particularly since most of the bits will be zero.
415  *   A sparse bitmap would really help in this case.
416  */
417 static __inline__ size_t
block_bitmap_size(off_t file_size,uint32_t block_size)418 block_bitmap_size(off_t file_size, uint32_t block_size)
419 {
420 	off_t blocks = howmany(file_size, block_size);
421 	return howmany(blocks, NBBY);
422 }
423 
424 /*
425  * Function: shadow_map_read
426  *
427  * Purpose:
428  *   Calculate the block offset within the shadow to read, and the number
429  *   blocks to read.  The input values (block_offset, block_count) refer
430  *   to the original file.
431  *
432  *   The output values (*incr_block_offset, *incr_block_count) refer to the
433  *   shadow file if the return value is TRUE.  They refer to the original
434  *   file if the return value is FALSE.
435  *
436  *   Blocks within a band may or may not have been written, in addition,
437  *   Bands are not necessarily contiguous, therefore:
438  *      *incr_block_count <= block_count
439  *   The caller must be prepared to call this function interatively
440  *   to complete the whole i/o.
441  * Returns:
442  *   TRUE if the shadow file should be read, FALSE if the original file
443  *   should be read.
444  */
445 boolean_t
shadow_map_read(shadow_map_t * map,off_t block_offset,size_t block_count,off_t * incr_block_offset,size_t * incr_block_count)446 shadow_map_read(shadow_map_t * map, off_t block_offset, size_t block_count,
447     off_t * incr_block_offset, size_t * incr_block_count)
448 {
449 	boolean_t           written = FALSE;
450 	uint32_t            n_blocks;
451 
452 	if (block_offset >= map->file_size_blocks
453 	    || (block_offset + block_count) > map->file_size_blocks) {
454 		printf("shadow_map_read: request (%lld, %lu) exceeds file size %d\n",
455 		    block_offset, block_count, map->file_size_blocks);
456 		*incr_block_count = 0;
457 	}
458 	n_blocks = bitmap_get(map->block_bitmap, block_offset, block_count,
459 	    &written);
460 	if (written == FALSE) {
461 		*incr_block_count = n_blocks;
462 		*incr_block_offset = block_offset;
463 	} else { /* start has been written, and therefore mapped */
464 		band_number_t   mapped_band;
465 		off_t           band_limit;
466 
467 		mapped_band = map->bands[shadow_map_block_to_band(map, block_offset)];
468 		*incr_block_offset = mapped_band * map->blocks_per_band
469 		    + (block_offset % map->blocks_per_band);
470 		band_limit
471 		        = shadow_map_contiguous(map, block_offset, block_count, FALSE);
472 		*incr_block_count = band_limit - block_offset;
473 		if (*incr_block_count > n_blocks) {
474 			*incr_block_count = n_blocks;
475 		}
476 	}
477 	return written;
478 }
479 
480 /*
481  * Function: shadow_map_write
482  *
483  * Purpose:
484  *   Calculate the block offset within the shadow to write, and the number
485  *   blocks to write.  The input values (block_offset, block_count) refer
486  *   to the original file.  The output values
487  *   (*incr_block_offset, *incr_block_count) refer to the shadow file.
488  *
489  *   Bands are not necessarily contiguous, therefore:
490  *      *incr_block_count <= block_count
491  *   The caller must be prepared to call this function interatively
492  *   to complete the whole i/o.
493  * Returns:
494  *   TRUE if the shadow file was grown, FALSE otherwise.
495  */
496 boolean_t
shadow_map_write(shadow_map_t * map,off_t block_offset,size_t block_count,off_t * incr_block_offset,size_t * incr_block_count)497 shadow_map_write(shadow_map_t * map, off_t block_offset,
498     size_t block_count, off_t * incr_block_offset,
499     size_t * incr_block_count)
500 {
501 	off_t               band_limit;
502 	band_number_t       mapped_band;
503 	boolean_t           shadow_grew = FALSE;
504 
505 	if (block_offset >= map->file_size_blocks
506 	    || (block_offset + block_count) > map->file_size_blocks) {
507 		printf("shadow_map_write: request (%lld, %zu) exceeds file size %d\n",
508 		    block_offset, block_count, map->file_size_blocks);
509 		*incr_block_count = 0;
510 	}
511 
512 	band_limit = shadow_map_contiguous(map, block_offset, block_count, TRUE);
513 	mapped_band = map->bands[shadow_map_block_to_band(map, block_offset)];
514 	*incr_block_offset = mapped_band * map->blocks_per_band
515 	    + (block_offset % map->blocks_per_band);
516 	*incr_block_count = band_limit - block_offset;
517 
518 	/* mark these blocks as written */
519 	bitmap_set(map->block_bitmap, block_offset, *incr_block_count);
520 
521 	if (map->next_band > map->shadow_size_bands) {
522 		map->shadow_size_bands = map->next_band;
523 		shadow_grew = TRUE;
524 	}
525 	return shadow_grew;
526 }
527 
528 boolean_t
shadow_map_is_written(shadow_map_t * map,off_t block_offset)529 shadow_map_is_written(shadow_map_t * map, off_t block_offset)
530 {
531 	bitmap_offset_t     b;
532 
533 	b = bitmap_offset(block_offset);
534 	return (map->block_bitmap[b.byte] & bit(b.bit)) ? TRUE : FALSE;
535 }
536 
537 /*
538  * Function: shadow_map_shadow_size
539  *
540  * Purpose:
541  *   To return the size of the shadow file in blocks.
542  */
543 uint32_t
shadow_map_shadow_size(shadow_map_t * map)544 shadow_map_shadow_size(shadow_map_t * map)
545 {
546 	return map->shadow_size_bands * map->blocks_per_band;
547 }
548 
549 /*
550  * Function: shadow_map_create
551  *
552  * Purpose:
553  *   Allocate the dynamic data for keeping track of the shadow dirty blocks
554  *   and the band mapping table.
555  * Returns:
556  *   NULL if an error occurred.
557  */
558 shadow_map_t *
shadow_map_create(off_t file_size,off_t shadow_size,uint32_t band_size,uint32_t block_size)559 shadow_map_create(off_t file_size, off_t shadow_size,
560     uint32_t band_size, uint32_t block_size)
561 {
562 	void *              block_bitmap = NULL;
563 	size_t              bitmap_size;
564 	band_number_t *     bands = NULL;
565 	shadow_map_t *      map;
566 	uint32_t            n_bands = 0;
567 
568 	if (band_size == 0) {
569 		band_size = BAND_SIZE_DEFAULT;
570 	}
571 
572 	off_t many = howmany(file_size, band_size);
573 	if (many > (BAND_MAX + 1)) {
574 		printf("file is too big: %lld > %d\n",
575 		    many, BAND_MAX);
576 		goto failure;
577 	}
578 	n_bands = (uint32_t)many;
579 
580 	/* create a block bitmap, one bit per block */
581 	bitmap_size = block_bitmap_size(file_size, block_size);
582 	block_bitmap = kalloc_data(bitmap_size, Z_ZERO);
583 	if (block_bitmap == NULL) {
584 		printf("failed to allocate bitmap\n");
585 		goto failure;
586 	}
587 
588 	/* get the band map */
589 	bands = (band_number_t *)kalloc_data(n_bands * sizeof(band_number_t), Z_ZERO);
590 	if (bands == NULL) {
591 		printf("failed to allocate bands\n");
592 		goto failure;
593 	}
594 
595 	map = kalloc_type(shadow_map_t, 0);
596 	if (map == NULL) {
597 		printf("failed to allocate map\n");
598 		goto failure;
599 	}
600 	map->blocks_per_band = band_size / block_size;
601 	map->block_bitmap = block_bitmap;
602 	map->bands = bands;
603 	map->file_size_blocks = n_bands * map->blocks_per_band;
604 	map->next_band = 0;
605 	map->zeroth_band = -1;
606 	map->shadow_size_bands = (uint32_t)howmany(shadow_size, band_size);
607 	map->block_size = block_size;
608 	return map;
609 
610 failure:
611 	if (block_bitmap) {
612 		kfree_data(block_bitmap, bitmap_size);
613 	}
614 	if (bands) {
615 		kfree_data(bands, n_bands * sizeof(band_number_t));
616 	}
617 	return NULL;
618 }
619 
620 /*
621  * Function: shadow_map_free
622  * Purpose:
623  *   Frees the data structure to deal with the shadow map.
624  */
625 void
shadow_map_free(shadow_map_t * map)626 shadow_map_free(shadow_map_t * map)
627 {
628 	if (map->block_bitmap) {
629 		kfree_data_addr(map->block_bitmap);
630 	}
631 	if (map->bands) {
632 		kfree_data(map->bands, (map->file_size_blocks / map->blocks_per_band) * sizeof(band_number_t));
633 	}
634 	map->block_bitmap = NULL;
635 	map->bands = NULL;
636 	kfree_type(shadow_map_t, map);
637 	return;
638 }
639 
640 #ifdef TEST_SHADOW
641 #define BAND_SIZE_BLOCKS        (BAND_SIZE_DEFAULT / 512)
642 
643 enum {
644 	ReadRequest,
645 	WriteRequest,
646 };
647 
648 typedef struct {
649 	int         type;
650 	uint32_t    offset;
651 	uint32_t    count;
652 } block_request_t;
653 
654 int
main()655 main()
656 {
657 	shadow_map_t *      map;
658 	int                 i;
659 	block_request_t     requests[] = {
660 		{ WriteRequest, BAND_SIZE_BLOCKS * 2, 1 },
661 		{ ReadRequest, BAND_SIZE_BLOCKS / 2, BAND_SIZE_BLOCKS * 2 - 2 },
662 		{ WriteRequest, BAND_SIZE_BLOCKS * 1, 5 * BAND_SIZE_BLOCKS + 3},
663 		{ ReadRequest, 0, BAND_SIZE_BLOCKS * 10 },
664 		{ WriteRequest, BAND_SIZE_BLOCKS * (BAND_MAX - 1),
665 		  BAND_SIZE_BLOCKS * 2},
666 		{ 0, 0 },
667 	};
668 
669 	map = shadow_map_create(1024 * 1024 * 1024 * 8ULL, 0, 0, 512);
670 	if (map == NULL) {
671 		printf("shadow_map_create failed\n");
672 		exit(1);
673 	}
674 	for (i = 0; TRUE; i++) {
675 		uint32_t                offset;
676 		uint32_t                resid;
677 		boolean_t       shadow_grew;
678 		boolean_t       read_shadow;
679 
680 		if (requests[i].count == 0) {
681 			break;
682 		}
683 		offset = requests[i].offset;
684 		resid = requests[i].count;
685 		printf("\n%s REQUEST (%ld, %ld)\n",
686 		    requests[i].type == WriteRequest ? "WRITE" : "READ",
687 		    offset, resid);
688 		switch (requests[i].type) {
689 		case WriteRequest:
690 			while (resid > 0) {
691 				uint32_t this_offset;
692 				uint32_t this_count;
693 
694 				shadow_grew = shadow_map_write(map, offset,
695 				    resid,
696 				    &this_offset,
697 				    &this_count);
698 				printf("\t(%ld, %ld) => (%ld, %ld)",
699 				    offset, resid, this_offset, this_count);
700 				resid -= this_count;
701 				offset += this_count;
702 				if (shadow_grew) {
703 					printf(" shadow grew to %ld", shadow_map_shadow_size(map));
704 				}
705 				printf("\n");
706 			}
707 			break;
708 		case ReadRequest:
709 			while (resid > 0) {
710 				uint32_t this_offset;
711 				uint32_t this_count;
712 
713 				read_shadow = shadow_map_read(map, offset,
714 				    resid,
715 				    &this_offset,
716 				    &this_count);
717 				printf("\t(%ld, %ld) => (%ld, %ld)%s\n",
718 				    offset, resid, this_offset, this_count,
719 				    read_shadow ? " from shadow" : "");
720 				if (this_count == 0) {
721 					printf("this_count is 0, aborting\n");
722 					break;
723 				}
724 				resid -= this_count;
725 				offset += this_count;
726 			}
727 			break;
728 		default:
729 			break;
730 		}
731 	}
732 	if (map) {
733 		shadow_map_free(map);
734 	}
735 	exit(0);
736 	return 0;
737 }
738 #endif
739