static VALUE array_to_outvar(VALUE self) { VALUE buf = rb_funcall(rb_cBuffer, id_new, 0); rb_funcall(buf, rb_intern("replace"), 1, self); buffer_outvar(buf); buffer_mark_dirty(buf); return buf; }
/* * Do I/O (either read or write) of a single whole block. * * Locking: must hold vnode lock. May get/release sfs_freemaplock. * * Requires up to 2 buffers. */ static int sfs_blockio(struct sfs_vnode *sv, struct uio *uio) { struct sfs_fs *sfs = sv->sv_absvn.vn_fs->fs_data; struct buf *iobuf; void *ioptr; daddr_t diskblock; uint32_t fileblock; int result; bool doalloc = (uio->uio_rw==UIO_WRITE); unsigned new_checksum = 0; KASSERT(lock_do_i_hold(sv->sv_lock)); /* Get the block number within the file */ fileblock = uio->uio_offset / SFS_BLOCKSIZE; /* Look up the disk block number */ result = sfs_bmap(sv, fileblock, doalloc, &diskblock); if (result) { return result; } if (diskblock == 0) { /* * No block - fill with zeros. * * We must be reading, or sfs_bmap would have * allocated a block for us. */ KASSERT(uio->uio_rw == UIO_READ); return uiomovezeros(SFS_BLOCKSIZE, uio); } if (uio->uio_rw == UIO_READ) { result = buffer_read(&sfs->sfs_absfs, diskblock, SFS_BLOCKSIZE, &iobuf); } else { result = buffer_get(&sfs->sfs_absfs, diskblock, SFS_BLOCKSIZE, &iobuf); } if (result) { return result; } /* * Do the I/O into the buffer. */ ioptr = buffer_map(iobuf); result = uiomove(ioptr, SFS_BLOCKSIZE, uio); if (result) { buffer_release(iobuf); return result; } if (uio->uio_rw == UIO_WRITE) { new_checksum = checksum(ioptr); sfs_jphys_write_wrapper(sfs, NULL, jentry_block_write(diskblock, new_checksum, false)); buffer_mark_valid(iobuf); buffer_mark_dirty(iobuf); // Journalled } buffer_release(iobuf); return 0; }
/* * This is much the same as sfs_partialio, but intended for use with * metadata (e.g. directory entries). It assumes the objects being * handled are smaller than whole blocks, do not cross block * boundaries, and originate in the kernel. * * It is separate from sfs_partialio because, although there is no * such code in this version of SFS, it is often desirable when doing * more advanced things to handle metadata and user data I/O * differently. */ int sfs_metaio(struct sfs_vnode *sv, off_t actualpos, void *data, size_t len, enum uio_rw rw) { struct sfs_fs *sfs = sv->sv_absvn.vn_fs->fs_data; struct sfs_dinode *dino; off_t endpos; uint32_t vnblock; uint32_t blockoffset; daddr_t diskblock; struct buf *iobuf; char *ioptr; bool doalloc; int result; KASSERT(lock_do_i_hold(sv->sv_lock)); /* Figure out which block of the vnode (directory, whatever) this is */ vnblock = actualpos / SFS_BLOCKSIZE; blockoffset = actualpos % SFS_BLOCKSIZE; result = sfs_dinode_load(sv); if (result) { return result; } dino = sfs_dinode_map(sv); /* Get the disk block number */ doalloc = (rw == UIO_WRITE); result = sfs_bmap(sv, vnblock, doalloc, &diskblock); if (result) { sfs_dinode_unload(sv); return result; } if (diskblock == 0) { /* Should only get block 0 back if doalloc is false */ KASSERT(rw == UIO_READ); /* Sparse file, read as zeros. */ bzero(data, len); sfs_dinode_unload(sv); return 0; } /* Read the block */ result = buffer_read(&sfs->sfs_absfs, diskblock, SFS_BLOCKSIZE, &iobuf); if (result) { /* * XXX: if we allocated, do we need to discard * the block we allocated? urgh... */ sfs_dinode_unload(sv); return result; } ioptr = buffer_map(iobuf); if (rw == UIO_READ) { /* Copy out the selected region */ memcpy(data, ioptr + blockoffset, len); } else { // Journal this!!! ioptr = buffer_map(iobuf); void *old_data = ioptr + blockoffset; sfs_jphys_write_wrapper(sfs, /*context*/ NULL, jentry_meta_update( diskblock, blockoffset, len, old_data, data)); /* Update the selected region */ memcpy(ioptr + blockoffset, data, len); buffer_mark_dirty(iobuf); // Journalled (meta_update) /* Update the vnode size if needed */ endpos = actualpos + len; if (endpos > (off_t)dino->sfi_size) { sfs_jphys_write_wrapper(sfs, NULL, jentry_resize( sv->sv_ino, // disk_addr dino->sfi_size, // old_size endpos)); // new_size dino->sfi_size = endpos; sfs_dinode_mark_dirty(sv); } } buffer_release(iobuf); sfs_dinode_unload(sv); /* Done */ return 0; }
/* * Do I/O to a block of a file that doesn't cover the whole block. We * need to read in the original block first, even if we're writing, so * we don't clobber the portion of the block we're not intending to * write over. * * SKIPSTART is the number of bytes to skip past at the beginning of * the sector; LEN is the number of bytes to actually read or write. * UIO is the area to do the I/O into. * * Requires up to 2 buffers. */ static int sfs_partialio(struct sfs_vnode *sv, struct uio *uio, uint32_t skipstart, uint32_t len) { struct sfs_fs *sfs = sv->sv_absvn.vn_fs->fs_data; struct buf *iobuffer; unsigned char *ioptr; daddr_t diskblock; uint32_t fileblock; int result; unsigned new_checksum = 0; /* Allocate missing blocks if and only if we're writing */ bool doalloc = (uio->uio_rw==UIO_WRITE); KASSERT(lock_do_i_hold(sv->sv_lock)); KASSERT(skipstart + len <= SFS_BLOCKSIZE); /* Compute the block offset of this block in the file */ fileblock = uio->uio_offset / SFS_BLOCKSIZE; /* Get the disk block number */ result = sfs_bmap(sv, fileblock, doalloc, &diskblock); if (result) { return result; } if (diskblock == 0) { /* * There was no block mapped at this point in the file. * * We must be reading, or sfs_bmap would have * allocated a block for us. */ KASSERT(uio->uio_rw == UIO_READ); return uiomovezeros(len, uio); } else { /* * Read the block. */ result = buffer_read(&sfs->sfs_absfs, diskblock, SFS_BLOCKSIZE, &iobuffer); if (result) { return result; } } /* * Now perform the requested operation into/out of the buffer. */ ioptr = buffer_map(iobuffer); result = uiomove(ioptr+skipstart, len, uio); if (result) { buffer_release(iobuffer); return result; } /* * If it was a write, mark the modified block dirty and journal */ if (uio->uio_rw == UIO_WRITE) { // Compute checksum and journal new_checksum = checksum(ioptr); sfs_jphys_write_wrapper(sfs, NULL, jentry_block_write(diskblock, new_checksum, false)); buffer_mark_dirty(iobuffer); // Journalled } buffer_release(iobuffer); return 0; }