int sfs_wblock(struct sfs_fs *sfs, void *data, u_int32_t block) { struct uio ku; SFSUIO(&ku, data, block, UIO_WRITE); return sfs_rwblock(sfs, &ku); }
int sfs_rblock(struct sfs_fs *sfs, void *data, uint32_t block) { struct iovec iov; struct uio ku; SFSUIO(&iov, &ku, data, block, UIO_READ); return sfs_rwblock(sfs, &ku); }
/* * Read a block. */ int sfs_readblock(struct fs *fs, daddr_t block, void *data, size_t len) { struct sfs_fs *sfs = fs->fs_data; struct iovec iov; struct uio ku; KASSERT(len == SFS_BLOCKSIZE); SFSUIO(&iov, &ku, data, block, UIO_READ); return sfs_rwblock(sfs, &ku); }
/* * Do I/O (either read or write) of a single whole block. */ static int sfs_blockio(struct sfs_vnode *sv, struct uio *uio) { struct sfs_fs *sfs = sv->sv_v.vn_fs->fs_data; u_int32_t diskblock; u_int32_t fileblock; int result; int doalloc = (uio->uio_rw==UIO_WRITE); off_t saveoff; off_t diskoff; off_t saveres; off_t diskres; /* 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. */ assert(uio->uio_rw == UIO_READ); return uiomovezeros(SFS_BLOCKSIZE, uio); } /* * Do the I/O directly to the uio region. Save the uio_offset, * and substitute one that makes sense to the device. */ saveoff = uio->uio_offset; diskoff = diskblock * SFS_BLOCKSIZE; uio->uio_offset = diskoff; /* * Temporarily set the residue to be one block size. */ assert(uio->uio_resid >= SFS_BLOCKSIZE); saveres = uio->uio_resid; diskres = SFS_BLOCKSIZE; uio->uio_resid = diskres; result = sfs_rwblock(sfs, uio); /* * Now, restore the original uio_offset and uio_resid and update * them by the amount of I/O done. */ uio->uio_offset = (uio->uio_offset - diskoff) + saveoff; uio->uio_resid = (uio->uio_resid - diskres) + saveres; return result; }
/* * Write a block. */ int sfs_writeblock(struct fs *fs, daddr_t block, void *fsbufdata, void *data, size_t len) { struct sfs_fs *sfs = fs->fs_data; struct iovec iov; struct uio ku; bool isjournal; int result; struct b_fsdata* b_fsdata = (struct b_fsdata*)fsbufdata; KASSERT(len == SFS_BLOCKSIZE); isjournal = sfs_block_is_journal(sfs, block); //kprintf("Writeblock metadata: %p\n", fsbufdata); if (isjournal) { /* * We're writing a journal buffer; the journal must be * written in order, so all earlier journal buffers * must be written first. * * One might think that a good and simple way to flush * the journal in order is to have each journal buffer * record that the previous journal buffer must be * written out before it. Then writing a journal * buffer will come here to write the previous one, * which will come here to write the previous one, and * so on until we get to the first remaining unwritten * journal buffer. This doesn't work: it runs off the * kernel stack. Also, it's likely to deadlock. * * Instead, we use special-case logic in the journal * code for this situation. */ //kprintf("Writing journal blocks\n"); result = sfs_jphys_flushforjournalblock(sfs, block); if (result) { return result; } } else if (b_fsdata != NULL) { //kprintf("\n\nBuffer %p is being written", b_fsdata->buf); // This is a standard non-journal block // Enforce write-ahead logging. Flush up to the most recent lsn to touch // this buffer KASSERT(b_fsdata->newest_lsn != 0); //kprintf("FLUSH (daddr %d): lsn %lld", b_fsdata->diskblock, b_fsdata->newest_lsn); sfs_jphys_flush(sfs, b_fsdata->newest_lsn); //kprintf("...Done.\n\n"); b_fsdata->newest_lsn = 0; b_fsdata->oldest_lsn = 0; } SFSUIO(&iov, &ku, data, block, UIO_WRITE); result = sfs_rwblock(sfs, &ku); if (result) { return result; } if (isjournal) { sfs_wrote_journal_block(sfs, block); } return 0; }