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