Annotation of sys/ufs/ffs/ffs_balloc.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: ffs_balloc.c,v 1.34 2007/06/01 18:54:27 pedro Exp $ */
! 2: /* $NetBSD: ffs_balloc.c,v 1.3 1996/02/09 22:22:21 christos Exp $ */
! 3:
! 4: /*
! 5: * Copyright (c) 2002 Networks Associates Technology, Inc.
! 6: * All rights reserved.
! 7: *
! 8: * This software was developed for the FreeBSD Project by Marshall
! 9: * Kirk McKusick and Network Associates Laboratories, the Security
! 10: * Research Division of Network Associates, Inc. under DARPA/SPAWAR
! 11: * contract N66001-01-C-8035 ("CBOSS"), as part of the DARPA CHATS
! 12: * research program.
! 13: *
! 14: * Copyright (c) 1982, 1986, 1989, 1993
! 15: * The Regents of the University of California. All rights reserved.
! 16: *
! 17: * Redistribution and use in source and binary forms, with or without
! 18: * modification, are permitted provided that the following conditions
! 19: * are met:
! 20: * 1. Redistributions of source code must retain the above copyright
! 21: * notice, this list of conditions and the following disclaimer.
! 22: * 2. Redistributions in binary form must reproduce the above copyright
! 23: * notice, this list of conditions and the following disclaimer in the
! 24: * documentation and/or other materials provided with the distribution.
! 25: * 3. Neither the name of the University nor the names of its contributors
! 26: * may be used to endorse or promote products derived from this software
! 27: * without specific prior written permission.
! 28: *
! 29: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
! 30: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
! 31: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
! 32: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
! 33: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
! 34: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
! 35: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
! 36: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
! 37: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
! 38: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
! 39: * SUCH DAMAGE.
! 40: *
! 41: * @(#)ffs_balloc.c 8.4 (Berkeley) 9/23/93
! 42: */
! 43:
! 44: #include <sys/param.h>
! 45: #include <sys/systm.h>
! 46: #include <sys/buf.h>
! 47: #include <sys/proc.h>
! 48: #include <sys/file.h>
! 49: #include <sys/mount.h>
! 50: #include <sys/vnode.h>
! 51:
! 52: #include <uvm/uvm_extern.h>
! 53:
! 54: #include <ufs/ufs/quota.h>
! 55: #include <ufs/ufs/inode.h>
! 56: #include <ufs/ufs/ufsmount.h>
! 57: #include <ufs/ufs/ufs_extern.h>
! 58:
! 59: #include <ufs/ffs/fs.h>
! 60: #include <ufs/ffs/ffs_extern.h>
! 61:
! 62: int ffs1_balloc(struct inode *, off_t, int, struct ucred *, int, struct buf **);
! 63: #ifdef FFS2
! 64: int ffs2_balloc(struct inode *, off_t, int, struct ucred *, int, struct buf **);
! 65: #endif
! 66:
! 67: /*
! 68: * Balloc defines the structure of file system storage
! 69: * by allocating the physical blocks on a device given
! 70: * the inode and the logical block number in a file.
! 71: */
! 72: int
! 73: ffs1_balloc(struct inode *ip, off_t startoffset, int size, struct ucred *cred,
! 74: int flags, struct buf **bpp)
! 75: {
! 76: daddr_t lbn;
! 77: struct fs *fs;
! 78: daddr_t nb;
! 79: struct buf *bp, *nbp;
! 80: struct vnode *vp;
! 81: struct proc *p;
! 82: struct indir indirs[NIADDR + 2];
! 83: int32_t newb, *bap, pref;
! 84: int deallocated, osize, nsize, num, i, error;
! 85: int32_t *allocib, *blkp, *allocblk, allociblk[NIADDR+1];
! 86: int unwindidx = -1;
! 87:
! 88: vp = ITOV(ip);
! 89: fs = ip->i_fs;
! 90: p = curproc;
! 91: lbn = lblkno(fs, startoffset);
! 92: size = blkoff(fs, startoffset) + size;
! 93: if (size > fs->fs_bsize)
! 94: panic("ffs1_balloc: blk too big");
! 95: if (bpp != NULL)
! 96: *bpp = NULL;
! 97: if (lbn < 0)
! 98: return (EFBIG);
! 99:
! 100: /*
! 101: * If the next write will extend the file into a new block,
! 102: * and the file is currently composed of a fragment
! 103: * this fragment has to be extended to be a full block.
! 104: */
! 105: nb = lblkno(fs, ip->i_ffs1_size);
! 106: if (nb < NDADDR && nb < lbn) {
! 107: osize = blksize(fs, ip, nb);
! 108: if (osize < fs->fs_bsize && osize > 0) {
! 109: error = ffs_realloccg(ip, nb,
! 110: ffs1_blkpref(ip, nb, (int)nb, &ip->i_ffs1_db[0]),
! 111: osize, (int)fs->fs_bsize, cred, bpp, &newb);
! 112: if (error)
! 113: return (error);
! 114: if (DOINGSOFTDEP(vp))
! 115: softdep_setup_allocdirect(ip, nb, newb,
! 116: ip->i_ffs1_db[nb], fs->fs_bsize, osize,
! 117: bpp ? *bpp : NULL);
! 118:
! 119: ip->i_ffs1_size = lblktosize(fs, nb + 1);
! 120: uvm_vnp_setsize(vp, ip->i_ffs1_size);
! 121: ip->i_ffs1_db[nb] = newb;
! 122: ip->i_flag |= IN_CHANGE | IN_UPDATE;
! 123: if (bpp != NULL) {
! 124: if (flags & B_SYNC)
! 125: bwrite(*bpp);
! 126: else
! 127: bawrite(*bpp);
! 128: }
! 129: }
! 130: }
! 131: /*
! 132: * The first NDADDR blocks are direct blocks
! 133: */
! 134: if (lbn < NDADDR) {
! 135: nb = ip->i_ffs1_db[lbn];
! 136: if (nb != 0 && ip->i_ffs1_size >= lblktosize(fs, lbn + 1)) {
! 137: /*
! 138: * The block is an already-allocated direct block
! 139: * and the file already extends past this block,
! 140: * thus this must be a whole block.
! 141: * Just read the block (if requested).
! 142: */
! 143:
! 144: if (bpp != NULL) {
! 145: error = bread(vp, lbn, fs->fs_bsize, NOCRED,
! 146: bpp);
! 147: if (error) {
! 148: brelse(*bpp);
! 149: return (error);
! 150: }
! 151: }
! 152: return (0);
! 153: }
! 154: if (nb != 0) {
! 155: /*
! 156: * Consider need to reallocate a fragment.
! 157: */
! 158: osize = fragroundup(fs, blkoff(fs, ip->i_ffs1_size));
! 159: nsize = fragroundup(fs, size);
! 160: if (nsize <= osize) {
! 161: /*
! 162: * The existing block is already
! 163: * at least as big as we want.
! 164: * Just read the block (if requested).
! 165: */
! 166: if (bpp != NULL) {
! 167: error = bread(vp, lbn, fs->fs_bsize,
! 168: NOCRED, bpp);
! 169: if (error) {
! 170: brelse(*bpp);
! 171: return (error);
! 172: }
! 173: (*bpp)->b_bcount = osize;
! 174: }
! 175: return (0);
! 176: } else {
! 177: /*
! 178: * The existing block is smaller than we
! 179: * want, grow it.
! 180: */
! 181: error = ffs_realloccg(ip, lbn,
! 182: ffs1_blkpref(ip, lbn, (int)lbn,
! 183: &ip->i_ffs1_db[0]),
! 184: osize, nsize, cred, bpp, &newb);
! 185: if (error)
! 186: return (error);
! 187: if (DOINGSOFTDEP(vp))
! 188: softdep_setup_allocdirect(ip, lbn,
! 189: newb, nb, nsize, osize,
! 190: bpp ? *bpp : NULL);
! 191: }
! 192: } else {
! 193: /*
! 194: * The block was not previously allocated,
! 195: * allocate a new block or fragment.
! 196: */
! 197:
! 198: if (ip->i_ffs1_size < lblktosize(fs, lbn + 1))
! 199: nsize = fragroundup(fs, size);
! 200: else
! 201: nsize = fs->fs_bsize;
! 202: error = ffs_alloc(ip, lbn,
! 203: ffs1_blkpref(ip, lbn, (int)lbn, &ip->i_ffs1_db[0]),
! 204: nsize, cred, &newb);
! 205: if (error)
! 206: return (error);
! 207: if (bpp != NULL) {
! 208: *bpp = getblk(vp, lbn, fs->fs_bsize, 0, 0);
! 209: if (nsize < fs->fs_bsize)
! 210: (*bpp)->b_bcount = nsize;
! 211: (*bpp)->b_blkno = fsbtodb(fs, newb);
! 212: if (flags & B_CLRBUF)
! 213: clrbuf(*bpp);
! 214: }
! 215: if (DOINGSOFTDEP(vp))
! 216: softdep_setup_allocdirect(ip, lbn, newb, 0,
! 217: nsize, 0, bpp ? *bpp : NULL);
! 218: }
! 219: ip->i_ffs1_db[lbn] = newb;
! 220: ip->i_flag |= IN_CHANGE | IN_UPDATE;
! 221: return (0);
! 222: }
! 223:
! 224: /*
! 225: * Determine the number of levels of indirection.
! 226: */
! 227: pref = 0;
! 228: if ((error = ufs_getlbns(vp, lbn, indirs, &num)) != 0)
! 229: return(error);
! 230: #ifdef DIAGNOSTIC
! 231: if (num < 1)
! 232: panic ("ffs1_balloc: ufs_bmaparray returned indirect block");
! 233: #endif
! 234: /*
! 235: * Fetch the first indirect block allocating if necessary.
! 236: */
! 237: --num;
! 238: nb = ip->i_ffs1_ib[indirs[0].in_off];
! 239:
! 240: allocib = NULL;
! 241: allocblk = allociblk;
! 242: if (nb == 0) {
! 243: pref = ffs1_blkpref(ip, lbn, 0, (daddr_t *)0);
! 244: error = ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize,
! 245: cred, &newb);
! 246: if (error)
! 247: goto fail;
! 248: nb = newb;
! 249:
! 250: *allocblk++ = nb;
! 251: bp = getblk(vp, indirs[1].in_lbn, fs->fs_bsize, 0, 0);
! 252: bp->b_blkno = fsbtodb(fs, nb);
! 253: clrbuf(bp);
! 254:
! 255: if (DOINGSOFTDEP(vp)) {
! 256: softdep_setup_allocdirect(ip, NDADDR + indirs[0].in_off,
! 257: newb, 0, fs->fs_bsize, 0, bp);
! 258: bdwrite(bp);
! 259: } else {
! 260: /*
! 261: * Write synchronously so that indirect blocks
! 262: * never point at garbage.
! 263: */
! 264: if ((error = bwrite(bp)) != 0)
! 265: goto fail;
! 266: }
! 267: allocib = &ip->i_ffs1_ib[indirs[0].in_off];
! 268: *allocib = nb;
! 269: ip->i_flag |= IN_CHANGE | IN_UPDATE;
! 270: }
! 271:
! 272: /*
! 273: * Fetch through the indirect blocks, allocating as necessary.
! 274: */
! 275: for (i = 1;;) {
! 276: error = bread(vp,
! 277: indirs[i].in_lbn, (int)fs->fs_bsize, NOCRED, &bp);
! 278: if (error) {
! 279: brelse(bp);
! 280: goto fail;
! 281: }
! 282: bap = (daddr_t *)bp->b_data;
! 283: nb = bap[indirs[i].in_off];
! 284: if (i == num)
! 285: break;
! 286: i++;
! 287: if (nb != 0) {
! 288: brelse(bp);
! 289: continue;
! 290: }
! 291: if (pref == 0)
! 292: pref = ffs1_blkpref(ip, lbn, 0, (daddr_t *)0);
! 293: error = ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize, cred,
! 294: &newb);
! 295: if (error) {
! 296: brelse(bp);
! 297: goto fail;
! 298: }
! 299: nb = newb;
! 300: *allocblk++ = nb;
! 301: nbp = getblk(vp, indirs[i].in_lbn, fs->fs_bsize, 0, 0);
! 302: nbp->b_blkno = fsbtodb(fs, nb);
! 303: clrbuf(nbp);
! 304:
! 305: if (DOINGSOFTDEP(vp)) {
! 306: softdep_setup_allocindir_meta(nbp, ip, bp,
! 307: indirs[i - 1].in_off, nb);
! 308: bdwrite(nbp);
! 309: } else {
! 310: /*
! 311: * Write synchronously so that indirect blocks
! 312: * never point at garbage.
! 313: */
! 314: if ((error = bwrite(nbp)) != 0) {
! 315: brelse(bp);
! 316: goto fail;
! 317: }
! 318: }
! 319: bap[indirs[i - 1].in_off] = nb;
! 320: if (allocib == NULL && unwindidx < 0)
! 321: unwindidx = i - 1;
! 322: /*
! 323: * If required, write synchronously, otherwise use
! 324: * delayed write.
! 325: */
! 326: if (flags & B_SYNC) {
! 327: bwrite(bp);
! 328: } else {
! 329: bdwrite(bp);
! 330: }
! 331: }
! 332: /*
! 333: * Get the data block, allocating if necessary.
! 334: */
! 335: if (nb == 0) {
! 336: pref = ffs1_blkpref(ip, lbn, indirs[i].in_off, &bap[0]);
! 337: error = ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize, cred,
! 338: &newb);
! 339: if (error) {
! 340: brelse(bp);
! 341: goto fail;
! 342: }
! 343: nb = newb;
! 344: *allocblk++ = nb;
! 345: if (bpp != NULL) {
! 346: nbp = getblk(vp, lbn, fs->fs_bsize, 0, 0);
! 347: nbp->b_blkno = fsbtodb(fs, nb);
! 348: if (flags & B_CLRBUF)
! 349: clrbuf(nbp);
! 350: *bpp = nbp;
! 351: }
! 352: if (DOINGSOFTDEP(vp))
! 353: softdep_setup_allocindir_page(ip, lbn, bp,
! 354: indirs[i].in_off, nb, 0, bpp ? *bpp : NULL);
! 355: bap[indirs[i].in_off] = nb;
! 356: /*
! 357: * If required, write synchronously, otherwise use
! 358: * delayed write.
! 359: */
! 360: if (flags & B_SYNC) {
! 361: bwrite(bp);
! 362: } else {
! 363: bdwrite(bp);
! 364: }
! 365: return (0);
! 366: }
! 367: brelse(bp);
! 368: if (bpp != NULL) {
! 369: if (flags & B_CLRBUF) {
! 370: error = bread(vp, lbn, (int)fs->fs_bsize, NOCRED, &nbp);
! 371: if (error) {
! 372: brelse(nbp);
! 373: goto fail;
! 374: }
! 375: } else {
! 376: nbp = getblk(vp, lbn, fs->fs_bsize, 0, 0);
! 377: nbp->b_blkno = fsbtodb(fs, nb);
! 378: }
! 379: *bpp = nbp;
! 380: }
! 381: return (0);
! 382:
! 383: fail:
! 384: /*
! 385: * If we have failed to allocate any blocks, simply return the error.
! 386: * This is the usual case and avoids the need to fsync the file.
! 387: */
! 388: if (allocblk == allociblk && allocib == NULL && unwindidx == -1)
! 389: return (error);
! 390: /*
! 391: * If we have failed part way through block allocation, we have to
! 392: * deallocate any indirect blocks that we have allocated. We have to
! 393: * fsync the file before we start to get rid of all of its
! 394: * dependencies so that we do not leave them dangling. We have to sync
! 395: * it at the end so that the softdep code does not find any untracked
! 396: * changes. Although this is really slow, running out of disk space is
! 397: * not expected to be a common occurence. The error return from fsync
! 398: * is ignored as we already have an error to return to the user.
! 399: */
! 400: VOP_FSYNC(vp, p->p_ucred, MNT_WAIT, p);
! 401: for (deallocated = 0, blkp = allociblk; blkp < allocblk; blkp++) {
! 402: ffs_blkfree(ip, *blkp, fs->fs_bsize);
! 403: deallocated += fs->fs_bsize;
! 404: }
! 405: if (allocib != NULL) {
! 406: *allocib = 0;
! 407: } else if (unwindidx >= 0) {
! 408: int r;
! 409:
! 410: r = bread(vp, indirs[unwindidx].in_lbn,
! 411: (int)fs->fs_bsize, NOCRED, &bp);
! 412: if (r)
! 413: panic("Could not unwind indirect block, error %d", r);
! 414: bap = (daddr_t *)bp->b_data;
! 415: bap[indirs[unwindidx].in_off] = 0;
! 416: if (flags & B_SYNC) {
! 417: bwrite(bp);
! 418: } else {
! 419: bdwrite(bp);
! 420: }
! 421: }
! 422: if (deallocated) {
! 423: /*
! 424: * Restore user's disk quota because allocation failed.
! 425: */
! 426: (void)ufs_quota_free_blocks(ip, btodb(deallocated), cred);
! 427:
! 428: ip->i_ffs1_blocks -= btodb(deallocated);
! 429: ip->i_flag |= IN_CHANGE | IN_UPDATE;
! 430: }
! 431: VOP_FSYNC(vp, p->p_ucred, MNT_WAIT, p);
! 432: return (error);
! 433: }
! 434:
! 435: #ifdef FFS2
! 436: int
! 437: ffs2_balloc(struct inode *ip, off_t off, int size, struct ucred *cred,
! 438: int flags, struct buf **bpp)
! 439: {
! 440: daddr_t lbn, lastlbn, nb, newb, *blkp;
! 441: daddr_t pref, *allocblk, allociblk[NIADDR + 1];
! 442: daddr64_t *bap, *allocib;
! 443: int deallocated, osize, nsize, num, i, error, unwindidx, r;
! 444: struct buf *bp, *nbp;
! 445: struct indir indirs[NIADDR + 2];
! 446: struct fs *fs;
! 447: struct vnode *vp;
! 448: struct proc *p;
! 449:
! 450: vp = ITOV(ip);
! 451: fs = ip->i_fs;
! 452: p = curproc;
! 453: unwindidx = -1;
! 454:
! 455: lbn = lblkno(fs, off);
! 456: size = blkoff(fs, off) + size;
! 457:
! 458: if (size > fs->fs_bsize)
! 459: panic("ffs2_balloc: block too big");
! 460:
! 461: if (bpp != NULL)
! 462: *bpp = NULL;
! 463:
! 464: if (lbn < 0)
! 465: return (EFBIG);
! 466:
! 467: /*
! 468: * If the next write will extend the file into a new block, and the
! 469: * file is currently composed of a fragment, this fragment has to be
! 470: * extended to be a full block.
! 471: */
! 472: lastlbn = lblkno(fs, ip->i_ffs2_size);
! 473: if (lastlbn < NDADDR && lastlbn < lbn) {
! 474: nb = lastlbn;
! 475: osize = blksize(fs, ip, nb);
! 476: if (osize < fs->fs_bsize && osize > 0) {
! 477: error = ffs_realloccg(ip, nb, ffs2_blkpref(ip,
! 478: lastlbn, nb, &ip->i_ffs2_db[0]), osize,
! 479: (int) fs->fs_bsize, cred, bpp, &newb);
! 480: if (error)
! 481: return (error);
! 482:
! 483: if (DOINGSOFTDEP(vp))
! 484: softdep_setup_allocdirect(ip, nb, newb,
! 485: ip->i_ffs2_db[nb], fs->fs_bsize, osize,
! 486: bpp ? *bpp : NULL);
! 487:
! 488: ip->i_ffs2_size = lblktosize(fs, nb + 1);
! 489: uvm_vnp_setsize(vp, ip->i_ffs2_size);
! 490: ip->i_ffs2_db[nb] = newb;
! 491: ip->i_flag |= IN_CHANGE | IN_UPDATE;
! 492:
! 493: if (bpp) {
! 494: if (flags & B_SYNC)
! 495: bwrite(*bpp);
! 496: else
! 497: bawrite(*bpp);
! 498: }
! 499: }
! 500: }
! 501:
! 502: /*
! 503: * The first NDADDR blocks are direct.
! 504: */
! 505: if (lbn < NDADDR) {
! 506:
! 507: nb = ip->i_ffs2_db[lbn];
! 508:
! 509: if (nb != 0 && ip->i_ffs2_size >= lblktosize(fs, lbn + 1)) {
! 510: /*
! 511: * The direct block is already allocated and the file
! 512: * extends past this block, thus this must be a whole
! 513: * block. Just read it, if requested.
! 514: */
! 515: if (bpp != NULL) {
! 516: error = bread(vp, lbn, fs->fs_bsize, NOCRED,
! 517: bpp);
! 518: if (error) {
! 519: brelse(*bpp);
! 520: return (error);
! 521: }
! 522: }
! 523:
! 524: return (0);
! 525: }
! 526:
! 527: if (nb != 0) {
! 528: /*
! 529: * Consider the need to allocate a fragment.
! 530: */
! 531: osize = fragroundup(fs, blkoff(fs, ip->i_ffs2_size));
! 532: nsize = fragroundup(fs, size);
! 533:
! 534: if (nsize <= osize) {
! 535: /*
! 536: * The existing block is already at least as
! 537: * big as we want. Just read it, if requested.
! 538: */
! 539: if (bpp != NULL) {
! 540: error = bread(vp, lbn, fs->fs_bsize,
! 541: NOCRED, bpp);
! 542: if (error) {
! 543: brelse(*bpp);
! 544: return (error);
! 545: }
! 546: (*bpp)->b_bcount = osize;
! 547: }
! 548:
! 549: return (0);
! 550: } else {
! 551: /*
! 552: * The existing block is smaller than we want,
! 553: * grow it.
! 554: */
! 555: error = ffs_realloccg(ip, lbn,
! 556: ffs2_blkpref(ip, lbn, (int) lbn,
! 557: &ip->i_ffs2_db[0]), osize, nsize, cred,
! 558: bpp, &newb);
! 559: if (error)
! 560: return (error);
! 561:
! 562: if (DOINGSOFTDEP(vp))
! 563: softdep_setup_allocdirect(ip, lbn,
! 564: newb, nb, nsize, osize,
! 565: bpp ? *bpp : NULL);
! 566: }
! 567: } else {
! 568: /*
! 569: * The block was not previously allocated, allocate a
! 570: * new block or fragment.
! 571: */
! 572: if (ip->i_ffs2_size < lblktosize(fs, lbn + 1))
! 573: nsize = fragroundup(fs, size);
! 574: else
! 575: nsize = fs->fs_bsize;
! 576:
! 577: error = ffs_alloc(ip, lbn, ffs2_blkpref(ip, lbn,
! 578: (int) lbn, &ip->i_ffs2_db[0]), nsize, cred, &newb);
! 579: if (error)
! 580: return (error);
! 581:
! 582: if (bpp != NULL) {
! 583: bp = getblk(vp, lbn, fs->fs_bsize, 0, 0);
! 584: if (nsize < fs->fs_bsize)
! 585: bp->b_bcount = nsize;
! 586: bp->b_blkno = fsbtodb(fs, newb);
! 587: if (flags & B_CLRBUF)
! 588: clrbuf(bp);
! 589: *bpp = bp;
! 590: }
! 591:
! 592: if (DOINGSOFTDEP(vp))
! 593: softdep_setup_allocdirect(ip, lbn, newb, 0,
! 594: nsize, 0, bpp ? *bpp : NULL);
! 595: }
! 596:
! 597: ip->i_ffs2_db[lbn] = newb;
! 598: ip->i_flag |= IN_CHANGE | IN_UPDATE;
! 599:
! 600: return (0);
! 601: }
! 602:
! 603: /*
! 604: * Determine the number of levels of indirection.
! 605: */
! 606: pref = 0;
! 607: error = ufs_getlbns(vp, lbn, indirs, &num);
! 608: if (error)
! 609: return (error);
! 610:
! 611: #ifdef DIAGNOSTIC
! 612: if (num < 1)
! 613: panic("ffs2_balloc: ufs_bmaparray returned indirect block");
! 614: #endif
! 615:
! 616: /*
! 617: * Fetch the first indirect block allocating it necessary.
! 618: */
! 619: --num;
! 620: nb = ip->i_ffs2_ib[indirs[0].in_off];
! 621: allocib = NULL;
! 622: allocblk = allociblk;
! 623:
! 624: if (nb == 0) {
! 625: pref = ffs2_blkpref(ip, lbn, 0, NULL);
! 626: error = ffs_alloc(ip, lbn, pref, (int) fs->fs_bsize, cred,
! 627: &newb);
! 628: if (error)
! 629: goto fail;
! 630:
! 631: nb = newb;
! 632: *allocblk++ = nb;
! 633: bp = getblk(vp, indirs[1].in_lbn, fs->fs_bsize, 0, 0);
! 634: bp->b_blkno = fsbtodb(fs, nb);
! 635: clrbuf(bp);
! 636:
! 637: if (DOINGSOFTDEP(vp)) {
! 638: softdep_setup_allocdirect(ip, NDADDR + indirs[0].in_off,
! 639: newb, 0, fs->fs_bsize, 0, bp);
! 640: bdwrite(bp);
! 641: } else {
! 642: /*
! 643: * Write synchronously so that indirect blocks never
! 644: * point at garbage.
! 645: */
! 646: error = bwrite(bp);
! 647: if (error)
! 648: goto fail;
! 649: }
! 650:
! 651: unwindidx = 0;
! 652: allocib = &ip->i_ffs2_ib[indirs[0].in_off];
! 653: *allocib = nb;
! 654: ip->i_flag |= IN_CHANGE | IN_UPDATE;
! 655: }
! 656:
! 657: /*
! 658: * Fetch through the indirect blocks, allocating as necessary.
! 659: */
! 660: for (i = 1;;) {
! 661: error = bread(vp, indirs[i].in_lbn, (int) fs->fs_bsize,
! 662: NOCRED, &bp);
! 663: if (error) {
! 664: brelse(bp);
! 665: goto fail;
! 666: }
! 667:
! 668: bap = (int64_t *) bp->b_data;
! 669: nb = bap[indirs[i].in_off];
! 670:
! 671: if (i == num)
! 672: break;
! 673:
! 674: i++;
! 675:
! 676: if (nb != 0) {
! 677: brelse(bp);
! 678: continue;
! 679: }
! 680:
! 681: if (pref == 0)
! 682: pref = ffs2_blkpref(ip, lbn, 0, NULL);
! 683:
! 684: error = ffs_alloc(ip, lbn, pref, (int) fs->fs_bsize, cred,
! 685: &newb);
! 686: if (error) {
! 687: brelse(bp);
! 688: goto fail;
! 689: }
! 690:
! 691: nb = newb;
! 692: *allocblk++ = nb;
! 693: nbp = getblk(vp, indirs[i].in_lbn, fs->fs_bsize, 0, 0);
! 694: nbp->b_blkno = fsbtodb(fs, nb);
! 695: clrbuf(nbp);
! 696:
! 697: if (DOINGSOFTDEP(vp)) {
! 698: softdep_setup_allocindir_meta(nbp, ip, bp,
! 699: indirs[i - 1].in_off, nb);
! 700: bdwrite(nbp);
! 701: } else {
! 702: /*
! 703: * Write synchronously so that indirect blocks never
! 704: * point at garbage.
! 705: */
! 706: error = bwrite(nbp);
! 707: if (error) {
! 708: brelse(bp);
! 709: goto fail;
! 710: }
! 711: }
! 712:
! 713: if (unwindidx < 0)
! 714: unwindidx = i - 1;
! 715:
! 716: bap[indirs[i - 1].in_off] = nb;
! 717:
! 718: /*
! 719: * If required, write synchronously, otherwise use delayed
! 720: * write.
! 721: */
! 722: if (flags & B_SYNC)
! 723: bwrite(bp);
! 724: else
! 725: bdwrite(bp);
! 726: }
! 727:
! 728: /*
! 729: * Get the data block, allocating if necessary.
! 730: */
! 731: if (nb == 0) {
! 732: pref = ffs2_blkpref(ip, lbn, indirs[num].in_off, &bap[0]);
! 733:
! 734: error = ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize, cred,
! 735: &newb);
! 736: if (error) {
! 737: brelse(bp);
! 738: goto fail;
! 739: }
! 740:
! 741: nb = newb;
! 742: *allocblk++ = nb;
! 743:
! 744: if (bpp != NULL) {
! 745: nbp = getblk(vp, lbn, fs->fs_bsize, 0, 0);
! 746: nbp->b_blkno = fsbtodb(fs, nb);
! 747: if (flags & B_CLRBUF)
! 748: clrbuf(nbp);
! 749: *bpp = nbp;
! 750: }
! 751:
! 752: if (DOINGSOFTDEP(vp))
! 753: softdep_setup_allocindir_page(ip, lbn, bp,
! 754: indirs[num].in_off, nb, 0, bpp ? *bpp : NULL);
! 755:
! 756: bap[indirs[num].in_off] = nb;
! 757:
! 758: if (allocib == NULL && unwindidx < 0)
! 759: unwindidx = i - 1;
! 760:
! 761: /*
! 762: * If required, write synchronously, otherwise use delayed
! 763: * write.
! 764: */
! 765: if (flags & B_SYNC)
! 766: bwrite(bp);
! 767: else
! 768: bdwrite(bp);
! 769:
! 770: return (0);
! 771: }
! 772:
! 773: brelse(bp);
! 774:
! 775: if (bpp != NULL) {
! 776: if (flags & B_CLRBUF) {
! 777: error = bread(vp, lbn, (int)fs->fs_bsize, NOCRED, &nbp);
! 778: if (error) {
! 779: brelse(nbp);
! 780: goto fail;
! 781: }
! 782: } else {
! 783: nbp = getblk(vp, lbn, fs->fs_bsize, 0, 0);
! 784: nbp->b_blkno = fsbtodb(fs, nb);
! 785: clrbuf(nbp);
! 786: }
! 787:
! 788: *bpp = nbp;
! 789: }
! 790:
! 791: return (0);
! 792:
! 793: fail:
! 794: /*
! 795: * If we have failed to allocate any blocks, simply return the error.
! 796: * This is the usual case and avoids the need to fsync the file.
! 797: */
! 798: if (allocblk == allociblk && allocib == NULL && unwindidx == -1)
! 799: return (error);
! 800: /*
! 801: * If we have failed part way through block allocation, we have to
! 802: * deallocate any indirect blocks that we have allocated. We have to
! 803: * fsync the file before we start to get rid of all of its
! 804: * dependencies so that we do not leave them dangling. We have to sync
! 805: * it at the end so that the softdep code does not find any untracked
! 806: * changes. Although this is really slow, running out of disk space is
! 807: * not expected to be a common occurence. The error return from fsync
! 808: * is ignored as we already have an error to return to the user.
! 809: */
! 810: VOP_FSYNC(vp, p->p_ucred, MNT_WAIT, p);
! 811: if (unwindidx >= 0) {
! 812: /*
! 813: * First write out any buffers we've created to resolve their
! 814: * softdeps. This must be done in reverse order of creation so
! 815: * that we resolve the dependencies in one pass.
! 816: * Write the cylinder group buffers for these buffers too.
! 817: */
! 818: for (i = num; i >= unwindidx; i--) {
! 819: if (i == 0)
! 820: break;
! 821:
! 822: bp = getblk(vp, indirs[i].in_lbn, (int) fs->fs_bsize,
! 823: 0, 0);
! 824: if (bp->b_flags & B_DELWRI) {
! 825: nb = fsbtodb(fs, cgtod(fs, dtog(fs,
! 826: dbtofsb(fs, bp->b_blkno))));
! 827: bwrite(bp);
! 828: bp = getblk(ip->i_devvp, nb,
! 829: (int) fs->fs_cgsize, 0, 0);
! 830: if (bp->b_flags & B_DELWRI)
! 831: bwrite(bp);
! 832: else {
! 833: bp->b_flags |= B_INVAL;
! 834: brelse(bp);
! 835: }
! 836: } else {
! 837: bp->b_flags |= B_INVAL;
! 838: brelse(bp);
! 839: }
! 840: }
! 841:
! 842: if (DOINGSOFTDEP(vp) && unwindidx == 0) {
! 843: ip->i_flag |= IN_CHANGE | IN_UPDATE;
! 844: ffs_update(ip, NULL, NULL, MNT_WAIT);
! 845: }
! 846:
! 847: /*
! 848: * Now that any dependencies that we created have been
! 849: * resolved, we can undo the partial allocation.
! 850: */
! 851: if (unwindidx == 0) {
! 852: *allocib = 0;
! 853: ip->i_flag |= IN_CHANGE | IN_UPDATE;
! 854: if (DOINGSOFTDEP(vp))
! 855: ffs_update(ip, NULL, NULL, MNT_WAIT);
! 856: } else {
! 857: r = bread(vp, indirs[unwindidx].in_lbn,
! 858: (int) fs->fs_bsize, NOCRED, &bp);
! 859: if (r)
! 860: panic("ffs2_balloc: unwind failed");
! 861:
! 862: bap = (int64_t *) bp->b_data;
! 863: bap[indirs[unwindidx].in_off] = 0;
! 864: bwrite(bp);
! 865: }
! 866:
! 867: for (i = unwindidx + 1; i <= num; i++) {
! 868: bp = getblk(vp, indirs[i].in_lbn, (int)fs->fs_bsize, 0,
! 869: 0);
! 870: bp->b_flags |= B_INVAL;
! 871: brelse(bp);
! 872: }
! 873: }
! 874:
! 875: for (deallocated = 0, blkp = allociblk; blkp < allocblk; blkp++) {
! 876: ffs_blkfree(ip, *blkp, fs->fs_bsize);
! 877: deallocated += fs->fs_bsize;
! 878: }
! 879:
! 880: if (deallocated) {
! 881: /*
! 882: * Restore user's disk quota because allocation failed.
! 883: */
! 884: (void) ufs_quota_free_blocks(ip, btodb(deallocated), cred);
! 885:
! 886: ip->i_ffs2_blocks -= btodb(deallocated);
! 887: ip->i_flag |= IN_CHANGE | IN_UPDATE;
! 888: }
! 889: VOP_FSYNC(vp, p->p_ucred, MNT_WAIT, p);
! 890: return (error);
! 891: }
! 892: #endif /* FFS2 */
! 893:
! 894: /*
! 895: * Balloc defines the structure of file system storage by allocating the
! 896: * physical blocks given the inode and the logical block number in a file.
! 897: */
! 898: int
! 899: ffs_balloc(struct inode *ip, off_t off, int size, struct ucred *cred,
! 900: int flags, struct buf **bpp)
! 901: {
! 902: #ifdef FFS2
! 903: if (ip->i_fs->fs_magic == FS_UFS2_MAGIC)
! 904: return (ffs2_balloc(ip, off, size, cred, flags, bpp));
! 905: else
! 906: #endif
! 907: return (ffs1_balloc(ip, off, size, cred, flags, bpp));
! 908: }
CVSweb