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: }