1 /* $NetBSD: lfs_inode.c,v 1.57 2002/05/14 20:03:54 perseant Exp $ */ 2 3 /*- 4 * Copyright (c) 1999, 2000 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Konrad E. Schroder <perseant@hhhh.org>. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by the NetBSD 21 * Foundation, Inc. and its contributors. 22 * 4. Neither the name of The NetBSD Foundation nor the names of its 23 * contributors may be used to endorse or promote products derived 24 * from this software without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 36 * POSSIBILITY OF SUCH DAMAGE. 37 */ 38 /* 39 * Copyright (c) 1986, 1989, 1991, 1993 40 * The Regents of the University of California. All rights reserved. 41 * 42 * Redistribution and use in source and binary forms, with or without 43 * modification, are permitted provided that the following conditions 44 * are met: 45 * 1. Redistributions of source code must retain the above copyright 46 * notice, this list of conditions and the following disclaimer. 47 * 2. Redistributions in binary form must reproduce the above copyright 48 * notice, this list of conditions and the following disclaimer in the 49 * documentation and/or other materials provided with the distribution. 50 * 3. All advertising materials mentioning features or use of this software 51 * must display the following acknowledgement: 52 * This product includes software developed by the University of 53 * California, Berkeley and its contributors. 54 * 4. Neither the name of the University nor the names of its contributors 55 * may be used to endorse or promote products derived from this software 56 * without specific prior written permission. 57 * 58 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 59 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 60 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 61 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 62 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 63 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 64 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 65 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 66 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 67 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 68 * SUCH DAMAGE. 69 * 70 * @(#)lfs_inode.c 8.9 (Berkeley) 5/8/95 71 */ 72 73 #include <sys/cdefs.h> 74 __KERNEL_RCSID(0, "$NetBSD: lfs_inode.c,v 1.57 2002/05/14 20:03:54 perseant Exp $"); 75 76 #if defined(_KERNEL_OPT) 77 #include "opt_quota.h" 78 #endif 79 80 #include <sys/param.h> 81 #include <sys/systm.h> 82 #include <sys/mount.h> 83 #include <sys/proc.h> 84 #include <sys/file.h> 85 #include <sys/buf.h> 86 #include <sys/vnode.h> 87 #include <sys/kernel.h> 88 #include <sys/malloc.h> 89 #include <sys/trace.h> 90 #include <sys/resourcevar.h> 91 92 #include <ufs/ufs/quota.h> 93 #include <ufs/ufs/inode.h> 94 #include <ufs/ufs/ufsmount.h> 95 #include <ufs/ufs/ufs_extern.h> 96 97 #include <ufs/lfs/lfs.h> 98 #include <ufs/lfs/lfs_extern.h> 99 100 extern int locked_queue_count; 101 extern long locked_queue_bytes; 102 103 static int lfs_update_seguse(struct lfs *, long, size_t); 104 static int lfs_indirtrunc (struct inode *, ufs_daddr_t, ufs_daddr_t, 105 ufs_daddr_t, int, long *, long *, long *, size_t *, 106 struct proc *); 107 static int lfs_blkfree (struct lfs *, daddr_t, size_t, long *, size_t *); 108 static int lfs_vtruncbuf(struct vnode *, daddr_t, int, int); 109 110 /* Search a block for a specific dinode. */ 111 struct dinode * 112 lfs_ifind(struct lfs *fs, ino_t ino, struct buf *bp) 113 { 114 struct dinode *dip = (struct dinode *)bp->b_data; 115 struct dinode *ldip, *fin; 116 117 #ifdef LFS_IFILE_FRAG_ADDRESSING 118 if (fs->lfs_version == 1) 119 fin = dip + INOPB(fs); 120 else 121 fin = dip + INOPF(fs); 122 #else 123 fin = dip + INOPB(fs); 124 #endif 125 126 /* 127 * XXX we used to go from the top down here, presumably with the 128 * idea that the same inode could be written twice in the same 129 * block (which is not supposed to be true). 130 */ 131 for (ldip = dip; ldip < fin; ++ldip) 132 if (ldip->di_inumber == ino) 133 return (ldip); 134 135 printf("searched %d entries\n", (int)(fin - dip)); 136 printf("offset is 0x%x (seg %d)\n", fs->lfs_offset, 137 dtosn(fs, fs->lfs_offset)); 138 printf("block is 0x%x (seg %d)\n", dbtofsb(fs, bp->b_blkno), 139 dtosn(fs, dbtofsb(fs, bp->b_blkno))); 140 141 return NULL; 142 } 143 144 int 145 lfs_update(void *v) 146 { 147 struct vop_update_args /* { 148 struct vnode *a_vp; 149 struct timespec *a_access; 150 struct timespec *a_modify; 151 int a_flags; 152 } */ *ap = v; 153 struct inode *ip; 154 struct vnode *vp = ap->a_vp; 155 struct timespec ts; 156 struct lfs *fs = VFSTOUFS(vp->v_mount)->um_lfs; 157 int s; 158 159 if (vp->v_mount->mnt_flag & MNT_RDONLY) 160 return (0); 161 ip = VTOI(vp); 162 163 /* 164 * If we are called from vinvalbuf, and the file's blocks have 165 * already been scheduled for writing, but the writes have not 166 * yet completed, lfs_vflush will not be called, and vinvalbuf 167 * will cause a panic. So, we must wait until any pending write 168 * for our inode completes, if we are called with UPDATE_WAIT set. 169 */ 170 s = splbio(); 171 while ((ap->a_flags & (UPDATE_WAIT|UPDATE_DIROP)) == UPDATE_WAIT && 172 WRITEINPROG(vp)) { 173 #ifdef DEBUG_LFS 174 printf("lfs_update: sleeping on inode %d (in-progress)\n", 175 ip->i_number); 176 #endif 177 tsleep(vp, (PRIBIO+1), "lfs_update", 0); 178 } 179 splx(s); 180 TIMEVAL_TO_TIMESPEC(&time, &ts); 181 LFS_ITIMES(ip, 182 ap->a_access ? ap->a_access : &ts, 183 ap->a_modify ? ap->a_modify : &ts, &ts); 184 if ((ip->i_flag & (IN_MODIFIED | IN_ACCESSED | IN_CLEANING)) == 0) { 185 return (0); 186 } 187 188 /* If sync, push back the vnode and any dirty blocks it may have. */ 189 if ((ap->a_flags & (UPDATE_WAIT|UPDATE_DIROP)) == UPDATE_WAIT) { 190 /* Avoid flushing VDIROP. */ 191 ++fs->lfs_diropwait; 192 while (vp->v_flag & VDIROP) { 193 #ifdef DEBUG_LFS 194 printf("lfs_update: sleeping on inode %d (dirops)\n", 195 ip->i_number); 196 printf("lfs_update: vflags 0x%lx, iflags 0x%x\n", 197 vp->v_flag, ip->i_flag); 198 #endif 199 if (fs->lfs_dirops == 0) 200 lfs_flush_fs(fs, SEGM_SYNC); 201 else 202 tsleep(&fs->lfs_writer, PRIBIO+1, "lfs_fsync", 203 0); 204 /* XXX KS - by falling out here, are we writing the vn 205 twice? */ 206 } 207 --fs->lfs_diropwait; 208 return lfs_vflush(vp); 209 } 210 return 0; 211 } 212 213 #define SINGLE 0 /* index of single indirect block */ 214 #define DOUBLE 1 /* index of double indirect block */ 215 #define TRIPLE 2 /* index of triple indirect block */ 216 /* 217 * Truncate the inode oip to at most length size, freeing the 218 * disk blocks. 219 */ 220 /* VOP_BWRITE 1 + NIADDR + VOP_BALLOC == 2 + 2*NIADDR times */ 221 int 222 lfs_truncate(void *v) 223 { 224 struct vop_truncate_args /* { 225 struct vnode *a_vp; 226 off_t a_length; 227 int a_flags; 228 struct ucred *a_cred; 229 struct proc *a_p; 230 } */ *ap = v; 231 struct vnode *ovp = ap->a_vp; 232 ufs_daddr_t lastblock; 233 struct inode *oip; 234 ufs_daddr_t bn, lbn, lastiblock[NIADDR], indir_lbn[NIADDR]; 235 ufs_daddr_t newblks[NDADDR + NIADDR]; 236 off_t length = ap->a_length; 237 struct lfs *fs; 238 struct buf *bp; 239 int offset, size, level; 240 long count, rcount, nblocks, blocksreleased = 0, real_released = 0; 241 int i; 242 int aflags, error, allerror = 0; 243 off_t osize; 244 long lastseg; 245 size_t bc; 246 int obufsize, odb; 247 248 if (length < 0) 249 return (EINVAL); 250 oip = VTOI(ovp); 251 252 /* 253 * Just return and not update modification times. 254 */ 255 if (oip->i_ffs_size == length) 256 return (0); 257 258 if (ovp->v_type == VLNK && 259 (oip->i_ffs_size < ovp->v_mount->mnt_maxsymlinklen || 260 (ovp->v_mount->mnt_maxsymlinklen == 0 && 261 oip->i_din.ffs_din.di_blocks == 0))) { 262 #ifdef DIAGNOSTIC 263 if (length != 0) 264 panic("lfs_truncate: partial truncate of symlink"); 265 #endif 266 memset((char *)&oip->i_ffs_shortlink, 0, (u_int)oip->i_ffs_size); 267 oip->i_ffs_size = 0; 268 oip->i_flag |= IN_CHANGE | IN_UPDATE; 269 return (VOP_UPDATE(ovp, NULL, NULL, 0)); 270 } 271 if (oip->i_ffs_size == length) { 272 oip->i_flag |= IN_CHANGE | IN_UPDATE; 273 return (VOP_UPDATE(ovp, NULL, NULL, 0)); 274 } 275 #ifdef QUOTA 276 if ((error = getinoquota(oip)) != 0) 277 return (error); 278 #endif 279 fs = oip->i_lfs; 280 lfs_imtime(fs); 281 osize = oip->i_ffs_size; 282 283 /* 284 * Lengthen the size of the file. We must ensure that the 285 * last byte of the file is allocated. Since the smallest 286 * value of osize is 0, length will be at least 1. 287 */ 288 if (osize < length) { 289 if (length > fs->lfs_maxfilesize) 290 return (EFBIG); 291 aflags = B_CLRBUF; 292 if (ap->a_flags & IO_SYNC) 293 aflags |= B_SYNC; 294 error = lfs_reserve(fs, ovp, btofsb(fs, (NIADDR + 2) << fs->lfs_bshift)); 295 if (error) 296 return (error); 297 error = VOP_BALLOC(ovp, length - 1, 1, ap->a_cred, aflags, &bp); 298 lfs_reserve(fs, ovp, -btofsb(fs, (NIADDR + 2) << fs->lfs_bshift)); 299 if (error) 300 return (error); 301 oip->i_ffs_size = length; 302 uvm_vnp_setsize(ovp, length); 303 (void) VOP_BWRITE(bp); 304 oip->i_flag |= IN_CHANGE | IN_UPDATE; 305 return (VOP_UPDATE(ovp, NULL, NULL, 0)); 306 } 307 308 if ((error = lfs_reserve(fs, ovp, btofsb(fs, (2 * NIADDR + 3) << fs->lfs_bshift))) != 0) 309 return (error); 310 /* 311 * Make sure no writes to this inode can happen while we're 312 * truncating. Otherwise, blocks which are accounted for on the 313 * inode *and* which have been created for cleaning can coexist, 314 * and cause an overcounting. 315 * 316 * (We don't need to *hold* the seglock, though, because we already 317 * hold the inode lock; draining the seglock is sufficient.) 318 */ 319 #ifdef LFS_AGGRESSIVE_SEGLOCK 320 lfs_seglock(fs, SEGM_PROT); 321 #else 322 if (ovp != fs->lfs_unlockvp) { 323 while (fs->lfs_seglock) { 324 tsleep(&fs->lfs_seglock, PRIBIO+1, "lfs_truncate", 0); 325 } 326 } 327 #endif 328 329 /* 330 * Shorten the size of the file. If the file is not being 331 * truncated to a block boundary, the contents of the 332 * partial block following the end of the file must be 333 * zero'ed in case it ever becomes accessible again because 334 * of subsequent file growth. Directories however are not 335 * zero'ed as they should grow back initialized to empty. 336 */ 337 offset = blkoff(fs, length); 338 lastseg = -1; 339 bc = 0; 340 if (offset == 0) { 341 oip->i_ffs_size = length; 342 } else { 343 lbn = lblkno(fs, length); 344 aflags = B_CLRBUF; 345 if (ap->a_flags & IO_SYNC) 346 aflags |= B_SYNC; 347 error = VOP_BALLOC(ovp, length - 1, 1, ap->a_cred, aflags, &bp); 348 if (error) { 349 lfs_reserve(fs, ovp, -btofsb(fs, (2 * NIADDR + 3) << fs->lfs_bshift)); 350 #ifdef LFS_AGGRESSIVE_SEGLOCK 351 lfs_segunlock(fs); 352 #endif 353 return (error); 354 } 355 obufsize = bp->b_bufsize; 356 odb = btofsb(fs, bp->b_bcount); 357 oip->i_ffs_size = length; 358 size = blksize(fs, oip, lbn); 359 if (ovp->v_type != VDIR) 360 memset((char *)bp->b_data + offset, 0, 361 (u_int)(size - offset)); 362 allocbuf(bp, size); 363 if ((bp->b_flags & (B_LOCKED | B_CALL)) == B_LOCKED) 364 locked_queue_bytes -= obufsize - bp->b_bufsize; 365 if (bp->b_flags & B_DELWRI) 366 fs->lfs_avail += odb - btofsb(fs, size); 367 (void) VOP_BWRITE(bp); 368 } 369 uvm_vnp_setsize(ovp, length); 370 /* 371 * Calculate index into inode's block list of 372 * last direct and indirect blocks (if any) 373 * which we want to keep. Lastblock is -1 when 374 * the file is truncated to 0. 375 */ 376 lastblock = lblkno(fs, length + fs->lfs_bsize - 1) - 1; 377 lastiblock[SINGLE] = lastblock - NDADDR; 378 lastiblock[DOUBLE] = lastiblock[SINGLE] - NINDIR(fs); 379 lastiblock[TRIPLE] = lastiblock[DOUBLE] - NINDIR(fs) * NINDIR(fs); 380 nblocks = btofsb(fs, fs->lfs_bsize); 381 /* 382 * Record changed file and block pointers before we start 383 * freeing blocks. lastiblock values are also normalized to -1 384 * for calls to lfs_indirtrunc below. 385 */ 386 memcpy((caddr_t)newblks, (caddr_t)&oip->i_ffs_db[0], sizeof newblks); 387 for (level = TRIPLE; level >= SINGLE; level--) 388 if (lastiblock[level] < 0) { 389 newblks[NDADDR+level] = 0; 390 lastiblock[level] = -1; 391 } 392 for (i = NDADDR - 1; i > lastblock; i--) 393 newblks[i] = 0; 394 395 oip->i_ffs_size = osize; 396 error = lfs_vtruncbuf(ovp, lastblock + 1, 0, 0); 397 if (error && !allerror) 398 allerror = error; 399 400 /* 401 * Indirect blocks first. 402 */ 403 indir_lbn[SINGLE] = -NDADDR; 404 indir_lbn[DOUBLE] = indir_lbn[SINGLE] - NINDIR(fs) - 1; 405 indir_lbn[TRIPLE] = indir_lbn[DOUBLE] - NINDIR(fs) * NINDIR(fs) - 1; 406 for (level = TRIPLE; level >= SINGLE; level--) { 407 bn = oip->i_ffs_ib[level]; 408 if (bn != 0) { 409 error = lfs_indirtrunc(oip, indir_lbn[level], 410 bn, lastiblock[level], 411 level, &count, &rcount, 412 &lastseg, &bc, ap->a_p); 413 if (error) 414 allerror = error; 415 real_released += rcount; 416 blocksreleased += count; 417 if (lastiblock[level] < 0) { 418 if (oip->i_ffs_ib[level] > 0) 419 real_released += nblocks; 420 blocksreleased += nblocks; 421 oip->i_ffs_ib[level] = 0; 422 lfs_blkfree(fs, bn, fs->lfs_bsize, &lastseg, &bc); 423 } 424 } 425 if (lastiblock[level] >= 0) 426 goto done; 427 } 428 429 /* 430 * All whole direct blocks or frags. 431 */ 432 for (i = NDADDR - 1; i > lastblock; i--) { 433 long bsize; 434 435 bn = oip->i_ffs_db[i]; 436 if (bn == 0) 437 continue; 438 bsize = blksize(fs, oip, i); 439 if (oip->i_ffs_db[i] > 0) 440 real_released += btofsb(fs, bsize); 441 blocksreleased += btofsb(fs, bsize); 442 oip->i_ffs_db[i] = 0; 443 lfs_blkfree(fs, bn, bsize, &lastseg, &bc); 444 } 445 if (lastblock < 0) 446 goto done; 447 448 /* 449 * Finally, look for a change in size of the 450 * last direct block; release any frags. 451 */ 452 bn = oip->i_ffs_db[lastblock]; 453 if (bn != 0) { 454 long oldspace, newspace; 455 456 /* 457 * Calculate amount of space we're giving 458 * back as old block size minus new block size. 459 */ 460 oldspace = blksize(fs, oip, lastblock); 461 oip->i_ffs_size = length; 462 newspace = blksize(fs, oip, lastblock); 463 if (newspace == 0) 464 panic("itrunc: newspace"); 465 if (oldspace - newspace > 0) { 466 lfs_blkfree(fs, bn, oldspace - newspace, &lastseg, &bc); 467 if (bn > 0) 468 real_released += btofsb(fs, oldspace - newspace); 469 blocksreleased += btofsb(fs, oldspace - newspace); 470 } 471 } 472 473 done: 474 /* Finish segment accounting corrections */ 475 lfs_update_seguse(fs, lastseg, bc); 476 #ifdef DIAGNOSTIC 477 for (level = SINGLE; level <= TRIPLE; level++) 478 if (newblks[NDADDR + level] != oip->i_ffs_ib[level]) 479 panic("lfs itrunc1"); 480 for (i = 0; i < NDADDR; i++) 481 if (newblks[i] != oip->i_ffs_db[i]) 482 panic("lfs itrunc2"); 483 if (length == 0 && 484 (!LIST_EMPTY(&ovp->v_cleanblkhd) || !LIST_EMPTY(&ovp->v_dirtyblkhd))) 485 panic("lfs itrunc3"); 486 #endif /* DIAGNOSTIC */ 487 /* 488 * Put back the real size. 489 */ 490 oip->i_ffs_size = length; 491 oip->i_lfs_effnblks -= blocksreleased; 492 oip->i_ffs_blocks -= real_released; 493 fs->lfs_bfree += blocksreleased; 494 #ifdef DIAGNOSTIC 495 if (oip->i_ffs_size == 0 && oip->i_ffs_blocks != 0) { 496 printf("lfs_truncate: truncate to 0 but %d blocks on inode\n", 497 oip->i_ffs_blocks); 498 panic("lfs_truncate: persistent blocks\n"); 499 } 500 #endif 501 oip->i_flag |= IN_CHANGE; 502 #ifdef QUOTA 503 (void) chkdq(oip, -blocksreleased, NOCRED, 0); 504 #endif 505 lfs_reserve(fs, ovp, -btofsb(fs, (2 * NIADDR + 3) << fs->lfs_bshift)); 506 #ifdef LFS_AGGRESSIVE_SEGLOCK 507 lfs_segunlock(fs); 508 #endif 509 return (allerror); 510 } 511 512 /* Update segment usage information when removing a block. */ 513 static int 514 lfs_blkfree(struct lfs *fs, daddr_t daddr, size_t bsize, long *lastseg, 515 size_t *num) 516 { 517 long seg; 518 int error = 0; 519 520 bsize = fragroundup(fs, bsize); 521 if (daddr > 0) { 522 if (*lastseg != (seg = dtosn(fs, daddr))) { 523 error = lfs_update_seguse(fs, *lastseg, *num); 524 *num = bsize; 525 *lastseg = seg; 526 } else 527 *num += bsize; 528 } 529 return error; 530 } 531 532 /* Finish the accounting updates for a segment. */ 533 static int 534 lfs_update_seguse(struct lfs *fs, long lastseg, size_t num) 535 { 536 SEGUSE *sup; 537 struct buf *bp; 538 int error; 539 540 if (lastseg < 0 || num == 0) 541 return 0; 542 543 LFS_SEGENTRY(sup, fs, lastseg, bp); 544 if (num > sup->su_nbytes) { 545 printf("lfs_truncate: segment %ld short by %ld\n", 546 lastseg, (long)num - sup->su_nbytes); 547 panic("lfs_truncate: negative bytes"); 548 sup->su_nbytes = num; 549 } 550 sup->su_nbytes -= num; 551 error = LFS_BWRITE_LOG(bp); /* Ifile */ 552 return error; 553 } 554 555 /* 556 * Release blocks associated with the inode ip and stored in the indirect 557 * block bn. Blocks are free'd in LIFO order up to (but not including) 558 * lastbn. If level is greater than SINGLE, the block is an indirect block 559 * and recursive calls to indirtrunc must be used to cleanse other indirect 560 * blocks. 561 * 562 * NB: triple indirect blocks are untested. 563 */ 564 static int 565 lfs_indirtrunc(struct inode *ip, ufs_daddr_t lbn, daddr_t dbn, 566 ufs_daddr_t lastbn, int level, long *countp, 567 long *rcountp, long *lastsegp, size_t *bcp, struct proc *p) 568 { 569 int i; 570 struct buf *bp; 571 struct lfs *fs = ip->i_lfs; 572 ufs_daddr_t *bap; 573 struct vnode *vp; 574 ufs_daddr_t *copy = NULL, nb, nlbn, last; 575 long blkcount, rblkcount, factor; 576 int nblocks, blocksreleased = 0, real_released = 0; 577 int error = 0, allerror = 0; 578 579 /* 580 * Calculate index in current block of last 581 * block to be kept. -1 indicates the entire 582 * block so we need not calculate the index. 583 */ 584 factor = 1; 585 for (i = SINGLE; i < level; i++) 586 factor *= NINDIR(fs); 587 last = lastbn; 588 if (lastbn > 0) 589 last /= factor; 590 nblocks = btofsb(fs, fs->lfs_bsize); 591 /* 592 * Get buffer of block pointers, zero those entries corresponding 593 * to blocks to be free'd, and update on disk copy first. Since 594 * double(triple) indirect before single(double) indirect, calls 595 * to bmap on these blocks will fail. However, we already have 596 * the on disk address, so we have to set the b_blkno field 597 * explicitly instead of letting bread do everything for us. 598 */ 599 vp = ITOV(ip); 600 bp = getblk(vp, lbn, (int)fs->lfs_bsize, 0, 0); 601 if (bp->b_flags & (B_DONE | B_DELWRI)) { 602 /* Braces must be here in case trace evaluates to nothing. */ 603 trace(TR_BREADHIT, pack(vp, fs->lfs_bsize), lbn); 604 } else { 605 trace(TR_BREADMISS, pack(vp, fs->lfs_bsize), lbn); 606 p->p_stats->p_ru.ru_inblock++; /* pay for read */ 607 bp->b_flags |= B_READ; 608 if (bp->b_bcount > bp->b_bufsize) 609 panic("lfs_indirtrunc: bad buffer size"); 610 bp->b_blkno = fsbtodb(fs, dbn); 611 VOP_STRATEGY(bp); 612 error = biowait(bp); 613 } 614 if (error) { 615 brelse(bp); 616 *countp = *rcountp = 0; 617 return (error); 618 } 619 620 bap = (ufs_daddr_t *)bp->b_data; 621 if (lastbn >= 0) { 622 MALLOC(copy, ufs_daddr_t *, fs->lfs_bsize, M_TEMP, M_WAITOK); 623 memcpy((caddr_t)copy, (caddr_t)bap, (u_int)fs->lfs_bsize); 624 memset((caddr_t)&bap[last + 1], 0, 625 (u_int)(NINDIR(fs) - (last + 1)) * sizeof (ufs_daddr_t)); 626 error = VOP_BWRITE(bp); 627 if (error) 628 allerror = error; 629 bap = copy; 630 } 631 632 /* 633 * Recursively free totally unused blocks. 634 */ 635 for (i = NINDIR(fs) - 1, nlbn = lbn + 1 - i * factor; i > last; 636 i--, nlbn += factor) { 637 nb = bap[i]; 638 if (nb == 0) 639 continue; 640 if (level > SINGLE) { 641 error = lfs_indirtrunc(ip, nlbn, nb, 642 (ufs_daddr_t)-1, level - 1, 643 &blkcount, &rblkcount, 644 lastsegp, bcp, p); 645 if (error) 646 allerror = error; 647 blocksreleased += blkcount; 648 real_released += rblkcount; 649 } 650 lfs_blkfree(fs, nb, fs->lfs_bsize, lastsegp, bcp); 651 if (bap[i] > 0) 652 real_released += nblocks; 653 blocksreleased += nblocks; 654 } 655 656 /* 657 * Recursively free last partial block. 658 */ 659 if (level > SINGLE && lastbn >= 0) { 660 last = lastbn % factor; 661 nb = bap[i]; 662 if (nb != 0) { 663 error = lfs_indirtrunc(ip, nlbn, nb, 664 last, level - 1, &blkcount, 665 &rblkcount, lastsegp, bcp, p); 666 if (error) 667 allerror = error; 668 real_released += rblkcount; 669 blocksreleased += blkcount; 670 } 671 } 672 673 if (copy != NULL) { 674 FREE(copy, M_TEMP); 675 } else { 676 if (bp->b_flags & B_DELWRI) { 677 LFS_UNLOCK_BUF(bp); 678 fs->lfs_avail += btofsb(fs, bp->b_bcount); 679 wakeup(&fs->lfs_avail); 680 } 681 bp->b_flags |= B_INVAL; 682 brelse(bp); 683 } 684 685 *countp = blocksreleased; 686 *rcountp = real_released; 687 return (allerror); 688 } 689 690 /* 691 * Destroy any in core blocks past the truncation length. 692 * Inlined from vtruncbuf, so that lfs_avail could be updated. 693 */ 694 static int 695 lfs_vtruncbuf(struct vnode *vp, daddr_t lbn, int slpflag, int slptimeo) 696 { 697 struct buf *bp, *nbp; 698 int s, error; 699 struct lfs *fs; 700 701 fs = VTOI(vp)->i_lfs; 702 s = splbio(); 703 704 restart: 705 for (bp = LIST_FIRST(&vp->v_cleanblkhd); bp; bp = nbp) { 706 nbp = LIST_NEXT(bp, b_vnbufs); 707 if (bp->b_lblkno < lbn) 708 continue; 709 if (bp->b_flags & B_BUSY) { 710 bp->b_flags |= B_WANTED; 711 error = tsleep((caddr_t)bp, slpflag | (PRIBIO + 1), 712 "lfs_vtruncbuf", slptimeo); 713 if (error) { 714 splx(s); 715 return (error); 716 } 717 goto restart; 718 } 719 bp->b_flags |= B_BUSY | B_INVAL | B_VFLUSH; 720 if (bp->b_flags & B_DELWRI) { 721 bp->b_flags &= ~B_DELWRI; 722 fs->lfs_avail += btofsb(fs, bp->b_bcount); 723 wakeup(&fs->lfs_avail); 724 } 725 LFS_UNLOCK_BUF(bp); 726 brelse(bp); 727 } 728 729 for (bp = LIST_FIRST(&vp->v_dirtyblkhd); bp; bp = nbp) { 730 nbp = LIST_NEXT(bp, b_vnbufs); 731 if (bp->b_lblkno < lbn) 732 continue; 733 if (bp->b_flags & B_BUSY) { 734 bp->b_flags |= B_WANTED; 735 error = tsleep((caddr_t)bp, slpflag | (PRIBIO + 1), 736 "lfs_vtruncbuf", slptimeo); 737 if (error) { 738 splx(s); 739 return (error); 740 } 741 goto restart; 742 } 743 bp->b_flags |= B_BUSY | B_INVAL | B_VFLUSH; 744 if (bp->b_flags & B_DELWRI) { 745 bp->b_flags &= ~B_DELWRI; 746 fs->lfs_avail += btofsb(fs, bp->b_bcount); 747 wakeup(&fs->lfs_avail); 748 } 749 LFS_UNLOCK_BUF(bp); 750 brelse(bp); 751 } 752 753 splx(s); 754 755 return (0); 756 } 757 758