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