Home | History | Annotate | Download | only in diskomizer
      1 /*
      2  * CDDL HEADER START
      3  *
      4  * The contents of this file are subject to the terms of the
      5  * Common Development and Distribution License (the "License").
      6  * You may not use this file except in compliance with the License.
      7  *
      8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9  * or http://www.opensolaris.org/os/licensing.
     10  * See the License for the specific language governing permissions
     11  * and limitations under the License.
     12  *
     13  * When distributing Covered Code, include this CDDL HEADER in each
     14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15  * If applicable, add the following below this CDDL HEADER, with the
     16  * fields enclosed by brackets "[]" replaced with your own identifying
     17  * information: Portions Copyright [yyyy] [name of copyright owner]
     18  *
     19  * CDDL HEADER END
     20  */
     21 
     22 #pragma ident	"@(#)bufs.c	1.52	09/05/26 SMI"
     23 
     24 /*
     25  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
     26  * Use is subject to license terms.
     27  */
     28 
     29 /*
     30  * Buffer manipulation routines.
     31  */
     32 #include <sys/systeminfo.h>
     33 #include <diskomizer/log.h>
     34 #include "args.h"
     35 #include "diskomizer64mpism.h"
     36 #include "asm.h"
     37 #include "bufs.h"
     38 #include "shm_ops.h"
     39 #include "time.h"
     40 #include "signal_catch.h"
     41 #include <tnf/probe.h>
     42 #include "errors.h"
     43 
     44 static uchar_t *write_bufs;
     45 static bitmap_t *writemap;
     46 static uchar_t *read_bufs;
     47 static bitmap_t *readmap;
     48 static struct shadow_hdr *shadow_headers;
     49 
     50 static char serial_and_provider[SIZEOF_SERIAL_AND_PROVIDER + 1];
     51 
     52 static ulong_t writemap_size = 0;
     53 static ulong_t readmap_size = 0;
     54 
     55 static void init_data_buf(uchar_t *buf, int bufno);
     56 static void init_func_buf(uchar_t *buf, int bufno);
     57 static void init_func_buf_branch(struct buf *buf, int bufno);
     58 static void init_func_buf_short(struct buf *buf, int bufno);
     59 static void init_func_buf_long(struct buf *buf, int bufno);
     60 static void set_bufhdr_a(uchar_t *buf, struct bufhdr_a hdr);
     61 static void set_bufhdr(uchar_t *buf, struct bufhdr hdr);
     62 static uint64_t get_hdrchksum(struct bufhdr hdr);
     63 static char *init_from_file(uchar_t *buf, ullong_t len);
     64 static void alloc_io_bufs(ulong_t nbufs, ulong_t buf_size,
     65 	ulong_t map_size, unsigned char **bufs, bitmap_t **map);
     66 static uchar_t *get_buf(uchar_t *bufpool, uint_t pool_size,
     67 	uint_t io_len, bitmap_t map[], ulong_t maplen, ullong_t *next_off);
     68 struct shadow_hdr const * get_shadow_hdr_by_off(ulong_t off);
     69 static uint32_t sizeof_shadow_header(void);
     70 static void protect_buf_func(uchar_t *buf);
     71 static void unprotect_buf_func(uchar_t *buf);
     72 
     73 void (*protect_buf)(uchar_t *buf) = (void (*)(uchar_t *))nop;
     74 void (*unprotect_buf)(uchar_t *buf) = (void (*)(uchar_t *))nop;
     75 
     76 
     77 static const char *madv_str[] = {
     78 	"MADV_NORMAL",
     79 	"MADV_RANDOM",
     80 	"MADV_SEQUENTIAL",
     81 	"MADV_WILLNEED",
     82 	"MADV_DONTNEED",
     83 	"MADV_FREE",
     84 	"Unknown"
     85 };
     86 
     87 #define	MADV_Unknown 7
     88 #define	MADV_STR(A) (madv_str[A > MADV_Unknown ? MADV_Unknown : A])
     89 
     90 static ulong_t
     91 get_buf_off(uchar_t *buf, uchar_t *bufpool, uint_t io_len)
     92 {
     93 	ulong_t off;
     94 
     95 	/*LINTED*/
     96 	off = (buf - bufpool);
     97 	off = off/io_len;
     98 	return (off);
     99 }
    100 
    101 static void
    102 return_buf(uchar_t *buf, uchar_t *bufpool, uint_t io_len,
    103 	bitmap_t map[], ulong_t maplen, uint_t pool_size)
    104 {
    105 	ulong_t off;
    106 
    107 	off = get_buf_off(buf, bufpool, io_len);
    108 
    109 	if (opts.use_madvise)
    110 		if (madvise((caddr_t)buf, io_len, opts.madvise_return)) {
    111 			MADVISE_ERROR((ulong_t)buf,
    112 			    io_len, opts.madvise_return,
    113 			    MADV_STR(opts.madvise_return));
    114 		}
    115 
    116 	TNF_PROBE_5(return_buf, "return_buf",
    117 	    "sunw%cte%diskomizer%bufs return",
    118 	    tnf_opaque, off, off,
    119 	    tnf_opaque, buf_pool, bufpool,
    120 	    tnf_opaque, buf, buf,
    121 	    tnf_opaque, sizeof_struct_buf, sizeof (struct buf),
    122 	    tnf_opaque, io_len, io_len);
    123 	assert(off < pool_size);
    124 
    125 	clear_write(map, off, maplen);
    126 }
    127 static uchar_t *
    128 get_buf(uchar_t *bufpool, uint_t pool_size, uint_t io_len,
    129 	bitmap_t map[], ulong_t maplen, ullong_t *next_off)
    130 {
    131 	ullong_t off;
    132 	uchar_t *buf;
    133 
    134 	off = find_next_free(map, *next_off, pool_size, maplen);
    135 
    136 	*next_off = (off + opts.nprocs + 1) % pool_size;
    137 
    138 	buf = &bufpool[off * io_len];
    139 	if (opts.use_madvise)
    140 		if (madvise((caddr_t)buf, io_len, opts.madvise_get)) {
    141 			MADVISE_ERROR((ulong_t)buf, io_len, opts.madvise_get,
    142 			    MADV_STR(opts.madvise_get));
    143 		}
    144 	TNF_PROBE_3(get_buf, "get_buf",
    145 	    "sunw%cte%diskomizer%bufs get",
    146 	    tnf_opaque, off, off,
    147 	    tnf_opaque, buf_pool, bufpool,
    148 	    tnf_opaque, buf, buf);
    149 	return (buf);
    150 }
    151 
    152 const char *
    153 get_buf_serial_and_provider(const uchar_t *b)
    154 {
    155 	struct bufhdr *hdrp = (struct bufhdr *)b;
    156 
    157 	if (hdrp->start == (BUF_TYPE_A)) {
    158 		return (hdrp->ab.a.serial_and_provider);
    159 	} else if (hdrp->start == BUF_TYPE_B) {
    160 		return (hdrp->ab.b.serial_and_provider);
    161 	} else {
    162 		return (NULL);
    163 	}
    164 }
    165 
    166 
    167 time_t
    168 get_buf_time(uchar_t *b)
    169 {
    170 	struct bufhdr *hdrp = (struct bufhdr *)b;
    171 
    172 	if (hdrp->start == BUF_TYPE_A) {
    173 		return (hdrp->ab.a.time);
    174 	} else if (hdrp->start == BUF_TYPE_B) {
    175 		return (hdrp->ab.b.time);
    176 	} else {
    177 		return (-1);
    178 	}
    179 }
    180 
    181 pid_t
    182 get_buf_did(uchar_t *b)
    183 {
    184 	struct bufhdr *hdrp = (struct bufhdr *)b;
    185 
    186 	if (hdrp->start == BUF_TYPE_A) {
    187 		return (hdrp->ab.a.did);
    188 	} else if (hdrp->start == BUF_TYPE_B) {
    189 		return (hdrp->ab.b.did);
    190 	} else {
    191 		return (-1);
    192 	}
    193 }
    194 
    195 void
    196 init_block_str(struct device *device)
    197 {
    198 	ulong_t tmp;
    199 	ulong_t len = device->length;
    200 	ulong_t size = INDEX_TO_DIOLEN(max_disk_io_len);
    201 
    202 	/*
    203 	 * (void) memset(device->blocks, NULL,
    204 	 *	((len/size) + 1) * sizeof (struct blks));
    205 	 */
    206 	for (tmp = 0; tmp < (len/size) + 1; tmp++) {
    207 		struct blks *block, *blocks;
    208 		blocks = shm_ops->attach(device->blocks->handles[tmp %
    209 		    device->blocks->count]);
    210 		if (blocks == NULL) {
    211 			ATTACH_ERROR(device->blocks->handles[tmp %
    212 			    device->blocks->count]);
    213 			exit(1);
    214 		}
    215 		block = &blocks[tmp / device->blocks->count];
    216 		/*
    217 		 * Make it look like all the buffers have already been read
    218 		 * enough times to allow a write to go ahead.
    219 		 */
    220 		block->read_count = opts.read_minimum;
    221 		/*
    222 		 * Zero out the rest of the data.
    223 		 */
    224 		block->hdrchksum = 0;
    225 		block->path_id = 0;
    226 		block->bad_hdr = 0;
    227 		block->ab = 0;
    228 		block->bad_chksum = 0;
    229 		block->sequence = 0;
    230 
    231 		block->r.w.last_io = NULL;
    232 		block->r.w.last_iolen = 0;
    233 		block->r.w.prev_io = NULL;
    234 		block->r.w.prev_iolen = 0;
    235 
    236 		block->last_returned_delta = 0;
    237 		(void) memset(&block->u, NULL, sizeof (block->u));
    238 		block->last_requested = 0;
    239 		shm_ops->detach(device->blocks->handles[tmp %
    240 		    device->blocks->count]);
    241 	}
    242 }
    243 
    244 /*
    245  * init_aio_bufs allocates and initilises the bitmaps and the blks structures
    246  * for each block on the device.
    247  *
    248  * The size of the bit map can be limited with the option OBSCURE_WRITEMAP_SIZE
    249  * in which case some or all of the bits in the map will protect more than one
    250  * blk structure.
    251  */
    252 static bitmap_t *
    253 init_aio_bufs(struct device *device)
    254 {
    255 	ullong_t tmp;
    256 	struct shm_flags shmflags;
    257 	int nhandles;
    258 	ullong_t left;
    259 	ullong_t blocks_per_bucket;
    260 	ullong_t total_blocks;
    261 
    262 	ZERO_OBJ(shmflags);
    263 
    264 	total_blocks = device->length/INDEX_TO_DIOLEN(max_disk_io_len);
    265 	blocks_per_bucket = (shm_ops->max_size() / sizeof (struct blks));
    266 	nhandles = (total_blocks / blocks_per_bucket);
    267 	/*
    268 	 * Handle any rounding, the last bucket may not be full
    269 	 * length.
    270 	 */
    271 	if (total_blocks % blocks_per_bucket) {
    272 		nhandles++;
    273 	}
    274 
    275 	if (opts.obscure_writemap_size == 0) {
    276 		tmp = total_blocks;
    277 		tmp = (tmp % MAP_BITS ? 1 : 0) + tmp / MAP_BITS;
    278 		device->writemap_size = tmp;
    279 	} else {
    280 		device->writemap_size = opts.obscure_writemap_size;
    281 	}
    282 
    283 	tmp = device->writemap_size;
    284 	/*
    285 	 * Pad to avoid alignment issues. The bitmaps are always read
    286 	 * in the sizeof (bitmap_t) chunks so this is needed on both
    287 	 * SPARC and x86.
    288 	 */
    289 	tmp += (tmp % sizeof (bitmap_t));
    290 
    291 	plog(LOG_DEBUG, "Writemap size %#llx, sizeof (bitmap_t) %#lx\n", tmp,
    292 	    (ulong_t)sizeof (bitmap_t));
    293 
    294 	shmflags.allow_detach = (opts.expert_allow_detach);
    295 	shmflags.always_detach = (opts.debug_always_detach != 0);
    296 	shmflags.leave_attached =
    297 	    (opts.obscure_leave_shm_attached_after_init != 0);
    298 
    299 	if ((device->writemap_handle =
    300 	    shm_ops->init(tmp, sizeof (bitmap_t), shmflags)) ==
    301 	    NULL) {
    302 		pfprintf(stderr,
    303 		    "FATAL: Unable to create shared memory %s\n",
    304 		    shm_ops->name(NULL));
    305 		exit(1);
    306 	}
    307 
    308 	plog(LOG_DEBUG, "writemap_handle %#lx\n",
    309 	    (long)device->writemap_handle);
    310 
    311 	/*
    312 	 * struct shm_handle contains the first void *
    313 	 * hence the subtraction of one from nhandles.
    314 	 */
    315 	device->blocks = calloc(sizeof (struct shm_handle) +
    316 	    ((nhandles - 1) * sizeof (void *)), 1);
    317 
    318 	if (device->blocks == NULL) {
    319 		CALLOC_ERROR((long) (sizeof (struct shm_handle) +
    320 		    ((nhandles - 1) * sizeof (void *))), (long)1);
    321 		exit(1);
    322 	}
    323 
    324 	device->blocks->count = nhandles;
    325 	/*
    326 	 * This should not really live here.
    327 	 */
    328 	device->blocks->len = blocks_per_bucket;
    329 	left = total_blocks;
    330 
    331 	for (nhandles = 0; nhandles < device->blocks->count; nhandles++) {
    332 		int n = MIN(blocks_per_bucket, left);
    333 		assert(n != 0);
    334 		device->blocks->handles[nhandles] = shm_ops->init(n,
    335 		    sizeof (struct blks), shmflags);
    336 		left -= n;
    337 		if (device->blocks->handles[nhandles] == NULL) {
    338 			SHM_INIT_ERROR(NULL,
    339 			    (ulong_t)n * sizeof (struct blks));
    340 			exit(1);
    341 		}
    342 		plog(LOG_DEBUG, "blocks handle %d %#lx len %#x\n", nhandles,
    343 		    (ulong_t)device->blocks->handles[nhandles], n);
    344 	}
    345 
    346 	if (opts.obscure_mprotect_write_bufs) {
    347 		unprotect_buf = unprotect_buf_func;
    348 		protect_buf = protect_buf_func;
    349 	}
    350 
    351 	return (device->writemap_handle);
    352 }
    353 
    354 static long
    355 getpagesz(void)
    356 {
    357 	static long pagesize;
    358 
    359 	if (pagesize == 0) {
    360 		pagesize = sysconf(_SC_PAGESIZE);
    361 	}
    362 	return (pagesize);
    363 }
    364 
    365 void
    366 protect_buf_func(uchar_t *b)
    367 {
    368 	long ps = getpagesz();
    369 	char *x = (char *)((((ulong_t)b)/ps)*ps);
    370 	long len = INDEX_TO_DIOLEN(max_disk_io_len);
    371 	TNF_PROBE_2(init_buf, "protect",
    372 	    "sunw%cte%diskomizer%bufs init",
    373 	    tnf_opaque, x, x, tnf_ulong, len, len);
    374 
    375 	len += (ulong_t)b - (ulong_t)x;
    376 	if (mprotect(x,  len, PROT_READ) == -1)
    377 		pperror("mprotect(%#lx, %#lx, PROT_READ)",
    378 		    (ulong_t)x, len);
    379 }
    380 
    381 void
    382 unprotect_buf_func(uchar_t *b)
    383 {
    384 	long ps = getpagesz();
    385 	char *x = (char *)((((ulong_t)b)/ps)*ps);
    386 	long len = INDEX_TO_DIOLEN(max_disk_io_len);
    387 
    388 	len += (ulong_t)b - (ulong_t)x;
    389 	TNF_PROBE_2(init_buf, "unprotect",
    390 	    "sunw%cte%diskomizer%bufs init",
    391 	    tnf_opaque, x, x, tnf_ulong, len, len);
    392 	if (mprotect(x,  len, PROT_WRITE|PROT_READ) == -1)
    393 		pperror("mprotect(%#lx, %#lx, PROT_WRITE|PROT_READ)",
    394 		    (ulong_t)x, len);
    395 }
    396 
    397 uchar_t *
    398 get_write_buf(void)
    399 {
    400 	static ullong_t next_off;
    401 	uchar_t *buf;
    402 	buf = get_buf(write_bufs, opts.nwritebufs,
    403 	    INDEX_TO_DIOLEN(max_disk_io_len) + opts.write_buffer_gap,
    404 	    writemap, writemap_size, &next_off);
    405 	TNF_PROBE_1(get_write_buf, "get_write_buf",
    406 	    "sunw%cte%diskomizer%bufs get write",
    407 	    tnf_opaque, buf, buf);
    408 	return (buf);
    409 }
    410 int
    411 get_write_buf_id(uchar_t *b)
    412 {
    413 	/*LINTED*/
    414 	return ((b - write_bufs)/
    415 	    (INDEX_TO_DIOLEN(max_disk_io_len) + opts.write_buffer_gap));
    416 }
    417 void
    418 return_write_buf(uchar_t *buf)
    419 {
    420 	TNF_PROBE_1(return_write_buf,
    421 	    "return_write_buf", "sunw%cte%diskomizer%bufs return write",
    422 	    tnf_opaque, buf, buf);
    423 	return_buf(buf, write_bufs, INDEX_TO_DIOLEN(max_disk_io_len) +
    424 	    opts.write_buffer_gap, writemap, writemap_size,
    425 	    opts.nwritebufs);
    426 }
    427 static uint32_t
    428 sizeof_shadow_header(void)
    429 {
    430 	return (sizeof (struct shadow_hdr) + (
    431 	    opts.disk_io_sizes.weightings[(opts.disk_io_sizes.wlen - 1)] *
    432 	    sizeof (check_t)));
    433 }
    434 static struct shadow_hdr *
    435 alloc_shadow_headers(ulong_t count)
    436 {
    437 	struct shadow_hdr *ptr;
    438 
    439 	ptr = (struct shadow_hdr *)alloc_mem(count, sizeof_shadow_header());
    440 	return (ptr);
    441 }
    442 /*
    443  * Initialize the buffers that we are writing from.
    444  *
    445  * Buffers are initialized at run time and  a flag in the shadow buffer is
    446  * then set to prevent them being initialized twice. The exception to this is
    447  * where a data file is provided by the user, then that file is used to
    448  * initialise the buffers, until there are either no more buffers or no more
    449  * data in the file left to use.  If the file runs out first the rest of the
    450  * buffers are initialzed at run time.
    451  */
    452 void
    453 init_all_write_bufs(struct aio_str *aio, struct device *devices)
    454 {
    455 	char *last_from_file = NULL;
    456 	int i, ndevices;
    457 	int all_wthreads;
    458 	int tmp;
    459 
    460 	all_wthreads = opts.wthreads + opts.wrthreads;
    461 
    462 	ndevices = how_many_devices(devices);
    463 
    464 	for (i = 0; i < all_wthreads; i++) {
    465 		struct device *tmpdev;
    466 		int k;
    467 		int j = i * ndevices;
    468 		time_t  (*handler)(struct aio_str *aiop, ullong_t start);
    469 
    470 		if (is_readonly()) {
    471 			handler = handle_readonly_seq;
    472 		} else if (i < opts.wthreads) {
    473 			handler = handle_write;
    474 		} else {
    475 			handler = handle_read_then_write;
    476 		}
    477 
    478 		for (k = 0, tmpdev = devices; tmpdev != NULL;
    479 		    tmpdev = tmpdev->next, k++) {
    480 			aio[j+k].buf = NULL;
    481 			aio[j+k].off = 0;
    482 			aio[j+k].handler = handler;
    483 			aio[j+k].dev = tmpdev;
    484 		}
    485 		assert(k == ndevices);
    486 	}
    487 
    488 	while (devices != NULL) {
    489 		devices->writemap_handle =
    490 		    init_aio_bufs(devices);
    491 		devices = devices->next;
    492 	}
    493 	if (is_readonly())
    494 		return;
    495 
    496 	tmp = ndevices*opts.nprocs*all_wthreads;
    497 	if (opts.nwritebufs == 0)
    498 		opts.nwritebufs = ndevices*opts.nprocs * all_wthreads *
    499 		    opts.obscure_buffer_multiplier;
    500 
    501 	opts.nwritebufs = MAX(opts.nwritebufs, (tmp*11)/10);
    502 	/*
    503 	 * Make sure there is a spare buffer for every process.
    504 	 */
    505 	opts.nwritebufs = MAX(opts.nwritebufs, tmp + opts.nprocs);
    506 
    507 	if (writemap_size == 0) {
    508 		ulong_t tmp = opts.nwritebufs;
    509 
    510 		tmp = (tmp % MAP_BITS ? 1 : 0) + tmp / MAP_BITS;
    511 
    512 		writemap_size = tmp;
    513 	}
    514 	print_number((long long)opts.nwritebufs, "write buf", "write bufs");
    515 
    516 	alloc_io_bufs(opts.nwritebufs,
    517 	    INDEX_TO_DIOLEN(max_disk_io_len) + opts.write_buffer_gap,
    518 	    writemap_size, &write_bufs, &writemap);
    519 
    520 	shadow_headers = alloc_shadow_headers(opts.nwritebufs);
    521 
    522 	if (opts.data_file && opts.init_from_data_file != 0) {
    523 		if ((last_from_file = init_from_file((uchar_t *)write_bufs,
    524 		    opts.nwritebufs *
    525 		    INDEX_TO_DIOLEN(max_disk_io_len))) != NULL) {
    526 			(void) printf(
    527 			    "\tData buffers initialzed from file %s\n",
    528 			    opts.data_file);
    529 		}
    530 	}
    531 
    532 	for (i = 0; i < opts.nwritebufs; i++) {
    533 		int j;
    534 		ulong_t x = i * (INDEX_TO_DIOLEN(max_disk_io_len) +
    535 		    opts.write_buffer_gap);
    536 		struct bufhdr_a hdr_a;
    537 		struct shadow_hdr *shadow;
    538 		if ((char *)&write_bufs[x] >= last_from_file)
    539 			break;
    540 
    541 		hdr_a = get_bufhdr_a(&write_bufs[x]);
    542 		shadow = (struct shadow_hdr *)get_shadow_hdr_by_off(i);
    543 		shadow->type = hdr_a.type;
    544 		for (j = 0; j < opts.disk_io_sizes.wlen; j++) {
    545 			shadow->chksums[j] = check_bufbody(&write_bufs[x],
    546 			    INDEX_TO_DIOLEN(j));
    547 		}
    548 		if (shadow->chksums[max_disk_io_len] != hdr_a.chksum) {
    549 			shadow->type.BUF_BAD_CHKSUM = 1;
    550 			if ((char *)&write_bufs[x] < last_from_file)
    551 				shadow_headers[i].type.BUF_READ_ONLY = 1;
    552 			shadow_headers->type.BUF_BAD_CHKSUM = 1;
    553 		}
    554 		shadow->type.BUF_READY = 1;
    555 		shadow->type.BUF_READ_ONLY = 1;
    556 	}
    557 }
    558 ulong_t
    559 u_long_chksum(ulong_t x)
    560 {
    561 	union {
    562 		ulong_t l;
    563 		uchar_t c[sizeof (ulong_t)];
    564 	} u;
    565 	int i;
    566 	ulong_t cksum;
    567 
    568 	u.l = x;
    569 
    570 	for (i = cksum = 0; i < sizeof (ulong_t); i++)
    571 		cksum += u.c[i];
    572 	return (cksum);
    573 }
    574 
    575 ulong_t
    576 u_int32_chksum(uint32_t x)
    577 {
    578 	union {
    579 		uint32_t l;
    580 		uchar_t c[sizeof (uint32_t)];
    581 	} u;
    582 	int i;
    583 	ulong_t cksum;
    584 
    585 	u.l = x;
    586 
    587 	for (i = cksum = 0; i < sizeof (uint32_t); i++)
    588 		cksum += u.c[i];
    589 	return (cksum);
    590 }
    591 ulong_t
    592 u_short_chksum(ushort16_t x)
    593 {
    594 	union {
    595 		ushort16_t l;
    596 		uchar_t c[sizeof (ushort16_t)];
    597 	} u;
    598 	int i;
    599 	ulong_t cksum;
    600 
    601 	u.l = x;
    602 
    603 	for (i = cksum = 0; i < sizeof (ushort16_t); i++)
    604 		cksum += u.c[i];
    605 	return (cksum);
    606 }
    607 void
    608 init_data_buf(uchar_t *buf, int bufno)
    609 {
    610 	int i;
    611 	int size = (INDEX_TO_DIOLEN(max_disk_io_len) -
    612 	    sizeof (struct bufhdr));
    613 	uchar_t *data = get_buf_data(buf);
    614 
    615 
    616 	for (i = 0; i < size; i++) {
    617 		*(data + i) = init_uchar_func(bufno, i);
    618 	}
    619 }
    620 
    621 /*ARGSUSED*/
    622 void
    623 init_func_buf_branch(struct buf *buf, int bufno)
    624 {
    625 	uint32_t *start;
    626 	uint32_t *last;
    627 	uint32_t *ptr;
    628 	uint32_t jump_size;
    629 
    630 #ifdef __sparcv9
    631 	union {
    632 		pid_t (*func)(pid_t);
    633 		pid_t pid_t;
    634 		uint32_t thirty_two[2];
    635 	} tmp;
    636 #elif __i386 || __amd64
    637 	varlen t_inst;	/* Some Intel assembler >32 bits */
    638 #endif
    639 
    640 	do {
    641 		jump_size = 0x1FFFF &
    642 		    (lrand48() % (INDEX_TO_DIOLEN(max_disk_io_len) /
    643 		    (2 * sizeof (uint32_t))));
    644 	} while (jump_size < 4);
    645 
    646 	start = &buf->data.i[0];
    647 
    648 
    649 	plog(LOG_DEBUG, "initializing a branch function %#lx buffer %#lx\n",
    650 	    getpgid, (ulong_t)start);
    651 
    652 	last = (uint32_t *)(start +
    653 	    ((INDEX_TO_DIOLEN(max_disk_io_len) - SIZEOF_BUFHDR)/
    654 	    sizeof (uint32_t)));
    655 
    656 	ptr = start;
    657 /*
    658  *  SPARC
    659  *
    660  *	The assembler that is written stores all but the bottom 10
    661  *	bits of getpgid in %l1 and all but the bottom 10 bits of
    662  *	pgrp in %l0. Then in the loop we jump to %l1 plus the bottom 10
    663  *      bits of getpgid and in the delay slot %lo gets added to the bottom
    664  * 	10 bits of pgrp and the result stored in %o0.
    665  *
    666  *  Intel
    667  *
    668  *	The assembler written pushes pgrp onto the stack, moves the address
    669  *	of getpgid into the %eax register. In the loop we call the function
    670  *	whose address is in %eax (getpgid).
    671  *
    672  */
    673 #ifdef __sparcv9
    674 /*
    675  *	The V9 assembler that is created should look something like this.
    676  *	the upper bits are nearly always zero but at the momment I don't
    677  *	check for that.
    678  *
    679  *	save    %sp, -0x100, %sp
    680  *	sethi   %hi(getpgid.upperbits), %o1
    681  *	add     %o1, %lo(getpgid.upperbits), %o1
    682  *	sllx    %o1, 32, %l1
    683  *	sethi   %hi(getpgid.lowerbits), %o2
    684  *	add     %o2, %l1, %l1
    685  *	sethi   %hi(pgrp), %l0 ! pgrp is a 32 bit quantity.
    686  *
    687  */
    688 	*ptr++ = save_asm(sp, sp, 1, -0x100);
    689 	tmp.func = getpgid;
    690 	if (getpgid(pgrp) == (pid_t)-1)
    691 		pperror("getpgpid(%d)\n", pgrp);
    692 	tmp.func(pgrp);
    693 	assert(tmp.func == &getpgid);
    694 	/* sethi %hi(tmp), %o1 */
    695 	*ptr++ = sethi_asm(hi(tmp.thirty_two[0]), o1);
    696 	*ptr++ = add_asm(o1, o1, 1, lo(tmp.thirty_two[0]));
    697 	*ptr++ = sllx_asm(l1, o1, 32);
    698 	*ptr++ = sethi_asm(hi(tmp.thirty_two[1]), o2);
    699 	*ptr++ = add_asm(l1, o2, 0, l1);
    700 
    701 	*ptr++ = sethi_asm(hi((ulong_t)pgrp), l0);
    702 #elif __sparc && !__sparcv9
    703 	*ptr++ = save_asm(sp, sp, 1, -0x70);
    704 	/* sethi %hi(getpgid), %o1 */
    705 	*ptr++ = sethi_asm(hi((ulong_t)pgrp), l0);
    706 	*ptr++ =  sethi_asm(hi((ulong_t)getpgid), l1);
    707 #elif __i386 || __amd64
    708 	*ptr++ = save_asm();
    709 #else
    710 #error "No assembler defined for this processor"
    711 #endif
    712 
    713 	for (; ptr < (last - (jump_size + 8)); ptr += jump_size) {
    714 		int i;
    715 #ifdef __sparc
    716 		/* sethi %hi(pgrp), %o0 */
    717 		/* jmpl %o1 + %lo(getpgid), %o7 */
    718 		*ptr++ = jmpl_asm(o7, l1, 1, lo((ulong_t)getpgid));
    719 		/* add %o0, %lo(pgrp), %o0 */
    720 		*ptr++ = add_asm(o0, l0, 1, lo(pgrp));
    721 		*ptr = ba_asm(1, jump_size);
    722 		for (i = 0; i < (jump_size - 1); i++) {
    723 			*(ptr + 1 + i) = lrand48();
    724 		}
    725 
    726 	}
    727 	*ptr++ = ret_asm(); /* ret */
    728 	*ptr++ = restore_asm(g0, g0, 1, g0); /* restore */
    729 #elif defined(__i386) || defined(__amd64)
    730 #if defined(__amd64)
    731 		/* move pgrp into %edi */
    732 		t_inst = mov32_asm((uint32_t)pgrp, edi);
    733 		*ptr++ = t_inst.thirtytwo[0];
    734 		*ptr++ = t_inst.thirtytwo[1];
    735 		/* Move the address of the pointer to the function into %rdx */
    736 		t_inst = movl_asm((uint64_t)&getpgid, rdx);
    737 		*ptr++ = t_inst.thirtytwo[0];
    738 		*ptr++ = t_inst.thirtytwo[1];
    739 		*ptr++ = t_inst.thirtytwo[2];
    740 		*ptr++ = call_asm();
    741 #elif defined(__i386)
    742 		/* push pgrp onto the stack */
    743 		t_inst = pushl_asm((uint32_t)pgrp);
    744 		*ptr++ = t_inst.thirtytwo[0];
    745 		*ptr++ = t_inst.thirtytwo[1];
    746 		t_inst = movl_asm((uint32_t)getpgid, eax);
    747 		*ptr++ = t_inst.thirtytwo[0];
    748 		*ptr++ = t_inst.thirtytwo[1];
    749 		*ptr++ = call_asm();
    750 		*ptr++ = add_asm((uchar_t)4, esp);
    751 #else
    752 #error "Unknown architecture!"
    753 #endif
    754 
    755 		t_inst = jmp_asm((jump_size - 1)  * sizeof (uint32_t));
    756 		*ptr++ = t_inst.thirtytwo[0];
    757 		*ptr = t_inst.thirtytwo[1];
    758 
    759 		for (i = 0; i < (jump_size - 1); i++) {
    760 			*(ptr + 1 + i) = lrand48();
    761 		}
    762 	}
    763 	*ptr++ = ret_asm();
    764 #endif
    765 	while (ptr < last) {
    766 		*ptr++ = nop_asm();
    767 	}
    768 }
    769 
    770 void
    771 init_func_buf_short(struct buf *buf, int bufno)
    772 {
    773 	uint32_t *start;
    774 	uint32_t *last;
    775 	uint32_t *ptr;
    776 
    777 	plog(LOG_DEBUG, "initializing a function buffer\n");
    778 	start = &buf->data.i[0];
    779 
    780 	last = (uint32_t *)(start +
    781 	    ((INDEX_TO_DIOLEN(max_disk_io_len) - SIZEOF_BUFHDR) /
    782 	    sizeof (uint32_t)));
    783 
    784 	/*
    785 	 * SPARC:
    786 	 *
    787 	 * We fill the main part of the code with the assembler:
    788 	 *
    789 	 * bn,a    0x2080000a
    790 	 * ZZZZ
    791 	 *
    792 	 * Intel:
    793 	 *
    794 	 * The equivalent to the SPARC operation is:
    795 	 *
    796 	 * nop
    797 	 * nop
    798 	 * jmp .+4	0x04eb9090
    799 	 * ZZZZ
    800 	 *
    801 	 * The random 32 bits along with Intel's non-aligned instructions
    802 	 * means this routine generates some fairly horrible assembler at
    803 	 * first sight. The secret is to follow the jumps themselves even
    804 	 * if they do appear to jump into the middle of other instructions
    805 	 * and not worry about the code that isn't executed.
    806 	 *
    807 	 * General:
    808 	 *
    809 	 * Where ZZZZ is random and will be skipped of over by the
    810 	 * annulled branch.
    811 	 */
    812 
    813 #if __i386 || __amd64
    814 	ptr = (uint32_t *)start;
    815 	*ptr++ = save_asm();
    816 	for (; ptr < (last - 2); ptr += 2) {
    817 		*ptr = 0x04eb9090;
    818 #elif __sparc
    819 	for (ptr = (uint32_t *)(start); ptr < (last - 2); ptr += 2) {
    820 		*(ptr) = bn_asm(1, 2); /* SPARC branch never annuled */
    821 #else
    822 #error "No assembler defined for this processor"
    823 #endif
    824 		if (ptr == (uint32_t *)(start))
    825 			*(ptr + 1) = bufno;
    826 		else
    827 			*(ptr + 1) = lrand48();
    828 
    829 	}
    830 #ifdef __sparc
    831 	*ptr++ = retl_asm(); /* sparc retl */
    832 #else
    833 	*ptr++ = ret_asm(); /* Hence the need for save_asm() */
    834 #endif
    835 	while (ptr < last) {
    836 #ifdef __sparc
    837 		*(ptr++) = nop_asm(); /* SPARC nop */
    838 #else
    839 		*(ptr++) = NOPWORD;
    840 #endif
    841 	}
    842 }
    843 void
    844 init_func_buf_long(struct buf *buf, int bufno)
    845 {
    846 	uint32_t *start;
    847 	uint32_t *last;
    848 	uint32_t *ptr;
    849 #if defined(__i386) || defined(__amd64)
    850 	varlen t_inst;
    851 #endif
    852 	uint32_t jump_size = 0x1FFFF &
    853 	    (lrand48() % (INDEX_TO_DIOLEN(max_disk_io_len) /
    854 	    sizeof (uint32_t)));
    855 
    856 	if (jump_size < 2) {
    857 		init_func_buf_short(buf, bufno);
    858 		return;
    859 	}
    860 
    861 	plog(LOG_DEBUG,
    862 	    "initializing a long function buffer with jump_size %d\n",
    863 	    jump_size);
    864 	start = &buf->data.i[0];
    865 
    866 	last = start +
    867 	    ((INDEX_TO_DIOLEN(max_disk_io_len) - SIZEOF_BUFHDR) /
    868 	    sizeof (uint32_t));
    869 
    870 	/*
    871 	 * We fill the main part of the code with the assembler:
    872 	 *
    873 	 * SPARC
    874 	 *
    875 	 * ba,a    jump_size
    876 	 * now jump_size - 1 random numbers...
    877 	 *
    878 	 * Intel
    879 	 *
    880 	 * jmpl	   jump_size
    881 	 * now jump_size - 1 random numbers...
    882 	 *
    883 	 * Where ZZZZ is random and will be skipped over by the
    884 	 * annuled branch never.  This is just to get the chksums of
    885 	 * executable sections to be different.
    886 	 */
    887 
    888 #if defined(__i386) || defined(__amd64)
    889 	ptr = ((uint32_t *)start);
    890 	*ptr++ = save_asm();
    891 
    892 	for (; ptr < (last - (jump_size + 2)); ptr += jump_size) {
    893 		int i;
    894 
    895 #if defined(__amd64)
    896 		t_inst = jmp_asm((jump_size - 1)  * sizeof (uint32_t));
    897 		*ptr++ = t_inst.thirtytwo[0];
    898 		*ptr = t_inst.thirtytwo[1];
    899 #else
    900 		t_inst = jmp_asm((jump_size - 1)  * sizeof (uint32_t));
    901 		*ptr++ = t_inst.thirtytwo[0];
    902 		*ptr = t_inst.thirtytwo[1];
    903 #endif
    904 #elif defined(SPARC)
    905 	for (ptr = start; ptr < (last - (jump_size + 2));
    906 	    ptr += jump_size) {
    907 		int i;
    908 
    909 		/* 0x30800000 | jump_size; SPARC ba,a jump_size */
    910 		*ptr = ba_asm(1, jump_size);
    911 #else
    912 #error "unknown pocesseor type"
    913 #endif
    914 
    915 		for (i = 0; i < (jump_size - 1); i++) {
    916 			if (i == 0)
    917 				*(ptr + 1 + i) = bufno;
    918 			else
    919 				*(ptr + 1 + i) = lrand48();
    920 		}
    921 	}
    922 #ifdef __sparc
    923 	*ptr++ = retl_asm(); /* sparc retl */
    924 #else /* Intel */
    925 	*ptr++ = ret_asm(); /* Again, hence the save_asm() earlier */
    926 #endif
    927 	while (ptr < last) {
    928 #ifdef __sparc
    929 		*(ptr++) = nop_asm(); /* SPARC nop */
    930 #else /* Intel */
    931 		*(ptr++) = NOPWORD;
    932 #endif
    933 	}
    934 }
    935 void
    936 init_func_buf(uchar_t *cbuf, int bufno)
    937 {
    938 	struct buf *buf;
    939 	/*
    940 	 * The under lying routines that init function buffers require
    941 	 * correct alignment so if the buffer passed in is not alligned
    942 	 * allocate a correctly aligned one and pass that to the other
    943 	 * routines.  memcpy all that data into the original buf.
    944 	 */
    945 	if (((ulong_t)cbuf % sizeof (uint64_t)) != 0) {
    946 		buf = (struct buf *)my_calloc(1,
    947 		    INDEX_TO_DIOLEN(max_disk_io_len));
    948 		if (buf == NULL) {
    949 			pfprintf(stderr,
    950 			    "unable to allocate temporary buffer\n");
    951 			exit(1);
    952 		}
    953 	} else {
    954 		/*LINTED Alignment*/
    955 		buf = (struct buf *)cbuf;
    956 	}
    957 
    958 	if ((lrand48() % 2) == 1)
    959 		init_func_buf_long(buf, bufno);
    960 	else
    961 		init_func_buf_branch(buf, bufno);
    962 
    963 	if (((ulong_t)cbuf % sizeof (uint64_t)) != 0) {
    964 		(void) memcpy(cbuf, (void *)buf,
    965 		    INDEX_TO_DIOLEN(max_disk_io_len));
    966 		free(buf);
    967 	}
    968 }
    969 
    970 struct bufhdr_a
    971 conv_bufhdr(struct bufhdr *in)
    972 {
    973 	struct bufhdr_a hdr;
    974 	ZERO_OBJ(hdr);
    975 	switch (in->start) {
    976 		case BUF_TYPE_A:
    977 			hdr = in->ab.a;
    978 			break;
    979 		case BUF_TYPE_B:
    980 			hdr.devid = in->ab.b.devid;
    981 			hdr.off = in->ab.b.off;
    982 			hdr.hdrchksum = in->ab.b.hdrchksum;
    983 			hdr.len = in->ab.b.len;
    984 			hdr.type = in->ab.b.type;
    985 			hdr.chksum = in->ab.b.chksum;
    986 			hdr.did = in->ab.b.did;
    987 			hdr.time = in->ab.b.time;
    988 			memcpy(hdr.serial_and_provider,
    989 			    in->ab.b.serial_and_provider,
    990 			    sizeof (hdr.serial_and_provider));
    991 			break;
    992 		default:
    993 			hdr.type.BUF_BAD_HDR = 1;
    994 			break;
    995 	}
    996 	return (hdr);
    997 }
    998 void
    999 toggle_bufhdr(uchar_t *buf)
   1000 {
   1001 	struct bufhdr newhdr, hdr;
   1002 	(void) memset(&newhdr, NULL, sizeof (struct bufhdr));
   1003 	hdr = get_bufhdr(buf);
   1004 
   1005 	switch (hdr.start) {
   1006 		case BUF_TYPE_A:
   1007 			newhdr.ab.b.time = hdr.ab.a.time;
   1008 			newhdr.ab.b.did = hdr.ab.a.did;
   1009 			newhdr.ab.b.chksum = hdr.ab.a.chksum;
   1010 			newhdr.ab.b.off = hdr.ab.a.off;
   1011 			newhdr.ab.b.type = hdr.ab.a.type;
   1012 			newhdr.ab.b.hdrchksum = hdr.ab.a.hdrchksum;
   1013 			newhdr.ab.b.len = hdr.ab.a.len;
   1014 			newhdr.ab.b.devid = hdr.ab.a.devid;
   1015 			memcpy(newhdr.ab.b.serial_and_provider,
   1016 			    hdr.ab.a.serial_and_provider,
   1017 			    sizeof (hdr.ab.a.serial_and_provider));
   1018 			newhdr.start = newhdr.end = BUF_TYPE_B;
   1019 			break;
   1020 		case BUF_TYPE_B:
   1021 			newhdr.ab.a.chksum = hdr.ab.b.chksum;
   1022 			newhdr.ab.a.len = hdr.ab.b.len;
   1023 			newhdr.ab.a.off = hdr.ab.b.off;
   1024 			newhdr.ab.a.type = hdr.ab.b.type;
   1025 			newhdr.ab.a.hdrchksum = hdr.ab.b.hdrchksum;
   1026 			newhdr.ab.a.devid = hdr.ab.b.devid;
   1027 			newhdr.ab.a.did = hdr.ab.b.did;
   1028 			newhdr.ab.a.time = hdr.ab.b.time;
   1029 			memcpy(newhdr.ab.a.serial_and_provider,
   1030 			    hdr.ab.b.serial_and_provider,
   1031 			    sizeof (hdr.ab.b.serial_and_provider));
   1032 			newhdr.start = newhdr.end = BUF_TYPE_A;
   1033 			break;
   1034 	}
   1035 	set_bufhdr(buf, newhdr);
   1036 }
   1037 
   1038 struct shadow_hdr const *
   1039 get_shadow_hdr_by_off(ulong_t off)
   1040 {
   1041 	char *ptr;
   1042 
   1043 	ptr = (char *)shadow_headers + (sizeof_shadow_header() * off);
   1044 	/*LINTED Alignment*/
   1045 	return ((struct shadow_hdr *)ptr);
   1046 }
   1047 
   1048 struct shadow_hdr const *
   1049 get_shadow_hdr(uchar_t *buf)
   1050 {
   1051 	ulong_t off;
   1052 
   1053 	off = get_buf_off(buf, write_bufs, INDEX_TO_DIOLEN(max_disk_io_len));
   1054 
   1055 	return (get_shadow_hdr_by_off(off));
   1056 }
   1057 
   1058 struct bufhdr
   1059 get_bufhdr(uchar_t *buf)
   1060 {
   1061 	struct bufhdr hdr;
   1062 	(void) memcpy(&hdr, (char *)buf, sizeof (struct bufhdr));
   1063 	return (hdr);
   1064 }
   1065 
   1066 struct bufhdr_a
   1067 get_bufhdr_a(uchar_t *buf)
   1068 {
   1069 	struct bufhdr_a hdr_a;
   1070 	struct bufhdr hdr;
   1071 
   1072 	hdr = get_bufhdr(buf);
   1073 	hdr_a = conv_bufhdr(&hdr);
   1074 	if (hdr_a.type.BUF_BAD_HDR)
   1075 		pfprintf(stderr, "Unknown buf type: buf %#lx type %#llx\n",
   1076 		    (ulong_t)buf, (long long)hdr.start);
   1077 	return (hdr_a);
   1078 }
   1079 
   1080 void
   1081 set_bufhdr(uchar_t *buf, struct bufhdr hdr)
   1082 {
   1083 	(void) memcpy(buf, (char *)&hdr, sizeof (struct bufhdr));
   1084 	assert(*buf == 0xAA || *buf == 0x55);
   1085 }
   1086 
   1087 struct bufhdr
   1088 set_hdr_a(struct bufhdr bufhdr, const struct bufhdr_a hdr)
   1089 {
   1090 	ZERO_OBJ(bufhdr.ab);
   1091 	switch (bufhdr.start) {
   1092 		case BUF_TYPE_A:
   1093 			bufhdr.ab.a = hdr;
   1094 			break;
   1095 		case BUF_TYPE_B:
   1096 			get_serial_and_provider(
   1097 			    bufhdr.ab.b.serial_and_provider,
   1098 			    SIZEOF_SERIAL_AND_PROVIDER);
   1099 			bufhdr.ab.b.chksum = hdr.chksum;
   1100 			bufhdr.ab.b.off = hdr.off;
   1101 			bufhdr.ab.b.len = hdr.len;
   1102 			bufhdr.ab.b.devid = hdr.devid;
   1103 			bufhdr.ab.b.hdrchksum = hdr.hdrchksum;
   1104 			bufhdr.ab.b.type = hdr.type;
   1105 			bufhdr.ab.b.time = hdr.time;
   1106 			bufhdr.ab.b.did = hdr.did;
   1107 			break;
   1108 		default:
   1109 			pfprintf(stderr,
   1110 			    "Unknown buf type: buf type %#llx "
   1111 			    "setting to A\n", (long long)bufhdr.start);
   1112 			bufhdr.ab.a = hdr;
   1113 			bufhdr.start = bufhdr.end = BUF_TYPE_A;
   1114 			break;
   1115 	}
   1116 	return (bufhdr);
   1117 }
   1118 static void
   1119 set_bufhdr_a(uchar_t *buf, struct bufhdr_a hdr_a)
   1120 {
   1121 	struct bufhdr hdr = get_bufhdr(buf);
   1122 	set_bufhdr(buf, set_hdr_a(hdr, hdr_a));
   1123 }
   1124 static uint64_t
   1125 get_hdrchksum(struct bufhdr hdr)
   1126 {
   1127 	struct bufhdr_a hdr_a;
   1128 	ZERO_OBJ(hdr_a);
   1129 	hdr_a = conv_bufhdr(&hdr);
   1130 	return (hdr_a.hdrchksum);
   1131 }
   1132 ushort16_t
   1133 get_bufhdr_hdrchksum(uchar_t *buf)
   1134 {
   1135 	return (get_hdrchksum(get_bufhdr(buf)));
   1136 }
   1137 ushort16_t
   1138 set_hdrchksum(struct bufhdr *hdr)
   1139 {
   1140 	struct bufhdr_a hdr_a;
   1141 	ushort16_t newchksum;
   1142 	ZERO_OBJ(hdr_a);
   1143 	hdr_a = conv_bufhdr(hdr);
   1144 	newchksum = check_hdr(hdr, hdr_a.hdrchksum);
   1145 	hdr_a.hdrchksum = newchksum;
   1146 	*hdr = set_hdr_a(*hdr, hdr_a);
   1147 	return (newchksum);
   1148 }
   1149 static uint_t
   1150 check_delay()
   1151 {
   1152 	uint_t delay_len;
   1153 	uint_t i;
   1154 
   1155 	if (opts.max_mem_delay == 0)
   1156 		return (0);
   1157 	for (i = delay_len = ((uint_t)lrand48() % opts.max_mem_delay);
   1158 	    i > 0; i--)
   1159 		/* LINTED */
   1160 		;
   1161 	return (delay_len);
   1162 }
   1163 
   1164 ushort16_t
   1165 set_buf_hdrchksum(uchar_t *buf)
   1166 {
   1167 	struct bufhdr_a hdr_a;
   1168 	struct bufhdr hdr;
   1169 	uint_t delay_len;
   1170 
   1171 	hdr = get_bufhdr(buf);
   1172 	hdr_a = conv_bufhdr(&hdr);
   1173 
   1174 	hdr_a.hdrchksum = check_hdr(&hdr, hdr_a.hdrchksum);
   1175 
   1176 	set_bufhdr_a(buf, hdr_a);
   1177 	delay_len = check_delay();
   1178 	if (hdr_a.hdrchksum != get_bufhdr_hdrchksum(buf)) {
   1179 		pfprintf(stderr, "buf %#lx bad header checksum read back "
   1180 		    "from memory after delay %d\n", (ulong_t)buf,
   1181 		    delay_len);
   1182 	}
   1183 	return (hdr_a.hdrchksum);
   1184 }
   1185 void
   1186 set_bufhdr_all(uchar_t *buf, check_t chksum, uint32_t len,
   1187 	struct device_id devid,
   1188 	ullong_t off,
   1189 	buf_data_type type,
   1190 	char sequence,
   1191 	time_t now)
   1192 {
   1193 	struct bufhdr_a hdr;
   1194 	ZERO_OBJ(hdr);
   1195 	hdr = get_bufhdr_a(buf);
   1196 	hdr.chksum = chksum;
   1197 	hdr.len = len;
   1198 	hdr.devid = devid;
   1199 	hdr.off = off;
   1200 	hdr.time = now;
   1201 	hdr.did = master_pid();
   1202 	get_serial_and_provider(hdr.serial_and_provider,
   1203 	    SIZEOF_SERIAL_AND_PROVIDER);
   1204 	hdr.type = type;
   1205 	hdr.type.sequence = sequence;
   1206 	hdr.type.padding = 0; /* not used */
   1207 	set_bufhdr_a(buf, hdr);
   1208 }
   1209 void
   1210 init_buf(uchar_t *buf)
   1211 {
   1212 	int x;
   1213 	struct bufhdr hdr;
   1214 	void *sig;
   1215 	int bufno = get_write_buf_id(buf);
   1216 	time_t now;
   1217 
   1218 	now = time(NULL);
   1219 
   1220 	x = lrand48();
   1221 
   1222 	x = x >> 10;
   1223 
   1224 	plog(LOG_DEBUG, "initalizing data buf %#lx\n", (ulong_t)buf);
   1225 	sig = expect_signal(SIGBUS, "memset", buf,
   1226 	    INDEX_TO_DIOLEN(max_disk_io_len) + opts.write_buffer_gap);
   1227 	unprotect_buf(buf);
   1228 	(void) memset((char *)buf, NULL, SIZEOF_BUFHDR);
   1229 	ZERO_OBJ(hdr);
   1230 	if (1 == opts.obscure_execute && x % 2) {
   1231 		init_func_buf(buf, bufno);
   1232 		hdr.start = hdr.end = BUF_TYPE_B;
   1233 		hdr.ab.b.chksum = 0;
   1234 		hdr.ab.b.len = 0;
   1235 		hdr.ab.b.type.BUF_EXECUTABLE = 1;
   1236 		hdr.ab.b.time = now;
   1237 		hdr.ab.b.did = master_pid();
   1238 		get_serial_and_provider(hdr.ab.b.serial_and_provider,
   1239 		    SIZEOF_SERIAL_AND_PROVIDER);
   1240 	} else {
   1241 		init_data_buf(buf, bufno);
   1242 		hdr.start = hdr.end = BUF_TYPE_A;
   1243 		hdr.ab.a.chksum = 0;
   1244 		hdr.ab.a.len = 0;
   1245 		hdr.ab.a.type.BUF_EXECUTABLE = 0;
   1246 		hdr.ab.a.time = now;
   1247 		hdr.ab.a.did = master_pid();
   1248 		get_serial_and_provider(hdr.ab.a.serial_and_provider,
   1249 		    SIZEOF_SERIAL_AND_PROVIDER);
   1250 	}
   1251 	(void) set_hdrchksum(&hdr);
   1252 	set_bufhdr(buf, hdr);
   1253 	protect_buf(buf);
   1254 
   1255 	TNF_PROBE_1(init_buf, "init_buf", "sunw%cte%diskomizer%bufs init",
   1256 	    tnf_opaque, buf, buf);
   1257 	cancel_expected_signal(SIGBUS, sig);
   1258 }
   1259 ushort16_t
   1260 check_hdr(struct bufhdr *hdr, ushort16_t hdrchksum)
   1261 {
   1262 	uchar_t *x;
   1263 	ushort16_t total;
   1264 	char i;
   1265 
   1266 	x = (uchar_t *)hdr;
   1267 
   1268 	for (i = total = 0; i < SIZEOF_BUFHDR; i++) {
   1269 		total += x[i];
   1270 	}
   1271 	total -= u_short_chksum(hdrchksum);
   1272 
   1273 	return (total);
   1274 }
   1275 
   1276 ushort16_t
   1277 check_bufhdr(uchar_t *buf, ushort16_t hdrchksum)
   1278 {
   1279 	struct bufhdr hdr = get_bufhdr(buf);
   1280 	return (check_hdr(&hdr, hdrchksum));
   1281 }
   1282 
   1283 check_t
   1284 check_bufbody(uchar_t *buf, ulong_t size)
   1285 {
   1286 	return (check_sum(buf + SIZEOF_BUFHDR, size - SIZEOF_BUFHDR));
   1287 }
   1288 
   1289 check_t
   1290 check_aiobuf(struct aio_str *aiop)
   1291 {
   1292 	return (check_buf(aiop->buf, opts.disk_io_sizes.vals[aiop->iolen],
   1293 	    &aiop->error));
   1294 }
   1295 
   1296 check_t
   1297 check_buf(uchar_t *buf, int len, struct error *error)
   1298 {
   1299 	struct bufhdr_a hdr_a;
   1300 	check_t total;
   1301 	ushort16_t hdrchksum;
   1302 	struct bufhdr hdr;
   1303 
   1304 	hdr = get_bufhdr(buf);
   1305 	hdr_a = conv_bufhdr(&hdr);
   1306 
   1307 	total = check_bufbody(buf, hdr_a.len);
   1308 	hdrchksum = check_hdr(&hdr, hdr_a.hdrchksum);
   1309 
   1310 	if (hdr_a.len != len) {
   1311 		error->desc.LENGTH_MISMATCH = 1;
   1312 		error->len = hdr_a.len;
   1313 	}
   1314 	if (hdr_a.hdrchksum != hdrchksum) {
   1315 		dfprintf(stderr, "buf %#lx bad header checksum "
   1316 		    "is %x should be %x\n", (ulong_t)buf,
   1317 		    hdr_a.hdrchksum, hdrchksum);
   1318 
   1319 		error->desc.HEADER_CHECKSUM_ERR = 1;
   1320 		error->bad_checksum = hdrchksum;
   1321 		return (0);
   1322 	}
   1323 
   1324 	if (hdr_a.chksum != total) {
   1325 		TNF_PROBE_4(check_buf, "check_buf",
   1326 		    "sunw%cte%diskomizer%bufs check",
   1327 		    tnf_opaque, hdrchksum, hdrchksum,
   1328 		    tnf_opaque, total, total,
   1329 		    tnf_opaque, hdr_a.chksum, hdr_a.chksum,
   1330 		    tnf_opaque, buf, buf);
   1331 
   1332 		error->desc.BODY_CHECKSUM_ERR = 1;
   1333 		error->bad_checksum = total;
   1334 
   1335 		if (opts.fix_bad_checksums) {
   1336 			hdr_a.chksum = total;
   1337 			set_bufhdr_a(buf, hdr_a);
   1338 			if (is_executable(buf)) {
   1339 				dfprintf(stderr,
   1340 				    "buf %#lx bad func checksum %#x != "
   1341 				    "%#llx - fixed\n", (ulong_t)buf, total,
   1342 				    (long long)hdr_a.chksum);
   1343 			} else {
   1344 				dfprintf(stderr,
   1345 				    "buf %#lx bad data checksum %#llx != "
   1346 				    "%#llx - fixed\n", (ulong_t)buf, total,
   1347 				    (long long)hdr_a.chksum);
   1348 			}
   1349 		} else {
   1350 			if (is_executable(buf)) {
   1351 				dfprintf(stderr,
   1352 				    "buf %#lx bad func checksum %#llx != "
   1353 				    "%#llx\n", (ulong_t)buf, total,
   1354 				    (long long)hdr_a.chksum);
   1355 			} else {
   1356 				dfprintf(stderr,
   1357 				    "buf %#lx bad data checksum %#llx != "
   1358 				    "%#llx\n", (ulong_t)buf, total,
   1359 				    (long long)hdr_a.chksum);
   1360 			}
   1361 		}
   1362 	}
   1363 	return (total);
   1364 }
   1365 void
   1366 save_data_bufs(void)
   1367 {
   1368 	FILE *save_file;
   1369 	uchar_t *buf = write_bufs;
   1370 	ullong_t blksize = INDEX_TO_DIOLEN(max_disk_io_len) +
   1371 	    opts.write_buffer_gap;
   1372 	ullong_t len = blksize * opts.nwritebufs;
   1373 	uint64_t i;
   1374 	uchar_t *new;
   1375 	char *path_buf;
   1376 	time_t now;
   1377 	if (opts.data_file == NULL || opts.save_data == 0) {
   1378 		return;
   1379 	}
   1380 
   1381 	path_buf = alloca(strlen(opts.data_file) + 32);
   1382 
   1383 	(void) sprintf(path_buf, "%s/data_file", opts.data_file);
   1384 
   1385 	(void) mkdir(opts.data_file, 0777);
   1386 
   1387 	if ((save_file = fopen(path_buf, "w")) == NULL) {
   1388 		FOPEN_ERROR(path_buf, "w");
   1389 		return;
   1390 	}
   1391 
   1392 	now = time(NULL);
   1393 	(void) fprintf(save_file, "#\n# diskomizer %s\n# Updated %s#\n",
   1394 	    VERSION, ctime(&now));
   1395 
   1396 	/*LINTED*/
   1397 	new = buf;
   1398 	for (i = 0; i < len/sizeof (uint64_t); i++, new += sizeof (uint64_t)) {
   1399 		(void) fprintf(save_file,
   1400 		    "%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x",
   1401 		    *new, *(new+1), *(new+2), *(new+3),
   1402 		    *(new+4), *(new+5), *(new+6), *(new+7));
   1403 		if (((ulong_t)new % blksize) == 0)
   1404 			(void) fprintf(save_file, " # New Block\n");
   1405 		else
   1406 			(void) fprintf(save_file, "\n");
   1407 	}
   1408 
   1409 	now = time(NULL);
   1410 	(void) fprintf(save_file, "#\n# diskomizer %s\n# Updated %s#\n",
   1411 	    VERSION, ctime(&now));
   1412 	(void) fflush(save_file);
   1413 	if (fsync(fileno(save_file)) == -1) {
   1414 		FSYNC_ERROR(fileno(save_file), path_buf);
   1415 	}
   1416 	(void) fclose(save_file);
   1417 
   1418 	(void) sprintf(path_buf, "%s/option_file", opts.data_file);
   1419 	if ((save_file = fopen(path_buf, "w")) == NULL) {
   1420 		FOPEN_ERROR(path_buf, "w");
   1421 		return;
   1422 	}
   1423 
   1424 	(void) fprintf(save_file, "# Diskimizer %s\n", VERSION);
   1425 	(void) print_options(save_file);
   1426 
   1427 	(void) fflush(save_file);
   1428 	if (fsync(fileno(save_file)) == -1) {
   1429 		FSYNC_ERROR(fileno(save_file), path_buf);
   1430 	}
   1431 	(void) fclose(save_file);
   1432 }
   1433 /*
   1434  * This needs rethinking.
   1435  */
   1436 static char *
   1437 init_from_file(uchar_t *buf, ullong_t len)
   1438 {
   1439 	char *data_file;
   1440 	char *tmp;
   1441 	uint64_t *new;
   1442 	uint64_t i = 0;
   1443 	time_t last_read = 0;
   1444 	size_t maping_len;
   1445 	char *path_buf = opts.data_file;
   1446 	/*LINTED*/
   1447 	new = (uint64_t *)buf;
   1448 
   1449 	if ((data_file = map_file(path_buf, &last_read,
   1450 	    &maping_len, pprintf, NULL)) == NULL) {
   1451 
   1452 		path_buf = alloca(strlen(opts.data_file) + 10);
   1453 		(void) sprintf(path_buf, "%s/data_file", opts.data_file);
   1454 		last_read = 0;
   1455 
   1456 		if ((data_file = map_file(path_buf, &last_read,
   1457 		    &maping_len, pprintf, NULL)) == NULL) {
   1458 			pperror("map_file: can't read data bufs from %s",
   1459 			    path_buf);
   1460 			return (NULL);
   1461 		}
   1462 	}
   1463 	if (*(data_file+maping_len-1) != '\n') {
   1464 		pprintf("Incomplete last line in data file %s\n",
   1465 		    path_buf);
   1466 		(void) munmap(data_file, maping_len);
   1467 		return (0);
   1468 	}
   1469 	*(data_file+maping_len-1) = NULL;
   1470 
   1471 
   1472 	tmp = data_file;
   1473 	while (i < len/sizeof (uint64_t)) {
   1474 		char *next;
   1475 		uint64_t x;
   1476 
   1477 		if (*tmp == NULL)
   1478 			break;
   1479 		while (*tmp != '0') {
   1480 			while (*tmp != '\n') {
   1481 				if (*tmp == NULL)
   1482 					break;
   1483 				tmp++;
   1484 			}
   1485 			if (*tmp == NULL)
   1486 				break;
   1487 			tmp++;
   1488 			if (*tmp == NULL)
   1489 				break;
   1490 		}
   1491 		if (*tmp == NULL)
   1492 			break;
   1493 		if (*tmp == '0' && (*(tmp+1) == 'x' || *(tmp+1) == 'X'))
   1494 			tmp += 2;
   1495 		x = strtoull(tmp, &next, 16);
   1496 #ifdef _BIG_ENDIAN
   1497 		*new = x;
   1498 #elif defined(_LITTLE_ENDIAN)
   1499 		swab((char *)&x, (char *)new, sizeof (uint64_t));
   1500 #else
   1501 
   1502 #error "niether _BIG_ENDIAN or _LITTLE_ENDIAN defined"
   1503 
   1504 #endif /* BIG_ENDIAN or _LITTLE_ENDIAN */
   1505 
   1506 		while (*next != '\n') {
   1507 			if (*next == NULL)
   1508 				break;
   1509 			next++;
   1510 		}
   1511 		i++;
   1512 		new++;
   1513 		if (*next == NULL)
   1514 			break;
   1515 		tmp = next + 1;
   1516 	}
   1517 
   1518 	(void) munmap(data_file, maping_len);
   1519 	return ((char *)&new[0]);
   1520 }
   1521 int
   1522 is_write_io(struct aio_str *aiop)
   1523 {
   1524 	return (aiop->handler == handle_write ||
   1525 	    aiop->handler == handle_write_then_read);
   1526 }
   1527 int
   1528 is_read_io(struct aio_str *aiop)
   1529 {
   1530 	return (!is_write_io(aiop));
   1531 }
   1532 static void
   1533 analyze_header(FILE *out, const struct bufhdr *good, const struct bufhdr *bad)
   1534 {
   1535 }
   1536 /*
   1537  * More macro hell.
   1538  *
   1539  * These 2 macros are used to print information about buffer headers. Before
   1540  * calling them, define the macros DO_PRINT, DO_PRINT_BIT_FIELD, DO_PRINT_TIME
   1541  * and DO_PRINT_STRING to do what you want.
   1542  *
   1543  */
   1544 #define	PRINT_A_HDR(O) \
   1545 	DO_PRINT(O, start); \
   1546 	DO_PRINT_STRING(O, ab.a.serial_and_provider); \
   1547 	DO_PRINT(O, ab.a.devid.ino); \
   1548 	DO_PRINT(O, ab.a.devid.dev); \
   1549 	DO_PRINT(O, ab.a.hdrchksum); \
   1550 	DO_PRINT_BIT_FIELD(O, ab.a.type); \
   1551 	DO_PRINT(O, ab.a.chksum); \
   1552 	DO_PRINT(O, ab.a.did); \
   1553 	DO_PRINT(O, ab.a.len); \
   1554 	DO_PRINT(O, ab.a.off); \
   1555 	DO_PRINT_TIME(O, ab.a.time); \
   1556 	DO_PRINT(O, end)
   1557 #define	PRINT_B_HDR(O) \
   1558 	DO_PRINT(O, start); \
   1559 	DO_PRINT(O, ab.b.off); \
   1560 	DO_PRINT_TIME(O, ab.b.time); \
   1561 	DO_PRINT(O, ab.b.len); \
   1562 	DO_PRINT(O, ab.b.did); \
   1563 	DO_PRINT(O, ab.b.devid.ino); \
   1564 	DO_PRINT(O, ab.b.devid.dev); \
   1565 	DO_PRINT(O, ab.b.hdrchksum); \
   1566 	DO_PRINT_BIT_FIELD(O, ab.b.type); \
   1567 	DO_PRINT(O, ab.b.chksum); \
   1568 	DO_PRINT_STRING(O, ab.b.serial_and_provider); \
   1569 	DO_PRINT(O, end)
   1570 void
   1571 decode_header(FILE *out,  uchar_t *good, uchar_t *bad)
   1572 {
   1573 	struct bufhdr bufhdr, bhdr;
   1574 	(void) memcpy(&bufhdr, good, sizeof (struct bufhdr));
   1575 	(void) memcpy(&bhdr, bad, sizeof (struct bufhdr));
   1576 	(void) fprintf(out, "%29s %18s %18s\n", gettext("Decoding header"),
   1577 	    gettext("Good"), gettext("Bad"));
   1578 #define	DO_PRINT(O, A) (void) fprintf(O, "hdr.%-25s %#18llx %#18llx\n", #A, \
   1579 		(long long)bufhdr.A, (long long)bhdr.A)
   1580 
   1581 #define	DO_PRINT_STRING(O, A) (void) fprintf(O, "hdr.%-25s \"%.*s\"\n" \
   1582 	"%-48s \"%.*s\"\n", #A, (int)sizeof (bufhdr.A), bufhdr.A, " ", \
   1583 		(int)sizeof (bhdr.A), bhdr.A)
   1584 
   1585 #define	DO_PRINT_TIME(O, A) {\
   1586 		char *x = alloc_time_str(bufhdr.A);\
   1587 \
   1588 		if (x != NULL) {\
   1589 			fprintf(O, "hdr.%-25s \"%s\"\n", #A, x); \
   1590 			free(x);\
   1591 			if ((x = alloc_time_str(bhdr.A)) != NULL) {\
   1592 				fprintf(O, "%-48s \"%s\"\n", " ", x);\
   1593 				free(x);\
   1594 			}\
   1595 		}\
   1596 	}
   1597 
   1598 #define	DO_PRINT_BIT_FIELD(O, A) \
   1599 	DO_PRINT(O, A.BUF_EXECUTABLE); \
   1600 	DO_PRINT(O, A.BUF_BAD_HDR); \
   1601 	DO_PRINT(O, A.BUF_BAD_CHKSUM); \
   1602 	DO_PRINT(O, A.BUF_READ_ONLY); \
   1603 	DO_PRINT(O, A.BUF_READY); \
   1604 	DO_PRINT(O, A.sequence)
   1605 /*
   1606  * If both headers are of the same type and both have good check sums then
   1607  * only decode the header as the claim to be.
   1608  */
   1609 	if (bhdr.start != BUF_TYPE_B || bufhdr.start != BUF_TYPE_B ||
   1610 	    check_hdr(&bhdr, bhdr.ab.b.hdrchksum) != bhdr.ab.b.hdrchksum ||
   1611 	    check_hdr(&bufhdr, bufhdr.ab.b.hdrchksum) !=
   1612 	    bufhdr.ab.b.hdrchksum) {
   1613 		PRINT_A_HDR(out);
   1614 	}
   1615 	if (bhdr.start != BUF_TYPE_A || bufhdr.start != BUF_TYPE_A ||
   1616 	    check_hdr(&bhdr, bhdr.ab.a.hdrchksum) != bhdr.ab.a.hdrchksum ||
   1617 	    check_hdr(&bufhdr, bufhdr.ab.a.hdrchksum) !=
   1618 	    bufhdr.ab.a.hdrchksum) {
   1619 		PRINT_B_HDR(out);
   1620 	}
   1621 #undef DO_PRINT
   1622 #undef DO_PRINT_TIME
   1623 #undef DO_PRINT_BIT_FIELD
   1624 #undef DO_PRINT_STRING
   1625 }
   1626 void
   1627 print_bufhdr_offsets(FILE *out)
   1628 {
   1629 #define	bufhdr (*((struct bufhdr *)0))
   1630 	static const char heading[] = "Element                 Offset"
   1631 	    "                                     Size\n";
   1632 	static const char fmt[] = "bufhdr.%-14s 0x%2.2lx (0t%3.3ld) "
   1633 	    "sizeof (bufhdr.%-14s) 0x%2.2x (0t%2.2d)\n";
   1634 	static const char fmt2[] = "bufhdr.%s\n%-21s 0x%2.2lx (0t%3.3ld) "
   1635 	    "sizeof (bufhdr.%-14.14s) 0x%2.2x (0t%2.2d)\n";
   1636 
   1637 #define	DO_PRINT(O, A) \
   1638 	if (strlen(#A) > 14) { \
   1639 		(void) fprintf(O, fmt2, #A, " ", \
   1640 		    ((ulong_t)&bufhdr.A) - ((ulong_t)&bufhdr), \
   1641 		    ((ulong_t)&bufhdr.A) - ((ulong_t)&bufhdr), #A, \
   1642 		    sizeof (bufhdr.A), sizeof (bufhdr.A)); \
   1643 	} else { \
   1644 		(void) fprintf(O, \
   1645 		    fmt, #A, ((ulong_t)&bufhdr.A) - ((ulong_t)&bufhdr), \
   1646 		    ((ulong_t)&bufhdr.A) - ((ulong_t)&bufhdr), #A, \
   1647 		    sizeof (bufhdr.A), sizeof (bufhdr.A)); \
   1648 	}
   1649 #define	DO_PRINT_STRING(O, A) DO_PRINT(O, A)
   1650 #define	DO_PRINT_TIME(O, A) DO_PRINT(O, A)
   1651 #define	DO_PRINT_BIT_FIELD(A, B) DO_PRINT(A, B)
   1652 
   1653 	(void) fprintf(out,
   1654 	    "Type A buffer header start and end value = %#llx:\n",
   1655 	    (unsigned long long)BUF_TYPE_A);
   1656 	(void) fprintf(out, heading);
   1657 	PRINT_A_HDR(out);
   1658 	(void) fprintf(out,
   1659 	    "Type B buffer header start and end value = %#llx:\n",
   1660 	    (unsigned long long)BUF_TYPE_B);
   1661 	(void) fprintf(out, heading);
   1662 	PRINT_B_HDR(out);
   1663 #undef bufhdr
   1664 }
   1665 uchar_t *
   1666 get_read_buf(void)
   1667 {
   1668 	static ullong_t next_off;
   1669 	uchar_t *buf;
   1670 	buf = get_buf(read_bufs, opts.nreadbufs,
   1671 	    INDEX_TO_DIOLEN(max_disk_io_len),
   1672 	    readmap, readmap_size, &next_off);
   1673 	TNF_PROBE_1(get_read_buf, "get_read_buf",
   1674 	    "sunw%cte%diskomizer%bufs get read",
   1675 	    tnf_opaque, buf, buf);
   1676 	return (buf);
   1677 }
   1678 void
   1679 return_read_buf(uchar_t *buf)
   1680 {
   1681 	TNF_PROBE_1(return_read_buf, "return_read_buf",
   1682 	    "sunw%cte%diskomizer%bufs return read",
   1683 	    tnf_opaque, buf, buf);
   1684 	return_buf(buf, read_bufs, INDEX_TO_DIOLEN(max_disk_io_len), readmap,
   1685 	    readmap_size, opts.nreadbufs);
   1686 }
   1687 void
   1688 init_read_bufs(struct device *devices)
   1689 {
   1690 	int ndevices = how_many_devices(devices);
   1691 	int total_reads = opts.rthreads + opts.wrthreads;
   1692 	ulong_t tmp, tmp1;
   1693 #ifndef _LP64
   1694 	long long q;
   1695 	ulong_t x;
   1696 #endif
   1697 	assert(ndevices);
   1698 	assert(opts.nprocs);
   1699 	if (is_readonly()) {
   1700 		total_reads += opts.wthreads;
   1701 	}
   1702 	tmp1 = tmp =  ndevices*opts.nprocs*total_reads;
   1703 
   1704 	tmp = (tmp*11)/10;
   1705 
   1706 	if (opts.nreadbufs == 0)
   1707 		opts.nreadbufs = tmp1 * opts.obscure_buffer_multiplier;
   1708 
   1709 	/*
   1710 	 * Make sure that there is at least one spare block per
   1711 	 * process.
   1712 	 */
   1713 	tmp1 += opts.nprocs;
   1714 
   1715 	tmp = MAX(tmp, tmp1);
   1716 
   1717 	opts.nreadbufs = MAX(opts.nreadbufs, tmp);
   1718 
   1719 	assert(opts.nreadbufs);
   1720 	tmp = opts.nreadbufs;
   1721 	tmp = (tmp % MAP_BITS ? 1 : 0) + tmp / MAP_BITS;
   1722 
   1723 	if (opts.obscure_readmap_size == 0)
   1724 		readmap_size = tmp;
   1725 	else
   1726 		readmap_size = opts.obscure_readmap_size;
   1727 	print_number((long long)opts.nreadbufs, "read buf", "read bufs");
   1728 
   1729 #ifndef _LP64
   1730 	q = opts.nreadbufs;
   1731 	q *= INDEX_TO_DIOLEN(max_disk_io_len);
   1732 	x = 0;
   1733 	x = ~x;
   1734 	if (q > (long long)x) {
   1735 		pprintf("Read buffers (%#llx) will not fit in a "
   1736 		    "%d (%#x) bit address space\n",
   1737 		    q, sizeof (long) * 8, sizeof (long) * 8);
   1738 		pprintf("nreadbufs * block_size: %#lx * %#lx = %#llx\n",
   1739 		    opts.nreadbufs,
   1740 		    (ulong_t)INDEX_TO_DIOLEN(max_disk_io_len), q);
   1741 		/* exit (1); */
   1742 	}
   1743 #endif
   1744 
   1745 	plog(LOG_DEBUG, "Allocating %ld * %ld\n", opts.nreadbufs,
   1746 	    INDEX_TO_DIOLEN(max_disk_io_len) * sizeof (char));
   1747 
   1748 	assert(opts.nreadbufs);
   1749 	alloc_io_bufs(opts.nreadbufs, INDEX_TO_DIOLEN(max_disk_io_len),
   1750 	    readmap_size, &read_bufs, &readmap);
   1751 	print_number((long long)(readmap_size * MAP_BITS), "Bit in read map",
   1752 	    "Bits in read map");
   1753 }
   1754 uchar_t *
   1755 get_buf_data(uchar_t *buf)
   1756 {
   1757 	return (buf + SIZEOF_BUFHDR);
   1758 }
   1759 void
   1760 alloc_io_bufs(ulong_t nbufs, ulong_t buf_size, ulong_t map_size,
   1761 	unsigned char **bufs, bitmap_t **map)
   1762 {
   1763 
   1764 	*bufs = (uchar_t *)alloc_mem(nbufs, buf_size * sizeof (char));
   1765 	*map = (bitmap_t *)alloc_mem(map_size, sizeof (bitmap_t));
   1766 }
   1767 char
   1768 is_executable(uchar_t *buf)
   1769 {
   1770 	struct bufhdr_a hdr = get_bufhdr_a(buf);
   1771 	return (hdr.type.BUF_EXECUTABLE);
   1772 }
   1773 void
   1774 random_string(char *str, int len)
   1775 {
   1776 	int i;
   1777 
   1778 	for (i = 0; i < len; i++) {
   1779 		str[i] = (char)(0x7f & lrand48());
   1780 	}
   1781 }
   1782 void
   1783 set_serial_and_provider(void)
   1784 {
   1785 	char serial[257];
   1786 	char provider[257];
   1787 
   1788 	ZERO_OBJ(serial_and_provider);
   1789 
   1790 	if (sysinfo(SI_HW_SERIAL, &serial[0], sizeof (serial)) == -1) {
   1791 		int err = errno;
   1792 
   1793 		random_string(serial, sizeof (serial));
   1794 		plog(LOG_NOTICE, "Unable to determine serial number: %s. "
   1795 		    "Using random value of %s", strerror(err), serial);
   1796 	}
   1797 	if (sysinfo(SI_HW_PROVIDER, &provider[0], sizeof (provider)) == -1) {
   1798 		int err = errno;
   1799 		random_string(provider, sizeof (provider));
   1800 		plog(LOG_NOTICE, "Unable to determine hardware provider: %s. "
   1801 		    "Using random value of %s", strerror(err), provider);
   1802 	}
   1803 	snprintf(serial_and_provider, sizeof (serial_and_provider),
   1804 	    "%.24s%s", serial, provider);
   1805 }
   1806 void
   1807 get_serial_and_provider(char *buf, int len)
   1808 {
   1809 	memcpy(buf, serial_and_provider, MIN(SIZEOF_SERIAL_AND_PROVIDER, len));
   1810 }
   1811 void
   1812 print_serial_and_provider(FILE *out)
   1813 {
   1814 	int i;
   1815 	(void) fprintf(out,
   1816 	    "Serial and provider:\n\tASCII\n\t\t\"%s\"\n\tHex:\n\t\t\"",
   1817 	    serial_and_provider);
   1818 	for (i = 0; i < SIZEOF_SERIAL_AND_PROVIDER; i++) {
   1819 		(void) fprintf(out, "%2.2x", serial_and_provider[i]);
   1820 	}
   1821 	(void) fprintf(out, "\"\n");
   1822 
   1823 }
   1824 
   1825 int
   1826 cmp_serial_and_provider(const char *buf)
   1827 {
   1828 	return (memcmp(buf, serial_and_provider, SIZEOF_SERIAL_AND_PROVIDER));
   1829 }
   1830