static int vnread_shadow(struct vn_softc * vn, struct uio *uio, int ioflag, vfs_context_t ctx) { u_int32_t blocksize = vn->sc_secsize; int error = 0; off_t offset; user_ssize_t resid; off_t orig_offset; user_ssize_t orig_resid; orig_resid = resid = uio_resid(uio); orig_offset = offset = uio_offset(uio); while (resid > 0) { u_int32_t remainder; u_int32_t this_block_number; u_int32_t this_block_count; off_t this_offset; user_ssize_t this_resid; struct vnode * vp; /* figure out which blocks to read */ remainder = block_remainder(offset, blocksize); if (shadow_map_read(vn->sc_shadow_map, block_truncate(offset, blocksize), block_round(resid + remainder, blocksize), &this_block_number, &this_block_count)) { vp = vn->sc_shadow_vp; } else { vp = vn->sc_vp; } /* read the blocks (or parts thereof) */ this_offset = (off_t)this_block_number * blocksize + remainder; uio_setoffset(uio, this_offset); this_resid = this_block_count * blocksize - remainder; if (this_resid > resid) { this_resid = resid; } uio_setresid(uio, this_resid); error = VNOP_READ(vp, uio, ioflag, ctx); if (error) { break; } /* figure out how much we actually read */ this_resid -= uio_resid(uio); if (this_resid == 0) { printf("vn device: vnread_shadow zero length read\n"); break; } resid -= this_resid; offset += this_resid; } uio_setresid(uio, resid); uio_setoffset(uio, offset); return (error); }
static int shadow_read(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 read_shadow; 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; struct vnode * vp; read_shadow = shadow_map_read(vn->sc_shadow_map, offset, resid, &this_offset, &this_resid); if (read_shadow) { vp = vn->sc_shadow_vp; } else { vp = vn->sc_vp; } error = file_io(vp, ctx, UIO_READ, 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_read zero length read\n"); break; } resid -= this_resid; offset += this_resid; start += this_resid * blocksize; } buf_setresid(bp, resid * blocksize); 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); }