diff options
author | bde <bde@FreeBSD.org> | 1997-03-23 00:45:27 +0000 |
---|---|---|
committer | bde <bde@FreeBSD.org> | 1997-03-23 00:45:27 +0000 |
commit | 3dc0739b4b3a164a9b9573b85bd93536d65c17ee (patch) | |
tree | efa32895546394d68bb68f530ad7b4bc185501de /sys/ufs/lfs/lfs_balloc.c | |
parent | 953b4a2c981017b3338bb9d6f2fcd194e034bda8 (diff) | |
download | FreeBSD-src-3dc0739b4b3a164a9b9573b85bd93536d65c17ee.zip FreeBSD-src-3dc0739b4b3a164a9b9573b85bd93536d65c17ee.tar.gz |
Merged the rest of lfs from Lite2. It compiles (uncleanly) but is as
unlikely to work as before.
Diffstat (limited to 'sys/ufs/lfs/lfs_balloc.c')
-rw-r--r-- | sys/ufs/lfs/lfs_balloc.c | 138 |
1 files changed, 120 insertions, 18 deletions
diff --git a/sys/ufs/lfs/lfs_balloc.c b/sys/ufs/lfs/lfs_balloc.c index ee2a86b..695049d 100644 --- a/sys/ufs/lfs/lfs_balloc.c +++ b/sys/ufs/lfs/lfs_balloc.c @@ -30,8 +30,8 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)lfs_balloc.c 8.1 (Berkeley) 6/11/93 - * $Id$ + * @(#)lfs_balloc.c 8.4 (Berkeley) 5/8/95 + * $Id: lfs_balloc.c,v 1.10 1997/02/22 09:47:17 peter Exp $ */ #include <sys/param.h> #include <sys/systm.h> @@ -52,18 +52,20 @@ #include <ufs/lfs/lfs_extern.h> int -lfs_balloc(vp, iosize, lbn, bpp) +lfs_balloc(vp, offset, iosize, lbn, bpp) struct vnode *vp; + int offset; u_long iosize; - daddr_t lbn; + ufs_daddr_t lbn; struct buf **bpp; { struct buf *ibp, *bp; struct inode *ip; struct lfs *fs; struct indir indirs[NIADDR+2]; - daddr_t daddr; - int bb, error, i, num; + ufs_daddr_t daddr, lastblock; + int bb; /* number of disk blocks in a block disk blocks */ + int error, frags, i, nsize, osize, num; ip = VTOI(vp); fs = ip->i_lfs; @@ -76,21 +78,37 @@ lfs_balloc(vp, iosize, lbn, bpp) * or written earlier). If it did, make sure we don't count it as a * new block or zero out its contents. If it did not, make sure * we allocate any necessary indirect blocks. + * If we are writing a block beyond the end of the file, we need to + * check if the old last block was a fragment. If it was, we need + * to rewrite it. */ *bpp = NULL; if (error = ufs_bmaparray(vp, lbn, &daddr, &indirs[0], &num, NULL, NULL )) return (error); - *bpp = bp = getblk(vp, lbn, fs->lfs_bsize, 0, 0); + /* Check for block beyond end of file and fragment extension needed. */ + lastblock = lblkno(fs, ip->i_size); + if (lastblock < NDADDR && lastblock < lbn) { + osize = blksize(fs, ip, lastblock); + if (osize < fs->lfs_bsize && osize > 0) { + if (error = lfs_fragextend(vp, osize, fs->lfs_bsize, + lastblock, &bp)) + return(error); + ip->i_size = (lastblock + 1) * fs->lfs_bsize; + vnode_pager_setsize(vp, (u_long)ip->i_size); + ip->i_flag |= IN_CHANGE | IN_UPDATE; + VOP_BWRITE(bp); + } + } + bb = VFSTOUFS(vp->v_mount)->um_seqinc; if (daddr == UNASSIGNED) /* May need to allocate indirect blocks */ for (i = 1; i < num; ++i) if (!indirs[i].in_exists) { - ibp = - getblk(vp, indirs[i].in_lbn, fs->lfs_bsize, - 0, 0); + ibp = getblk(vp, indirs[i].in_lbn, fs->lfs_bsize, + 0, 0); if (!(ibp->b_flags & (B_DONE | B_DELWRI))) { if (!ISSPACE(fs, bb, curproc->p_ucred)){ ibp->b_flags |= B_INVAL; @@ -104,15 +122,57 @@ lfs_balloc(vp, iosize, lbn, bpp) } } else panic ("Indirect block should not exist"); + + if (!ISSPACE(fs, bb, curproc->p_ucred)){ + ibp->b_flags |= B_INVAL; + brelse(ibp); + return(ENOSPC); + } else { + ip->i_blocks += bb; + ip->i_lfs->lfs_bfree -= bb; + clrbuf(ibp); + if(error = VOP_BWRITE(ibp)) + return(error); + } } - if (error) { - if (bp) - brelse(bp); - return(error); - } + /* + * If the block we are writing is a direct block, it's the last + * block in the file, and offset + iosize is less than a full + * block, we can write one or more fragments. There are two cases: + * the block is brand new and we should allocate it the correct + * size or it already exists and contains some fragments and + * may need to extend it. + */ + if (lbn < NDADDR && lblkno(fs, ip->i_size) == lbn) { + nsize = fragroundup(fs, offset + iosize); + frags = numfrags(fs, nsize); + bb = fragstodb(fs, frags); + if (lblktosize(fs, lbn) == ip->i_size) + /* Brand new block or fragment */ + *bpp = bp = getblk(vp, lbn, nsize, 0, 0); + else { + /* Extend existing block */ + if (error = lfs_fragextend(vp, (int)blksize(fs, ip, lbn), + nsize, lbn, &bp)) + return(error); + *bpp = bp; + } + } else { + /* + * Get the existing block from the cache either because the + * block is 1) not a direct block or because it's not the last + * block in the file. + */ + frags = dbtofrags(fs, bb); + *bpp = bp = getblk(vp, lbn, blksize(fs, ip, lbn), 0, 0); + } - /* Now, we may need to allocate the data block */ + /* + * The block we are writing may be a brand new block + * in which case we need to do accounting (i.e. check + * for free space and update the inode number of blocks. + */ if (!(bp->b_flags & (B_CACHE | B_DONE | B_DELWRI))) { if (daddr == UNASSIGNED) if (!ISSPACE(fs, bb, curproc->p_ucred)) { @@ -126,8 +186,13 @@ lfs_balloc(vp, iosize, lbn, bpp) vfs_bio_clrbuf(bp); } else if (iosize == fs->lfs_bsize) - bp->b_blkno = daddr; /* Skip the I/O */ + /* Optimization: I/O is unnecessary. */ + bp->b_blkno = daddr; else { + /* + * We need to read the block to preserve the + * existing bytes. + */ bp->b_blkno = daddr; bp->b_flags |= B_READ; vfs_busy_pages(bp, 0); @@ -135,5 +200,42 @@ lfs_balloc(vp, iosize, lbn, bpp) return(biowait(bp)); } } - return (error); + return (0); +} + +lfs_fragextend(vp, osize, nsize, lbn, bpp) + struct vnode *vp; + int osize; + int nsize; + daddr_t lbn; + struct buf **bpp; +{ + struct inode *ip; + struct lfs *fs; + long bb; + int error; + + ip = VTOI(vp); + fs = ip->i_lfs; + bb = (long)fragstodb(fs, numfrags(fs, nsize - osize)); + if (!ISSPACE(fs, bb, curproc->p_ucred)) { + return(ENOSPC); + } + + if (error = bread(vp, lbn, osize, NOCRED, bpp)) { + brelse(*bpp); + return(error); + } +#ifdef QUOTA + if (error = chkdq(ip, bb, curproc->p_ucred, 0)) { + brelse(*bpp); + return (error); + } +#endif + ip->i_blocks += bb; + ip->i_flag |= IN_CHANGE | IN_UPDATE; + fs->lfs_bfree -= fragstodb(fs, numfrags(fs, (nsize - osize))); + allocbuf(*bpp, nsize); + bzero((char *)((*bpp)->b_data) + osize, (u_int)(nsize - osize)); + return(0); } |