Annotation of src/sys/ufs/ffs/ffs_balloc.c, Revision 1.23.2.4
1.23.2.4! nathanw 1: /* $NetBSD: ffs_balloc.c,v 1.23.2.3 2001/08/24 00:13:16 nathanw Exp $ */
1.2 cgd 2:
1.1 mycroft 3: /*
4: * Copyright (c) 1982, 1986, 1989, 1993
5: * The Regents of the University of California. All rights reserved.
6: *
7: * Redistribution and use in source and binary forms, with or without
8: * modification, are permitted provided that the following conditions
9: * are met:
10: * 1. Redistributions of source code must retain the above copyright
11: * notice, this list of conditions and the following disclaimer.
12: * 2. Redistributions in binary form must reproduce the above copyright
13: * notice, this list of conditions and the following disclaimer in the
14: * documentation and/or other materials provided with the distribution.
15: * 3. All advertising materials mentioning features or use of this software
16: * must display the following acknowledgement:
17: * This product includes software developed by the University of
18: * California, Berkeley and its contributors.
19: * 4. Neither the name of the University nor the names of its contributors
20: * may be used to endorse or promote products derived from this software
21: * without specific prior written permission.
22: *
23: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33: * SUCH DAMAGE.
34: *
1.8 fvdl 35: * @(#)ffs_balloc.c 8.8 (Berkeley) 6/16/95
1.1 mycroft 36: */
1.7 mrg 37:
1.23.2.2 nathanw 38: #if defined(_KERNEL_OPT)
1.10 scottr 39: #include "opt_quota.h"
1.11 scottr 40: #endif
1.1 mycroft 41:
42: #include <sys/param.h>
43: #include <sys/systm.h>
44: #include <sys/buf.h>
1.23.2.1 nathanw 45: #include <sys/lwp.h>
1.1 mycroft 46: #include <sys/proc.h>
47: #include <sys/file.h>
1.15 fvdl 48: #include <sys/mount.h>
1.1 mycroft 49: #include <sys/vnode.h>
1.9 bouyer 50: #include <sys/mount.h>
1.6 mrg 51:
1.1 mycroft 52: #include <ufs/ufs/quota.h>
1.9 bouyer 53: #include <ufs/ufs/ufsmount.h>
1.1 mycroft 54: #include <ufs/ufs/inode.h>
55: #include <ufs/ufs/ufs_extern.h>
1.9 bouyer 56: #include <ufs/ufs/ufs_bswap.h>
1.1 mycroft 57:
58: #include <ufs/ffs/fs.h>
59: #include <ufs/ffs/ffs_extern.h>
60:
1.23 chs 61: #include <uvm/uvm.h>
62:
1.1 mycroft 63: /*
64: * Balloc defines the structure of file system storage
65: * by allocating the physical blocks on a device given
66: * the inode and the logical block number in a file.
67: */
1.3 christos 68: int
1.15 fvdl 69: ffs_balloc(v)
70: void *v;
71: {
72: struct vop_balloc_args /* {
73: struct vnode *a_vp;
1.23.2.3 nathanw 74: off_t a_startoffset;
1.15 fvdl 75: int a_size;
76: struct ucred *a_cred;
77: int a_flags;
1.23 chs 78: struct buf **a_bpp;
1.15 fvdl 79: } */ *ap = v;
80: ufs_daddr_t lbn;
1.1 mycroft 81: int size;
82: struct ucred *cred;
83: int flags;
1.15 fvdl 84: ufs_daddr_t nb;
1.1 mycroft 85: struct buf *bp, *nbp;
1.15 fvdl 86: struct vnode *vp = ap->a_vp;
87: struct inode *ip = VTOI(vp);
88: struct fs *fs = ip->i_fs;
1.1 mycroft 89: struct indir indirs[NIADDR + 2];
1.8 fvdl 90: ufs_daddr_t newb, *bap, pref;
91: int deallocated, osize, nsize, num, i, error;
92: ufs_daddr_t *allocib, *blkp, *allocblk, allociblk[NIADDR + 1];
1.17 fvdl 93: int unwindidx = -1;
1.23 chs 94: struct buf **bpp = ap->a_bpp;
1.15 fvdl 95: #ifdef FFS_EI
96: const int needswap = UFS_FSNEEDSWAP(fs);
97: #endif
1.23 chs 98: UVMHIST_FUNC("ffs_balloc"); UVMHIST_CALLED(ubchist);
1.1 mycroft 99:
1.15 fvdl 100: lbn = lblkno(fs, ap->a_startoffset);
101: size = blkoff(fs, ap->a_startoffset) + ap->a_size;
102: if (size > fs->fs_bsize)
103: panic("ffs_balloc: blk too big");
1.23 chs 104: if (bpp != NULL) {
105: *bpp = NULL;
106: }
107: UVMHIST_LOG(ubchist, "vp %p lbn 0x%x size 0x%x", vp, lbn, size,0);
108:
109: KASSERT(size <= fs->fs_bsize);
1.8 fvdl 110: if (lbn < 0)
1.1 mycroft 111: return (EFBIG);
1.15 fvdl 112: cred = ap->a_cred;
113: flags = ap->a_flags;
1.1 mycroft 114:
115: /*
116: * If the next write will extend the file into a new block,
117: * and the file is currently composed of a fragment
118: * this fragment has to be extended to be a full block.
119: */
1.23 chs 120:
1.4 bouyer 121: nb = lblkno(fs, ip->i_ffs_size);
1.8 fvdl 122: if (nb < NDADDR && nb < lbn) {
1.1 mycroft 123: osize = blksize(fs, ip, nb);
124: if (osize < fs->fs_bsize && osize > 0) {
125: error = ffs_realloccg(ip, nb,
1.4 bouyer 126: ffs_blkpref(ip, nb, (int)nb, &ip->i_ffs_db[0]),
1.23 chs 127: osize, (int)fs->fs_bsize, cred, bpp, &newb);
1.1 mycroft 128: if (error)
129: return (error);
1.15 fvdl 130: if (DOINGSOFTDEP(vp))
1.23 chs 131: softdep_setup_allocdirect(ip, nb, newb,
1.15 fvdl 132: ufs_rw32(ip->i_ffs_db[nb], needswap),
1.23 chs 133: fs->fs_bsize, osize, bpp ? *bpp : NULL);
134: ip->i_ffs_size = lblktosize(fs, nb + 1);
1.6 mrg 135: uvm_vnp_setsize(vp, ip->i_ffs_size);
1.23 chs 136: ip->i_ffs_db[nb] = ufs_rw32(newb, needswap);
1.1 mycroft 137: ip->i_flag |= IN_CHANGE | IN_UPDATE;
1.23 chs 138: if (bpp) {
139: if (flags & B_SYNC)
140: bwrite(*bpp);
141: else
142: bawrite(*bpp);
143: }
1.1 mycroft 144: }
145: }
1.23 chs 146:
1.1 mycroft 147: /*
148: * The first NDADDR blocks are direct blocks
149: */
1.23 chs 150:
1.8 fvdl 151: if (lbn < NDADDR) {
1.15 fvdl 152: nb = ufs_rw32(ip->i_ffs_db[lbn], needswap);
1.23 chs 153: if (nb != 0 && ip->i_ffs_size >= lblktosize(fs, lbn + 1)) {
154:
155: /*
156: * The block is an already-allocated direct block
157: * and the file already extends past this block,
158: * thus this must be a whole block.
159: * Just read the block (if requested).
160: */
161:
162: if (bpp != NULL) {
163: error = bread(vp, lbn, fs->fs_bsize, NOCRED,
164: bpp);
165: if (error) {
166: brelse(*bpp);
167: return (error);
168: }
1.1 mycroft 169: }
170: return (0);
171: }
172: if (nb != 0) {
1.23 chs 173:
1.1 mycroft 174: /*
175: * Consider need to reallocate a fragment.
176: */
1.23 chs 177:
1.4 bouyer 178: osize = fragroundup(fs, blkoff(fs, ip->i_ffs_size));
1.1 mycroft 179: nsize = fragroundup(fs, size);
180: if (nsize <= osize) {
1.23 chs 181:
182: /*
183: * The existing block is already
184: * at least as big as we want.
185: * Just read the block (if requested).
186: */
187:
188: if (bpp != NULL) {
189: error = bread(vp, lbn, osize, NOCRED,
190: bpp);
191: if (error) {
192: brelse(*bpp);
193: return (error);
194: }
1.1 mycroft 195: }
1.23 chs 196: return 0;
1.1 mycroft 197: } else {
1.23 chs 198:
199: /*
200: * The existing block is smaller than we want,
201: * grow it.
202: */
203:
1.8 fvdl 204: error = ffs_realloccg(ip, lbn,
205: ffs_blkpref(ip, lbn, (int)lbn,
206: &ip->i_ffs_db[0]), osize, nsize, cred,
1.23 chs 207: bpp, &newb);
1.1 mycroft 208: if (error)
209: return (error);
1.15 fvdl 210: if (DOINGSOFTDEP(vp))
211: softdep_setup_allocdirect(ip, lbn,
1.23 chs 212: newb, nb, nsize, osize,
213: bpp ? *bpp : NULL);
1.1 mycroft 214: }
215: } else {
1.23 chs 216:
217: /*
218: * the block was not previously allocated,
219: * allocate a new block or fragment.
220: */
221:
222: if (ip->i_ffs_size < lblktosize(fs, lbn + 1))
1.1 mycroft 223: nsize = fragroundup(fs, size);
224: else
225: nsize = fs->fs_bsize;
1.8 fvdl 226: error = ffs_alloc(ip, lbn,
227: ffs_blkpref(ip, lbn, (int)lbn, &ip->i_ffs_db[0]),
228: nsize, cred, &newb);
1.1 mycroft 229: if (error)
230: return (error);
1.23 chs 231: if (bpp != NULL) {
232: bp = getblk(vp, lbn, nsize, 0, 0);
233: bp->b_blkno = fsbtodb(fs, newb);
234: if (flags & B_CLRBUF)
235: clrbuf(bp);
236: *bpp = bp;
237: }
238: if (DOINGSOFTDEP(vp)) {
1.15 fvdl 239: softdep_setup_allocdirect(ip, lbn, newb, 0,
1.23 chs 240: nsize, 0, bpp ? *bpp : NULL);
241: }
1.1 mycroft 242: }
1.23 chs 243: ip->i_ffs_db[lbn] = ufs_rw32(newb, needswap);
1.1 mycroft 244: ip->i_flag |= IN_CHANGE | IN_UPDATE;
245: return (0);
246: }
247: /*
248: * Determine the number of levels of indirection.
249: */
250: pref = 0;
1.8 fvdl 251: if ((error = ufs_getlbns(vp, lbn, indirs, &num)) != 0)
1.1 mycroft 252: return(error);
1.23 chs 253:
1.1 mycroft 254: #ifdef DIAGNOSTIC
255: if (num < 1)
256: panic ("ffs_balloc: ufs_bmaparray returned indirect block\n");
257: #endif
258: /*
259: * Fetch the first indirect block allocating if necessary.
260: */
261: --num;
1.15 fvdl 262: nb = ufs_rw32(ip->i_ffs_ib[indirs[0].in_off], needswap);
1.8 fvdl 263: allocib = NULL;
264: allocblk = allociblk;
1.1 mycroft 265: if (nb == 0) {
1.8 fvdl 266: pref = ffs_blkpref(ip, lbn, 0, (ufs_daddr_t *)0);
1.18 mycroft 267: error = ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize, cred,
268: &newb);
1.3 christos 269: if (error)
1.1 mycroft 270: return (error);
271: nb = newb;
1.8 fvdl 272: *allocblk++ = nb;
1.1 mycroft 273: bp = getblk(vp, indirs[1].in_lbn, fs->fs_bsize, 0, 0);
1.8 fvdl 274: bp->b_blkno = fsbtodb(fs, nb);
1.1 mycroft 275: clrbuf(bp);
1.15 fvdl 276: if (DOINGSOFTDEP(vp)) {
277: softdep_setup_allocdirect(ip, NDADDR + indirs[0].in_off,
278: newb, 0, fs->fs_bsize, 0, bp);
279: bdwrite(bp);
280: } else {
281: /*
282: * Write synchronously so that indirect blocks
283: * never point at garbage.
284: */
285: if ((error = bwrite(bp)) != 0)
286: goto fail;
287: }
1.18 mycroft 288: unwindidx = 0;
1.8 fvdl 289: allocib = &ip->i_ffs_ib[indirs[0].in_off];
1.15 fvdl 290: *allocib = ufs_rw32(nb, needswap);
1.1 mycroft 291: ip->i_flag |= IN_CHANGE | IN_UPDATE;
292: }
293: /*
294: * Fetch through the indirect blocks, allocating as necessary.
295: */
296: for (i = 1;;) {
297: error = bread(vp,
298: indirs[i].in_lbn, (int)fs->fs_bsize, NOCRED, &bp);
299: if (error) {
300: brelse(bp);
1.8 fvdl 301: goto fail;
1.1 mycroft 302: }
1.8 fvdl 303: bap = (ufs_daddr_t *)bp->b_data;
1.15 fvdl 304: nb = ufs_rw32(bap[indirs[i].in_off], needswap);
1.1 mycroft 305: if (i == num)
306: break;
1.18 mycroft 307: i++;
1.1 mycroft 308: if (nb != 0) {
309: brelse(bp);
310: continue;
311: }
312: if (pref == 0)
1.8 fvdl 313: pref = ffs_blkpref(ip, lbn, 0, (ufs_daddr_t *)0);
1.3 christos 314: error = ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize, cred,
1.18 mycroft 315: &newb);
1.3 christos 316: if (error) {
1.1 mycroft 317: brelse(bp);
1.8 fvdl 318: goto fail;
1.1 mycroft 319: }
320: nb = newb;
1.8 fvdl 321: *allocblk++ = nb;
1.1 mycroft 322: nbp = getblk(vp, indirs[i].in_lbn, fs->fs_bsize, 0, 0);
323: nbp->b_blkno = fsbtodb(fs, nb);
324: clrbuf(nbp);
1.15 fvdl 325: if (DOINGSOFTDEP(vp)) {
326: softdep_setup_allocindir_meta(nbp, ip, bp,
327: indirs[i - 1].in_off, nb);
328: bdwrite(nbp);
329: } else {
330: /*
331: * Write synchronously so that indirect blocks
332: * never point at garbage.
333: */
334: if ((error = bwrite(nbp)) != 0) {
335: brelse(bp);
336: goto fail;
337: }
1.1 mycroft 338: }
1.18 mycroft 339: if (unwindidx < 0)
340: unwindidx = i - 1;
1.15 fvdl 341: bap[indirs[i - 1].in_off] = ufs_rw32(nb, needswap);
1.1 mycroft 342: /*
343: * If required, write synchronously, otherwise use
344: * delayed write.
345: */
346: if (flags & B_SYNC) {
347: bwrite(bp);
348: } else {
349: bdwrite(bp);
350: }
351: }
352: /*
353: * Get the data block, allocating if necessary.
354: */
355: if (nb == 0) {
1.19 mycroft 356: pref = ffs_blkpref(ip, lbn, indirs[num].in_off, &bap[0]);
1.3 christos 357: error = ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize, cred,
1.18 mycroft 358: &newb);
1.3 christos 359: if (error) {
1.1 mycroft 360: brelse(bp);
1.8 fvdl 361: goto fail;
1.1 mycroft 362: }
363: nb = newb;
1.8 fvdl 364: *allocblk++ = nb;
1.23 chs 365: if (bpp != NULL) {
366: nbp = getblk(vp, lbn, fs->fs_bsize, 0, 0);
367: nbp->b_blkno = fsbtodb(fs, nb);
368: if (flags & B_CLRBUF)
369: clrbuf(nbp);
370: *bpp = nbp;
371: }
1.15 fvdl 372: if (DOINGSOFTDEP(vp))
373: softdep_setup_allocindir_page(ip, lbn, bp,
1.23 chs 374: indirs[num].in_off, nb, 0, bpp ? *bpp : NULL);
1.19 mycroft 375: bap[indirs[num].in_off] = ufs_rw32(nb, needswap);
1.23 chs 376: if (allocib == NULL && unwindidx < 0) {
377: unwindidx = i - 1;
378: }
1.1 mycroft 379: /*
380: * If required, write synchronously, otherwise use
381: * delayed write.
382: */
383: if (flags & B_SYNC) {
384: bwrite(bp);
385: } else {
386: bdwrite(bp);
387: }
388: return (0);
389: }
390: brelse(bp);
1.23 chs 391: if (bpp != NULL) {
392: if (flags & B_CLRBUF) {
393: error = bread(vp, lbn, (int)fs->fs_bsize, NOCRED, &nbp);
394: if (error) {
395: brelse(nbp);
396: goto fail;
397: }
398: } else {
399: nbp = getblk(vp, lbn, fs->fs_bsize, 0, 0);
400: nbp->b_blkno = fsbtodb(fs, nb);
401: clrbuf(nbp);
1.1 mycroft 402: }
1.23 chs 403: *bpp = nbp;
1.1 mycroft 404: }
405: return (0);
1.8 fvdl 406: fail:
407: /*
408: * If we have failed part way through block allocation, we
409: * have to deallocate any indirect blocks that we have allocated.
1.16 fvdl 410: * We have to fsync the file before we start to get rid of all
411: * of its dependencies so that we do not leave them dangling.
412: * We have to sync it at the end so that the soft updates code
413: * does not find any untracked changes. Although this is really
414: * slow, running out of disk space is not expected to be a common
415: * occurence. The error return from fsync is ignored as we already
416: * have an error to return to the user.
1.8 fvdl 417: */
1.23.2.1 nathanw 418: (void) VOP_FSYNC(vp, cred, FSYNC_WAIT, 0, 0, curproc->l_proc);
1.8 fvdl 419: for (deallocated = 0, blkp = allociblk; blkp < allocblk; blkp++) {
420: ffs_blkfree(ip, *blkp, fs->fs_bsize);
421: deallocated += fs->fs_bsize;
422: }
1.18 mycroft 423: if (unwindidx >= 0) {
424: if (unwindidx == 0) {
425: *allocib = 0;
1.17 fvdl 426: } else {
1.18 mycroft 427: int r;
428:
429: r = bread(vp, indirs[unwindidx].in_lbn,
430: (int)fs->fs_bsize, NOCRED, &bp);
431: if (r) {
432: panic("Could not unwind indirect block, error %d", r);
433: brelse(bp);
434: } else {
435: bap = (ufs_daddr_t *)bp->b_data;
436: bap[indirs[unwindidx].in_off] = 0;
437: if (flags & B_SYNC)
438: bwrite(bp);
439: else
440: bdwrite(bp);
441: }
1.17 fvdl 442: }
1.19 mycroft 443: for (i = unwindidx + 1; i <= num; i++) {
444: bp = getblk(vp, indirs[i].in_lbn, (int)fs->fs_bsize, 0,
445: 0);
446: bp->b_flags |= B_INVAL;
447: brelse(bp);
448: }
1.17 fvdl 449: }
1.8 fvdl 450: if (deallocated) {
451: #ifdef QUOTA
452: /*
453: * Restore user's disk quota because allocation failed.
454: */
455: (void)chkdq(ip, (long)-btodb(deallocated), cred, FORCE);
456: #endif
457: ip->i_ffs_blocks -= btodb(deallocated);
1.13 mycroft 458: ip->i_flag |= IN_CHANGE | IN_UPDATE;
1.8 fvdl 459: }
1.23.2.1 nathanw 460: (void) VOP_FSYNC(vp, cred, FSYNC_WAIT, 0, 0, curproc->l_proc);
1.8 fvdl 461: return (error);
1.23 chs 462: }
463:
464:
465: int
1.23.2.4! nathanw 466: ffs_gop_alloc(struct vnode *vp, off_t off, off_t len, int flags,
! 467: struct ucred *cred)
1.23 chs 468: {
469: struct inode *ip = VTOI(vp);
470: struct fs *fs = ip->i_fs;
471: int error, delta, bshift, bsize;
1.23.2.4! nathanw 472: UVMHIST_FUNC("ffs_gop_alloc"); UVMHIST_CALLED(ubchist);
1.23 chs 473:
474: error = 0;
475: bshift = fs->fs_bshift;
476: bsize = 1 << bshift;
477:
478: delta = off & (bsize - 1);
479: off -= delta;
480: len += delta;
481:
482: while (len > 0) {
1.23.2.4! nathanw 483: bsize = MIN(bsize, len);
1.23 chs 484:
1.23.2.4! nathanw 485: error = VOP_BALLOC(vp, off, bsize, cred, flags, NULL);
1.23 chs 486: if (error) {
487: goto out;
488: }
489:
490: /*
491: * increase file size now, VOP_BALLOC() requires that
492: * EOF be up-to-date before each call.
493: */
494:
495: if (ip->i_ffs_size < off + bsize) {
1.23.2.4! nathanw 496: UVMHIST_LOG(ubchist, "vp %p old 0x%x new 0x%x",
! 497: vp, ip->i_ffs_size, off + bsize, 0);
1.23 chs 498: ip->i_ffs_size = off + bsize;
499: }
500:
501: off += bsize;
502: len -= bsize;
503: }
504:
505: out:
506: return error;
1.1 mycroft 507: }
CVSweb <webmaster@jp.NetBSD.org>