Annotation of src/sys/ufs/ffs/ffs_balloc.c, Revision 1.45.6.2
1.45.6.2! jmcneill 1: /* $NetBSD: ffs_balloc.c,v 1.47 2007/12/08 15:21:19 ad Exp $ */
1.2 cgd 2:
1.1 mycroft 3: /*
1.33 fvdl 4: * Copyright (c) 2002 Networks Associates Technology, Inc.
5: * All rights reserved.
6: *
7: * This software was developed for the FreeBSD Project by Marshall
8: * Kirk McKusick and Network Associates Laboratories, the Security
9: * Research Division of Network Associates, Inc. under DARPA/SPAWAR
10: * contract N66001-01-C-8035 ("CBOSS"), as part of the DARPA CHATS
11: * research program
12: *
1.1 mycroft 13: * Copyright (c) 1982, 1986, 1989, 1993
14: * The Regents of the University of California. All rights reserved.
15: *
16: * Redistribution and use in source and binary forms, with or without
17: * modification, are permitted provided that the following conditions
18: * are met:
19: * 1. Redistributions of source code must retain the above copyright
20: * notice, this list of conditions and the following disclaimer.
21: * 2. Redistributions in binary form must reproduce the above copyright
22: * notice, this list of conditions and the following disclaimer in the
23: * documentation and/or other materials provided with the distribution.
1.34 agc 24: * 3. Neither the name of the University nor the names of its contributors
1.1 mycroft 25: * may be used to endorse or promote products derived from this software
26: * without specific prior written permission.
27: *
28: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
29: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
30: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
31: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
32: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
33: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
34: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
35: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
36: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
37: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
38: * SUCH DAMAGE.
39: *
1.8 fvdl 40: * @(#)ffs_balloc.c 8.8 (Berkeley) 6/16/95
1.1 mycroft 41: */
1.28 lukem 42:
43: #include <sys/cdefs.h>
1.45.6.2! jmcneill 44: __KERNEL_RCSID(0, "$NetBSD: ffs_balloc.c,v 1.47 2007/12/08 15:21:19 ad Exp $");
1.7 mrg 45:
1.24 mrg 46: #if defined(_KERNEL_OPT)
1.10 scottr 47: #include "opt_quota.h"
1.11 scottr 48: #endif
1.1 mycroft 49:
50: #include <sys/param.h>
51: #include <sys/systm.h>
52: #include <sys/buf.h>
53: #include <sys/file.h>
1.15 fvdl 54: #include <sys/mount.h>
1.1 mycroft 55: #include <sys/vnode.h>
1.43 elad 56: #include <sys/kauth.h>
1.6 mrg 57:
1.1 mycroft 58: #include <ufs/ufs/quota.h>
1.9 bouyer 59: #include <ufs/ufs/ufsmount.h>
1.1 mycroft 60: #include <ufs/ufs/inode.h>
61: #include <ufs/ufs/ufs_extern.h>
1.9 bouyer 62: #include <ufs/ufs/ufs_bswap.h>
1.1 mycroft 63:
64: #include <ufs/ffs/fs.h>
65: #include <ufs/ffs/ffs_extern.h>
66:
1.23 chs 67: #include <uvm/uvm.h>
68:
1.43 elad 69: static int ffs_balloc_ufs1(struct vnode *, off_t, int, kauth_cred_t, int,
1.39 yamt 70: struct buf **);
1.43 elad 71: static int ffs_balloc_ufs2(struct vnode *, off_t, int, kauth_cred_t, int,
1.39 yamt 72: struct buf **);
1.33 fvdl 73:
1.1 mycroft 74: /*
75: * Balloc defines the structure of file system storage
76: * by allocating the physical blocks on a device given
77: * the inode and the logical block number in a file.
78: */
1.33 fvdl 79:
1.3 christos 80: int
1.43 elad 81: ffs_balloc(struct vnode *vp, off_t off, int size, kauth_cred_t cred, int flags,
1.39 yamt 82: struct buf **bpp)
1.15 fvdl 83: {
1.33 fvdl 84:
1.39 yamt 85: if (VTOI(vp)->i_fs->fs_magic == FS_UFS2_MAGIC)
86: return ffs_balloc_ufs2(vp, off, size, cred, flags, bpp);
1.33 fvdl 87: else
1.39 yamt 88: return ffs_balloc_ufs1(vp, off, size, cred, flags, bpp);
1.33 fvdl 89: }
90:
91: static int
1.43 elad 92: ffs_balloc_ufs1(struct vnode *vp, off_t off, int size, kauth_cred_t cred,
1.39 yamt 93: int flags, struct buf **bpp)
1.33 fvdl 94: {
95: daddr_t lbn, lastlbn;
1.1 mycroft 96: struct buf *bp, *nbp;
1.15 fvdl 97: struct inode *ip = VTOI(vp);
98: struct fs *fs = ip->i_fs;
1.45.6.1 joerg 99: struct ufsmount *ump = ip->i_ump;
1.1 mycroft 100: struct indir indirs[NIADDR + 2];
1.37 mycroft 101: daddr_t newb, pref, nb;
1.31 fvdl 102: int32_t *bap; /* XXX ondisk32 */
1.8 fvdl 103: int deallocated, osize, nsize, num, i, error;
1.33 fvdl 104: int32_t *blkp, *allocblk, allociblk[NIADDR + 1];
105: int32_t *allocib;
1.17 fvdl 106: int unwindidx = -1;
1.15 fvdl 107: #ifdef FFS_EI
108: const int needswap = UFS_FSNEEDSWAP(fs);
109: #endif
1.23 chs 110: UVMHIST_FUNC("ffs_balloc"); UVMHIST_CALLED(ubchist);
1.1 mycroft 111:
1.39 yamt 112: lbn = lblkno(fs, off);
113: size = blkoff(fs, off) + size;
1.15 fvdl 114: if (size > fs->fs_bsize)
115: panic("ffs_balloc: blk too big");
1.23 chs 116: if (bpp != NULL) {
117: *bpp = NULL;
118: }
119: UVMHIST_LOG(ubchist, "vp %p lbn 0x%x size 0x%x", vp, lbn, size,0);
120:
1.8 fvdl 121: if (lbn < 0)
1.1 mycroft 122: return (EFBIG);
123:
124: /*
125: * If the next write will extend the file into a new block,
126: * and the file is currently composed of a fragment
127: * this fragment has to be extended to be a full block.
128: */
1.23 chs 129:
1.33 fvdl 130: lastlbn = lblkno(fs, ip->i_size);
131: if (lastlbn < NDADDR && lastlbn < lbn) {
132: nb = lastlbn;
1.1 mycroft 133: osize = blksize(fs, ip, nb);
134: if (osize < fs->fs_bsize && osize > 0) {
1.45.6.1 joerg 135: mutex_enter(&ump->um_lock);
1.1 mycroft 136: error = ffs_realloccg(ip, nb,
1.33 fvdl 137: ffs_blkpref_ufs1(ip, lastlbn, nb,
138: &ip->i_ffs1_db[0]),
139: osize, (int)fs->fs_bsize, cred, bpp, &newb);
1.1 mycroft 140: if (error)
141: return (error);
1.15 fvdl 142: if (DOINGSOFTDEP(vp))
1.23 chs 143: softdep_setup_allocdirect(ip, nb, newb,
1.33 fvdl 144: ufs_rw32(ip->i_ffs1_db[nb], needswap),
1.23 chs 145: fs->fs_bsize, osize, bpp ? *bpp : NULL);
1.33 fvdl 146: ip->i_size = lblktosize(fs, nb + 1);
147: ip->i_ffs1_size = ip->i_size;
148: uvm_vnp_setsize(vp, ip->i_ffs1_size);
1.37 mycroft 149: ip->i_ffs1_db[nb] = ufs_rw32((u_int32_t)newb, needswap);
1.1 mycroft 150: ip->i_flag |= IN_CHANGE | IN_UPDATE;
1.42 christos 151: if (bpp && *bpp) {
1.23 chs 152: if (flags & B_SYNC)
153: bwrite(*bpp);
154: else
155: bawrite(*bpp);
156: }
1.1 mycroft 157: }
158: }
1.23 chs 159:
1.1 mycroft 160: /*
161: * The first NDADDR blocks are direct blocks
162: */
1.23 chs 163:
1.8 fvdl 164: if (lbn < NDADDR) {
1.33 fvdl 165: nb = ufs_rw32(ip->i_ffs1_db[lbn], needswap);
166: if (nb != 0 && ip->i_size >= lblktosize(fs, lbn + 1)) {
1.23 chs 167:
168: /*
169: * The block is an already-allocated direct block
170: * and the file already extends past this block,
171: * thus this must be a whole block.
172: * Just read the block (if requested).
173: */
174:
175: if (bpp != NULL) {
176: error = bread(vp, lbn, fs->fs_bsize, NOCRED,
177: bpp);
178: if (error) {
1.45.6.1 joerg 179: brelse(*bpp, 0);
1.23 chs 180: return (error);
181: }
1.1 mycroft 182: }
183: return (0);
184: }
185: if (nb != 0) {
1.23 chs 186:
1.1 mycroft 187: /*
188: * Consider need to reallocate a fragment.
189: */
1.23 chs 190:
1.33 fvdl 191: osize = fragroundup(fs, blkoff(fs, ip->i_size));
1.1 mycroft 192: nsize = fragroundup(fs, size);
193: if (nsize <= osize) {
1.23 chs 194:
195: /*
196: * The existing block is already
197: * at least as big as we want.
198: * Just read the block (if requested).
199: */
200:
201: if (bpp != NULL) {
202: error = bread(vp, lbn, osize, NOCRED,
203: bpp);
204: if (error) {
1.45.6.1 joerg 205: brelse(*bpp, 0);
1.23 chs 206: return (error);
207: }
1.1 mycroft 208: }
1.23 chs 209: return 0;
1.1 mycroft 210: } else {
1.23 chs 211:
212: /*
213: * The existing block is smaller than we want,
214: * grow it.
215: */
1.45.6.1 joerg 216: mutex_enter(&ump->um_lock);
1.8 fvdl 217: error = ffs_realloccg(ip, lbn,
1.33 fvdl 218: ffs_blkpref_ufs1(ip, lbn, (int)lbn,
219: &ip->i_ffs1_db[0]), osize, nsize, cred,
1.23 chs 220: bpp, &newb);
1.1 mycroft 221: if (error)
222: return (error);
1.15 fvdl 223: if (DOINGSOFTDEP(vp))
224: softdep_setup_allocdirect(ip, lbn,
1.23 chs 225: newb, nb, nsize, osize,
226: bpp ? *bpp : NULL);
1.1 mycroft 227: }
228: } else {
1.23 chs 229:
230: /*
231: * the block was not previously allocated,
232: * allocate a new block or fragment.
233: */
234:
1.33 fvdl 235: if (ip->i_size < lblktosize(fs, lbn + 1))
1.1 mycroft 236: nsize = fragroundup(fs, size);
237: else
238: nsize = fs->fs_bsize;
1.45.6.1 joerg 239: mutex_enter(&ump->um_lock);
1.8 fvdl 240: error = ffs_alloc(ip, lbn,
1.33 fvdl 241: ffs_blkpref_ufs1(ip, lbn, (int)lbn,
242: &ip->i_ffs1_db[0]),
1.8 fvdl 243: nsize, cred, &newb);
1.1 mycroft 244: if (error)
245: return (error);
1.23 chs 246: if (bpp != NULL) {
247: bp = getblk(vp, lbn, nsize, 0, 0);
248: bp->b_blkno = fsbtodb(fs, newb);
249: if (flags & B_CLRBUF)
250: clrbuf(bp);
251: *bpp = bp;
252: }
253: if (DOINGSOFTDEP(vp)) {
1.15 fvdl 254: softdep_setup_allocdirect(ip, lbn, newb, 0,
1.23 chs 255: nsize, 0, bpp ? *bpp : NULL);
256: }
1.1 mycroft 257: }
1.37 mycroft 258: ip->i_ffs1_db[lbn] = ufs_rw32((u_int32_t)newb, needswap);
1.1 mycroft 259: ip->i_flag |= IN_CHANGE | IN_UPDATE;
260: return (0);
261: }
1.29 chs 262:
1.1 mycroft 263: /*
264: * Determine the number of levels of indirection.
265: */
1.29 chs 266:
1.1 mycroft 267: pref = 0;
1.8 fvdl 268: if ((error = ufs_getlbns(vp, lbn, indirs, &num)) != 0)
1.29 chs 269: return (error);
1.23 chs 270:
1.1 mycroft 271: /*
272: * Fetch the first indirect block allocating if necessary.
273: */
1.29 chs 274:
1.1 mycroft 275: --num;
1.33 fvdl 276: nb = ufs_rw32(ip->i_ffs1_ib[indirs[0].in_off], needswap);
1.8 fvdl 277: allocib = NULL;
278: allocblk = allociblk;
1.1 mycroft 279: if (nb == 0) {
1.45.6.1 joerg 280: mutex_enter(&ump->um_lock);
1.33 fvdl 281: pref = ffs_blkpref_ufs1(ip, lbn, 0, (int32_t *)0);
1.18 mycroft 282: error = ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize, cred,
283: &newb);
1.3 christos 284: if (error)
1.27 chs 285: goto fail;
1.1 mycroft 286: nb = newb;
1.8 fvdl 287: *allocblk++ = nb;
1.1 mycroft 288: bp = getblk(vp, indirs[1].in_lbn, fs->fs_bsize, 0, 0);
1.8 fvdl 289: bp->b_blkno = fsbtodb(fs, nb);
1.1 mycroft 290: clrbuf(bp);
1.15 fvdl 291: if (DOINGSOFTDEP(vp)) {
292: softdep_setup_allocdirect(ip, NDADDR + indirs[0].in_off,
293: newb, 0, fs->fs_bsize, 0, bp);
294: bdwrite(bp);
295: } else {
1.29 chs 296:
1.15 fvdl 297: /*
298: * Write synchronously so that indirect blocks
299: * never point at garbage.
300: */
1.29 chs 301:
1.15 fvdl 302: if ((error = bwrite(bp)) != 0)
303: goto fail;
304: }
1.18 mycroft 305: unwindidx = 0;
1.33 fvdl 306: allocib = &ip->i_ffs1_ib[indirs[0].in_off];
307: *allocib = ufs_rw32(nb, needswap);
1.1 mycroft 308: ip->i_flag |= IN_CHANGE | IN_UPDATE;
309: }
1.29 chs 310:
1.1 mycroft 311: /*
312: * Fetch through the indirect blocks, allocating as necessary.
313: */
1.29 chs 314:
1.1 mycroft 315: for (i = 1;;) {
316: error = bread(vp,
317: indirs[i].in_lbn, (int)fs->fs_bsize, NOCRED, &bp);
318: if (error) {
1.45.6.1 joerg 319: brelse(bp, 0);
1.8 fvdl 320: goto fail;
1.1 mycroft 321: }
1.31 fvdl 322: bap = (int32_t *)bp->b_data; /* XXX ondisk32 */
1.15 fvdl 323: nb = ufs_rw32(bap[indirs[i].in_off], needswap);
1.1 mycroft 324: if (i == num)
325: break;
1.18 mycroft 326: i++;
1.1 mycroft 327: if (nb != 0) {
1.45.6.1 joerg 328: brelse(bp, 0);
1.1 mycroft 329: continue;
330: }
1.45.6.1 joerg 331: mutex_enter(&ump->um_lock);
1.1 mycroft 332: if (pref == 0)
1.33 fvdl 333: pref = ffs_blkpref_ufs1(ip, lbn, 0, (int32_t *)0);
1.3 christos 334: error = ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize, cred,
1.18 mycroft 335: &newb);
1.3 christos 336: if (error) {
1.45.6.1 joerg 337: brelse(bp, 0);
1.8 fvdl 338: goto fail;
1.1 mycroft 339: }
340: nb = newb;
1.8 fvdl 341: *allocblk++ = nb;
1.1 mycroft 342: nbp = getblk(vp, indirs[i].in_lbn, fs->fs_bsize, 0, 0);
343: nbp->b_blkno = fsbtodb(fs, nb);
344: clrbuf(nbp);
1.15 fvdl 345: if (DOINGSOFTDEP(vp)) {
346: softdep_setup_allocindir_meta(nbp, ip, bp,
347: indirs[i - 1].in_off, nb);
348: bdwrite(nbp);
349: } else {
1.29 chs 350:
1.15 fvdl 351: /*
352: * Write synchronously so that indirect blocks
353: * never point at garbage.
354: */
1.29 chs 355:
1.15 fvdl 356: if ((error = bwrite(nbp)) != 0) {
1.45.6.1 joerg 357: brelse(bp, 0);
1.15 fvdl 358: goto fail;
359: }
1.1 mycroft 360: }
1.18 mycroft 361: if (unwindidx < 0)
362: unwindidx = i - 1;
1.33 fvdl 363: bap[indirs[i - 1].in_off] = ufs_rw32(nb, needswap);
1.29 chs 364:
1.1 mycroft 365: /*
366: * If required, write synchronously, otherwise use
367: * delayed write.
368: */
1.29 chs 369:
1.1 mycroft 370: if (flags & B_SYNC) {
371: bwrite(bp);
372: } else {
373: bdwrite(bp);
374: }
375: }
1.29 chs 376:
1.35 hannken 377: if (flags & B_METAONLY) {
1.41 hannken 378: KASSERT(bpp != NULL);
1.35 hannken 379: *bpp = bp;
380: return (0);
381: }
382:
1.1 mycroft 383: /*
384: * Get the data block, allocating if necessary.
385: */
1.29 chs 386:
1.1 mycroft 387: if (nb == 0) {
1.45.6.1 joerg 388: mutex_enter(&ump->um_lock);
1.33 fvdl 389: pref = ffs_blkpref_ufs1(ip, lbn, indirs[num].in_off, &bap[0]);
1.3 christos 390: error = ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize, cred,
1.18 mycroft 391: &newb);
1.3 christos 392: if (error) {
1.45.6.1 joerg 393: brelse(bp, 0);
1.8 fvdl 394: goto fail;
1.1 mycroft 395: }
396: nb = newb;
1.8 fvdl 397: *allocblk++ = nb;
1.23 chs 398: if (bpp != NULL) {
399: nbp = getblk(vp, lbn, fs->fs_bsize, 0, 0);
400: nbp->b_blkno = fsbtodb(fs, nb);
401: if (flags & B_CLRBUF)
402: clrbuf(nbp);
403: *bpp = nbp;
404: }
1.15 fvdl 405: if (DOINGSOFTDEP(vp))
406: softdep_setup_allocindir_page(ip, lbn, bp,
1.23 chs 407: indirs[num].in_off, nb, 0, bpp ? *bpp : NULL);
1.33 fvdl 408: bap[indirs[num].in_off] = ufs_rw32(nb, needswap);
1.23 chs 409: if (allocib == NULL && unwindidx < 0) {
410: unwindidx = i - 1;
411: }
1.29 chs 412:
1.1 mycroft 413: /*
414: * If required, write synchronously, otherwise use
415: * delayed write.
416: */
1.29 chs 417:
1.1 mycroft 418: if (flags & B_SYNC) {
419: bwrite(bp);
420: } else {
421: bdwrite(bp);
422: }
423: return (0);
424: }
1.45.6.1 joerg 425: brelse(bp, 0);
1.23 chs 426: if (bpp != NULL) {
427: if (flags & B_CLRBUF) {
428: error = bread(vp, lbn, (int)fs->fs_bsize, NOCRED, &nbp);
429: if (error) {
1.45.6.1 joerg 430: brelse(nbp, 0);
1.23 chs 431: goto fail;
432: }
433: } else {
434: nbp = getblk(vp, lbn, fs->fs_bsize, 0, 0);
435: nbp->b_blkno = fsbtodb(fs, nb);
436: clrbuf(nbp);
1.1 mycroft 437: }
1.23 chs 438: *bpp = nbp;
1.1 mycroft 439: }
440: return (0);
1.27 chs 441:
1.8 fvdl 442: fail:
1.27 chs 443: /*
1.29 chs 444: * If we have failed part way through block allocation, we
445: * have to deallocate any indirect blocks that we have allocated.
1.27 chs 446: */
447:
1.29 chs 448: if (unwindidx >= 0) {
1.27 chs 449:
1.29 chs 450: /*
451: * First write out any buffers we've created to resolve their
452: * softdeps. This must be done in reverse order of creation
453: * so that we resolve the dependencies in one pass.
454: * Write the cylinder group buffers for these buffers too.
455: */
456:
457: for (i = num; i >= unwindidx; i--) {
458: if (i == 0) {
459: break;
460: }
461: bp = getblk(vp, indirs[i].in_lbn, (int)fs->fs_bsize, 0,
462: 0);
463: if (bp->b_flags & B_DELWRI) {
464: nb = fsbtodb(fs, cgtod(fs, dtog(fs,
1.30 chs 465: dbtofsb(fs, bp->b_blkno))));
1.29 chs 466: bwrite(bp);
467: bp = getblk(ip->i_devvp, nb, (int)fs->fs_cgsize,
468: 0, 0);
469: if (bp->b_flags & B_DELWRI) {
470: bwrite(bp);
471: } else {
1.45.6.1 joerg 472: brelse(bp, BC_INVAL);
1.29 chs 473: }
474: } else {
1.45.6.1 joerg 475: brelse(bp, BC_INVAL);
1.29 chs 476: }
477: }
1.45.6.2! jmcneill 478:
! 479: /* Now flush all dependencies to disk. */
! 480: #ifdef notyet
! 481: /* XXX pages locked */
! 482: (void)softdep_sync_metadata(vp);
! 483: #endif
! 484:
1.36 mycroft 485: if (DOINGSOFTDEP(vp) && unwindidx == 0) {
486: ip->i_flag |= IN_CHANGE | IN_UPDATE;
1.39 yamt 487: ffs_update(vp, NULL, NULL, UPDATE_WAIT);
1.27 chs 488: }
489:
1.29 chs 490: /*
491: * Now that any dependencies that we created have been
492: * resolved, we can undo the partial allocation.
493: */
1.27 chs 494:
1.18 mycroft 495: if (unwindidx == 0) {
496: *allocib = 0;
1.36 mycroft 497: ip->i_flag |= IN_CHANGE | IN_UPDATE;
498: if (DOINGSOFTDEP(vp))
1.39 yamt 499: ffs_update(vp, NULL, NULL, UPDATE_WAIT);
1.17 fvdl 500: } else {
1.18 mycroft 501: int r;
1.29 chs 502:
503: r = bread(vp, indirs[unwindidx].in_lbn,
1.18 mycroft 504: (int)fs->fs_bsize, NOCRED, &bp);
505: if (r) {
506: panic("Could not unwind indirect block, error %d", r);
1.45.6.1 joerg 507: brelse(bp, 0);
1.18 mycroft 508: } else {
1.31 fvdl 509: bap = (int32_t *)bp->b_data; /* XXX ondisk32 */
1.18 mycroft 510: bap[indirs[unwindidx].in_off] = 0;
1.29 chs 511: bwrite(bp);
1.18 mycroft 512: }
1.17 fvdl 513: }
1.19 mycroft 514: for (i = unwindidx + 1; i <= num; i++) {
515: bp = getblk(vp, indirs[i].in_lbn, (int)fs->fs_bsize, 0,
516: 0);
1.45.6.1 joerg 517: brelse(bp, BC_INVAL);
1.19 mycroft 518: }
1.17 fvdl 519: }
1.29 chs 520: for (deallocated = 0, blkp = allociblk; blkp < allocblk; blkp++) {
1.35 hannken 521: ffs_blkfree(fs, ip->i_devvp, *blkp, fs->fs_bsize, ip->i_number);
1.29 chs 522: deallocated += fs->fs_bsize;
523: }
1.8 fvdl 524: if (deallocated) {
525: #ifdef QUOTA
526: /*
527: * Restore user's disk quota because allocation failed.
528: */
1.33 fvdl 529: (void)chkdq(ip, -btodb(deallocated), cred, FORCE);
530: #endif
531: ip->i_ffs1_blocks -= btodb(deallocated);
532: ip->i_flag |= IN_CHANGE | IN_UPDATE;
533: }
1.45.6.2! jmcneill 534: /*
! 535: * Flush all dependencies again so that the soft updates code
! 536: * doesn't find any untracked changes.
! 537: */
! 538: #ifdef notyet
! 539: /* XXX pages locked */
! 540: (void)softdep_sync_metadata(vp);
! 541: #endif
1.33 fvdl 542: return (error);
543: }
544:
545: static int
1.43 elad 546: ffs_balloc_ufs2(struct vnode *vp, off_t off, int size, kauth_cred_t cred,
1.39 yamt 547: int flags, struct buf **bpp)
1.33 fvdl 548: {
549: daddr_t lbn, lastlbn;
550: struct buf *bp, *nbp;
551: struct inode *ip = VTOI(vp);
552: struct fs *fs = ip->i_fs;
1.45.6.1 joerg 553: struct ufsmount *ump = ip->i_ump;
1.33 fvdl 554: struct indir indirs[NIADDR + 2];
555: daddr_t newb, pref, nb;
556: int64_t *bap;
557: int deallocated, osize, nsize, num, i, error;
558: daddr_t *blkp, *allocblk, allociblk[NIADDR + 1];
559: int64_t *allocib;
560: int unwindidx = -1;
561: #ifdef FFS_EI
562: const int needswap = UFS_FSNEEDSWAP(fs);
563: #endif
564: UVMHIST_FUNC("ffs_balloc"); UVMHIST_CALLED(ubchist);
565:
1.39 yamt 566: lbn = lblkno(fs, off);
567: size = blkoff(fs, off) + size;
1.33 fvdl 568: if (size > fs->fs_bsize)
569: panic("ffs_balloc: blk too big");
570: if (bpp != NULL) {
571: *bpp = NULL;
572: }
573: UVMHIST_LOG(ubchist, "vp %p lbn 0x%x size 0x%x", vp, lbn, size,0);
574:
575: if (lbn < 0)
576: return (EFBIG);
577:
578: #ifdef notyet
579: /*
580: * Check for allocating external data.
581: */
582: if (flags & IO_EXT) {
583: if (lbn >= NXADDR)
584: return (EFBIG);
585: /*
586: * If the next write will extend the data into a new block,
587: * and the data is currently composed of a fragment
588: * this fragment has to be extended to be a full block.
589: */
590: lastlbn = lblkno(fs, dp->di_extsize);
591: if (lastlbn < lbn) {
592: nb = lastlbn;
593: osize = sblksize(fs, dp->di_extsize, nb);
594: if (osize < fs->fs_bsize && osize > 0) {
1.45.6.1 joerg 595: mutex_enter(&ump->um_lock);
1.33 fvdl 596: error = ffs_realloccg(ip, -1 - nb,
597: dp->di_extb[nb],
598: ffs_blkpref_ufs2(ip, lastlbn, (int)nb,
599: &dp->di_extb[0]), osize,
600: (int)fs->fs_bsize, cred, &bp);
601: if (error)
602: return (error);
603: if (DOINGSOFTDEP(vp))
604: softdep_setup_allocext(ip, nb,
605: dbtofsb(fs, bp->b_blkno),
606: dp->di_extb[nb],
607: fs->fs_bsize, osize, bp);
608: dp->di_extsize = smalllblktosize(fs, nb + 1);
609: dp->di_extb[nb] = dbtofsb(fs, bp->b_blkno);
610: bp->b_xflags |= BX_ALTDATA;
611: ip->i_flag |= IN_CHANGE | IN_UPDATE;
612: if (flags & IO_SYNC)
613: bwrite(bp);
614: else
615: bawrite(bp);
616: }
617: }
618: /*
619: * All blocks are direct blocks
620: */
621: if (flags & BA_METAONLY)
622: panic("ffs_balloc_ufs2: BA_METAONLY for ext block");
623: nb = dp->di_extb[lbn];
624: if (nb != 0 && dp->di_extsize >= smalllblktosize(fs, lbn + 1)) {
625: error = bread(vp, -1 - lbn, fs->fs_bsize, NOCRED, &bp);
626: if (error) {
1.45.6.1 joerg 627: brelse(bp, 0);
1.33 fvdl 628: return (error);
629: }
630: bp->b_blkno = fsbtodb(fs, nb);
631: bp->b_xflags |= BX_ALTDATA;
632: *bpp = bp;
633: return (0);
634: }
635: if (nb != 0) {
636: /*
637: * Consider need to reallocate a fragment.
638: */
639: osize = fragroundup(fs, blkoff(fs, dp->di_extsize));
640: nsize = fragroundup(fs, size);
641: if (nsize <= osize) {
642: error = bread(vp, -1 - lbn, osize, NOCRED, &bp);
643: if (error) {
1.45.6.1 joerg 644: brelse(bp, 0);
1.33 fvdl 645: return (error);
646: }
1.45.6.1 joerg 647: mutex_enter(&bp->b_interlock);
1.33 fvdl 648: bp->b_blkno = fsbtodb(fs, nb);
649: bp->b_xflags |= BX_ALTDATA;
1.45.6.1 joerg 650: mutex_exit(&bp->b_interlock);
1.33 fvdl 651: } else {
1.45.6.1 joerg 652: mutex_enter(&ump->um_lock);
1.33 fvdl 653: error = ffs_realloccg(ip, -1 - lbn,
654: dp->di_extb[lbn],
655: ffs_blkpref_ufs2(ip, lbn, (int)lbn,
656: &dp->di_extb[0]), osize, nsize, cred, &bp);
657: if (error)
658: return (error);
659: bp->b_xflags |= BX_ALTDATA;
660: if (DOINGSOFTDEP(vp))
661: softdep_setup_allocext(ip, lbn,
662: dbtofsb(fs, bp->b_blkno), nb,
663: nsize, osize, bp);
664: }
665: } else {
666: if (dp->di_extsize < smalllblktosize(fs, lbn + 1))
667: nsize = fragroundup(fs, size);
668: else
669: nsize = fs->fs_bsize;
1.45.6.1 joerg 670: mutex_enter(&ump->um_lock);
1.33 fvdl 671: error = ffs_alloc(ip, lbn,
672: ffs_blkpref_ufs2(ip, lbn, (int)lbn, &dp->di_extb[0]),
673: nsize, cred, &newb);
674: if (error)
675: return (error);
676: bp = getblk(vp, -1 - lbn, nsize, 0, 0);
677: bp->b_blkno = fsbtodb(fs, newb);
678: bp->b_xflags |= BX_ALTDATA;
679: if (flags & BA_CLRBUF)
680: vfs_bio_clrbuf(bp);
681: if (DOINGSOFTDEP(vp))
682: softdep_setup_allocext(ip, lbn, newb, 0,
683: nsize, 0, bp);
684: }
685: dp->di_extb[lbn] = dbtofsb(fs, bp->b_blkno);
686: ip->i_flag |= IN_CHANGE | IN_UPDATE;
687: *bpp = bp;
688: return (0);
689: }
690: #endif
691: /*
692: * If the next write will extend the file into a new block,
693: * and the file is currently composed of a fragment
694: * this fragment has to be extended to be a full block.
695: */
696:
697: lastlbn = lblkno(fs, ip->i_size);
698: if (lastlbn < NDADDR && lastlbn < lbn) {
699: nb = lastlbn;
700: osize = blksize(fs, ip, nb);
701: if (osize < fs->fs_bsize && osize > 0) {
1.45.6.1 joerg 702: mutex_enter(&ump->um_lock);
1.33 fvdl 703: error = ffs_realloccg(ip, nb,
704: ffs_blkpref_ufs2(ip, lastlbn, nb,
705: &ip->i_ffs2_db[0]),
706: osize, (int)fs->fs_bsize, cred, bpp, &newb);
707: if (error)
708: return (error);
709: if (DOINGSOFTDEP(vp))
710: softdep_setup_allocdirect(ip, nb, newb,
711: ufs_rw64(ip->i_ffs2_db[nb], needswap),
712: fs->fs_bsize, osize, bpp ? *bpp : NULL);
713: ip->i_size = lblktosize(fs, nb + 1);
714: ip->i_ffs2_size = ip->i_size;
715: uvm_vnp_setsize(vp, ip->i_size);
716: ip->i_ffs2_db[nb] = ufs_rw64(newb, needswap);
717: ip->i_flag |= IN_CHANGE | IN_UPDATE;
718: if (bpp) {
719: if (flags & B_SYNC)
720: bwrite(*bpp);
721: else
722: bawrite(*bpp);
723: }
724: }
725: }
726:
727: /*
728: * The first NDADDR blocks are direct blocks
729: */
730:
731: if (lbn < NDADDR) {
732: nb = ufs_rw64(ip->i_ffs2_db[lbn], needswap);
733: if (nb != 0 && ip->i_size >= lblktosize(fs, lbn + 1)) {
734:
735: /*
736: * The block is an already-allocated direct block
737: * and the file already extends past this block,
738: * thus this must be a whole block.
739: * Just read the block (if requested).
740: */
741:
742: if (bpp != NULL) {
743: error = bread(vp, lbn, fs->fs_bsize, NOCRED,
744: bpp);
745: if (error) {
1.45.6.1 joerg 746: brelse(*bpp, 0);
1.33 fvdl 747: return (error);
748: }
749: }
750: return (0);
751: }
752: if (nb != 0) {
753:
754: /*
755: * Consider need to reallocate a fragment.
756: */
757:
758: osize = fragroundup(fs, blkoff(fs, ip->i_size));
759: nsize = fragroundup(fs, size);
760: if (nsize <= osize) {
761:
762: /*
763: * The existing block is already
764: * at least as big as we want.
765: * Just read the block (if requested).
766: */
767:
768: if (bpp != NULL) {
769: error = bread(vp, lbn, osize, NOCRED,
770: bpp);
771: if (error) {
1.45.6.1 joerg 772: brelse(*bpp, 0);
1.33 fvdl 773: return (error);
774: }
775: }
776: return 0;
777: } else {
778:
779: /*
780: * The existing block is smaller than we want,
781: * grow it.
782: */
1.45.6.1 joerg 783: mutex_enter(&ump->um_lock);
1.33 fvdl 784: error = ffs_realloccg(ip, lbn,
785: ffs_blkpref_ufs2(ip, lbn, (int)lbn,
786: &ip->i_ffs2_db[0]), osize, nsize, cred,
787: bpp, &newb);
788: if (error)
789: return (error);
790: if (DOINGSOFTDEP(vp))
791: softdep_setup_allocdirect(ip, lbn,
792: newb, nb, nsize, osize,
793: bpp ? *bpp : NULL);
794: }
795: } else {
796:
797: /*
798: * the block was not previously allocated,
799: * allocate a new block or fragment.
800: */
801:
802: if (ip->i_size < lblktosize(fs, lbn + 1))
803: nsize = fragroundup(fs, size);
804: else
805: nsize = fs->fs_bsize;
1.45.6.1 joerg 806: mutex_enter(&ump->um_lock);
1.33 fvdl 807: error = ffs_alloc(ip, lbn,
808: ffs_blkpref_ufs2(ip, lbn, (int)lbn,
809: &ip->i_ffs2_db[0]), nsize, cred, &newb);
810: if (error)
811: return (error);
812: if (bpp != NULL) {
813: bp = getblk(vp, lbn, nsize, 0, 0);
814: bp->b_blkno = fsbtodb(fs, newb);
815: if (flags & B_CLRBUF)
816: clrbuf(bp);
817: *bpp = bp;
818: }
819: if (DOINGSOFTDEP(vp)) {
820: softdep_setup_allocdirect(ip, lbn, newb, 0,
821: nsize, 0, bpp ? *bpp : NULL);
822: }
823: }
824: ip->i_ffs2_db[lbn] = ufs_rw64(newb, needswap);
825: ip->i_flag |= IN_CHANGE | IN_UPDATE;
826: return (0);
827: }
828:
829: /*
830: * Determine the number of levels of indirection.
831: */
832:
833: pref = 0;
834: if ((error = ufs_getlbns(vp, lbn, indirs, &num)) != 0)
835: return (error);
836:
837: /*
838: * Fetch the first indirect block allocating if necessary.
839: */
840:
841: --num;
842: nb = ufs_rw64(ip->i_ffs2_ib[indirs[0].in_off], needswap);
843: allocib = NULL;
844: allocblk = allociblk;
845: if (nb == 0) {
1.45.6.1 joerg 846: mutex_enter(&ump->um_lock);
1.33 fvdl 847: pref = ffs_blkpref_ufs2(ip, lbn, 0, (int64_t *)0);
848: error = ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize, cred,
849: &newb);
850: if (error)
851: goto fail;
852: nb = newb;
853: *allocblk++ = nb;
854: bp = getblk(vp, indirs[1].in_lbn, fs->fs_bsize, 0, 0);
855: bp->b_blkno = fsbtodb(fs, nb);
856: clrbuf(bp);
857: if (DOINGSOFTDEP(vp)) {
858: softdep_setup_allocdirect(ip, NDADDR + indirs[0].in_off,
859: newb, 0, fs->fs_bsize, 0, bp);
860: bdwrite(bp);
861: } else {
862:
863: /*
864: * Write synchronously so that indirect blocks
865: * never point at garbage.
866: */
867:
868: if ((error = bwrite(bp)) != 0)
869: goto fail;
870: }
871: unwindidx = 0;
872: allocib = &ip->i_ffs2_ib[indirs[0].in_off];
873: *allocib = ufs_rw64(nb, needswap);
874: ip->i_flag |= IN_CHANGE | IN_UPDATE;
875: }
876:
877: /*
878: * Fetch through the indirect blocks, allocating as necessary.
879: */
880:
881: for (i = 1;;) {
882: error = bread(vp,
883: indirs[i].in_lbn, (int)fs->fs_bsize, NOCRED, &bp);
884: if (error) {
1.45.6.1 joerg 885: brelse(bp, 0);
1.33 fvdl 886: goto fail;
887: }
888: bap = (int64_t *)bp->b_data;
889: nb = ufs_rw64(bap[indirs[i].in_off], needswap);
890: if (i == num)
891: break;
892: i++;
893: if (nb != 0) {
1.45.6.1 joerg 894: brelse(bp, 0);
1.33 fvdl 895: continue;
896: }
1.45.6.1 joerg 897: mutex_enter(&ump->um_lock);
1.33 fvdl 898: if (pref == 0)
899: pref = ffs_blkpref_ufs2(ip, lbn, 0, (int64_t *)0);
900: error = ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize, cred,
901: &newb);
902: if (error) {
1.45.6.1 joerg 903: brelse(bp, 0);
1.33 fvdl 904: goto fail;
905: }
906: nb = newb;
907: *allocblk++ = nb;
908: nbp = getblk(vp, indirs[i].in_lbn, fs->fs_bsize, 0, 0);
909: nbp->b_blkno = fsbtodb(fs, nb);
910: clrbuf(nbp);
911: if (DOINGSOFTDEP(vp)) {
912: softdep_setup_allocindir_meta(nbp, ip, bp,
913: indirs[i - 1].in_off, nb);
914: bdwrite(nbp);
915: } else {
916:
917: /*
918: * Write synchronously so that indirect blocks
919: * never point at garbage.
920: */
921:
922: if ((error = bwrite(nbp)) != 0) {
1.45.6.1 joerg 923: brelse(bp, 0);
1.33 fvdl 924: goto fail;
925: }
926: }
927: if (unwindidx < 0)
928: unwindidx = i - 1;
929: bap[indirs[i - 1].in_off] = ufs_rw64(nb, needswap);
930:
931: /*
932: * If required, write synchronously, otherwise use
933: * delayed write.
934: */
935:
936: if (flags & B_SYNC) {
937: bwrite(bp);
938: } else {
939: bdwrite(bp);
940: }
941: }
942:
1.35 hannken 943: if (flags & B_METAONLY) {
1.41 hannken 944: KASSERT(bpp != NULL);
1.35 hannken 945: *bpp = bp;
946: return (0);
947: }
948:
1.33 fvdl 949: /*
950: * Get the data block, allocating if necessary.
951: */
952:
953: if (nb == 0) {
1.45.6.1 joerg 954: mutex_enter(&ump->um_lock);
1.33 fvdl 955: pref = ffs_blkpref_ufs2(ip, lbn, indirs[num].in_off, &bap[0]);
956: error = ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize, cred,
957: &newb);
958: if (error) {
1.45.6.1 joerg 959: brelse(bp, 0);
1.33 fvdl 960: goto fail;
961: }
962: nb = newb;
963: *allocblk++ = nb;
964: if (bpp != NULL) {
965: nbp = getblk(vp, lbn, fs->fs_bsize, 0, 0);
966: nbp->b_blkno = fsbtodb(fs, nb);
967: if (flags & B_CLRBUF)
968: clrbuf(nbp);
969: *bpp = nbp;
970: }
971: if (DOINGSOFTDEP(vp))
972: softdep_setup_allocindir_page(ip, lbn, bp,
973: indirs[num].in_off, nb, 0, bpp ? *bpp : NULL);
974: bap[indirs[num].in_off] = ufs_rw64(nb, needswap);
975: if (allocib == NULL && unwindidx < 0) {
976: unwindidx = i - 1;
977: }
978:
979: /*
980: * If required, write synchronously, otherwise use
981: * delayed write.
982: */
983:
984: if (flags & B_SYNC) {
985: bwrite(bp);
986: } else {
987: bdwrite(bp);
988: }
989: return (0);
990: }
1.45.6.1 joerg 991: brelse(bp, 0);
1.33 fvdl 992: if (bpp != NULL) {
993: if (flags & B_CLRBUF) {
994: error = bread(vp, lbn, (int)fs->fs_bsize, NOCRED, &nbp);
995: if (error) {
1.45.6.1 joerg 996: brelse(nbp, 0);
1.33 fvdl 997: goto fail;
998: }
999: } else {
1000: nbp = getblk(vp, lbn, fs->fs_bsize, 0, 0);
1001: nbp->b_blkno = fsbtodb(fs, nb);
1002: clrbuf(nbp);
1003: }
1004: *bpp = nbp;
1005: }
1006: return (0);
1007:
1008: fail:
1009: /*
1010: * If we have failed part way through block allocation, we
1011: * have to deallocate any indirect blocks that we have allocated.
1012: */
1013:
1014: if (unwindidx >= 0) {
1015:
1016: /*
1017: * First write out any buffers we've created to resolve their
1018: * softdeps. This must be done in reverse order of creation
1019: * so that we resolve the dependencies in one pass.
1020: * Write the cylinder group buffers for these buffers too.
1021: */
1022:
1023: for (i = num; i >= unwindidx; i--) {
1024: if (i == 0) {
1025: break;
1026: }
1027: bp = getblk(vp, indirs[i].in_lbn, (int)fs->fs_bsize, 0,
1028: 0);
1029: if (bp->b_flags & B_DELWRI) {
1030: nb = fsbtodb(fs, cgtod(fs, dtog(fs,
1031: dbtofsb(fs, bp->b_blkno))));
1032: bwrite(bp);
1033: bp = getblk(ip->i_devvp, nb, (int)fs->fs_cgsize,
1034: 0, 0);
1035: if (bp->b_flags & B_DELWRI) {
1036: bwrite(bp);
1037: } else {
1.45.6.1 joerg 1038: brelse(bp, BC_INVAL);
1.33 fvdl 1039: }
1040: } else {
1.45.6.1 joerg 1041: brelse(bp, BC_INVAL);
1.33 fvdl 1042: }
1043: }
1.45.6.2! jmcneill 1044:
! 1045: /* Now flush the dependencies to disk. */
! 1046: #ifdef notyet
! 1047: /* XXX pages locked */
! 1048: (void)softdep_sync_metadata(vp);
! 1049: #endif
! 1050:
1.36 mycroft 1051: if (DOINGSOFTDEP(vp) && unwindidx == 0) {
1052: ip->i_flag |= IN_CHANGE | IN_UPDATE;
1.39 yamt 1053: ffs_update(vp, NULL, NULL, UPDATE_WAIT);
1.33 fvdl 1054: }
1055:
1056: /*
1057: * Now that any dependencies that we created have been
1058: * resolved, we can undo the partial allocation.
1059: */
1060:
1061: if (unwindidx == 0) {
1062: *allocib = 0;
1.36 mycroft 1063: ip->i_flag |= IN_CHANGE | IN_UPDATE;
1064: if (DOINGSOFTDEP(vp))
1.39 yamt 1065: ffs_update(vp, NULL, NULL, UPDATE_WAIT);
1.33 fvdl 1066: } else {
1067: int r;
1068:
1069: r = bread(vp, indirs[unwindidx].in_lbn,
1070: (int)fs->fs_bsize, NOCRED, &bp);
1071: if (r) {
1072: panic("Could not unwind indirect block, error %d", r);
1.45.6.1 joerg 1073: brelse(bp, 0);
1.33 fvdl 1074: } else {
1075: bap = (int64_t *)bp->b_data;
1076: bap[indirs[unwindidx].in_off] = 0;
1077: bwrite(bp);
1078: }
1079: }
1080: for (i = unwindidx + 1; i <= num; i++) {
1081: bp = getblk(vp, indirs[i].in_lbn, (int)fs->fs_bsize, 0,
1082: 0);
1.45.6.1 joerg 1083: brelse(bp, BC_INVAL);
1.33 fvdl 1084: }
1085: }
1086: for (deallocated = 0, blkp = allociblk; blkp < allocblk; blkp++) {
1.35 hannken 1087: ffs_blkfree(fs, ip->i_devvp, *blkp, fs->fs_bsize, ip->i_number);
1.33 fvdl 1088: deallocated += fs->fs_bsize;
1089: }
1090: if (deallocated) {
1091: #ifdef QUOTA
1092: /*
1093: * Restore user's disk quota because allocation failed.
1094: */
1095: (void)chkdq(ip, -btodb(deallocated), cred, FORCE);
1.8 fvdl 1096: #endif
1.33 fvdl 1097: ip->i_ffs2_blocks -= btodb(deallocated);
1.13 mycroft 1098: ip->i_flag |= IN_CHANGE | IN_UPDATE;
1.8 fvdl 1099: }
1.45.6.2! jmcneill 1100:
! 1101: /*
! 1102: * Flush all dependencies again so that the soft updates code
! 1103: * doesn't find any untracked changes.
! 1104: */
! 1105: #ifdef notyet
! 1106: /* XXX pages locked */
! 1107: (void)softdep_sync_metadata(vp);
! 1108: #endif
1.8 fvdl 1109: return (error);
1.1 mycroft 1110: }
CVSweb <webmaster@jp.NetBSD.org>