1 /* 2 * Copyright (c) 1982, 1986, 1989 Regents of the University of California. 3 * All rights reserved. 4 * 5 * %sccs.include.redist.c% 6 * 7 * @(#)lfs_inode.c 7.44 (Berkeley) 10/09/91 8 */ 9 10 #ifdef LOGFS 11 #include "param.h" 12 #include "systm.h" 13 #include "mount.h" 14 #include "proc.h" 15 #include "file.h" 16 #include "buf.h" 17 #include "vnode.h" 18 #include "kernel.h" 19 #include "malloc.h" 20 21 #include "../ufs/quota.h" 22 #include "../ufs/inode.h" 23 #include "../ufs/ufsmount.h" 24 #include "../vm/vm_param.h" 25 #include "../vm/lock.h" 26 #include "lfs.h" 27 #include "lfs_extern.h" 28 29 #define INOHSZ 512 30 #if ((INOHSZ&(INOHSZ-1)) == 0) 31 #define INOHASH(dev,ino) (((dev)+(ino))&(INOHSZ-1)) 32 #else 33 #define INOHASH(dev,ino) (((unsigned)((dev)+(ino)))%INOHSZ) 34 #endif 35 36 union lfsihead { /* LFS */ 37 union lfsihead *ih_head[2]; 38 struct inode *ih_chain[2]; 39 } lfsihead[INOHSZ]; 40 41 /* LFS */ 42 extern int prtactive; /* 1 => print out reclaim of active vnodes */ 43 44 lock_data_t lfs_sync_lock; 45 46 /* 47 * Initialize hash links for inodes. 48 */ 49 int 50 lfs_init() 51 { 52 register int i; 53 register union lfsihead *ih = lfsihead; 54 55 printf("lfs_init\n"); 56 57 #ifndef lint 58 if (VN_MAXPRIVATE < sizeof(struct inode)) 59 panic("ihinit: too small"); 60 #endif 61 lock_init(&lfs_sync_lock, 1); 62 63 for (i = INOHSZ; --i >= 0; ih++) { 64 ih->ih_head[0] = ih; 65 ih->ih_head[1] = ih; 66 } 67 #ifdef NOTLFS /* LFS */ 68 #ifdef QUOTA 69 dqinit(); 70 #endif /* QUOTA */ 71 #endif 72 return (0); 73 } 74 75 void 76 lfs_hqueue(ip) 77 struct inode *ip; 78 { 79 union lfsihead *ih; 80 81 ih = &lfsihead[INOHASH(ip->i_dev, ip->i_number)]; 82 insque(ip, ih); 83 ILOCK(ip); 84 } 85 86 87 /* 88 * Look up a UFS dinode number to find its incore vnode. 89 * If it is not in core, read it in from the specified device. 90 * If it is in core, wait for the lock bit to clear, then 91 * return the inode locked. Detection and handling of mount 92 * points must be done by the calling routine. 93 */ 94 int 95 lfs_iget(xp, ino, ipp) 96 struct inode *xp; 97 ino_t ino; 98 struct inode **ipp; 99 { 100 dev_t dev = xp->i_dev; 101 struct mount *mntp = ITOV(xp)->v_mount; 102 register LFS *fs = VFSTOUFS(mntp)->um_lfs; /* LFS */ 103 extern struct vnodeops spec_inodeops; 104 register struct inode *ip, *iq; 105 register struct vnode *vp; 106 struct vnode *nvp; 107 struct buf *bp; 108 union lfsihead *ih; 109 int error; 110 111 printf("lfs_iget ino %d\n", ino); 112 ih = &lfsihead[INOHASH(dev, ino)]; 113 loop: 114 for (ip = ih->ih_chain[0]; ip != (struct inode *)ih; ip = ip->i_forw) { 115 if (ino != ip->i_number || dev != ip->i_dev) 116 continue; 117 if ((ip->i_flag&ILOCKED) != 0) { 118 ip->i_flag |= IWANT; 119 sleep((caddr_t)ip, PINOD); 120 goto loop; 121 } 122 if (vget(ITOV(ip))) 123 goto loop; 124 *ipp = ip; 125 return(0); 126 } 127 128 /* Allocate new vnode/inode. */ 129 error = lfs_vcreate(mntp, ino, &nvp); 130 if (error) { 131 *ipp = 0; 132 return (error); 133 } 134 ip = VTOI(nvp); 135 136 /* 137 * Put it onto its hash chain and lock it so that other requests for 138 * this inode will block if they arrive while we are sleeping waiting 139 * for old data structures to be purged or for the contents of the 140 * disk portion of this inode to be read. 141 */ 142 insque(ip, ih); 143 ILOCK(ip); 144 145 /* Read in the disk contents for the inode, copy into the vnode. */ 146 if (error = bread(VFSTOUFS(mntp)->um_devvp, itod(fs, ino), 147 (int)fs->lfs_bsize, NOCRED, &bp)) { /* LFS */ 148 /* 149 * The inode does not contain anything useful, so it would 150 * be misleading to leave it on its hash chain. 151 * Iput() will take care of putting it back on the free list. 152 */ 153 remque(ip); 154 ip->i_forw = ip; 155 ip->i_back = ip; 156 /* 157 * Unlock and discard unneeded inode. 158 */ 159 iput(ip); 160 brelse(bp); 161 *ipp = 0; 162 return (error); 163 } 164 ip->i_din = *lfs_ifind(fs, ino, bp->b_un.b_dino); 165 brelse(bp); 166 167 /* 168 * Initialize the associated vnode 169 */ 170 vp = ITOV(ip); 171 vp->v_type = IFTOVT(ip->i_mode); 172 if (vp->v_type == VFIFO) { 173 #ifdef FIFO 174 extern struct vnodeops fifo_inodeops; 175 vp->v_op = &fifo_inodeops; 176 #else 177 iput(ip); 178 *ipp = 0; 179 return (EOPNOTSUPP); 180 #endif /* FIFO */ 181 } 182 if (vp->v_type == VCHR || vp->v_type == VBLK) { 183 vp->v_op = &spec_inodeops; 184 if (nvp = checkalias(vp, ip->i_rdev, mntp)) { 185 /* 186 * Reinitialize aliased inode. 187 */ 188 vp = nvp; 189 iq = VTOI(vp); 190 iq->i_vnode = vp; 191 iq->i_flag = 0; 192 ILOCK(iq); 193 iq->i_din = ip->i_din; 194 iq->i_dev = dev; 195 iq->i_number = ino; 196 insque(iq, ih); 197 /* 198 * Discard unneeded vnode 199 */ 200 ip->i_mode = 0; 201 iput(ip); 202 ip = iq; 203 } 204 } 205 if (ino == ROOTINO) 206 vp->v_flag |= VROOT; 207 208 VREF(ip->i_devvp); 209 210 *ipp = ip; 211 return (0); 212 } 213 214 /* 215 * Last reference to an inode, write the inode out and if necessary, 216 * truncate and deallocate the file. 217 */ 218 int 219 lfs_inactive(vp, p) 220 struct vnode *vp; 221 struct proc *p; 222 { 223 register struct inode *ip = VTOI(vp); 224 int mode, error = 0; 225 226 printf("lfs_inactive: ino %d mode %d nlink %d\n", 227 ip->i_number, ip->i_mode, ip->i_nlink); 228 229 if (prtactive && vp->v_usecount != 0) 230 vprint("ufs_inactive: pushing active", vp); 231 /* 232 * Get rid of inodes related to stale file handles. 233 */ 234 if (ip->i_mode == 0) { 235 if ((vp->v_flag & VXLOCK) == 0) 236 vgone(vp); 237 return (0); 238 } 239 ILOCK(ip); 240 if (ip->i_nlink <= 0 && (vp->v_mount->mnt_flag & MNT_RDONLY) == 0) { 241 #ifdef QUOTA 242 if (!getinoquota(ip)) 243 (void) chkiq(ip, -1, NOCRED, 0); 244 #endif 245 error = lfs_itrunc(ip, (u_long)0, 0); /* LFS */ 246 mode = ip->i_mode; 247 ip->i_mode = 0; 248 ip->i_rdev = 0; 249 ip->i_flag |= IUPD|ICHG; 250 #ifdef NOTLFS /* LFS */ 251 ifree(ip, ip->i_number, mode); 252 #else 253 lfs_ifree(ip); 254 #endif 255 } 256 ITIMES(ip, &time, &time); 257 IUNLOCK(ip); 258 ip->i_flag = 0; 259 /* 260 * If we are done with the inode, reclaim it 261 * so that it can be reused immediately. 262 */ 263 if (vp->v_usecount == 0 && ip->i_mode == 0) 264 vgone(vp); 265 return (error); 266 } 267 268 #define SINGLE 0 /* index of single indirect block */ 269 #define DOUBLE 1 /* index of double indirect block */ 270 #define TRIPLE 2 /* index of triple indirect block */ 271 /* 272 * Truncate the inode ip to at most length size. Free affected disk 273 * blocks -- the blocks of the file are removed in reverse order. 274 * 275 * NB: triple indirect blocks are untested. 276 */ 277 lfs_itrunc(oip, length, flags) 278 register struct inode *oip; 279 u_long length; 280 int flags; 281 { 282 register daddr_t lastblock; 283 daddr_t bn, lbn, lastiblock[NIADDR]; 284 register LFS *fs; /* LFS */ 285 register struct inode *ip; 286 struct buf *bp; 287 int offset, osize, size, level; 288 long count, nblocks, blocksreleased = 0; 289 register int i; 290 int aflags, error, allerror; 291 struct inode tip; 292 293 vnode_pager_setsize(ITOV(oip), length); 294 if (oip->i_size <= length) { 295 oip->i_flag |= ICHG|IUPD; 296 ITIMES(oip, &time, &time); 297 return (0); 298 } 299 /* 300 * Calculate index into inode's block list of 301 * last direct and indirect blocks (if any) 302 * which we want to keep. Lastblock is -1 when 303 * the file is truncated to 0. 304 */ 305 fs = oip->i_lfs; /* LFS */ 306 lastblock = lblkno(fs, length + fs->lfs_bsize - 1) - 1; /* LFS */ 307 lastiblock[SINGLE] = lastblock - NDADDR; 308 lastiblock[DOUBLE] = lastiblock[SINGLE] - NINDIR(fs); 309 lastiblock[TRIPLE] = lastiblock[DOUBLE] - NINDIR(fs) * NINDIR(fs); 310 nblocks = btodb(fs->lfs_bsize); /* LFS */ 311 /* 312 * Update the size of the file. If the file is not being 313 * truncated to a block boundry, the contents of the 314 * partial block following the end of the file must be 315 * zero'ed in case it ever become accessable again because 316 * of subsequent file growth. 317 */ 318 osize = oip->i_size; 319 offset = blkoff(fs, length); 320 if (offset == 0) { 321 oip->i_size = length; 322 } else { 323 lbn = lblkno(fs, length); 324 aflags = B_CLRBUF; 325 if (flags & IO_SYNC) 326 aflags |= B_SYNC; 327 #ifdef QUOTA 328 if (error = getinoquota(oip)) 329 return (error); 330 #endif 331 if (error = bread(ITOV(oip), lbn, fs->lfs_bsize, NOCRED, &bp)) 332 return (error); 333 oip->i_size = length; 334 size = blksize(fs); /* LFS */ 335 (void) vnode_pager_uncache(ITOV(oip)); 336 bzero(bp->b_un.b_addr + offset, (unsigned)(size - offset)); 337 allocbuf(bp, size); 338 #ifdef NOTLFS 339 if (flags & IO_SYNC) /* LFS */ 340 bwrite(bp); 341 else 342 bdwrite(bp); 343 #else 344 lfs_bwrite(bp); 345 #endif 346 } 347 /* 348 * Update file and block pointers 349 * on disk before we start freeing blocks. 350 * If we crash before free'ing blocks below, 351 * the blocks will be returned to the free list. 352 * lastiblock values are also normalized to -1 353 * for calls to indirtrunc below. 354 */ 355 /* Will need to modify the segment usage information */ /* LFS */ 356 tip = *oip; 357 tip.i_size = osize; 358 for (level = TRIPLE; level >= SINGLE; level--) 359 if (lastiblock[level] < 0) { 360 oip->i_ib[level] = 0; 361 lastiblock[level] = -1; 362 } 363 for (i = NDADDR - 1; i > lastblock; i--) 364 oip->i_db[i] = 0; 365 oip->i_flag |= ICHG|IUPD; 366 #ifdef NOTLFS 367 vinvalbuf(ITOV(oip), (length > 0)); 368 allerror = ITIMES(oip, &time, &time); 369 #else 370 /* Need lfs_vinvalbuf to get rid of invalid buffers in the cache */ 371 ITIMES(oip, &time, &time); 372 allerror = 0; 373 #endif 374 375 #ifdef NOTLFS 376 /* 377 * Indirect blocks first. 378 */ 379 ip = &tip; 380 for (level = TRIPLE; level >= SINGLE; level--) { 381 bn = ip->i_ib[level]; 382 if (bn != 0) { 383 error = indirtrunc(ip, bn, lastiblock[level], level, 384 &count); 385 if (error) 386 allerror = error; 387 blocksreleased += count; 388 if (lastiblock[level] < 0) { 389 ip->i_ib[level] = 0; 390 blkfree(ip, bn, (off_t)fs->fs_bsize); 391 blocksreleased += nblocks; 392 } 393 } 394 if (lastiblock[level] >= 0) 395 goto done; 396 } 397 #else 398 /* LFS -- not yet implemented. Need to rewrite indirect blocks */ 399 panic("lfs_itrunc: not yet implemented"); 400 #endif 401 402 /* 403 * All whole direct blocks or frags. 404 */ 405 for (i = NDADDR - 1; i > lastblock; i--) { 406 register off_t bsize; 407 408 bn = ip->i_db[i]; 409 if (bn == 0) 410 continue; 411 ip->i_db[i] = 0; 412 bsize = (off_t)blksize(fs); /* LFS */ 413 #ifdef NOTLFS 414 blkfree(ip, bn, bsize); 415 #else 416 /* LFS Update segment usage information */ 417 #endif 418 blocksreleased += btodb(bsize); 419 } 420 if (lastblock < 0) 421 goto done; 422 423 /* 424 * Finally, look for a change in size of the 425 * last direct block; release any frags. 426 */ 427 bn = ip->i_db[lastblock]; 428 if (bn != 0) { 429 off_t oldspace, newspace; 430 431 /* 432 * Calculate amount of space we're giving 433 * back as old block size minus new block size. 434 */ 435 oldspace = blksize(fs); /* LFS */ 436 ip->i_size = length; 437 newspace = blksize(fs); /* LFS */ 438 if (newspace == 0) 439 panic("lfs_itrunc: newspace"); 440 if (oldspace - newspace > 0) { 441 /* 442 * Block number of space to be free'd is 443 * the old block # plus the number of frags 444 * required for the storage we're keeping. 445 */ 446 bn += numfrags(fs, newspace); 447 blkfree(ip, bn, oldspace - newspace); 448 blocksreleased += btodb(oldspace - newspace); 449 } 450 } 451 done: 452 /* BEGIN PARANOIA */ 453 for (level = SINGLE; level <= TRIPLE; level++) 454 if (ip->i_ib[level] != oip->i_ib[level]) 455 panic("lfs_itrunc1"); 456 for (i = 0; i < NDADDR; i++) 457 if (ip->i_db[i] != oip->i_db[i]) 458 panic("lfs_itrunc2"); 459 /* END PARANOIA */ 460 oip->i_blocks -= blocksreleased; 461 if (oip->i_blocks < 0) /* sanity */ 462 oip->i_blocks = 0; 463 oip->i_flag |= ICHG; 464 #ifdef QUOTA 465 if (!getinoquota(oip)) 466 (void) chkdq(oip, -blocksreleased, NOCRED, 0); 467 #endif 468 return (allerror); 469 } 470 471 /* 472 * Release blocks associated with the inode ip and 473 * stored in the indirect block bn. Blocks are free'd 474 * in LIFO order up to (but not including) lastbn. If 475 * level is greater than SINGLE, the block is an indirect 476 * block and recursive calls to indirtrunc must be used to 477 * cleanse other indirect blocks. 478 * 479 * NB: triple indirect blocks are untested. 480 */ 481 lfs_indirtrunc(ip, bn, lastbn, level, countp) 482 register struct inode *ip; 483 daddr_t bn, lastbn; 484 int level; 485 long *countp; 486 { 487 #ifdef NOTLFS 488 register int i; 489 struct buf *bp; 490 register struct fs *fs = ip->i_fs; 491 register daddr_t *bap; 492 daddr_t *copy, nb, last; 493 long blkcount, factor; 494 int nblocks, blocksreleased = 0; 495 int error, allerror = 0; 496 497 /* 498 * Calculate index in current block of last 499 * block to be kept. -1 indicates the entire 500 * block so we need not calculate the index. 501 */ 502 factor = 1; 503 for (i = SINGLE; i < level; i++) 504 factor *= NINDIR(fs); 505 last = lastbn; 506 if (lastbn > 0) 507 last /= factor; 508 nblocks = btodb(fs->fs_bsize); 509 /* 510 * Get buffer of block pointers, zero those 511 * entries corresponding to blocks to be free'd, 512 * and update on disk copy first. 513 */ 514 error = bread(ip->i_devvp, fsbtodb(fs, bn), (int)fs->fs_bsize, 515 NOCRED, &bp); 516 if (error) { 517 brelse(bp); 518 *countp = 0; 519 return (error); 520 } 521 bap = bp->b_un.b_daddr; 522 MALLOC(copy, daddr_t *, fs->fs_bsize, M_TEMP, M_WAITOK); 523 bcopy((caddr_t)bap, (caddr_t)copy, (u_int)fs->fs_bsize); 524 bzero((caddr_t)&bap[last + 1], 525 (u_int)(NINDIR(fs) - (last + 1)) * sizeof (daddr_t)); 526 if (last == -1) 527 bp->b_flags |= B_INVAL; 528 error = bwrite(bp); 529 if (error) 530 allerror = error; 531 bap = copy; 532 533 /* 534 * Recursively free totally unused blocks. 535 */ 536 for (i = NINDIR(fs) - 1; i > last; i--) { 537 nb = bap[i]; 538 if (nb == 0) 539 continue; 540 if (level > SINGLE) { 541 error = indirtrunc(ip, nb, (daddr_t)-1, level - 1, 542 &blkcount); 543 if (error) 544 allerror = error; 545 blocksreleased += blkcount; 546 } 547 blkfree(ip, nb, (off_t)fs->fs_bsize); 548 blocksreleased += nblocks; 549 } 550 551 /* 552 * Recursively free last partial block. 553 */ 554 if (level > SINGLE && lastbn >= 0) { 555 last = lastbn % factor; 556 nb = bap[i]; 557 if (nb != 0) { 558 error = indirtrunc(ip, nb, last, level - 1, &blkcount); 559 if (error) 560 allerror = error; 561 blocksreleased += blkcount; 562 } 563 } 564 FREE(copy, M_TEMP); 565 *countp = blocksreleased; 566 return (allerror); 567 #else 568 /* LFS IMPLEMENT -- lfs_indirtrunc */ 569 panic("lfs_indirtrunc not implemented"); 570 #endif 571 } 572 #endif /* LOGFS */ 573