1: /*
   2:  * Copyright (c) 1986 Regents of the University of California.
   3:  * All rights reserved.  The Berkeley software License Agreement
   4:  * specifies the terms and conditions for redistribution.
   5:  *
   6:  *	@(#)ufs_inode.c	1.7 (2.11BSD GTE) 1997/2/7
   7:  */
   8: 
   9: #include "param.h"
  10: #include "../machine/seg.h"
  11: 
  12: #include "user.h"
  13: #include "proc.h"
  14: #include "inode.h"
  15: #include "fs.h"
  16: #include "mount.h"
  17: #include "kernel.h"
  18: #include "buf.h"
  19: #include "text.h"
  20: #include "systm.h"
  21: #ifdef QUOTA
  22: #include "quota.h"
  23: #endif
  24: #include "syslog.h"
  25: 
  26: #define INOHSZ  16      /* must be power of two */
  27: #define INOHASH(dev,ino)    (((dev)+(ino))&(INOHSZ-1))
  28: 
  29: union ihead {               /* inode LRU cache, stolen */
  30:     union  ihead *ih_head[2];
  31:     struct inode *ih_chain[2];
  32: } ihead[INOHSZ];
  33: 
  34: struct inode *ifreeh, **ifreet;
  35: 
  36: /*
  37:  * Initialize hash links for inodes
  38:  * and build inode free list.
  39:  */
  40: ihinit()
  41: {
  42:     register int i;
  43:     register struct inode *ip = inode;
  44:     register union  ihead *ih = ihead;
  45: 
  46:     for (i = INOHSZ; --i >= 0; ih++) {
  47:         ih->ih_head[0] = ih;
  48:         ih->ih_head[1] = ih;
  49:     }
  50:     ifreeh = ip;
  51:     ifreet = &ip->i_freef;
  52:     ip->i_freeb = &ifreeh;
  53:     ip->i_forw = ip;
  54:     ip->i_back = ip;
  55:     for (i = ninode; --i > 0; ) {
  56:         ++ip;
  57:         ip->i_forw = ip;
  58:         ip->i_back = ip;
  59:         *ifreet = ip;
  60:         ip->i_freeb = ifreet;
  61:         ifreet = &ip->i_freef;
  62:     }
  63:     ip->i_freef = NULL;
  64: }
  65: 
  66: /*
  67:  * Find an inode if it is incore.
  68:  */
  69: struct inode *
  70: ifind(dev, ino)
  71:     register dev_t dev;
  72:     register ino_t ino;
  73: {
  74:     register struct inode *ip;
  75:     union ihead *ih;
  76: 
  77:     ih = &ihead[INOHASH(dev, ino)];
  78:     for (ip = ih->ih_chain[0]; ip != (struct inode *)ih; ip = ip->i_forw)
  79:         if (ino == ip->i_number && dev == ip->i_dev)
  80:             return(ip);
  81:     return((struct inode *)NULL);
  82: }
  83: 
  84: /*
  85:  * Look up an inode by device,inumber.
  86:  * If it is in core (in the inode structure),
  87:  * honor the locking protocol.
  88:  * If it is not in core, read it in from the
  89:  * specified device.
  90:  * If the inode is mounted on, perform
  91:  * the indicated indirection.
  92:  * In all cases, a pointer to a locked
  93:  * inode structure is returned.
  94:  *
  95:  * panic: no imt -- if the mounted file
  96:  *	system is not in the mount table.
  97:  *	"cannot happen"
  98:  */
  99: struct inode *
 100: iget(dev, fs, ino)
 101:     dev_t dev;
 102:     register struct fs *fs;
 103:     ino_t ino;
 104: {
 105:     register struct inode *ip;
 106:     union ihead *ih;
 107:     struct buf *bp;
 108:     struct dinode *dp;
 109: #ifdef EXTERNALITIMES
 110:     struct icommon2 xic2;
 111: #endif
 112: #ifdef  QUOTA
 113:     struct dquot **xdq;
 114: #endif
 115: 
 116: loop:
 117:     ih = &ihead[INOHASH(dev, ino)];
 118:     for (ip = ih->ih_chain[0]; ip != (struct inode *)ih; ip = ip->i_forw)
 119:         if (ino == ip->i_number && dev == ip->i_dev) {
 120:             /*
 121: 			 * Following is essentially an inline expanded
 122: 			 * copy of igrab(), expanded inline for speed,
 123: 			 * and so that the test for a mounted on inode
 124: 			 * can be deferred until after we are sure that
 125: 			 * the inode isn't busy.
 126: 			 */
 127:             if ((ip->i_flag&ILOCKED) != 0) {
 128:                 ip->i_flag |= IWANT;
 129:                 sleep((caddr_t)ip, PINOD);
 130:                 goto loop;
 131:             }
 132:             if ((ip->i_flag&IMOUNT) != 0) {
 133:                 register struct mount *mp;
 134: 
 135:                 for (mp = &mount[0]; mp < &mount[NMOUNT]; mp++)
 136:                     if(mp->m_inodp == ip) {
 137:                         dev = mp->m_dev;
 138:                         fs = &mp->m_filsys;
 139:                         ino = ROOTINO;
 140:                         goto loop;
 141:                     }
 142:                 panic("no imt");
 143:             }
 144:             if (ip->i_count == 0) {     /* ino on free list */
 145:                 register struct inode *iq;
 146: 
 147:                 if (iq = ip->i_freef)
 148:                     iq->i_freeb = ip->i_freeb;
 149:                 else
 150:                     ifreet = ip->i_freeb;
 151:                 *ip->i_freeb = iq;
 152:                 ip->i_freef = NULL;
 153:                 ip->i_freeb = NULL;
 154:             }
 155:             ip->i_count++;
 156:             ip->i_flag |= ILOCKED;
 157:             return(ip);
 158:         }
 159: 
 160:     if ((ip = ifreeh) == NULL) {
 161:         tablefull("inode");
 162:         u.u_error = ENFILE;
 163:         return(NULL);
 164:     }
 165:     if (ip->i_count)
 166:         panic("free inode isn't");
 167: {
 168:     register struct inode *iq;
 169: 
 170:     if (iq = ip->i_freef)
 171:         iq->i_freeb = &ifreeh;
 172:     ifreeh = iq;
 173: }
 174:     ip->i_freef = NULL;
 175:     ip->i_freeb = NULL;
 176:     /*
 177: 	 * Now to take inode off the hash chain it was on
 178: 	 * (initially, or after an iflush, it is on a "hash chain"
 179: 	 * consisting entirely of itself, and pointed to by no-one,
 180: 	 * but that doesn't matter), and put it on the chain for
 181: 	 * its new (ino, dev) pair
 182: 	 */
 183:     remque(ip);
 184:     insque(ip, ih);
 185:     ip->i_dev = dev;
 186:     ip->i_fs = fs;
 187:     ip->i_number = ino;
 188:     cacheinval(ip);
 189:     ip->i_flag = ILOCKED;
 190:     ip->i_count++;
 191:     ip->i_lastr = 0;
 192: #ifdef QUOTA
 193:     QUOTAMAP();
 194:     xdq = &ix_dquot[ip - inode];
 195:     dqrele(*xdq);
 196:     QUOTAUNMAP();
 197: #endif
 198:     bp = bread(dev, itod(ino));
 199:     /*
 200: 	 * Check I/O errors
 201: 	 */
 202:     if ((bp->b_flags&B_ERROR) != 0) {
 203:         brelse(bp);
 204:         /*
 205: 		 * the inode doesn't contain anything useful, so it would
 206: 		 * be misleading to leave it on its hash chain.
 207: 		 * 'iput' will take care of putting it back on the free list.
 208: 		 */
 209:         remque(ip);
 210:         ip->i_forw = ip;
 211:         ip->i_back = ip;
 212:         /*
 213: 		 * we also loose its inumber, just in case (as iput
 214: 		 * doesn't do that any more) - but as it isn't on its
 215: 		 * hash chain, I doubt if this is really necessary .. kre
 216: 		 * (probably the two methods are interchangable)
 217: 		 */
 218:         ip->i_number = 0;
 219: #ifdef QUOTA
 220:         QUOTAMAP();
 221:         *xdq = NODQUOT;
 222:         QUOTAUNMAP();
 223: #endif
 224:         iput(ip);
 225:         return(NULL);
 226:     }
 227:     dp = (struct dinode *)mapin(bp);
 228:     dp += itoo(ino);
 229:     ip->i_ic1 = dp->di_ic1;
 230:     ip->i_flags = dp->di_flags;
 231: #ifdef EXTERNALITIMES
 232:     xic2 = dp->di_ic2;
 233: #else
 234:     ip->i_ic2 = dp->di_ic2;
 235: #endif
 236:     bcopy(dp->di_addr, ip->i_addr, NADDR * sizeof (daddr_t));
 237:     mapout(bp);
 238:     brelse(bp);
 239: #ifdef EXTERNALITIMES
 240:     mapseg5(xitimes, xitdesc);
 241:     ((struct icommon2 *)SEG5)[ip-inode] = xic2;
 242:     normalseg5();
 243: #endif
 244: #ifdef QUOTA
 245:     QUOTAMAP();
 246:     if  (ip->i_mode == 0)
 247:         *xdq = NODQUOT;
 248:     else
 249:         *xdq = inoquota(ip);
 250:     QUOTAUNMAP();
 251: #endif
 252:     return (ip);
 253: }
 254: 
 255: /*
 256:  * Convert a pointer to an inode into a reference to an inode.
 257:  *
 258:  * This is basically the internal piece of iget (after the
 259:  * inode pointer is located) but without the test for mounted
 260:  * filesystems.  It is caller's responsibility to check that
 261:  * the inode pointer is valid.
 262:  */
 263: igrab(ip)
 264:     register struct inode *ip;
 265: {
 266:     while ((ip->i_flag&ILOCKED) != 0) {
 267:         ip->i_flag |= IWANT;
 268:         sleep((caddr_t)ip, PINOD);
 269:     }
 270:     if (ip->i_count == 0) {     /* ino on free list */
 271:         register struct inode *iq;
 272: 
 273:         if (iq = ip->i_freef)
 274:             iq->i_freeb = ip->i_freeb;
 275:         else
 276:             ifreet = ip->i_freeb;
 277:         *ip->i_freeb = iq;
 278:         ip->i_freef = NULL;
 279:         ip->i_freeb = NULL;
 280:     }
 281:     ip->i_count++;
 282:     ip->i_flag |= ILOCKED;
 283: }
 284: 
 285: /*
 286:  * Decrement reference count of
 287:  * an inode structure.
 288:  * On the last reference,
 289:  * write the inode out and if necessary,
 290:  * truncate and deallocate the file.
 291:  */
 292: iput(ip)
 293:     register struct inode *ip;
 294: {
 295: 
 296: #ifdef notnow
 297:     /*
 298: 	 * This code requires a lot of workarounds, you have to change
 299: 	 * lots of places to gratuitously lock just so we can unlock it.
 300: 	 * Not worth it.  -- KB
 301: 	 */
 302:     if ((ip->i_flag & ILOCKED) == 0)
 303:         panic("iput");
 304: #endif
 305:     IUNLOCK(ip);
 306:     irele(ip);
 307: }
 308: 
 309: irele(ip)
 310:     register struct inode *ip;
 311: {
 312:     if (ip->i_count == 1) {
 313:         ip->i_flag |= ILOCKED;
 314:         if (ip->i_nlink <= 0 && ip->i_fs->fs_ronly == 0) {
 315: #ifdef QUOTA
 316:             QUOTAMAP();
 317:             (void) chkiq(ip->i_dev, ip, ip->i_uid, 0);
 318:             dqrele(ix_dquot[ip - inode]);
 319:             ix_dquot[ip - inode] = NODQUOT;
 320:             QUOTAUNMAP();
 321: #endif
 322:             itrunc(ip, (u_long)0, 0);
 323:             ip->i_mode = 0;
 324:             ip->i_rdev = 0;
 325:             ip->i_flag |= IUPD|ICHG;
 326:             ifree(ip, ip->i_number);
 327:         }
 328:         IUPDAT(ip, &time, &time, 0);
 329:         IUNLOCK(ip);
 330:         ip->i_flag = 0;
 331:         /*
 332: 		 * Put the inode on the end of the free list.
 333: 		 * Possibly in some cases it would be better to
 334: 		 * put the inode at the head of the free list,
 335: 		 * (eg: where i_mode == 0 || i_number == 0)
 336: 		 * but I will think about that later .. kre
 337: 		 * (i_number is rarely 0 - only after an i/o error in iget,
 338: 		 * where i_mode == 0, the inode will probably be wanted
 339: 		 * again soon for an ialloc, so possibly we should keep it)
 340: 		 */
 341:         if (ifreeh) {
 342:             *ifreet = ip;
 343:             ip->i_freeb = ifreet;
 344:         } else {
 345:             ifreeh = ip;
 346:             ip->i_freeb = &ifreeh;
 347:         }
 348:         ip->i_freef = NULL;
 349:         ifreet = &ip->i_freef;
 350:     } else if (!(ip->i_flag & ILOCKED))
 351:         ITIMES(ip, &time, &time);
 352:     ip->i_count--;
 353: }
 354: 
 355: /*
 356:  * Check accessed and update flags on
 357:  * an inode structure.
 358:  * If any are on, update the inode
 359:  * with the current time.
 360:  * If waitfor set, then must insure
 361:  * i/o order so wait for the write to complete.
 362:  */
 363: iupdat(ip, ta, tm, waitfor)
 364:     struct inode *ip;
 365:     struct timeval *ta, *tm;
 366:     int waitfor;
 367: {
 368:     register struct buf *bp;
 369:     register struct dinode *dp;
 370: #ifdef EXTERNALITIMES
 371:     struct icommon2 xic2, *xicp2;
 372: #endif
 373:     register struct inode *tip = ip;
 374: 
 375:     if ((tip->i_flag & (IUPD|IACC|ICHG|IMOD)) == 0)
 376:         return;
 377:     if (tip->i_fs->fs_ronly)
 378:         return;
 379:     bp = bread(tip->i_dev, itod(tip->i_number));
 380:     if (bp->b_flags & B_ERROR) {
 381:         brelse(bp);
 382:         return;
 383:     }
 384: #ifdef EXTERNALITIMES
 385:     mapseg5(xitimes, xitdesc);
 386:     xicp2 = &((struct icommon2 *)SEG5)[ip - inode];
 387:     if (tip->i_flag & IACC)
 388:         xicp2->ic_atime = ta->tv_sec;
 389:     if (tip->i_flag & IUPD)
 390:         xicp2->ic_mtime = tm->tv_sec;
 391:     if (tip->i_flag & ICHG)
 392:         xicp2->ic_ctime = time.tv_sec;
 393:     xic2 = *xicp2;
 394:     normalseg5();
 395: #else
 396:     if (tip->i_flag&IACC)
 397:         tip->i_atime = ta->tv_sec;
 398:     if (tip->i_flag&IUPD)
 399:         tip->i_mtime = tm->tv_sec;
 400:     if (tip->i_flag&ICHG)
 401:         tip->i_ctime = time.tv_sec;
 402: #endif
 403:     tip->i_flag &= ~(IUPD|IACC|ICHG|IMOD);
 404:     dp = (struct dinode *)mapin(bp) + itoo(tip->i_number);
 405:     dp->di_ic1 = tip->i_ic1;
 406:     dp->di_flags = tip->i_flags;
 407: #ifdef EXTERNALITIMES
 408:     dp->di_ic2 = xic2;
 409: #else
 410:     dp->di_ic2 = tip->i_ic2;
 411: #endif
 412:     bcopy(ip->i_addr, dp->di_addr, NADDR * sizeof (daddr_t));
 413:     mapout(bp);
 414:     if (waitfor && ((ip->i_fs->fs_flags & MNT_ASYNC) == 0))
 415:         bwrite(bp);
 416:     else
 417:         bdwrite(bp);
 418: }
 419: 
 420: #define SINGLE  0   /* index of single indirect block */
 421: #define DOUBLE  1   /* index of double indirect block */
 422: #define TRIPLE  2   /* index of triple indirect block */
 423: /*
 424:  * Truncate the inode ip to at most
 425:  * length size.  Free affected disk
 426:  * blocks -- the blocks of the file
 427:  * are removed in reverse order.
 428:  *
 429:  * NB: triple indirect blocks are untested.
 430:  */
 431: itrunc(oip,length, ioflags)
 432:     register struct inode *oip;
 433:     u_long length;
 434:     int ioflags;
 435: {
 436:     daddr_t lastblock;
 437:     register int i;
 438:     register struct inode *ip;
 439:     daddr_t bn, lastiblock[NIADDR];
 440:     struct buf *bp;
 441:     int offset, level;
 442:     struct inode tip;
 443:     int aflags;
 444: #ifdef QUOTA
 445:     long bytesreleased;
 446: #endif
 447: 
 448:     aflags = B_CLRBUF;
 449:     if (ioflags & IO_SYNC)
 450:         aflags |= B_SYNC;
 451: 
 452:     /*
 453: 	 * special hack for pipes, since size for them isn't the size of
 454: 	 * the file, it's the amount currently waiting for transfer.  It's
 455: 	 * unclear that this will work, though, because pipes can (although
 456: 	 * rarely do) get bigger than MAXPIPSIZ.  Don't think it worked
 457: 	 * in V7 either, I don't really understand what's going on.
 458: 	 */
 459:     if (oip->i_flag & IPIPE)
 460:         oip->i_size = MAXPIPSIZ;
 461:     else if (oip->i_size == length)
 462:         goto updret;
 463: 
 464:     /*
 465: 	 * Lengthen the size of the file. We must ensure that the
 466: 	 * last byte of the file is allocated. Since the smallest
 467: 	 * value of osize is 0, length will be at least 1.
 468: 	 */
 469:     if (oip->i_size < length) {
 470:         bn = bmap(oip, lblkno(length - 1), B_WRITE, aflags);
 471:         if (u.u_error || bn < 0)
 472:             return;
 473: #ifdef  QUOTA
 474:         bytesreleased = oip->i_size - length;
 475: #endif
 476:         oip->i_size = length;
 477:         goto doquotaupd;
 478:     }
 479: 
 480:     /*
 481: 	 * Calculate index into inode's block list of
 482: 	 * last direct and indirect blocks (if any)
 483: 	 * which we want to keep.  Lastblock is -1 when
 484: 	 * the file is truncated to 0.
 485: 	 */
 486:     lastblock = lblkno(length + DEV_BSIZE - 1) - 1;
 487:     lastiblock[SINGLE] = lastblock - NDADDR;
 488:     lastiblock[DOUBLE] = lastiblock[SINGLE] - NINDIR;
 489:     lastiblock[TRIPLE] = lastiblock[DOUBLE] - NINDIR * NINDIR;
 490:     /*
 491: 	 * Update the size of the file. If the file is not being
 492: 	 * truncated to a block boundry, the contents of the
 493: 	 * partial block following the end of the file must be
 494: 	 * zero'ed in case it ever become accessable again because
 495: 	 * of subsequent file growth.
 496: 	 */
 497:     offset = blkoff(length);
 498:     if (offset) {
 499:         bn = bmap(oip, lblkno(length), B_WRITE, aflags);
 500:         if (u.u_error || bn < 0)
 501:             return;
 502:         bp = bread(oip->i_dev, bn);
 503:         if (bp->b_flags & B_ERROR) {
 504:             u.u_error = EIO;
 505:             brelse(bp);
 506:             return;
 507:         }
 508:         bzero(mapin(bp) + offset, (u_int)(DEV_BSIZE - offset));
 509:         mapout(bp);
 510:         bdwrite(bp);
 511:     }
 512:     /*
 513: 	 * Update file and block pointers
 514: 	 * on disk before we start freeing blocks.
 515: 	 * If we crash before free'ing blocks below,
 516: 	 * the blocks will be returned to the free list.
 517: 	 * lastiblock values are also normalized to -1
 518: 	 * for calls to indirtrunc below.
 519: 	 */
 520:     tip = *oip;
 521: #ifdef QUOTA
 522:     bytesreleased = oip->i_size - length;
 523: #endif
 524:     oip->i_size = length;
 525:     for (level = TRIPLE; level >= SINGLE; level--)
 526:         if (lastiblock[level] < 0) {
 527:             oip->i_ib[level] = 0;
 528:             lastiblock[level] = -1;
 529:         }
 530:     for (i = NDADDR - 1; i > lastblock; i--)
 531:         oip->i_db[i] = 0;
 532: 
 533:     /*
 534: 	 * Indirect blocks first.
 535: 	 */
 536:     ip = &tip;
 537:     for (level = TRIPLE; level >= SINGLE; level--) {
 538:         bn = ip->i_ib[level];
 539:         if (bn != 0) {
 540:             indirtrunc(ip, bn, lastiblock[level], level, aflags);
 541:             if (lastiblock[level] < 0) {
 542:                 ip->i_ib[level] = 0;
 543:                 free(ip, bn);
 544:             }
 545:         }
 546:         if (lastiblock[level] >= 0)
 547:             goto done;
 548:     }
 549: 
 550:     /*
 551: 	 * All whole direct blocks.
 552: 	 */
 553:     for (i = NDADDR - 1; i > lastblock; i--) {
 554:         bn = ip->i_db[i];
 555:         if (bn == 0)
 556:             continue;
 557:         ip->i_db[i] = 0;
 558:         free(ip, bn);
 559:     }
 560:     if (lastblock < 0)
 561:         goto done;
 562: 
 563: done:
 564: #ifdef DIAGNOSTIC
 565: /* BEGIN PARANOIA */
 566:     for (level = SINGLE; level <= TRIPLE; level++)
 567:         if (ip->i_ib[level] != oip->i_ib[level])
 568:             panic("itrunc1");
 569:     for (i = 0; i < NDADDR; i++)
 570:         if (ip->i_db[i] != oip->i_db[i])
 571:             panic("itrunc2");
 572: /* END PARANOIA */
 573: #endif
 574: 
 575: doquotaupd:
 576: #ifdef QUOTA
 577:     QUOTAMAP();
 578:     (void)chkdq(oip, -bytesreleased, 0);
 579:     QUOTAUNMAP();
 580: #endif
 581: updret:
 582:     oip->i_flag |= ICHG|IUPD;
 583:     iupdat(oip, &time, &time, 1);
 584: }
 585: 
 586: /*
 587:  * Release blocks associated with the inode ip and
 588:  * stored in the indirect block bn.  Blocks are free'd
 589:  * in LIFO order up to (but not including) lastbn.  If
 590:  * level is greater than SINGLE, the block is an indirect
 591:  * block and recursive calls to indirtrunc must be used to
 592:  * cleanse other indirect blocks.
 593:  *
 594:  * NB: triple indirect blocks are untested.
 595:  */
 596: indirtrunc(ip, bn, lastbn, level, aflags)
 597:     struct inode *ip;
 598:     daddr_t bn, lastbn;
 599:     int level;
 600:     int aflags;
 601: {
 602:     register struct buf *bp;
 603:     daddr_t nb, last;
 604:     long factor;
 605: 
 606:     /*
 607: 	 * Calculate index in current block of last
 608: 	 * block to be kept.  -1 indicates the entire
 609: 	 * block so we need not calculate the index.
 610: 	 */
 611:     switch(level) {
 612:         case SINGLE:
 613:             factor = 1;
 614:             break;
 615:         case DOUBLE:
 616:             factor = NINDIR;
 617:             break;
 618:         case TRIPLE:
 619:             factor = NINDIR * NINDIR;
 620:             break;
 621:     }
 622:     last = lastbn;
 623:     if (lastbn > 0)
 624:         last = last / factor;
 625:     /*
 626: 	 * Get buffer of block pointers, zero those
 627: 	 * entries corresponding to blocks to be free'd,
 628: 	 * and update on disk copy first.
 629: 	 */
 630:     {
 631:         register daddr_t *bap;
 632:         register struct buf *cpy;
 633: 
 634:         bp = bread(ip->i_dev, bn);
 635:         if (bp->b_flags&B_ERROR) {
 636:             brelse(bp);
 637:             return;
 638:         }
 639:         cpy = geteblk();
 640:         copy(bftopaddr(bp), bftopaddr(cpy), btoc(DEV_BSIZE));
 641:         bap = (daddr_t *)mapin(bp);
 642:         bzero((caddr_t)&bap[last + 1],
 643:             (u_int)(NINDIR - (last + 1)) * sizeof(daddr_t));
 644:         mapout(bp);
 645:         if (aflags & B_SYNC)
 646:             bwrite(bp);
 647:         else
 648:             bawrite(bp);
 649:         bp = cpy;
 650:     }
 651: 
 652:     /*
 653: 	 * Optimized for single indirect blocks, i.e. until a file is
 654: 	 * greater than 4K + 256K you don't have to do a mapin/mapout
 655: 	 * for every entry.  The mapin/mapout is required since free()
 656: 	 * may have to map an item in.  Have to use another routine
 657: 	 * since it requires 1K of kernel stack to get around the problem
 658: 	 * and that doesn't work well with recursion.
 659: 	 */
 660:     if (level == SINGLE)
 661:         trsingle(ip, bp, last, aflags);
 662:     else {
 663:         register daddr_t *bstart, *bstop;
 664: 
 665:         bstart = (daddr_t *)mapin(bp);
 666:         bstop = &bstart[last];
 667:         bstart += NINDIR - 1;
 668:         /*
 669: 		 * Recursively free totally unused blocks.
 670: 		 */
 671:         for (;bstart > bstop;--bstart) {
 672:             nb = *bstart;
 673:             if (nb) {
 674:                 mapout(bp);
 675:                 indirtrunc(ip,nb,(daddr_t)-1, level-1, aflags);
 676:                 free(ip, nb);
 677:                 mapin(bp);
 678:             }
 679:         }
 680:         mapout(bp);
 681: 
 682:         /*
 683: 		 * Recursively free last partial block.
 684: 		 */
 685:         if (lastbn >= 0) {
 686: 
 687:             mapin(bp);
 688:             nb = *bstop;
 689:             mapout(bp);
 690:             last = lastbn % factor;
 691:             if (nb != 0)
 692:                 indirtrunc(ip, nb, last, level - 1, aflags);
 693:         }
 694:     }
 695:     brelse(bp);
 696: }
 697: 
 698: static
 699: trsingle(ip, bp,last, aflags)
 700:     register struct inode *ip;
 701:     caddr_t bp;
 702:     daddr_t last;
 703:     int aflags;
 704: {
 705:     register daddr_t *bstart, *bstop;
 706:     daddr_t blarray[NINDIR];
 707: 
 708:     bcopy(mapin(bp),blarray,NINDIR * sizeof(daddr_t));
 709:     mapout(bp);
 710:     bstart = &blarray[NINDIR - 1];
 711:     bstop = &blarray[last];
 712:     for (;bstart > bstop;--bstart)
 713:         if (*bstart)
 714:             free(ip, *bstart);
 715: }
 716: 
 717: /*
 718:  * remove any inodes in the inode cache belonging to dev
 719:  *
 720:  * There should not be any active ones, return error if any are found
 721:  * (nb: this is a user error, not a system err)
 722:  *
 723:  * Also, count the references to dev by block devices - this really
 724:  * has nothing to do with the object of the procedure, but as we have
 725:  * to scan the inode table here anyway, we might as well get the
 726:  * extra benefit.
 727:  *
 728:  * this is called from sumount() when dev is being unmounted
 729:  */
 730: #ifdef QUOTA
 731: iflush(dev, iq)
 732:     struct inode *iq;
 733: #else
 734: iflush(dev)
 735: #endif
 736:     dev_t dev;
 737: {
 738:     register struct inode *ip;
 739:     register int open = 0;
 740: 
 741:     for (ip = inode; ip < inodeNINODE; ip++) {
 742: #ifdef QUOTA
 743:         if (ip != iq && ip->i_dev == dev)
 744: #else
 745:         if (ip->i_dev == dev)
 746: #endif
 747:             if (ip->i_count)
 748:                 return(-1);
 749:             else {
 750:                 remque(ip);
 751:                 ip->i_forw = ip;
 752:                 ip->i_back = ip;
 753:                 /*
 754: 				 * as i_count == 0, the inode was on the free
 755: 				 * list already, just leave it there, it will
 756: 				 * fall off the bottom eventually. We could
 757: 				 * perhaps move it to the head of the free
 758: 				 * list, but as umounts are done so
 759: 				 * infrequently, we would gain very little,
 760: 				 * while making the code bigger.
 761: 				 */
 762: #ifdef QUOTA
 763:                 QUOTAMAP();
 764:                 dqrele(ix_dquot[ip - inode]);
 765:                 ix_dquot[ip - inode] = NODQUOT;
 766:                 QUOTAUNMAP();
 767: #endif
 768:             }
 769:         else if (ip->i_count && (ip->i_mode&IFMT)==IFBLK &&
 770:             ip->i_rdev == dev)
 771:             open++;
 772:     }
 773:     return (open);
 774: }
 775: 
 776: /*
 777:  * Lock an inode. If its already locked, set the WANT bit and sleep.
 778:  */
 779: ilock(ip)
 780:     register struct inode *ip;
 781: {
 782: 
 783:     ILOCK(ip);
 784: }
 785: 
 786: /*
 787:  * Unlock an inode.  If WANT bit is on, wakeup.
 788:  */
 789: iunlock(ip)
 790:     register struct inode *ip;
 791: {
 792: 
 793:     IUNLOCK(ip);
 794: }

Defined functions

ifind defined in line 69; used 2 times
iflush defined in line 734; used 3 times
igrab defined in line 263; used 2 times
ihinit defined in line 40; used 1 times
indirtrunc defined in line 596; used 3 times
trsingle defined in line 698; used 1 times

Defined variables

ifreeh defined in line 34; used 8 times
ifreet defined in line 34; used 9 times
ihead defined in line 32; used 3 times

Defined union's

ihead defined in line 29; used 8 times

Defined macros

DOUBLE defined in line 421; used 2 times
INOHASH defined in line 27; used 2 times
INOHSZ defined in line 26; used 3 times
SINGLE defined in line 420; used 6 times
TRIPLE defined in line 422; used 4 times
Last modified: 1997-02-07
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 5407
Valid CSS Valid XHTML 1.0 Strict