1 /* $NetBSD: lfs_inode.c,v 1.60 2002/09/27 15:38:05 provos 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.60 2002/09/27 15:38:05 provos 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 * Read the inode block backwards, since later versions of the 128 * inode will supercede earlier ones. Though it is unlikely, it is 129 * possible that the same inode will appear in the same inode block. 130 */ 131 for (ldip = fin - 1; ldip >= dip; --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%x, 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 222 int 223 lfs_truncate(void *v) 224 { 225 struct vop_truncate_args /* { 226 struct vnode *a_vp; 227 off_t a_length; 228 int a_flags; 229 struct ucred *a_cred; 230 struct proc *a_p; 231 } */ *ap = v; 232 struct vnode *ovp = ap->a_vp; 233 ufs_daddr_t lastblock; 234 struct inode *oip; 235 ufs_daddr_t bn, lbn, lastiblock[NIADDR], indir_lbn[NIADDR]; 236 ufs_daddr_t newblks[NDADDR + NIADDR]; 237 off_t length = ap->a_length; 238 struct lfs *fs; 239 struct buf *bp; 240 int offset, size, level; 241 long count, rcount, nblocks, blocksreleased = 0, real_released = 0; 242 int i; 243 int aflags, error, allerror = 0; 244 off_t osize; 245 long lastseg; 246 size_t bc; 247 int obufsize, odb; 248 249 if (length < 0) 250 return (EINVAL); 251 oip = VTOI(ovp); 252 253 /* 254 * Just return and not update modification times. 255 */ 256 if (oip->i_ffs_size == length) 257 return (0); 258 259 if (ovp->v_type == VLNK && 260 (oip->i_ffs_size < ovp->v_mount->mnt_maxsymlinklen || 261 (ovp->v_mount->mnt_maxsymlinklen == 0 && 262 oip->i_din.ffs_din.di_blocks == 0))) { 263 #ifdef DIAGNOSTIC 264 if (length != 0) 265 panic("lfs_truncate: partial truncate of symlink"); 266 #endif 267 memset((char *)&oip->i_ffs_shortlink, 0, (u_int)oip->i_ffs_size); 268 oip->i_ffs_size = 0; 269 oip->i_flag |= IN_CHANGE | IN_UPDATE; 270 return (VOP_UPDATE(ovp, NULL, NULL, 0)); 271 } 272 if (oip->i_ffs_size == length) { 273 oip->i_flag |= IN_CHANGE | IN_UPDATE; 274 return (VOP_UPDATE(ovp, NULL, NULL, 0)); 275 } 276 #ifdef QUOTA 277 if ((error = getinoquota(oip)) != 0) 278 return (error); 279 #endif 280 fs = oip->i_lfs; 281 lfs_imtime(fs); 282 osize = oip->i_ffs_size; 283 284 /* 285 * Lengthen the size of the file. We must ensure that the 286 * last byte of the file is allocated. Since the smallest 287 * value of osize is 0, length will be at least 1. 288 */ 289 if (osize < length) { 290 if (length > fs->lfs_maxfilesize) 291 return (EFBIG); 292 aflags = B_CLRBUF; 293 if (ap->a_flags & IO_SYNC) 294 aflags |= B_SYNC; 295 error = lfs_reserve(fs, ovp, btofsb(fs, (NIADDR + 2) << fs->lfs_bshift)); 296 if (error) 297 return (error); 298 error = VOP_BALLOC(ovp, length - 1, 1, ap->a_cred, aflags, &bp); 299 lfs_reserve(fs, ovp, -btofsb(fs, (NIADDR + 2) << fs->lfs_bshift)); 300 if (error) 301 return (error); 302 oip->i_ffs_size = length; 303 uvm_vnp_setsize(ovp, length); 304 (void) VOP_BWRITE(bp); 305 oip->i_flag |= IN_CHANGE | IN_UPDATE; 306 return (VOP_UPDATE(ovp, NULL, NULL, 0)); 307 } 308 309 if ((error = lfs_reserve(fs, ovp, btofsb(fs, (2 * NIADDR + 3) << fs->lfs_bshift))) != 0) 310 return (error); 311 /* 312 * Make sure no writes to this inode can happen while we're 313 * truncating. Otherwise, blocks which are accounted for on the 314 * inode *and* which have been created for cleaning can coexist, 315 * and cause an overcounting. 316 */ 317 #ifdef LFS_FRAGSIZE_SEGLOCK 318 lfs_seglock(fs, SEGM_PROT); 319 #else 320 lockmgr(&fs->lfs_fraglock, LK_SHARED, 0); 321 #endif 322 323 /* 324 * Shorten the size of the file. If the file is not being 325 * truncated to a block boundary, the contents of the 326 * partial block following the end of the file must be 327 * zero'ed in case it ever becomes accessible again because 328 * of subsequent file growth. Directories however are not 329 * zero'ed as they should grow back initialized to empty. 330 */ 331 offset = blkoff(fs, length); 332 lastseg = -1; 333 bc = 0; 334 if (offset == 0) { 335 oip->i_ffs_size = length; 336 } else { 337 lbn = lblkno(fs, length); 338 aflags = B_CLRBUF; 339 if (ap->a_flags & IO_SYNC) 340 aflags |= B_SYNC; 341 error = VOP_BALLOC(ovp, length - 1, 1, ap->a_cred, aflags, &bp); 342 if (error) { 343 lfs_reserve(fs, ovp, -btofsb(fs, (2 * NIADDR + 3) << fs->lfs_bshift)); 344 #ifdef LFS_FRAGSIZE_SEGLOCK 345 lfs_segunlock(fs); 346 #else 347 lockmgr(&fs->lfs_fraglock, LK_RELEASE, 0); 348 #endif 349 return (error); 350 } 351 obufsize = bp->b_bufsize; 352 odb = btofsb(fs, bp->b_bcount); 353 oip->i_ffs_size = length; 354 size = blksize(fs, oip, lbn); 355 if (ovp->v_type != VDIR) 356 memset((char *)bp->b_data + offset, 0, 357 (u_int)(size - offset)); 358 allocbuf(bp, size); 359 if ((bp->b_flags & (B_LOCKED | B_CALL)) == B_LOCKED) 360 locked_queue_bytes -= obufsize - bp->b_bufsize; 361 if (bp->b_flags & B_DELWRI) 362 fs->lfs_avail += odb - btofsb(fs, size); 363 (void) VOP_BWRITE(bp); 364 } 365 uvm_vnp_setsize(ovp, length); 366 /* 367 * Calculate index into inode's block list of 368 * last direct and indirect blocks (if any) 369 * which we want to keep. Lastblock is -1 when 370 * the file is truncated to 0. 371 */ 372 lastblock = lblkno(fs, length + fs->lfs_bsize - 1) - 1; 373 lastiblock[SINGLE] = lastblock - NDADDR; 374 lastiblock[DOUBLE] = lastiblock[SINGLE] - NINDIR(fs); 375 lastiblock[TRIPLE] = lastiblock[DOUBLE] - NINDIR(fs) * NINDIR(fs); 376 nblocks = btofsb(fs, fs->lfs_bsize); 377 /* 378 * Record changed file and block pointers before we start 379 * freeing blocks. lastiblock values are also normalized to -1 380 * for calls to lfs_indirtrunc below. 381 */ 382 memcpy((caddr_t)newblks, (caddr_t)&oip->i_ffs_db[0], sizeof newblks); 383 for (level = TRIPLE; level >= SINGLE; level--) 384 if (lastiblock[level] < 0) { 385 newblks[NDADDR+level] = 0; 386 lastiblock[level] = -1; 387 } 388 for (i = NDADDR - 1; i > lastblock; i--) 389 newblks[i] = 0; 390 391 oip->i_ffs_size = osize; 392 error = lfs_vtruncbuf(ovp, lastblock + 1, 0, 0); 393 if (error && !allerror) 394 allerror = error; 395 396 /* 397 * Indirect blocks first. 398 */ 399 indir_lbn[SINGLE] = -NDADDR; 400 indir_lbn[DOUBLE] = indir_lbn[SINGLE] - NINDIR(fs) - 1; 401 indir_lbn[TRIPLE] = indir_lbn[DOUBLE] - NINDIR(fs) * NINDIR(fs) - 1; 402 for (level = TRIPLE; level >= SINGLE; level--) { 403 bn = oip->i_ffs_ib[level]; 404 if (bn != 0) { 405 error = lfs_indirtrunc(oip, indir_lbn[level], 406 bn, lastiblock[level], 407 level, &count, &rcount, 408 &lastseg, &bc, ap->a_p); 409 if (error) 410 allerror = error; 411 real_released += rcount; 412 blocksreleased += count; 413 if (lastiblock[level] < 0) { 414 if (oip->i_ffs_ib[level] > 0) 415 real_released += nblocks; 416 blocksreleased += nblocks; 417 oip->i_ffs_ib[level] = 0; 418 lfs_blkfree(fs, bn, fs->lfs_bsize, &lastseg, &bc); 419 } 420 } 421 if (lastiblock[level] >= 0) 422 goto done; 423 } 424 425 /* 426 * All whole direct blocks or frags. 427 */ 428 for (i = NDADDR - 1; i > lastblock; i--) { 429 long bsize, obsize; 430 431 bn = oip->i_ffs_db[i]; 432 if (bn == 0) 433 continue; 434 bsize = blksize(fs, oip, i); 435 if (oip->i_ffs_db[i] > 0) { 436 /* Check for fragment size changes */ 437 obsize = oip->i_lfs_fragsize[i]; 438 real_released += btofsb(fs, obsize); 439 oip->i_lfs_fragsize[i] = 0; 440 } else 441 obsize = 0; 442 blocksreleased += btofsb(fs, bsize); 443 oip->i_ffs_db[i] = 0; 444 lfs_blkfree(fs, bn, obsize, &lastseg, &bc); 445 } 446 if (lastblock < 0) 447 goto done; 448 449 /* 450 * Finally, look for a change in size of the 451 * last direct block; release any frags. 452 */ 453 bn = oip->i_ffs_db[lastblock]; 454 if (bn != 0) { 455 long oldspace, newspace, olddspace; 456 457 /* 458 * Calculate amount of space we're giving 459 * back as old block size minus new block size. 460 */ 461 oldspace = blksize(fs, oip, lastblock); 462 olddspace = oip->i_lfs_fragsize[lastblock]; 463 464 oip->i_ffs_size = length; 465 newspace = blksize(fs, oip, lastblock); 466 if (newspace == 0) 467 panic("itrunc: newspace"); 468 if (oldspace - newspace > 0) { 469 blocksreleased += btofsb(fs, oldspace - newspace); 470 } 471 #if 0 472 if (bn > 0 && olddspace - newspace > 0) { 473 /* No segment accounting here, just vnode */ 474 real_released += btofsb(fs, olddspace - newspace); 475 } 476 #endif 477 } 478 479 done: 480 /* Finish segment accounting corrections */ 481 lfs_update_seguse(fs, lastseg, bc); 482 #ifdef DIAGNOSTIC 483 for (level = SINGLE; level <= TRIPLE; level++) 484 if (newblks[NDADDR + level] != oip->i_ffs_ib[level]) 485 panic("lfs itrunc1"); 486 for (i = 0; i < NDADDR; i++) 487 if (newblks[i] != oip->i_ffs_db[i]) 488 panic("lfs itrunc2"); 489 if (length == 0 && 490 (!LIST_EMPTY(&ovp->v_cleanblkhd) || !LIST_EMPTY(&ovp->v_dirtyblkhd))) 491 panic("lfs itrunc3"); 492 #endif /* DIAGNOSTIC */ 493 /* 494 * Put back the real size. 495 */ 496 oip->i_ffs_size = length; 497 oip->i_lfs_effnblks -= blocksreleased; 498 oip->i_ffs_blocks -= real_released; 499 fs->lfs_bfree += blocksreleased; 500 #ifdef DIAGNOSTIC 501 if (oip->i_ffs_size == 0 && oip->i_ffs_blocks != 0) { 502 printf("lfs_truncate: truncate to 0 but %d blocks on inode\n", 503 oip->i_ffs_blocks); 504 panic("lfs_truncate: persistent blocks"); 505 } 506 #endif 507 oip->i_flag |= IN_CHANGE; 508 #ifdef QUOTA 509 (void) chkdq(oip, -blocksreleased, NOCRED, 0); 510 #endif 511 lfs_reserve(fs, ovp, -btofsb(fs, (2 * NIADDR + 3) << fs->lfs_bshift)); 512 #ifdef LFS_FRAGSIZE_SEGLOCK 513 lfs_segunlock(fs); 514 #else 515 lockmgr(&fs->lfs_fraglock, LK_RELEASE, 0); 516 #endif 517 return (allerror); 518 } 519 520 /* Update segment usage information when removing a block. */ 521 static int 522 lfs_blkfree(struct lfs *fs, daddr_t daddr, size_t bsize, long *lastseg, 523 size_t *num) 524 { 525 long seg; 526 int error = 0; 527 528 bsize = fragroundup(fs, bsize); 529 if (daddr > 0) { 530 if (*lastseg != (seg = dtosn(fs, daddr))) { 531 error = lfs_update_seguse(fs, *lastseg, *num); 532 *num = bsize; 533 *lastseg = seg; 534 } else 535 *num += bsize; 536 } 537 return error; 538 } 539 540 /* Finish the accounting updates for a segment. */ 541 static int 542 lfs_update_seguse(struct lfs *fs, long lastseg, size_t num) 543 { 544 SEGUSE *sup; 545 struct buf *bp; 546 int error; 547 548 if (lastseg < 0 || num == 0) 549 return 0; 550 551 LFS_SEGENTRY(sup, fs, lastseg, bp); 552 if (num > sup->su_nbytes) { 553 printf("lfs_truncate: segment %ld short by %ld\n", 554 lastseg, (long)num - sup->su_nbytes); 555 panic("lfs_truncate: negative bytes"); 556 sup->su_nbytes = num; 557 } 558 sup->su_nbytes -= num; 559 error = LFS_BWRITE_LOG(bp); /* Ifile */ 560 return error; 561 } 562 563 /* 564 * Release blocks associated with the inode ip and stored in the indirect 565 * block bn. Blocks are free'd in LIFO order up to (but not including) 566 * lastbn. If level is greater than SINGLE, the block is an indirect block 567 * and recursive calls to indirtrunc must be used to cleanse other indirect 568 * blocks. 569 * 570 * NB: triple indirect blocks are untested. 571 */ 572 static int 573 lfs_indirtrunc(struct inode *ip, ufs_daddr_t lbn, daddr_t dbn, 574 ufs_daddr_t lastbn, int level, long *countp, 575 long *rcountp, long *lastsegp, size_t *bcp, struct proc *p) 576 { 577 int i; 578 struct buf *bp; 579 struct lfs *fs = ip->i_lfs; 580 ufs_daddr_t *bap; 581 struct vnode *vp; 582 ufs_daddr_t *copy = NULL, nb, nlbn, last; 583 long blkcount, rblkcount, factor; 584 int nblocks, blocksreleased = 0, real_released = 0; 585 int error = 0, allerror = 0; 586 587 /* 588 * Calculate index in current block of last 589 * block to be kept. -1 indicates the entire 590 * block so we need not calculate the index. 591 */ 592 factor = 1; 593 for (i = SINGLE; i < level; i++) 594 factor *= NINDIR(fs); 595 last = lastbn; 596 if (lastbn > 0) 597 last /= factor; 598 nblocks = btofsb(fs, fs->lfs_bsize); 599 /* 600 * Get buffer of block pointers, zero those entries corresponding 601 * to blocks to be free'd, and update on disk copy first. Since 602 * double(triple) indirect before single(double) indirect, calls 603 * to bmap on these blocks will fail. However, we already have 604 * the on disk address, so we have to set the b_blkno field 605 * explicitly instead of letting bread do everything for us. 606 */ 607 vp = ITOV(ip); 608 bp = getblk(vp, lbn, (int)fs->lfs_bsize, 0, 0); 609 if (bp->b_flags & (B_DONE | B_DELWRI)) { 610 /* Braces must be here in case trace evaluates to nothing. */ 611 trace(TR_BREADHIT, pack(vp, fs->lfs_bsize), lbn); 612 } else { 613 trace(TR_BREADMISS, pack(vp, fs->lfs_bsize), lbn); 614 p->p_stats->p_ru.ru_inblock++; /* pay for read */ 615 bp->b_flags |= B_READ; 616 if (bp->b_bcount > bp->b_bufsize) 617 panic("lfs_indirtrunc: bad buffer size"); 618 bp->b_blkno = fsbtodb(fs, dbn); 619 VOP_STRATEGY(bp); 620 error = biowait(bp); 621 } 622 if (error) { 623 brelse(bp); 624 *countp = *rcountp = 0; 625 return (error); 626 } 627 628 bap = (ufs_daddr_t *)bp->b_data; 629 if (lastbn >= 0) { 630 MALLOC(copy, ufs_daddr_t *, fs->lfs_bsize, M_TEMP, M_WAITOK); 631 memcpy((caddr_t)copy, (caddr_t)bap, (u_int)fs->lfs_bsize); 632 memset((caddr_t)&bap[last + 1], 0, 633 (u_int)(NINDIR(fs) - (last + 1)) * sizeof (ufs_daddr_t)); 634 error = VOP_BWRITE(bp); 635 if (error) 636 allerror = error; 637 bap = copy; 638 } 639 640 /* 641 * Recursively free totally unused blocks. 642 */ 643 for (i = NINDIR(fs) - 1, nlbn = lbn + 1 - i * factor; i > last; 644 i--, nlbn += factor) { 645 nb = bap[i]; 646 if (nb == 0) 647 continue; 648 if (level > SINGLE) { 649 error = lfs_indirtrunc(ip, nlbn, nb, 650 (ufs_daddr_t)-1, level - 1, 651 &blkcount, &rblkcount, 652 lastsegp, bcp, p); 653 if (error) 654 allerror = error; 655 blocksreleased += blkcount; 656 real_released += rblkcount; 657 } 658 lfs_blkfree(fs, nb, fs->lfs_bsize, lastsegp, bcp); 659 if (bap[i] > 0) 660 real_released += nblocks; 661 blocksreleased += nblocks; 662 } 663 664 /* 665 * Recursively free last partial block. 666 */ 667 if (level > SINGLE && lastbn >= 0) { 668 last = lastbn % factor; 669 nb = bap[i]; 670 if (nb != 0) { 671 error = lfs_indirtrunc(ip, nlbn, nb, 672 last, level - 1, &blkcount, 673 &rblkcount, lastsegp, bcp, p); 674 if (error) 675 allerror = error; 676 real_released += rblkcount; 677 blocksreleased += blkcount; 678 } 679 } 680 681 if (copy != NULL) { 682 FREE(copy, M_TEMP); 683 } else { 684 if (bp->b_flags & B_DELWRI) { 685 LFS_UNLOCK_BUF(bp); 686 fs->lfs_avail += btofsb(fs, bp->b_bcount); 687 wakeup(&fs->lfs_avail); 688 } 689 bp->b_flags |= B_INVAL; 690 brelse(bp); 691 } 692 693 *countp = blocksreleased; 694 *rcountp = real_released; 695 return (allerror); 696 } 697 698 /* 699 * Destroy any in core blocks past the truncation length. 700 * Inlined from vtruncbuf, so that lfs_avail could be updated. 701 */ 702 static int 703 lfs_vtruncbuf(struct vnode *vp, daddr_t lbn, int slpflag, int slptimeo) 704 { 705 struct buf *bp, *nbp; 706 int s, error; 707 struct lfs *fs; 708 709 fs = VTOI(vp)->i_lfs; 710 s = splbio(); 711 712 restart: 713 for (bp = LIST_FIRST(&vp->v_cleanblkhd); bp; bp = nbp) { 714 nbp = LIST_NEXT(bp, b_vnbufs); 715 if (bp->b_lblkno < lbn) 716 continue; 717 if (bp->b_flags & B_BUSY) { 718 bp->b_flags |= B_WANTED; 719 error = tsleep((caddr_t)bp, slpflag | (PRIBIO + 1), 720 "lfs_vtruncbuf", slptimeo); 721 if (error) { 722 splx(s); 723 return (error); 724 } 725 goto restart; 726 } 727 bp->b_flags |= B_BUSY | B_INVAL | B_VFLUSH; 728 if (bp->b_flags & B_DELWRI) { 729 bp->b_flags &= ~B_DELWRI; 730 fs->lfs_avail += btofsb(fs, bp->b_bcount); 731 wakeup(&fs->lfs_avail); 732 } 733 LFS_UNLOCK_BUF(bp); 734 brelse(bp); 735 } 736 737 for (bp = LIST_FIRST(&vp->v_dirtyblkhd); bp; bp = nbp) { 738 nbp = LIST_NEXT(bp, b_vnbufs); 739 if (bp->b_lblkno < lbn) 740 continue; 741 if (bp->b_flags & B_BUSY) { 742 bp->b_flags |= B_WANTED; 743 error = tsleep((caddr_t)bp, slpflag | (PRIBIO + 1), 744 "lfs_vtruncbuf", slptimeo); 745 if (error) { 746 splx(s); 747 return (error); 748 } 749 goto restart; 750 } 751 bp->b_flags |= B_BUSY | B_INVAL | B_VFLUSH; 752 if (bp->b_flags & B_DELWRI) { 753 bp->b_flags &= ~B_DELWRI; 754 fs->lfs_avail += btofsb(fs, bp->b_bcount); 755 wakeup(&fs->lfs_avail); 756 } 757 LFS_UNLOCK_BUF(bp); 758 brelse(bp); 759 } 760 761 splx(s); 762 763 return (0); 764 } 765 766