Annotation of src/sys/ufs/ffs/ffs_inode.c, Revision 1.24.2.3
1.24.2.3! chs 1: /* $NetBSD: ffs_inode.c,v 1.24.2.2 1999/02/25 04:03:31 chs Exp $ */
1.5 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.18 fvdl 35: * @(#)ffs_inode.c 8.13 (Berkeley) 4/21/95
1.1 mycroft 36: */
1.17 mrg 37:
1.21 scottr 38: #if defined(_KERNEL) && !defined(_LKM)
1.20 scottr 39: #include "opt_quota.h"
1.17 mrg 40: #include "opt_uvm.h"
1.21 scottr 41: #endif
1.1 mycroft 42:
43: #include <sys/param.h>
44: #include <sys/systm.h>
45: #include <sys/mount.h>
46: #include <sys/proc.h>
47: #include <sys/file.h>
48: #include <sys/buf.h>
49: #include <sys/vnode.h>
50: #include <sys/kernel.h>
51: #include <sys/malloc.h>
52: #include <sys/trace.h>
53: #include <sys/resourcevar.h>
54:
55: #include <vm/vm.h>
56:
1.16 mrg 57: #if defined(UVM)
58: #include <uvm/uvm_extern.h>
59: #endif
60:
1.1 mycroft 61: #include <ufs/ufs/quota.h>
62: #include <ufs/ufs/inode.h>
63: #include <ufs/ufs/ufsmount.h>
64: #include <ufs/ufs/ufs_extern.h>
1.19 bouyer 65: #include <ufs/ufs/ufs_bswap.h>
1.1 mycroft 66:
67: #include <ufs/ffs/fs.h>
68: #include <ufs/ffs/ffs_extern.h>
69:
1.18 fvdl 70: static int ffs_indirtrunc __P((struct inode *, ufs_daddr_t, ufs_daddr_t,
71: ufs_daddr_t, int, long *));
1.1 mycroft 72:
73: /*
1.13 tls 74: * Update the access, modified, and inode change times as specified
75: * by the IN_ACCESS, IN_UPDATE, and IN_CHANGE flags respectively.
76: * The IN_MODIFIED flag is used to specify that the inode needs to be
77: * updated but that the times have already been set. The access
78: * and modified times are taken from the second and third parameters;
79: * the inode change time is always taken from the current time. If
80: * waitfor is set, then wait for the disk write of the inode to
1.1 mycroft 81: * complete.
82: */
1.13 tls 83:
1.1 mycroft 84: int
1.9 christos 85: ffs_update(v)
86: void *v;
87: {
1.1 mycroft 88: struct vop_update_args /* {
89: struct vnode *a_vp;
1.10 mycroft 90: struct timespec *a_access;
91: struct timespec *a_modify;
1.1 mycroft 92: int a_waitfor;
1.9 christos 93: } */ *ap = v;
1.1 mycroft 94: register struct fs *fs;
95: struct buf *bp;
96: struct inode *ip;
97: int error;
1.11 mycroft 98: struct timespec ts;
1.24 thorpej 99: caddr_t cp;
1.1 mycroft 100:
1.11 mycroft 101: if (ap->a_vp->v_mount->mnt_flag & MNT_RDONLY)
102: return (0);
1.1 mycroft 103: ip = VTOI(ap->a_vp);
1.11 mycroft 104: TIMEVAL_TO_TIMESPEC(&time, &ts);
1.14 bouyer 105: FFS_ITIMES(ip, ap->a_access, ap->a_modify, &ts);
1.11 mycroft 106: if ((ip->i_flag & IN_MODIFIED) == 0)
1.1 mycroft 107: return (0);
1.11 mycroft 108: ip->i_flag &= ~IN_MODIFIED;
1.1 mycroft 109: fs = ip->i_fs;
110: /*
111: * Ensure that uid and gid are correct. This is a temporary
112: * fix until fsck has been changed to do the update.
113: */
1.18 fvdl 114: if (fs->fs_inodefmt < FS_44INODEFMT) { /* XXX */
115: ip->i_din.ffs_din.di_ouid = ip->i_ffs_uid; /* XXX */
116: ip->i_din.ffs_din.di_ogid = ip->i_ffs_gid; /* XXX */
117: } /* XXX */
1.9 christos 118: error = bread(ip->i_devvp,
119: fsbtodb(fs, ino_to_fsba(fs, ip->i_number)),
120: (int)fs->fs_bsize, NOCRED, &bp);
121: if (error) {
1.1 mycroft 122: brelse(bp);
123: return (error);
124: }
1.24 thorpej 125: cp = (caddr_t)bp->b_data +
126: (ino_to_fsbo(fs, ip->i_number) * DINODE_SIZE);
1.23 christos 127: #ifdef FFS_EI
1.19 bouyer 128: if (UFS_MPNEEDSWAP(ap->a_vp->v_mount))
1.24 thorpej 129: ffs_dinode_swap(&ip->i_din.ffs_din, (struct dinode *)cp);
1.19 bouyer 130: else
1.23 christos 131: #endif
1.24 thorpej 132: memcpy(cp, &ip->i_din.ffs_din, DINODE_SIZE);
1.18 fvdl 133: if (ap->a_waitfor && (ap->a_vp->v_mount->mnt_flag & MNT_ASYNC) == 0)
1.1 mycroft 134: return (bwrite(bp));
135: else {
136: bdwrite(bp);
137: return (0);
138: }
139: }
140:
141: #define SINGLE 0 /* index of single indirect block */
142: #define DOUBLE 1 /* index of double indirect block */
143: #define TRIPLE 2 /* index of triple indirect block */
144: /*
145: * Truncate the inode oip to at most length size, freeing the
146: * disk blocks.
147: */
1.9 christos 148: int
149: ffs_truncate(v)
150: void *v;
151: {
1.1 mycroft 152: struct vop_truncate_args /* {
153: struct vnode *a_vp;
154: off_t a_length;
155: int a_flags;
156: struct ucred *a_cred;
157: struct proc *a_p;
1.9 christos 158: } */ *ap = v;
1.1 mycroft 159: register struct vnode *ovp = ap->a_vp;
1.18 fvdl 160: register ufs_daddr_t lastblock;
1.1 mycroft 161: register struct inode *oip;
1.18 fvdl 162: ufs_daddr_t bn, lbn, lastiblock[NIADDR], indir_lbn[NIADDR];
163: ufs_daddr_t oldblks[NDADDR + NIADDR], newblks[NDADDR + NIADDR];
1.1 mycroft 164: off_t length = ap->a_length;
165: register struct fs *fs;
166: struct buf *bp;
167: int offset, size, level;
168: long count, nblocks, vflags, blocksreleased = 0;
1.10 mycroft 169: struct timespec ts;
1.1 mycroft 170: register int i;
171: int aflags, error, allerror;
172: off_t osize;
173:
1.2 pk 174: if (length < 0)
1.3 mycroft 175: return (EINVAL);
1.1 mycroft 176: oip = VTOI(ovp);
1.10 mycroft 177: TIMEVAL_TO_TIMESPEC(&time, &ts);
1.1 mycroft 178: if (ovp->v_type == VLNK &&
1.14 bouyer 179: (oip->i_ffs_size < ovp->v_mount->mnt_maxsymlinklen ||
1.4 mycroft 180: (ovp->v_mount->mnt_maxsymlinklen == 0 &&
1.14 bouyer 181: oip->i_din.ffs_din.di_blocks == 0))) {
1.1 mycroft 182: #ifdef DIAGNOSTIC
183: if (length != 0)
184: panic("ffs_truncate: partial truncate of symlink");
185: #endif
1.22 perry 186: memset((char *)&oip->i_ffs_shortlink, 0, (u_int)oip->i_ffs_size);
1.14 bouyer 187: oip->i_ffs_size = 0;
1.1 mycroft 188: oip->i_flag |= IN_CHANGE | IN_UPDATE;
1.10 mycroft 189: return (VOP_UPDATE(ovp, &ts, &ts, 1));
1.1 mycroft 190: }
1.14 bouyer 191: if (oip->i_ffs_size == length) {
1.1 mycroft 192: oip->i_flag |= IN_CHANGE | IN_UPDATE;
1.10 mycroft 193: return (VOP_UPDATE(ovp, &ts, &ts, 0));
1.1 mycroft 194: }
195: #ifdef QUOTA
1.9 christos 196: if ((error = getinoquota(oip)) != 0)
1.1 mycroft 197: return (error);
198: #endif
199: fs = oip->i_fs;
1.14 bouyer 200: osize = oip->i_ffs_size;
1.18 fvdl 201: ovp->v_lasta = ovp->v_clen = ovp->v_cstart = ovp->v_lastw = 0;
1.1 mycroft 202: /*
203: * Lengthen the size of the file. We must ensure that the
204: * last byte of the file is allocated. Since the smallest
1.6 mycroft 205: * value of osize is 0, length will be at least 1.
1.1 mycroft 206: */
1.24.2.2 chs 207: /*
208: * XXXCHS why must the last byte of the file be allocated?
209: * this seems bogus.
210: */
1.1 mycroft 211: if (osize < length) {
1.6 mycroft 212: if (length > fs->fs_maxfilesize)
213: return (EFBIG);
1.24.2.2 chs 214: #ifdef UBC
215: aflags = 0;
216: bp = 0;
217: #else
1.1 mycroft 218: offset = blkoff(fs, length - 1);
219: lbn = lblkno(fs, length - 1);
220: aflags = B_CLRBUF;
221: if (ap->a_flags & IO_SYNC)
222: aflags |= B_SYNC;
1.24.2.2 chs 223: error = ffs_balloc(oip, lbn, offset + 1, ap->a_cred, &bp, NULL,
1.24.2.3! chs 224: aflags);
1.9 christos 225: if (error)
1.1 mycroft 226: return (error);
1.24.2.2 chs 227: #endif
1.14 bouyer 228: oip->i_ffs_size = length;
1.16 mrg 229: #if defined(UVM)
1.18 fvdl 230: uvm_vnp_setsize(ovp, length);
1.16 mrg 231: (void) uvm_vnp_uncache(ovp);
232: #else
1.18 fvdl 233: vnode_pager_setsize(ovp, length);
1.1 mycroft 234: (void) vnode_pager_uncache(ovp);
1.16 mrg 235: #endif
1.24.2.1 chs 236: #ifdef UBC
237: #else
1.1 mycroft 238: if (aflags & B_SYNC)
239: bwrite(bp);
240: else
241: bawrite(bp);
1.24.2.1 chs 242: #endif
1.1 mycroft 243: oip->i_flag |= IN_CHANGE | IN_UPDATE;
1.10 mycroft 244: return (VOP_UPDATE(ovp, &ts, &ts, 1));
1.1 mycroft 245: }
246: /*
247: * Shorten the size of the file. If the file is not being
248: * truncated to a block boundry, the contents of the
249: * partial block following the end of the file must be
250: * zero'ed in case it ever become accessable again because
251: * of subsequent file growth.
252: */
253: offset = blkoff(fs, length);
254: if (offset == 0) {
1.14 bouyer 255: oip->i_ffs_size = length;
1.1 mycroft 256: } else {
1.24.2.3! chs 257: lbn = lblkno(fs, length);
1.24.2.2 chs 258: #ifdef UBC
259: #else
1.1 mycroft 260: aflags = B_CLRBUF;
261: if (ap->a_flags & IO_SYNC)
262: aflags |= B_SYNC;
1.24.2.2 chs 263: error = ffs_balloc(oip, lbn, offset, ap->a_cred, &bp, NULL,
1.24.2.3! chs 264: aflags);
1.9 christos 265: if (error)
1.1 mycroft 266: return (error);
1.24.2.2 chs 267: #endif
1.14 bouyer 268: oip->i_ffs_size = length;
1.1 mycroft 269: size = blksize(fs, oip, lbn);
1.16 mrg 270: #if defined(UVM)
271: (void) uvm_vnp_uncache(ovp);
272: #else
1.1 mycroft 273: (void) vnode_pager_uncache(ovp);
1.16 mrg 274: #endif
1.24.2.2 chs 275: #ifdef UBC
276: uvm_vnp_zerorange(ovp, oip->i_ffs_size, size - offset);
277: #else
1.22 perry 278: memset((char *)bp->b_data + offset, 0, (u_int)(size - offset));
1.1 mycroft 279: allocbuf(bp, size);
280: if (aflags & B_SYNC)
281: bwrite(bp);
282: else
283: bawrite(bp);
1.24.2.2 chs 284: #endif
1.1 mycroft 285: }
1.18 fvdl 286: #if defined(UVM)
287: uvm_vnp_setsize(ovp, length);
288: #else
289: vnode_pager_setsize(ovp, length);
290: #endif
1.1 mycroft 291: /*
292: * Calculate index into inode's block list of
293: * last direct and indirect blocks (if any)
294: * which we want to keep. Lastblock is -1 when
295: * the file is truncated to 0.
296: */
297: lastblock = lblkno(fs, length + fs->fs_bsize - 1) - 1;
298: lastiblock[SINGLE] = lastblock - NDADDR;
299: lastiblock[DOUBLE] = lastiblock[SINGLE] - NINDIR(fs);
300: lastiblock[TRIPLE] = lastiblock[DOUBLE] - NINDIR(fs) * NINDIR(fs);
301: nblocks = btodb(fs->fs_bsize);
302: /*
303: * Update file and block pointers on disk before we start freeing
304: * blocks. If we crash before free'ing blocks below, the blocks
305: * will be returned to the free list. lastiblock values are also
306: * normalized to -1 for calls to ffs_indirtrunc below.
307: */
1.22 perry 308: memcpy((caddr_t)oldblks, (caddr_t)&oip->i_ffs_db[0], sizeof oldblks);
1.1 mycroft 309: for (level = TRIPLE; level >= SINGLE; level--)
310: if (lastiblock[level] < 0) {
1.14 bouyer 311: oip->i_ffs_ib[level] = 0;
1.1 mycroft 312: lastiblock[level] = -1;
313: }
314: for (i = NDADDR - 1; i > lastblock; i--)
1.14 bouyer 315: oip->i_ffs_db[i] = 0;
1.1 mycroft 316: oip->i_flag |= IN_CHANGE | IN_UPDATE;
1.10 mycroft 317: if ((error = VOP_UPDATE(ovp, &ts, &ts, 1)) != 0)
1.1 mycroft 318: allerror = error;
319: /*
320: * Having written the new inode to disk, save its new configuration
321: * and put back the old block pointers long enough to process them.
322: * Note that we save the new block configuration so we can check it
323: * when we are done.
324: */
1.22 perry 325: memcpy((caddr_t)newblks, (caddr_t)&oip->i_ffs_db[0], sizeof newblks);
326: memcpy((caddr_t)&oip->i_ffs_db[0], (caddr_t)oldblks, sizeof oldblks);
1.14 bouyer 327: oip->i_ffs_size = osize;
1.1 mycroft 328: vflags = ((length > 0) ? V_SAVE : 0) | V_SAVEMETA;
329: allerror = vinvalbuf(ovp, vflags, ap->a_cred, ap->a_p, 0, 0);
330:
331: /*
332: * Indirect blocks first.
333: */
334: indir_lbn[SINGLE] = -NDADDR;
335: indir_lbn[DOUBLE] = indir_lbn[SINGLE] - NINDIR(fs) - 1;
336: indir_lbn[TRIPLE] = indir_lbn[DOUBLE] - NINDIR(fs) * NINDIR(fs) - 1;
337: for (level = TRIPLE; level >= SINGLE; level--) {
1.19 bouyer 338: bn = ufs_rw32(oip->i_ffs_ib[level], UFS_MPNEEDSWAP(ovp->v_mount));
1.1 mycroft 339: if (bn != 0) {
340: error = ffs_indirtrunc(oip, indir_lbn[level],
341: fsbtodb(fs, bn), lastiblock[level], level, &count);
342: if (error)
343: allerror = error;
344: blocksreleased += count;
345: if (lastiblock[level] < 0) {
1.14 bouyer 346: oip->i_ffs_ib[level] = 0;
1.1 mycroft 347: ffs_blkfree(oip, bn, fs->fs_bsize);
348: blocksreleased += nblocks;
349: }
350: }
351: if (lastiblock[level] >= 0)
352: goto done;
353: }
354:
355: /*
356: * All whole direct blocks or frags.
357: */
358: for (i = NDADDR - 1; i > lastblock; i--) {
359: register long bsize;
360:
1.19 bouyer 361: bn = ufs_rw32(oip->i_ffs_db[i], UFS_MPNEEDSWAP(ovp->v_mount));
1.1 mycroft 362: if (bn == 0)
363: continue;
1.14 bouyer 364: oip->i_ffs_db[i] = 0;
1.1 mycroft 365: bsize = blksize(fs, oip, i);
366: ffs_blkfree(oip, bn, bsize);
367: blocksreleased += btodb(bsize);
368: }
369: if (lastblock < 0)
370: goto done;
371:
372: /*
373: * Finally, look for a change in size of the
374: * last direct block; release any frags.
375: */
1.19 bouyer 376: bn = ufs_rw32(oip->i_ffs_db[lastblock], UFS_MPNEEDSWAP(ovp->v_mount));
1.1 mycroft 377: if (bn != 0) {
378: long oldspace, newspace;
379:
380: /*
381: * Calculate amount of space we're giving
382: * back as old block size minus new block size.
383: */
384: oldspace = blksize(fs, oip, lastblock);
1.14 bouyer 385: oip->i_ffs_size = length;
1.1 mycroft 386: newspace = blksize(fs, oip, lastblock);
387: if (newspace == 0)
388: panic("itrunc: newspace");
389: if (oldspace - newspace > 0) {
390: /*
391: * Block number of space to be free'd is
392: * the old block # plus the number of frags
393: * required for the storage we're keeping.
394: */
395: bn += numfrags(fs, newspace);
396: ffs_blkfree(oip, bn, oldspace - newspace);
397: blocksreleased += btodb(oldspace - newspace);
398: }
399: }
400: done:
401: #ifdef DIAGNOSTIC
402: for (level = SINGLE; level <= TRIPLE; level++)
1.14 bouyer 403: if (newblks[NDADDR + level] != oip->i_ffs_ib[level])
1.1 mycroft 404: panic("itrunc1");
405: for (i = 0; i < NDADDR; i++)
1.14 bouyer 406: if (newblks[i] != oip->i_ffs_db[i])
1.1 mycroft 407: panic("itrunc2");
408: if (length == 0 &&
409: (ovp->v_dirtyblkhd.lh_first || ovp->v_cleanblkhd.lh_first))
410: panic("itrunc3");
411: #endif /* DIAGNOSTIC */
412: /*
413: * Put back the real size.
414: */
1.14 bouyer 415: oip->i_ffs_size = length;
416: oip->i_ffs_blocks -= blocksreleased;
417: if (oip->i_ffs_blocks < 0) /* sanity */
418: oip->i_ffs_blocks = 0;
1.1 mycroft 419: oip->i_flag |= IN_CHANGE;
420: #ifdef QUOTA
421: (void) chkdq(oip, -blocksreleased, NOCRED, 0);
422: #endif
423: return (allerror);
424: }
425:
426: /*
427: * Release blocks associated with the inode ip and stored in the indirect
428: * block bn. Blocks are free'd in LIFO order up to (but not including)
429: * lastbn. If level is greater than SINGLE, the block is an indirect block
430: * and recursive calls to indirtrunc must be used to cleanse other indirect
431: * blocks.
432: *
433: * NB: triple indirect blocks are untested.
434: */
435: static int
436: ffs_indirtrunc(ip, lbn, dbn, lastbn, level, countp)
437: register struct inode *ip;
1.18 fvdl 438: ufs_daddr_t lbn, lastbn;
439: ufs_daddr_t dbn;
1.1 mycroft 440: int level;
441: long *countp;
442: {
443: register int i;
444: struct buf *bp;
445: register struct fs *fs = ip->i_fs;
1.18 fvdl 446: register ufs_daddr_t *bap;
1.1 mycroft 447: struct vnode *vp;
1.18 fvdl 448: ufs_daddr_t *copy = NULL, nb, nlbn, last;
1.1 mycroft 449: long blkcount, factor;
450: int nblocks, blocksreleased = 0;
451: int error = 0, allerror = 0;
452:
453: /*
454: * Calculate index in current block of last
455: * block to be kept. -1 indicates the entire
456: * block so we need not calculate the index.
457: */
458: factor = 1;
459: for (i = SINGLE; i < level; i++)
460: factor *= NINDIR(fs);
461: last = lastbn;
462: if (lastbn > 0)
463: last /= factor;
464: nblocks = btodb(fs->fs_bsize);
465: /*
466: * Get buffer of block pointers, zero those entries corresponding
467: * to blocks to be free'd, and update on disk copy first. Since
468: * double(triple) indirect before single(double) indirect, calls
469: * to bmap on these blocks will fail. However, we already have
470: * the on disk address, so we have to set the b_blkno field
471: * explicitly instead of letting bread do everything for us.
472: */
473: vp = ITOV(ip);
474: bp = getblk(vp, lbn, (int)fs->fs_bsize, 0, 0);
475: if (bp->b_flags & (B_DONE | B_DELWRI)) {
476: /* Braces must be here in case trace evaluates to nothing. */
477: trace(TR_BREADHIT, pack(vp, fs->fs_bsize), lbn);
478: } else {
479: trace(TR_BREADMISS, pack(vp, fs->fs_bsize), lbn);
480: curproc->p_stats->p_ru.ru_inblock++; /* pay for read */
481: bp->b_flags |= B_READ;
482: if (bp->b_bcount > bp->b_bufsize)
483: panic("ffs_indirtrunc: bad buffer size");
484: bp->b_blkno = dbn;
485: VOP_STRATEGY(bp);
486: error = biowait(bp);
487: }
488: if (error) {
489: brelse(bp);
490: *countp = 0;
491: return (error);
492: }
493:
1.18 fvdl 494: bap = (ufs_daddr_t *)bp->b_data;
1.12 thorpej 495: if (lastbn != -1) {
1.18 fvdl 496: MALLOC(copy, ufs_daddr_t *, fs->fs_bsize, M_TEMP, M_WAITOK);
1.22 perry 497: memcpy((caddr_t)copy, (caddr_t)bap, (u_int)fs->fs_bsize);
498: memset((caddr_t)&bap[last + 1], 0,
1.18 fvdl 499: (u_int)(NINDIR(fs) - (last + 1)) * sizeof (ufs_daddr_t));
1.12 thorpej 500: error = bwrite(bp);
501: if (error)
502: allerror = error;
503: bap = copy;
504: }
1.1 mycroft 505:
506: /*
507: * Recursively free totally unused blocks.
508: */
509: for (i = NINDIR(fs) - 1, nlbn = lbn + 1 - i * factor; i > last;
510: i--, nlbn += factor) {
1.19 bouyer 511: nb = ufs_rw32(bap[i], UFS_MPNEEDSWAP(vp->v_mount));
1.1 mycroft 512: if (nb == 0)
513: continue;
514: if (level > SINGLE) {
1.9 christos 515: error = ffs_indirtrunc(ip, nlbn, fsbtodb(fs, nb),
1.18 fvdl 516: (ufs_daddr_t)-1, level - 1,
1.9 christos 517: &blkcount);
518: if (error)
1.1 mycroft 519: allerror = error;
520: blocksreleased += blkcount;
521: }
522: ffs_blkfree(ip, nb, fs->fs_bsize);
523: blocksreleased += nblocks;
524: }
525:
526: /*
527: * Recursively free last partial block.
528: */
529: if (level > SINGLE && lastbn >= 0) {
530: last = lastbn % factor;
1.19 bouyer 531: nb = ufs_rw32(bap[i], UFS_MPNEEDSWAP(vp->v_mount));
1.1 mycroft 532: if (nb != 0) {
1.9 christos 533: error = ffs_indirtrunc(ip, nlbn, fsbtodb(fs, nb),
534: last, level - 1, &blkcount);
535: if (error)
1.1 mycroft 536: allerror = error;
537: blocksreleased += blkcount;
538: }
539: }
1.12 thorpej 540:
541: if (copy != NULL) {
542: FREE(copy, M_TEMP);
543: } else {
544: bp->b_flags |= B_INVAL;
545: brelse(bp);
546: }
547:
1.1 mycroft 548: *countp = blocksreleased;
549: return (allerror);
550: }
CVSweb <webmaster@jp.NetBSD.org>