add macro `cacheinval' to purge stale entries in the inode table
[unix-history] / usr / src / sys / ufs / lfs / lfs_inode.c
CommitLineData
bed1bb6e 1/* lfs_inode.c 6.8 84/07/15 */
5d5124a1
BJ
2
3#include "../h/param.h"
4#include "../h/systm.h"
5#include "../h/mount.h"
6#include "../h/dir.h"
7#include "../h/user.h"
8#include "../h/inode.h"
6459ebe0 9#include "../h/fs.h"
5d5124a1
BJ
10#include "../h/conf.h"
11#include "../h/buf.h"
b4567e9c 12#ifdef QUOTA
4147b3f6
BJ
13#include "../h/quota.h"
14#endif
3e63ef5b 15#include "../h/kernel.h"
5d5124a1 16
4da9d052 17#define INOHSZ 64
3ebac878
RE
18#if ((INOHSZ&(INOHSZ-1)) == 0)
19#define INOHASH(dev,ino) (((dev)+(ino))&(INOHSZ-1))
20#else
a3a9487d 21#define INOHASH(dev,ino) (((unsigned)((dev)+(ino)))%INOHSZ)
3ebac878
RE
22#endif
23
24union ihead { /* inode LRU cache, Chris Maltby */
25 union ihead *ih_head[2];
26 struct inode *ih_chain[2];
27} ihead[INOHSZ];
28
29struct inode *ifreeh, **ifreet;
5d5124a1
BJ
30
31/*
32 * Initialize hash links for inodes
33 * and build inode free list.
34 */
35ihinit()
36{
37 register int i;
75105cf0 38 register struct inode *ip = inode;
3ebac878 39 register union ihead *ih = ihead;
5d5124a1 40
3ebac878
RE
41 for (i = INOHSZ; --i >= 0; ih++) {
42 ih->ih_head[0] = ih;
43 ih->ih_head[1] = ih;
44 }
45 ifreeh = ip;
46 ifreet = &ip->i_freef;
47 ip->i_freeb = &ifreeh;
48 ip->i_forw = ip;
49 ip->i_back = ip;
50 for (i = ninode; --i > 0; ) {
51 ++ip;
52 ip->i_forw = ip;
53 ip->i_back = ip;
54 *ifreet = ip;
55 ip->i_freeb = ifreet;
56 ifreet = &ip->i_freef;
57 }
58 ip->i_freef = NULL;
5d5124a1
BJ
59}
60
3ebac878
RE
61#ifdef notdef
62/*
63 * Find an inode if it is incore.
64 * This is the equivalent, for inodes,
65 * of ``incore'' in bio.c or ``pfind'' in subr.c.
66 */
67struct inode *
68ifind(dev, ino)
69 dev_t dev;
70 ino_t ino;
71{
72 register struct inode *ip;
73 register union ihead *ih;
74
75 ih = &ihead[INOHASH(dev, ino)];
76 for (ip = ih->ih_chain[0]; ip != (struct inode *)ih; ip = ip->i_forw)
77 if (ino==ip->i_number && dev==ip->i_dev)
78 return (ip);
79 return ((struct inode *)0);
80}
81#endif notdef
82
5d5124a1
BJ
83/*
84 * Look up an inode by device,inumber.
85 * If it is in core (in the inode structure),
86 * honor the locking protocol.
87 * If it is not in core, read it in from the
88 * specified device.
89 * If the inode is mounted on, perform
90 * the indicated indirection.
91 * In all cases, a pointer to a locked
92 * inode structure is returned.
93 *
5d5124a1
BJ
94 * panic: no imt -- if the mounted file
95 * system is not in the mount table.
96 * "cannot happen"
97 */
98struct inode *
6459ebe0 99iget(dev, fs, ino)
7494ef16 100 dev_t dev;
6459ebe0 101 register struct fs *fs;
7494ef16 102 ino_t ino;
5d5124a1 103{
32dc2b7e
RE
104 register struct inode *ip;
105 register union ihead *ih;
5d5124a1
BJ
106 register struct mount *mp;
107 register struct buf *bp;
108 register struct dinode *dp;
3ebac878 109 register struct inode *iq;
2e64ab65
KM
110 struct inode *xp;
111
5d5124a1
BJ
112
113loop:
3ebac878
RE
114 ih = &ihead[INOHASH(dev, ino)];
115 for (ip = ih->ih_chain[0]; ip != (struct inode *)ih; ip = ip->i_forw)
7494ef16 116 if (ino == ip->i_number && dev == ip->i_dev) {
8ac1234a
SL
117 /*
118 * Following is essentially an inline expanded
119 * copy of igrab(), expanded inline for speed,
120 * and so that the test for a mounted on inode
121 * can be deferred until after we are sure that
122 * the inode isn't busy.
123 */
5c2ba954 124 if ((ip->i_flag&ILOCKED) != 0) {
5d5124a1
BJ
125 ip->i_flag |= IWANT;
126 sleep((caddr_t)ip, PINOD);
127 goto loop;
128 }
7494ef16 129 if ((ip->i_flag&IMOUNT) != 0) {
6459ebe0 130 for (mp = &mount[0]; mp < &mount[NMOUNT]; mp++)
3ebac878
RE
131 if(mp->m_inodp == ip) {
132 dev = mp->m_dev;
133 fs = mp->m_bufp->b_un.b_fs;
134 ino = ROOTINO;
135 goto loop;
136 }
5d5124a1
BJ
137 panic("no imt");
138 }
3ebac878
RE
139 if (ip->i_count == 0) { /* ino on free list */
140 if (iq = ip->i_freef)
141 iq->i_freeb = ip->i_freeb;
142 else
143 ifreet = ip->i_freeb;
144 *ip->i_freeb = iq;
145 ip->i_freef = NULL;
146 ip->i_freeb = NULL;
147 }
5d5124a1 148 ip->i_count++;
5c2ba954 149 ip->i_flag |= ILOCKED;
5d5124a1
BJ
150 return(ip);
151 }
3ebac878
RE
152
153 if ((ip = ifreeh) == NULL) {
945fbb1b 154 tablefull("inode");
5d5124a1
BJ
155 u.u_error = ENFILE;
156 return(NULL);
157 }
bed1bb6e
MK
158 if (ip->i_count)
159 panic("free inode isn't");
3ebac878
RE
160 if (iq = ip->i_freef)
161 iq->i_freeb = &ifreeh;
162 ifreeh = iq;
163 ip->i_freef = NULL;
164 ip->i_freeb = NULL;
165 /*
166 * Now to take inode off the hash chain it was on
167 * (initially, or after an iflush, it is on a "hash chain"
168 * consisting entirely of itself, and pointed to by no-one,
169 * but that doesn't matter), and put it on the chain for
170 * its new (ino, dev) pair
171 */
32dc2b7e
RE
172 remque(ip);
173 insque(ip, ih);
5d5124a1 174 ip->i_dev = dev;
6459ebe0 175 ip->i_fs = fs;
5d5124a1 176 ip->i_number = ino;
8ac1234a
SL
177 ip->i_id = ++nextinodeid; /* also used in rename */
178 /*
179 * At an absurd rate of 100 calls/second,
2e64ab65 180 * this should occur once every 8 months.
8ac1234a 181 */
2e64ab65
KM
182 if (nextinodeid < 0)
183 for (nextinodeid = 0, xp = inode; xp < inodeNINODE; xp++)
184 xp->i_id = 0;
5c2ba954 185 ip->i_flag = ILOCKED;
5d5124a1 186 ip->i_count++;
6459ebe0 187 ip->i_lastr = 0;
bed1bb6e
MK
188#ifdef QUOTA
189 dqrele(ip->i_dquot);
190#endif
954ce9b1 191 bp = bread(dev, fsbtodb(fs, itod(fs, ino)), (int)fs->fs_bsize);
5d5124a1
BJ
192 /*
193 * Check I/O errors
194 */
7494ef16 195 if ((bp->b_flags&B_ERROR) != 0) {
5d5124a1 196 brelse(bp);
3ebac878
RE
197 /*
198 * the inode doesn't contain anything useful, so it would
199 * be misleading to leave it on its hash chain.
200 * 'iput' will take care of putting it back on the free list.
201 */
32dc2b7e 202 remque(ip);
3ebac878
RE
203 ip->i_forw = ip;
204 ip->i_back = ip;
205 /*
206 * we also loose its inumber, just in case (as iput
207 * doesn't do that any more) - but as it isn't on its
208 * hash chain, I doubt if this is really necessary .. kre
209 * (probably the two methods are interchangable)
210 */
211 ip->i_number = 0;
b4567e9c 212#ifdef QUOTA
89045c38
RE
213 ip->i_dquot = NODQUOT;
214#endif
5d5124a1
BJ
215 iput(ip);
216 return(NULL);
217 }
218 dp = bp->b_un.b_dino;
6459ebe0
KM
219 dp += itoo(fs, ino);
220 ip->i_ic = dp->di_ic;
5d5124a1 221 brelse(bp);
b4567e9c 222#ifdef QUOTA
89045c38
RE
223 if (ip->i_mode == 0)
224 ip->i_dquot = NODQUOT;
225 else
226 ip->i_dquot = inoquota(ip);
227#endif
6459ebe0 228 return (ip);
5d5124a1
BJ
229}
230
8ac1234a
SL
231/*
232 * Convert a pointer to an inode into a reference to an inode.
233 *
234 * This is basically the internal piece of iget (after the
235 * inode pointer is located) but without the test for mounted
236 * filesystems. It is caller's responsibility to check that
237 * the inode pointer is valid.
238 */
239igrab(ip)
240 register struct inode *ip;
241{
242 while ((ip->i_flag&ILOCKED) != 0) {
243 ip->i_flag |= IWANT;
244 sleep((caddr_t)ip, PINOD);
245 }
246 if (ip->i_count == 0) { /* ino on free list */
247 register struct inode *iq;
248
249 if (iq = ip->i_freef)
250 iq->i_freeb = ip->i_freeb;
251 else
252 ifreet = ip->i_freeb;
253 *ip->i_freeb = iq;
254 ip->i_freef = NULL;
255 ip->i_freeb = NULL;
256 }
257 ip->i_count++;
258 ip->i_flag |= ILOCKED;
259}
260
5d5124a1
BJ
261/*
262 * Decrement reference count of
263 * an inode structure.
264 * On the last reference,
265 * write the inode out and if necessary,
266 * truncate and deallocate the file.
267 */
268iput(ip)
7494ef16 269 register struct inode *ip;
5d5124a1 270{
ff56f48a 271
5c2ba954 272 if ((ip->i_flag & ILOCKED) == 0)
ff56f48a 273 panic("iput");
a388503d 274 IUNLOCK(ip);
ff56f48a
KM
275 irele(ip);
276}
277
278irele(ip)
279 register struct inode *ip;
280{
6459ebe0 281 int mode;
5d5124a1 282
7494ef16 283 if (ip->i_count == 1) {
5c2ba954 284 ip->i_flag |= ILOCKED;
7494ef16 285 if (ip->i_nlink <= 0) {
4f083fd7 286 itrunc(ip, (u_long)0);
6459ebe0 287 mode = ip->i_mode;
5d5124a1 288 ip->i_mode = 0;
85f9cfb8 289 ip->i_rdev = 0;
5d5124a1 290 ip->i_flag |= IUPD|ICHG;
6459ebe0 291 ifree(ip, ip->i_number, mode);
b4567e9c 292#ifdef QUOTA
08d9a8ec 293 (void) chkiq(ip->i_dev, ip, ip->i_uid, 0);
89045c38
RE
294 dqrele(ip->i_dquot);
295 ip->i_dquot = NODQUOT;
296#endif
5d5124a1 297 }
3fd23f5c 298 IUPDAT(ip, &time, &time, 0);
a388503d 299 IUNLOCK(ip);
3ebac878
RE
300 ip->i_flag = 0;
301 /*
302 * Put the inode on the end of the free list.
303 * Possibly in some cases it would be better to
304 * put the inode at the head of the free list,
305 * (eg: where i_mode == 0 || i_number == 0)
306 * but I will think about that later .. kre
307 * (i_number is rarely 0 - only after an i/o error in iget,
308 * where i_mode == 0, the inode will probably be wanted
309 * again soon for an ialloc, so possibly we should keep it)
310 */
311 if (ifreeh) {
312 *ifreet = ip;
313 ip->i_freeb = ifreet;
5d5124a1 314 } else {
3ebac878
RE
315 ifreeh = ip;
316 ip->i_freeb = &ifreeh;
5d5124a1 317 }
3ebac878
RE
318 ip->i_freef = NULL;
319 ifreet = &ip->i_freef;
b33d9da4
MK
320 } else if (!(ip->i_flag & ILOCKED))
321 ITIMES(ip, &time, &time);
5d5124a1
BJ
322 ip->i_count--;
323}
324
325/*
326 * Check accessed and update flags on
327 * an inode structure.
328 * If any is on, update the inode
329 * with the current time.
c0bb1685
BJ
330 * If waitfor is given, then must insure
331 * i/o order so wait for write to complete.
5d5124a1 332 */
c0bb1685 333iupdat(ip, ta, tm, waitfor)
7494ef16 334 register struct inode *ip;
b32450f4 335 struct timeval *ta, *tm;
7494ef16 336 int waitfor;
5d5124a1
BJ
337{
338 register struct buf *bp;
339 struct dinode *dp;
6459ebe0 340 register struct fs *fp;
5d5124a1 341
6459ebe0 342 fp = ip->i_fs;
b33d9da4 343 if ((ip->i_flag & (IUPD|IACC|ICHG|IMOD)) != 0) {
6459ebe0 344 if (fp->fs_ronly)
5d5124a1 345 return;
6459ebe0 346 bp = bread(ip->i_dev, fsbtodb(fp, itod(fp, ip->i_number)),
954ce9b1 347 (int)fp->fs_bsize);
5d5124a1
BJ
348 if (bp->b_flags & B_ERROR) {
349 brelse(bp);
350 return;
351 }
7494ef16 352 if (ip->i_flag&IACC)
b32450f4 353 ip->i_atime = ta->tv_sec;
7494ef16 354 if (ip->i_flag&IUPD)
b32450f4 355 ip->i_mtime = tm->tv_sec;
7494ef16 356 if (ip->i_flag&ICHG)
3e63ef5b 357 ip->i_ctime = time.tv_sec;
b33d9da4 358 ip->i_flag &= ~(IUPD|IACC|ICHG|IMOD);
c39ea692
RE
359 dp = bp->b_un.b_dino + itoo(fp, ip->i_number);
360 dp->di_ic = ip->i_ic;
c0bb1685
BJ
361 if (waitfor)
362 bwrite(bp);
363 else
364 bdwrite(bp);
5d5124a1
BJ
365 }
366}
367
9c03b2c0
SL
368#define SINGLE 0 /* index of single indirect block */
369#define DOUBLE 1 /* index of double indirect block */
370#define TRIPLE 2 /* index of triple indirect block */
5d5124a1 371/*
528f664c
SL
372 * Truncate the inode ip to at most
373 * length size. Free affected disk
374 * blocks -- the blocks of the file
375 * are removed in reverse order.
9c03b2c0
SL
376 *
377 * NB: triple indirect blocks are untested.
5d5124a1 378 */
9c03b2c0
SL
379itrunc(oip, length)
380 struct inode *oip;
4f083fd7 381 u_long length;
5d5124a1
BJ
382{
383 register i;
4f083fd7 384 register daddr_t lastblock;
9c03b2c0 385 daddr_t bn, lastiblock[NIADDR];
6459ebe0 386 register struct fs *fs;
9c03b2c0
SL
387 register struct inode *ip;
388 struct inode tip;
4f083fd7
SL
389 long blocksreleased = 0, nblocks;
390 long indirtrunc();
08d9a8ec 391 int level;
4f083fd7 392
7b2e4f05
SL
393 if (oip->i_size <= length) {
394 oip->i_flag |= ICHG|IUPD;
395 iupdat(oip, &time, &time, 1);
4f083fd7 396 return;
7b2e4f05 397 }
c0bb1685 398 /*
9c03b2c0
SL
399 * Calculate index into inode's block list of
400 * last direct and indirect blocks (if any)
401 * which we want to keep. Lastblock is -1 when
402 * the file is truncated to 0.
c0bb1685 403 */
9c03b2c0 404 fs = oip->i_fs;
4f083fd7 405 lastblock = lblkno(fs, length + fs->fs_bsize - 1) - 1;
9c03b2c0
SL
406 lastiblock[SINGLE] = lastblock - NDADDR;
407 lastiblock[DOUBLE] = lastiblock[SINGLE] - NINDIR(fs);
408 lastiblock[TRIPLE] = lastiblock[DOUBLE] - NINDIR(fs) * NINDIR(fs);
08d9a8ec 409 nblocks = btodb(fs->fs_bsize);
6459ebe0 410 /*
9c03b2c0
SL
411 * Update size of file and block pointers
412 * on disk before we start freeing blocks.
413 * If we crash before free'ing blocks below,
414 * the blocks will be returned to the free list.
415 * lastiblock values are also normalized to -1
416 * for calls to indirtrunc below.
417 * (? fsck doesn't check validity of pointers in indirect blocks)
6459ebe0 418 */
9c03b2c0
SL
419 tip = *oip;
420 for (level = TRIPLE; level >= SINGLE; level--)
421 if (lastiblock[level] < 0) {
422 oip->i_ib[level] = 0;
423 lastiblock[level] = -1;
4f083fd7 424 }
9c03b2c0
SL
425 for (i = NDADDR - 1; i > lastblock; i--)
426 oip->i_db[i] = 0;
427 oip->i_size = length;
428 oip->i_flag |= ICHG|IUPD;
429 iupdat(oip, &time, &time, 1);
430 ip = &tip;
431
6459ebe0 432 /*
9c03b2c0 433 * Indirect blocks first.
6459ebe0 434 */
9c03b2c0
SL
435 for (level = TRIPLE; level >= SINGLE; level--) {
436 bn = ip->i_ib[level];
4f083fd7 437 if (bn != 0) {
9c03b2c0 438 blocksreleased +=
08d9a8ec 439 indirtrunc(ip, bn, lastiblock[level], level);
9c03b2c0
SL
440 if (lastiblock[level] < 0) {
441 ip->i_ib[level] = 0;
442 free(ip, bn, (off_t)fs->fs_bsize);
9c03b2c0 443 blocksreleased += nblocks;
9c03b2c0
SL
444 }
445 }
446 if (lastiblock[level] >= 0)
447 goto done;
4f083fd7 448 }
9c03b2c0 449
6459ebe0 450 /*
9c03b2c0 451 * All whole direct blocks or frags.
6459ebe0 452 */
4f083fd7
SL
453 for (i = NDADDR - 1; i > lastblock; i--) {
454 register int size;
455
6459ebe0 456 bn = ip->i_db[i];
4f083fd7 457 if (bn == 0)
5d5124a1 458 continue;
4f083fd7
SL
459 ip->i_db[i] = 0;
460 size = (off_t)blksize(fs, ip, i);
461 free(ip, bn, size);
08d9a8ec 462 blocksreleased += btodb(size);
4f083fd7 463 }
9c03b2c0
SL
464 if (lastblock < 0)
465 goto done;
466
4f083fd7
SL
467 /*
468 * Finally, look for a change in size of the
469 * last direct block; release any frags.
470 */
9c03b2c0
SL
471 bn = ip->i_db[lastblock];
472 if (bn != 0) {
473 int oldspace, newspace;
474
4f083fd7
SL
475 /*
476 * Calculate amount of space we're giving
477 * back as old block size minus new block size.
478 */
9c03b2c0 479 oldspace = blksize(fs, ip, lastblock);
4f083fd7 480 ip->i_size = length;
9c03b2c0
SL
481 newspace = blksize(fs, ip, lastblock);
482 if (newspace == 0)
483 panic("itrunc: newspace");
484 if (oldspace - newspace > 0) {
4f083fd7
SL
485 /*
486 * Block number of space to be free'd is
487 * the old block # plus the number of frags
488 * required for the storage we're keeping.
489 */
9c03b2c0
SL
490 bn += numfrags(fs, newspace);
491 free(ip, bn, oldspace - newspace);
08d9a8ec 492 blocksreleased += btodb(oldspace - newspace);
4f083fd7 493 }
5d5124a1 494 }
4f083fd7 495done:
9c03b2c0
SL
496/* BEGIN PARANOIA */
497 for (level = SINGLE; level <= TRIPLE; level++)
498 if (ip->i_ib[level] != oip->i_ib[level])
499 panic("itrunc1");
500 for (i = 0; i < NDADDR; i++)
501 if (ip->i_db[i] != oip->i_db[i])
502 panic("itrunc2");
503/* END PARANOIA */
08d9a8ec
SL
504 oip->i_blocks -= blocksreleased;
505 if (oip->i_blocks < 0) /* sanity */
506 oip->i_blocks = 0;
507 oip->i_flag |= ICHG;
b4567e9c 508#ifdef QUOTA
08d9a8ec 509 (void) chkdq(oip, -blocksreleased, 0);
89045c38 510#endif
5d5124a1
BJ
511}
512
4f083fd7
SL
513/*
514 * Release blocks associated with the inode ip and
515 * stored in the indirect block bn. Blocks are free'd
516 * in LIFO order up to (but not including) lastbn. If
9c03b2c0
SL
517 * level is greater than SINGLE, the block is an indirect
518 * block and recursive calls to indirtrunc must be used to
519 * cleanse other indirect blocks.
520 *
521 * NB: triple indirect blocks are untested.
4f083fd7 522 */
89045c38 523long
9c03b2c0 524indirtrunc(ip, bn, lastbn, level)
6459ebe0 525 register struct inode *ip;
4f083fd7 526 daddr_t bn, lastbn;
9c03b2c0 527 int level;
5d5124a1 528{
4f083fd7 529 register int i;
9c03b2c0 530 struct buf *bp, *copy;
5d5124a1 531 register daddr_t *bap;
9c03b2c0 532 register struct fs *fs = ip->i_fs;
4f083fd7 533 daddr_t nb, last;
9c03b2c0 534 long factor;
4f083fd7 535 int blocksreleased = 0, nblocks;
5d5124a1 536
9c03b2c0
SL
537 /*
538 * Calculate index in current block of last
539 * block to be kept. -1 indicates the entire
540 * block so we need not calculate the index.
541 */
542 factor = 1;
543 for (i = SINGLE; i < level; i++)
544 factor *= NINDIR(fs);
4f083fd7 545 last = lastbn;
9c03b2c0
SL
546 if (lastbn > 0)
547 last /= factor;
08d9a8ec 548 nblocks = btodb(fs->fs_bsize);
9c03b2c0
SL
549 /*
550 * Get buffer of block pointers, zero those
551 * entries corresponding to blocks to be free'd,
552 * and update on disk copy first.
553 */
554 copy = geteblk((int)fs->fs_bsize);
555 bp = bread(ip->i_dev, fsbtodb(fs, bn), (int)fs->fs_bsize);
556 if (bp->b_flags&B_ERROR) {
557 brelse(copy);
558 brelse(bp);
9c03b2c0 559 return (0);
9c03b2c0
SL
560 }
561 bap = bp->b_un.b_daddr;
562 bcopy((caddr_t)bap, (caddr_t)copy->b_un.b_daddr, (u_int)fs->fs_bsize);
563 bzero((caddr_t)&bap[last + 1],
564 (u_int)(NINDIR(fs) - (last + 1)) * sizeof (daddr_t));
565 bwrite(bp);
566 bp = copy, bap = bp->b_un.b_daddr;
4f083fd7 567
9c03b2c0
SL
568 /*
569 * Recursively free totally unused blocks.
570 */
571 for (i = NINDIR(fs) - 1; i > last; i--) {
5d5124a1 572 nb = bap[i];
4f083fd7 573 if (nb == 0)
5d5124a1 574 continue;
9c03b2c0 575 if (level > SINGLE)
4f083fd7 576 blocksreleased +=
08d9a8ec 577 indirtrunc(ip, nb, (daddr_t)-1, level - 1);
4f083fd7 578 free(ip, nb, (int)fs->fs_bsize);
4f083fd7 579 blocksreleased += nblocks;
4f083fd7 580 }
9c03b2c0
SL
581
582 /*
583 * Recursively free last partial block.
584 */
585 if (level > SINGLE && lastbn >= 0) {
586 last = lastbn % factor;
4f083fd7
SL
587 nb = bap[i];
588 if (nb != 0)
08d9a8ec 589 blocksreleased += indirtrunc(ip, nb, last, level - 1);
5d5124a1 590 }
9c03b2c0 591 brelse(bp);
4f083fd7 592 return (blocksreleased);
5d5124a1
BJ
593}
594
3ebac878
RE
595/*
596 * remove any inodes in the inode cache belonging to dev
597 *
598 * There should not be any active ones, return error if any are found
599 * (nb: this is a user error, not a system err)
600 *
601 * Also, count the references to dev by block devices - this really
602 * has nothing to do with the object of the procedure, but as we have
603 * to scan the inode table here anyway, we might as well get the
604 * extra benefit.
605 *
606 * this is called from sumount()/sys3.c when dev is being unmounted
607 */
b4567e9c 608#ifdef QUOTA
4147b3f6 609iflush(dev, iq)
89045c38 610 dev_t dev;
4147b3f6 611 struct inode *iq;
89045c38 612#else
3ebac878
RE
613iflush(dev)
614 dev_t dev;
89045c38 615#endif
3ebac878 616{
32dc2b7e 617 register struct inode *ip;
3ebac878
RE
618 register open = 0;
619
620 for (ip = inode; ip < inodeNINODE; ip++) {
b4567e9c 621#ifdef QUOTA
89045c38
RE
622 if (ip != iq && ip->i_dev == dev)
623#else
3ebac878 624 if (ip->i_dev == dev)
89045c38 625#endif
3ebac878
RE
626 if (ip->i_count)
627 return(-1);
628 else {
32dc2b7e 629 remque(ip);
3ebac878
RE
630 ip->i_forw = ip;
631 ip->i_back = ip;
632 /*
633 * as i_count == 0, the inode was on the free
634 * list already, just leave it there, it will
635 * fall off the bottom eventually. We could
636 * perhaps move it to the head of the free
637 * list, but as umounts are done so
638 * infrequently, we would gain very little,
639 * while making the code bigger.
640 */
b4567e9c 641#ifdef QUOTA
89045c38
RE
642 dqrele(ip->i_dquot);
643 ip->i_dquot = NODQUOT;
644#endif
3ebac878
RE
645 }
646 else if (ip->i_count && (ip->i_mode&IFMT)==IFBLK &&
647 ip->i_rdev == dev)
648 open++;
649 }
650 return (open);
651}
652
d6a210b8 653/*
7494ef16 654 * Lock an inode. If its already locked, set the WANT bit and sleep.
d6a210b8 655 */
7494ef16
BJ
656ilock(ip)
657 register struct inode *ip;
d6a210b8
BJ
658{
659
5c2ba954 660 ILOCK(ip);
d6a210b8
BJ
661}
662
663/*
7494ef16 664 * Unlock an inode. If WANT bit is on, wakeup.
d6a210b8 665 */
ff56f48a 666iunlock(ip)
7494ef16 667 register struct inode *ip;
d6a210b8
BJ
668{
669
5c2ba954 670 IUNLOCK(ip);
d6a210b8 671}