static int shadow_write(struct vn_softc * vn, struct buf * bp, char * base, vfs_context_t ctx) { u_int32_t blocksize = vn->sc_secsize; int error = 0; u_int32_t offset; boolean_t shadow_grew; u_int32_t resid; u_int32_t start = 0; offset = buf_blkno(bp); resid = buf_resid(bp) / blocksize; while (resid > 0) { user_ssize_t temp_resid; u_int32_t this_offset; u_int32_t this_resid; shadow_grew = shadow_map_write(vn->sc_shadow_map, offset, resid, &this_offset, &this_resid); if (shadow_grew) { #if 0 off_t size; /* truncate the file to its new length before write */ size = (off_t)shadow_map_shadow_size(vn->sc_shadow_map) * blocksize; vnode_setsize(vn->sc_shadow_vp, size, IO_SYNC, ctx); #endif } error = file_io(vn->sc_shadow_vp, ctx, UIO_WRITE, base + start, (off_t)this_offset * blocksize, (user_ssize_t)this_resid * blocksize, &temp_resid); if (error) { break; } this_resid -= (temp_resid / blocksize); if (this_resid == 0) { printf("vn device: shadow_write zero length write\n"); break; } resid -= this_resid; offset += this_resid; start += this_resid * blocksize; } buf_setresid(bp, resid * blocksize); return (error); }
static int vnwrite_shadow(struct vn_softc * vn, struct uio *uio, int ioflag, vfs_context_t ctx) { u_int32_t blocksize = vn->sc_secsize; int error = 0; user_ssize_t resid; off_t offset; resid = uio_resid(uio); offset = uio_offset(uio); while (resid > 0) { int flags = 0; u_int32_t offset_block_number; u_int32_t remainder; u_int32_t resid_block_count; u_int32_t shadow_block_count; u_int32_t shadow_block_number; user_ssize_t this_resid; /* figure out which blocks to write */ offset_block_number = block_truncate(offset, blocksize); remainder = block_remainder(offset, blocksize); resid_block_count = block_round(resid + remainder, blocksize); /* figure out if the first or last blocks are partial writes */ if (remainder > 0 && !shadow_map_is_written(vn->sc_shadow_map, offset_block_number)) { /* the first block is a partial write */ flags |= FLAGS_FIRST_BLOCK_PARTIAL; } if (resid_block_count > 1 && !shadow_map_is_written(vn->sc_shadow_map, offset_block_number + resid_block_count - 1) && block_remainder(offset + resid, blocksize) > 0) { /* the last block is a partial write */ flags |= FLAGS_LAST_BLOCK_PARTIAL; } if (shadow_map_write(vn->sc_shadow_map, offset_block_number, resid_block_count, &shadow_block_number, &shadow_block_count)) { /* shadow file is growing */ #if 0 /* truncate the file to its new length before write */ off_t size; size = (off_t)shadow_map_shadow_size(vn->sc_shadow_map) * vn->sc_secsize; vnode_setsize(vn->sc_shadow_vp, size, IO_SYNC, ctx); #endif } /* write the blocks (or parts thereof) */ uio_setoffset(uio, (off_t) shadow_block_number * blocksize + remainder); this_resid = (off_t)shadow_block_count * blocksize - remainder; if (this_resid >= resid) { this_resid = resid; if ((flags & FLAGS_LAST_BLOCK_PARTIAL) != 0) { /* copy the last block to the shadow */ u_int32_t d; u_int32_t s; s = offset_block_number + resid_block_count - 1; d = shadow_block_number + shadow_block_count - 1; error = vncopy_block_to_shadow(vn, ctx, s, d); if (error) { printf("vnwrite_shadow: failed to copy" " block %u to shadow block %u\n", s, d); break; } } } uio_setresid(uio, this_resid); if ((flags & FLAGS_FIRST_BLOCK_PARTIAL) != 0) { /* copy the first block to the shadow */ error = vncopy_block_to_shadow(vn, ctx, offset_block_number, shadow_block_number); if (error) { printf("vnwrite_shadow: failed to" " copy block %u to shadow block %u\n", offset_block_number, shadow_block_number); break; } } error = VNOP_WRITE(vn->sc_shadow_vp, uio, ioflag, ctx); if (error) { break; } /* figure out how much we actually wrote */ this_resid -= uio_resid(uio); if (this_resid == 0) { printf("vn device: vnwrite_shadow zero length write\n"); break; } resid -= this_resid; offset += this_resid; } uio_setresid(uio, resid); uio_setoffset(uio, offset); return (error); }
int main() { shadow_map_t * map; int i; block_request_t requests[] = { { WriteRequest, BAND_SIZE_BLOCKS * 2, 1 }, { ReadRequest, BAND_SIZE_BLOCKS / 2, BAND_SIZE_BLOCKS * 2 - 2 }, { WriteRequest, BAND_SIZE_BLOCKS * 1, 5 * BAND_SIZE_BLOCKS + 3}, { ReadRequest, 0, BAND_SIZE_BLOCKS * 10 }, { WriteRequest, BAND_SIZE_BLOCKS * (BAND_MAX - 1), BAND_SIZE_BLOCKS * 2}, { 0, 0 }, }; map = shadow_map_create(1024 * 1024 * 1024 * 8ULL, 0, 0, 512); if (map == NULL) { printf("shadow_map_create failed\n"); exit(1); } for (i = 0; TRUE; i++) { u_long offset; u_long resid; boolean_t shadow_grew; boolean_t read_shadow; if (requests[i].count == 0) { break; } offset = requests[i].offset; resid = requests[i].count; printf("\n%s REQUEST (%ld, %ld)\n", requests[i].type == WriteRequest ? "WRITE" : "READ", offset, resid); switch (requests[i].type) { case WriteRequest: while (resid > 0) { u_long this_offset; u_long this_count; shadow_grew = shadow_map_write(map, offset, resid, &this_offset, &this_count); printf("\t(%ld, %ld) => (%ld, %ld)", offset, resid, this_offset, this_count); resid -= this_count; offset += this_count; if (shadow_grew) { printf(" shadow grew to %ld", shadow_map_shadow_size(map)); } printf("\n"); } break; case ReadRequest: while (resid > 0) { u_long this_offset; u_long this_count; read_shadow = shadow_map_read(map, offset, resid, &this_offset, &this_count); printf("\t(%ld, %ld) => (%ld, %ld)%s\n", offset, resid, this_offset, this_count, read_shadow ? " from shadow" : ""); if (this_count == 0) { printf("this_count is 0, aborting\n"); break; } resid -= this_count; offset += this_count; } break; default: break; } } if (map) { shadow_map_free(map); } exit(0); return (0); }