diff options
Diffstat (limited to 'sys/ufs/ffs/ffs_balloc.c')
-rw-r--r-- | sys/ufs/ffs/ffs_balloc.c | 116 |
1 files changed, 68 insertions, 48 deletions
diff --git a/sys/ufs/ffs/ffs_balloc.c b/sys/ufs/ffs/ffs_balloc.c index 4d382fa..5d7d798 100644 --- a/sys/ufs/ffs/ffs_balloc.c +++ b/sys/ufs/ffs/ffs_balloc.c @@ -30,7 +30,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)ffs_balloc.c 8.4 (Berkeley) 9/23/93 + * @(#)ffs_balloc.c 8.8 (Berkeley) 6/16/95 * $FreeBSD$ */ @@ -56,27 +56,27 @@ * the inode and the logical block number in a file. */ int -ffs_balloc(ip, bn, size, cred, bpp, flags) +ffs_balloc(ip, lbn, size, cred, bpp, flags) register struct inode *ip; - register daddr_t bn; + register ufs_daddr_t lbn; int size; struct ucred *cred; struct buf **bpp; int flags; { register struct fs *fs; - register daddr_t nb; + register ufs_daddr_t nb; struct buf *bp, *nbp; struct vnode *vp = ITOV(ip); struct indir indirs[NIADDR + 2]; - daddr_t newb, lbn, *bap, pref; - int osize, nsize, num, i, error; + ufs_daddr_t newb, *bap, pref; + int deallocated, osize, nsize, num, i, error; + ufs_daddr_t *allocib, *blkp, *allocblk, allociblk[NIADDR + 1]; *bpp = NULL; - if (bn < 0) + if (lbn < 0) return (EFBIG); fs = ip->i_fs; - lbn = bn; /* * If the next write will extend the file into a new block, @@ -84,7 +84,7 @@ ffs_balloc(ip, bn, size, cred, bpp, flags) * this fragment has to be extended to be a full block. */ nb = lblkno(fs, ip->i_size); - if (nb < NDADDR && nb < bn) { + if (nb < NDADDR && nb < lbn) { osize = blksize(fs, ip, nb); if (osize < fs->fs_bsize && osize > 0) { error = ffs_realloccg(ip, nb, @@ -104,10 +104,10 @@ ffs_balloc(ip, bn, size, cred, bpp, flags) /* * The first NDADDR blocks are direct blocks */ - if (bn < NDADDR) { - nb = ip->i_db[bn]; - if (nb != 0 && ip->i_size >= (bn + 1) * fs->fs_bsize) { - error = bread(vp, bn, fs->fs_bsize, NOCRED, &bp); + if (lbn < NDADDR) { + nb = ip->i_db[lbn]; + if (nb != 0 && ip->i_size >= (lbn + 1) * fs->fs_bsize) { + error = bread(vp, lbn, fs->fs_bsize, NOCRED, &bp); if (error) { brelse(bp); return (error); @@ -123,35 +123,35 @@ ffs_balloc(ip, bn, size, cred, bpp, flags) osize = fragroundup(fs, blkoff(fs, ip->i_size)); nsize = fragroundup(fs, size); if (nsize <= osize) { - error = bread(vp, bn, osize, NOCRED, &bp); + error = bread(vp, lbn, osize, NOCRED, &bp); if (error) { brelse(bp); return (error); } bp->b_blkno = fsbtodb(fs, nb); } else { - error = ffs_realloccg(ip, bn, - ffs_blkpref(ip, bn, (int)bn, &ip->i_db[0]), - osize, nsize, cred, &bp); + error = ffs_realloccg(ip, lbn, + ffs_blkpref(ip, lbn, (int)lbn, + &ip->i_db[0]), osize, nsize, cred, &bp); if (error) return (error); } } else { - if (ip->i_size < (bn + 1) * fs->fs_bsize) + if (ip->i_size < (lbn + 1) * fs->fs_bsize) nsize = fragroundup(fs, size); else nsize = fs->fs_bsize; - error = ffs_alloc(ip, bn, - ffs_blkpref(ip, bn, (int)bn, &ip->i_db[0]), + error = ffs_alloc(ip, lbn, + ffs_blkpref(ip, lbn, (int)lbn, &ip->i_db[0]), nsize, cred, &newb); if (error) return (error); - bp = getblk(vp, bn, nsize, 0, 0); + bp = getblk(vp, lbn, nsize, 0, 0); bp->b_blkno = fsbtodb(fs, newb); if (flags & B_CLRBUF) vfs_bio_clrbuf(bp); } - ip->i_db[bn] = dbtofsb(fs, bp->b_blkno); + ip->i_db[lbn] = dbtofsb(fs, bp->b_blkno); ip->i_flag |= IN_CHANGE | IN_UPDATE; *bpp = bp; return (0); @@ -160,8 +160,7 @@ ffs_balloc(ip, bn, size, cred, bpp, flags) * Determine the number of levels of indirection. */ pref = 0; - error = ufs_getlbns(vp, bn, indirs, &num); - if (error) + if (error = ufs_getlbns(vp, lbn, indirs, &num)) return(error); #ifdef DIAGNOSTIC if (num < 1) @@ -172,26 +171,26 @@ ffs_balloc(ip, bn, size, cred, bpp, flags) */ --num; nb = ip->i_ib[indirs[0].in_off]; + allocib = NULL; + allocblk = allociblk; if (nb == 0) { - pref = ffs_blkpref(ip, lbn, 0, (daddr_t *)0); - error = ffs_alloc(ip, lbn, pref, - (int)fs->fs_bsize, cred, &newb); - if (error) + pref = ffs_blkpref(ip, lbn, 0, (ufs_daddr_t *)0); + if (error = ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize, + cred, &newb)) return (error); nb = newb; + *allocblk++ = nb; bp = getblk(vp, indirs[1].in_lbn, fs->fs_bsize, 0, 0); - bp->b_blkno = fsbtodb(fs, newb); + bp->b_blkno = fsbtodb(fs, nb); vfs_bio_clrbuf(bp); /* * Write synchronously so that indirect blocks * never point at garbage. */ - error = bwrite(bp); - if (error) { - ffs_blkfree(ip, nb, fs->fs_bsize); - return (error); - } - ip->i_ib[indirs[0].in_off] = newb; + if (error = bwrite(bp)) + goto fail; + allocib = &ip->i_ib[indirs[0].in_off]; + *allocib = nb; ip->i_flag |= IN_CHANGE | IN_UPDATE; } /* @@ -202,9 +201,9 @@ ffs_balloc(ip, bn, size, cred, bpp, flags) indirs[i].in_lbn, (int)fs->fs_bsize, NOCRED, &bp); if (error) { brelse(bp); - return (error); + goto fail; } - bap = (daddr_t *)bp->b_data; + bap = (ufs_daddr_t *)bp->b_data; nb = bap[indirs[i].in_off]; if (i == num) break; @@ -214,14 +213,14 @@ ffs_balloc(ip, bn, size, cred, bpp, flags) continue; } if (pref == 0) - pref = ffs_blkpref(ip, lbn, 0, (daddr_t *)0); - error = - ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize, cred, &newb); - if (error) { + pref = ffs_blkpref(ip, lbn, 0, (ufs_daddr_t *)0); + if (error = + ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize, cred, &newb)) { brelse(bp); - return (error); + goto fail; } nb = newb; + *allocblk++ = nb; nbp = getblk(vp, indirs[i].in_lbn, fs->fs_bsize, 0, 0); nbp->b_blkno = fsbtodb(fs, nb); vfs_bio_clrbuf(nbp); @@ -229,11 +228,9 @@ ffs_balloc(ip, bn, size, cred, bpp, flags) * Write synchronously so that indirect blocks * never point at garbage. */ - error = bwrite(nbp); - if (error) { - ffs_blkfree(ip, nb, fs->fs_bsize); + if (error = bwrite(nbp)) { brelse(bp); - return (error); + goto fail; } bap[indirs[i - 1].in_off] = nb; /* @@ -255,9 +252,10 @@ ffs_balloc(ip, bn, size, cred, bpp, flags) lbn, pref, (int)fs->fs_bsize, cred, &newb); if (error) { brelse(bp); - return (error); + goto fail; } nb = newb; + *allocblk++ = nb; nbp = getblk(vp, lbn, fs->fs_bsize, 0, 0); nbp->b_blkno = fsbtodb(fs, nb); if (flags & B_CLRBUF) @@ -280,7 +278,7 @@ ffs_balloc(ip, bn, size, cred, bpp, flags) error = bread(vp, lbn, (int)fs->fs_bsize, NOCRED, &nbp); if (error) { brelse(nbp); - return (error); + goto fail; } } else { nbp = getblk(vp, lbn, fs->fs_bsize, 0, 0); @@ -288,4 +286,26 @@ ffs_balloc(ip, bn, size, cred, bpp, flags) } *bpp = nbp; return (0); +fail: + /* + * If we have failed part way through block allocation, we + * have to deallocate any indirect blocks that we have allocated. + */ + for (deallocated = 0, blkp = allociblk; blkp < allocblk; blkp++) { + ffs_blkfree(ip, *blkp, fs->fs_bsize); + deallocated += fs->fs_bsize; + } + if (allocib != NULL) + *allocib = 0; + if (deallocated) { +#ifdef QUOTA + /* + * Restore user's disk quota because allocation failed. + */ + (void) chkdq(ip, (long)-btodb(deallocated), cred, FORCE); +#endif + ip->i_blocks -= btodb(deallocated); + ip->i_flag |= IN_CHANGE | IN_UPDATE; + } + return (error); } |