/* * Do I/O of a whole region of data, whether or not it's block-aligned. */ static int sfs_io(struct sfs_vnode *sv, struct uio *uio) { u_int32_t blkoff; u_int32_t nblocks, i; int result = 0; u_int32_t extraresid = 0; /* * If reading, check for EOF. If we can read a partial area, * remember how much extra there was in EXTRARESID so we can * add it back to uio_resid at the end. */ if (uio->uio_rw == UIO_READ) { off_t size = sv->sv_i.sfi_size; off_t endpos = uio->uio_offset + uio->uio_resid; if (uio->uio_offset >= size) { /* At or past EOF - just return */ return 0; } if (endpos > size) { extraresid = endpos - size; assert(uio->uio_resid > extraresid); uio->uio_resid -= extraresid; } } /* * First, do any leading partial block. */ blkoff = uio->uio_offset % SFS_BLOCKSIZE; if (blkoff != 0) { /* Number of bytes at beginning of block to skip */ u_int32_t skip = blkoff; /* Number of bytes to read/write after that point */ u_int32_t len = SFS_BLOCKSIZE - blkoff; /* ...which might be less than the rest of the block */ if (len > uio->uio_resid) { len = uio->uio_resid; } /* Call sfs_partialio() to do it. */ result = sfs_partialio(sv, uio, skip, len); if (result) { goto out; } } /* If we're done, quit. */ if (uio->uio_resid==0) { goto out; } /* * Now we should be block-aligned. Do the remaining whole blocks. */ assert(uio->uio_offset % SFS_BLOCKSIZE == 0); nblocks = uio->uio_resid / SFS_BLOCKSIZE; for (i=0; i<nblocks; i++) { result = sfs_blockio(sv, uio); if (result) { goto out; } } /* * Now do any remaining partial block at the end. */ assert(uio->uio_resid < SFS_BLOCKSIZE); if (uio->uio_resid > 0) { result = sfs_partialio(sv, uio, 0, uio->uio_resid); if (result) { goto out; } } out: /* If writing, adjust file length */ if (uio->uio_rw == UIO_WRITE && uio->uio_offset > (off_t)sv->sv_i.sfi_size) { sv->sv_i.sfi_size = uio->uio_offset; sv->sv_dirty = 1; } /* Add in any extra amount we couldn't read because of EOF */ uio->uio_resid += extraresid; /* Done */ return result; }
/* * Do I/O of a whole region of data, whether or not it's block-aligned. * * Locking: must hold vnode lock. May get/release sfs_freemaplock. * * Requires up to 3 buffers. */ int sfs_io(struct sfs_vnode *sv, struct uio *uio) { uint32_t blkoff; uint32_t nblocks, i; int result = 0; uint32_t origresid, extraresid = 0; struct sfs_dinode *inodeptr; KASSERT(lock_do_i_hold(sv->sv_lock)); origresid = uio->uio_resid; result = sfs_dinode_load(sv); if (result) { return result; } inodeptr = sfs_dinode_map(sv); /* * If reading, check for EOF. If we can read a partial area, * remember how much extra there was in EXTRARESID so we can * add it back to uio_resid at the end. */ if (uio->uio_rw == UIO_READ) { off_t size, endpos; size = inodeptr->sfi_size; endpos = uio->uio_offset + uio->uio_resid; if (uio->uio_offset >= size) { /* At or past EOF - just return */ sfs_dinode_unload(sv); return 0; } if (endpos > size) { extraresid = endpos - size; KASSERT(uio->uio_resid > extraresid); uio->uio_resid -= extraresid; } } /* * First, do any leading partial block. */ blkoff = uio->uio_offset % SFS_BLOCKSIZE; if (blkoff != 0) { /* Number of bytes at beginning of block to skip */ uint32_t skip = blkoff; /* Number of bytes to read/write after that point */ uint32_t len = SFS_BLOCKSIZE - blkoff; /* ...which might be less than the rest of the block */ if (len > uio->uio_resid) { len = uio->uio_resid; } /* Call sfs_partialio() to do it. */ result = sfs_partialio(sv, uio, skip, len); if (result) { goto out; } } /* If we're done, quit. */ if (uio->uio_resid==0) { goto out; } /* * Now we should be block-aligned. Do the remaining whole blocks. */ KASSERT(uio->uio_offset % SFS_BLOCKSIZE == 0); nblocks = uio->uio_resid / SFS_BLOCKSIZE; for (i=0; i<nblocks; i++) { result = sfs_blockio(sv, uio); if (result) { goto out; } } /* * Now do any remaining partial block at the end. */ KASSERT(uio->uio_resid < SFS_BLOCKSIZE); if (uio->uio_resid > 0) { result = sfs_partialio(sv, uio, 0, uio->uio_resid); if (result) { goto out; } } out: /* If writing and we did anything, adjust file length */ if (uio->uio_resid != origresid && uio->uio_rw == UIO_WRITE && uio->uio_offset > (off_t)inodeptr->sfi_size) { sfs_jphys_write_wrapper(sv->sv_absvn.vn_fs->fs_data, NULL, jentry_resize( sv->sv_ino, // disk_addr inodeptr->sfi_size, // old_size uio->uio_offset)); // new_size inodeptr->sfi_size = uio->uio_offset; sfs_dinode_mark_dirty(sv); } sfs_dinode_unload(sv); /* Add in any extra amount we couldn't read because of EOF */ uio->uio_resid += extraresid; /* Done */ return result; }