more fixes: write boot block if writing, not editing;
[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 *
609e7cfa 6 * @(#)ffs_inode.c 7.2 (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
ec67a3ce
MK
188#ifdef SECSIZE
189 bp = bread(dev, fsbtodb(fs, itod(fs, ino)), (int)fs->fs_bsize,
190 fs->fs_dbsize);
191#else SECSIZE
954ce9b1 192 bp = bread(dev, fsbtodb(fs, itod(fs, ino)), (int)fs->fs_bsize);
ec67a3ce 193#endif SECSIZE
5d5124a1
BJ
194 /*
195 * Check I/O errors
196 */
7494ef16 197 if ((bp->b_flags&B_ERROR) != 0) {
5d5124a1 198 brelse(bp);
3ebac878
RE
199 /*
200 * the inode doesn't contain anything useful, so it would
201 * be misleading to leave it on its hash chain.
202 * 'iput' will take care of putting it back on the free list.
203 */
32dc2b7e 204 remque(ip);
3ebac878
RE
205 ip->i_forw = ip;
206 ip->i_back = ip;
207 /*
208 * we also loose its inumber, just in case (as iput
209 * doesn't do that any more) - but as it isn't on its
210 * hash chain, I doubt if this is really necessary .. kre
211 * (probably the two methods are interchangable)
212 */
213 ip->i_number = 0;
b4567e9c 214#ifdef QUOTA
89045c38
RE
215 ip->i_dquot = NODQUOT;
216#endif
5d5124a1
BJ
217 iput(ip);
218 return(NULL);
219 }
220 dp = bp->b_un.b_dino;
6459ebe0
KM
221 dp += itoo(fs, ino);
222 ip->i_ic = dp->di_ic;
5d5124a1 223 brelse(bp);
b4567e9c 224#ifdef QUOTA
89045c38
RE
225 if (ip->i_mode == 0)
226 ip->i_dquot = NODQUOT;
227 else
228 ip->i_dquot = inoquota(ip);
229#endif
6459ebe0 230 return (ip);
5d5124a1
BJ
231}
232
8ac1234a
SL
233/*
234 * Convert a pointer to an inode into a reference to an inode.
235 *
236 * This is basically the internal piece of iget (after the
237 * inode pointer is located) but without the test for mounted
238 * filesystems. It is caller's responsibility to check that
239 * the inode pointer is valid.
240 */
241igrab(ip)
242 register struct inode *ip;
243{
244 while ((ip->i_flag&ILOCKED) != 0) {
245 ip->i_flag |= IWANT;
246 sleep((caddr_t)ip, PINOD);
247 }
248 if (ip->i_count == 0) { /* ino on free list */
249 register struct inode *iq;
250
251 if (iq = ip->i_freef)
252 iq->i_freeb = ip->i_freeb;
253 else
254 ifreet = ip->i_freeb;
255 *ip->i_freeb = iq;
256 ip->i_freef = NULL;
257 ip->i_freeb = NULL;
258 }
259 ip->i_count++;
260 ip->i_flag |= ILOCKED;
261}
262
5d5124a1
BJ
263/*
264 * Decrement reference count of
265 * an inode structure.
266 * On the last reference,
267 * write the inode out and if necessary,
268 * truncate and deallocate the file.
269 */
270iput(ip)
7494ef16 271 register struct inode *ip;
5d5124a1 272{
ff56f48a 273
5c2ba954 274 if ((ip->i_flag & ILOCKED) == 0)
ff56f48a 275 panic("iput");
a388503d 276 IUNLOCK(ip);
ff56f48a
KM
277 irele(ip);
278}
279
280irele(ip)
281 register struct inode *ip;
282{
6459ebe0 283 int mode;
5d5124a1 284
62a3df02 285 if (ip->i_count == 1) {
5c2ba954 286 ip->i_flag |= ILOCKED;
62a3df02 287 if (ip->i_nlink <= 0 && ip->i_fs->fs_ronly == 0) {
4f083fd7 288 itrunc(ip, (u_long)0);
6459ebe0 289 mode = ip->i_mode;
5d5124a1 290 ip->i_mode = 0;
85f9cfb8 291 ip->i_rdev = 0;
5d5124a1 292 ip->i_flag |= IUPD|ICHG;
6459ebe0 293 ifree(ip, ip->i_number, mode);
b4567e9c 294#ifdef QUOTA
08d9a8ec 295 (void) chkiq(ip->i_dev, ip, ip->i_uid, 0);
89045c38
RE
296 dqrele(ip->i_dquot);
297 ip->i_dquot = NODQUOT;
298#endif
5d5124a1 299 }
3fd23f5c 300 IUPDAT(ip, &time, &time, 0);
a388503d 301 IUNLOCK(ip);
3ebac878
RE
302 ip->i_flag = 0;
303 /*
304 * Put the inode on the end of the free list.
305 * Possibly in some cases it would be better to
306 * put the inode at the head of the free list,
307 * (eg: where i_mode == 0 || i_number == 0)
308 * but I will think about that later .. kre
309 * (i_number is rarely 0 - only after an i/o error in iget,
310 * where i_mode == 0, the inode will probably be wanted
311 * again soon for an ialloc, so possibly we should keep it)
312 */
313 if (ifreeh) {
314 *ifreet = ip;
315 ip->i_freeb = ifreet;
5d5124a1 316 } else {
3ebac878
RE
317 ifreeh = ip;
318 ip->i_freeb = &ifreeh;
5d5124a1 319 }
3ebac878
RE
320 ip->i_freef = NULL;
321 ifreet = &ip->i_freef;
b33d9da4
MK
322 } else if (!(ip->i_flag & ILOCKED))
323 ITIMES(ip, &time, &time);
5d5124a1
BJ
324 ip->i_count--;
325}
326
327/*
328 * Check accessed and update flags on
329 * an inode structure.
330 * If any is on, update the inode
331 * with the current time.
c0bb1685
BJ
332 * If waitfor is given, then must insure
333 * i/o order so wait for write to complete.
5d5124a1 334 */
c0bb1685 335iupdat(ip, ta, tm, waitfor)
7494ef16 336 register struct inode *ip;
b32450f4 337 struct timeval *ta, *tm;
7494ef16 338 int waitfor;
5d5124a1
BJ
339{
340 register struct buf *bp;
341 struct dinode *dp;
ec67a3ce 342 register struct fs *fs;
5d5124a1 343
ec67a3ce 344 fs = ip->i_fs;
b33d9da4 345 if ((ip->i_flag & (IUPD|IACC|ICHG|IMOD)) != 0) {
ec67a3ce 346 if (fs->fs_ronly)
5d5124a1 347 return;
ec67a3ce
MK
348#ifdef SECSIZE
349 bp = bread(ip->i_dev, fsbtodb(fs, itod(fs, ip->i_number)),
350 (int)fs->fs_bsize, fs->fs_dbsize);
351#else SECSIZE
352 bp = bread(ip->i_dev, fsbtodb(fs, itod(fs, ip->i_number)),
353 (int)fs->fs_bsize);
354#endif SECSIZE
5d5124a1
BJ
355 if (bp->b_flags & B_ERROR) {
356 brelse(bp);
357 return;
358 }
7494ef16 359 if (ip->i_flag&IACC)
b32450f4 360 ip->i_atime = ta->tv_sec;
7494ef16 361 if (ip->i_flag&IUPD)
b32450f4 362 ip->i_mtime = tm->tv_sec;
7494ef16 363 if (ip->i_flag&ICHG)
6287e863 364 ip->i_ctime = time.tv_sec;
b33d9da4 365 ip->i_flag &= ~(IUPD|IACC|ICHG|IMOD);
ec67a3ce 366 dp = bp->b_un.b_dino + itoo(fs, ip->i_number);
c39ea692 367 dp->di_ic = ip->i_ic;
c0bb1685
BJ
368 if (waitfor)
369 bwrite(bp);
370 else
371 bdwrite(bp);
5d5124a1
BJ
372 }
373}
374
9c03b2c0
SL
375#define SINGLE 0 /* index of single indirect block */
376#define DOUBLE 1 /* index of double indirect block */
377#define TRIPLE 2 /* index of triple indirect block */
5d5124a1 378/*
528f664c
SL
379 * Truncate the inode ip to at most
380 * length size. Free affected disk
381 * blocks -- the blocks of the file
382 * are removed in reverse order.
9c03b2c0
SL
383 *
384 * NB: triple indirect blocks are untested.
5d5124a1 385 */
9c03b2c0 386itrunc(oip, length)
28821bc5 387 register struct inode *oip;
4f083fd7 388 u_long length;
5d5124a1 389{
4f083fd7 390 register daddr_t lastblock;
a5e62f37 391 daddr_t bn, lbn, lastiblock[NIADDR];
6459ebe0 392 register struct fs *fs;
9c03b2c0 393 register struct inode *ip;
28821bc5 394 struct buf *bp;
ec67a3ce 395 int offset, osize, size, count, level;
28821bc5
KM
396 long nblocks, blocksreleased = 0;
397 register int i;
398 dev_t dev;
9c03b2c0 399 struct inode tip;
28821bc5 400 extern long indirtrunc();
4f083fd7 401
7b2e4f05
SL
402 if (oip->i_size <= length) {
403 oip->i_flag |= ICHG|IUPD;
404 iupdat(oip, &time, &time, 1);
4f083fd7 405 return;
7b2e4f05 406 }
c0bb1685 407 /*
9c03b2c0
SL
408 * Calculate index into inode's block list of
409 * last direct and indirect blocks (if any)
410 * which we want to keep. Lastblock is -1 when
411 * the file is truncated to 0.
c0bb1685 412 */
9c03b2c0 413 fs = oip->i_fs;
4f083fd7 414 lastblock = lblkno(fs, length + fs->fs_bsize - 1) - 1;
9c03b2c0
SL
415 lastiblock[SINGLE] = lastblock - NDADDR;
416 lastiblock[DOUBLE] = lastiblock[SINGLE] - NINDIR(fs);
417 lastiblock[TRIPLE] = lastiblock[DOUBLE] - NINDIR(fs) * NINDIR(fs);
08d9a8ec 418 nblocks = btodb(fs->fs_bsize);
6459ebe0 419 /*
28821bc5
KM
420 * Update the size of the file. If the file is not being
421 * truncated to a block boundry, the contents of the
422 * partial block following the end of the file must be
423 * zero'ed in case it ever become accessable again because
424 * of subsequent file growth.
425 */
426 osize = oip->i_size;
427 offset = blkoff(fs, length);
428 if (offset == 0) {
429 oip->i_size = length;
430 } else {
431 lbn = lblkno(fs, length);
432 bn = fsbtodb(fs, bmap(oip, lbn, B_WRITE, offset));
433 if (u.u_error || (long)bn < 0)
434 return;
435 oip->i_size = length;
436 size = blksize(fs, oip, lbn);
ec67a3ce 437 count = howmany(size, CLBYTES);
28821bc5 438 dev = oip->i_dev;
ec67a3ce
MK
439 for (i = 0; i < count; i++)
440#ifdef SECSIZE
441 munhash(dev, bn + i * CLBYTES / fs->fs_dbsize);
442#else SECSIZE
443 munhash(dev, bn + i * CLBYTES / DEV_BSIZE);
444#endif SECSIZE
28821bc5
KM
445 bp = bread(dev, bn, size);
446 if (bp->b_flags & B_ERROR) {
447 u.u_error = EIO;
448 oip->i_size = osize;
449 brelse(bp);
450 return;
451 }
a5e62f37 452 bzero(bp->b_un.b_addr + offset, (unsigned)(size - offset));
28821bc5
KM
453 bdwrite(bp);
454 }
455 /*
456 * Update file and block pointers
9c03b2c0
SL
457 * on disk before we start freeing blocks.
458 * If we crash before free'ing blocks below,
459 * the blocks will be returned to the free list.
460 * lastiblock values are also normalized to -1
461 * for calls to indirtrunc below.
6459ebe0 462 */
9c03b2c0 463 tip = *oip;
28821bc5 464 tip.i_size = osize;
9c03b2c0
SL
465 for (level = TRIPLE; level >= SINGLE; level--)
466 if (lastiblock[level] < 0) {
467 oip->i_ib[level] = 0;
468 lastiblock[level] = -1;
4f083fd7 469 }
9c03b2c0
SL
470 for (i = NDADDR - 1; i > lastblock; i--)
471 oip->i_db[i] = 0;
9c03b2c0 472 oip->i_flag |= ICHG|IUPD;
28821bc5 473 syncip(oip);
9c03b2c0 474
6459ebe0 475 /*
9c03b2c0 476 * Indirect blocks first.
6459ebe0 477 */
28821bc5 478 ip = &tip;
9c03b2c0
SL
479 for (level = TRIPLE; level >= SINGLE; level--) {
480 bn = ip->i_ib[level];
4f083fd7 481 if (bn != 0) {
9c03b2c0 482 blocksreleased +=
08d9a8ec 483 indirtrunc(ip, bn, lastiblock[level], level);
9c03b2c0
SL
484 if (lastiblock[level] < 0) {
485 ip->i_ib[level] = 0;
486 free(ip, bn, (off_t)fs->fs_bsize);
9c03b2c0 487 blocksreleased += nblocks;
9c03b2c0
SL
488 }
489 }
490 if (lastiblock[level] >= 0)
491 goto done;
4f083fd7 492 }
9c03b2c0 493
6459ebe0 494 /*
9c03b2c0 495 * All whole direct blocks or frags.
6459ebe0 496 */
4f083fd7 497 for (i = NDADDR - 1; i > lastblock; i--) {
8011f5df 498 register off_t bsize;
4f083fd7 499
6459ebe0 500 bn = ip->i_db[i];
4f083fd7 501 if (bn == 0)
5d5124a1 502 continue;
4f083fd7 503 ip->i_db[i] = 0;
0b355a6e
JB
504 bsize = (off_t)blksize(fs, ip, i);
505 free(ip, bn, bsize);
506 blocksreleased += btodb(bsize);
4f083fd7 507 }
9c03b2c0
SL
508 if (lastblock < 0)
509 goto done;
510
4f083fd7
SL
511 /*
512 * Finally, look for a change in size of the
513 * last direct block; release any frags.
514 */
9c03b2c0
SL
515 bn = ip->i_db[lastblock];
516 if (bn != 0) {
8011f5df 517 off_t oldspace, newspace;
9c03b2c0 518
4f083fd7
SL
519 /*
520 * Calculate amount of space we're giving
521 * back as old block size minus new block size.
522 */
9c03b2c0 523 oldspace = blksize(fs, ip, lastblock);
4f083fd7 524 ip->i_size = length;
9c03b2c0
SL
525 newspace = blksize(fs, ip, lastblock);
526 if (newspace == 0)
527 panic("itrunc: newspace");
528 if (oldspace - newspace > 0) {
4f083fd7
SL
529 /*
530 * Block number of space to be free'd is
531 * the old block # plus the number of frags
532 * required for the storage we're keeping.
533 */
9c03b2c0
SL
534 bn += numfrags(fs, newspace);
535 free(ip, bn, oldspace - newspace);
08d9a8ec 536 blocksreleased += btodb(oldspace - newspace);
4f083fd7 537 }
5d5124a1 538 }
4f083fd7 539done:
9c03b2c0
SL
540/* BEGIN PARANOIA */
541 for (level = SINGLE; level <= TRIPLE; level++)
542 if (ip->i_ib[level] != oip->i_ib[level])
543 panic("itrunc1");
544 for (i = 0; i < NDADDR; i++)
545 if (ip->i_db[i] != oip->i_db[i])
546 panic("itrunc2");
547/* END PARANOIA */
08d9a8ec
SL
548 oip->i_blocks -= blocksreleased;
549 if (oip->i_blocks < 0) /* sanity */
550 oip->i_blocks = 0;
551 oip->i_flag |= ICHG;
b4567e9c 552#ifdef QUOTA
08d9a8ec 553 (void) chkdq(oip, -blocksreleased, 0);
89045c38 554#endif
5d5124a1
BJ
555}
556
4f083fd7
SL
557/*
558 * Release blocks associated with the inode ip and
559 * stored in the indirect block bn. Blocks are free'd
560 * in LIFO order up to (but not including) lastbn. If
9c03b2c0
SL
561 * level is greater than SINGLE, the block is an indirect
562 * block and recursive calls to indirtrunc must be used to
563 * cleanse other indirect blocks.
564 *
565 * NB: triple indirect blocks are untested.
4f083fd7 566 */
89045c38 567long
9c03b2c0 568indirtrunc(ip, bn, lastbn, level)
6459ebe0 569 register struct inode *ip;
4f083fd7 570 daddr_t bn, lastbn;
9c03b2c0 571 int level;
5d5124a1 572{
4f083fd7 573 register int i;
9c03b2c0 574 struct buf *bp, *copy;
5d5124a1 575 register daddr_t *bap;
9c03b2c0 576 register struct fs *fs = ip->i_fs;
4f083fd7 577 daddr_t nb, last;
9c03b2c0 578 long factor;
4f083fd7 579 int blocksreleased = 0, nblocks;
5d5124a1 580
9c03b2c0
SL
581 /*
582 * Calculate index in current block of last
583 * block to be kept. -1 indicates the entire
584 * block so we need not calculate the index.
585 */
586 factor = 1;
587 for (i = SINGLE; i < level; i++)
588 factor *= NINDIR(fs);
4f083fd7 589 last = lastbn;
9c03b2c0
SL
590 if (lastbn > 0)
591 last /= factor;
08d9a8ec 592 nblocks = btodb(fs->fs_bsize);
9c03b2c0
SL
593 /*
594 * Get buffer of block pointers, zero those
595 * entries corresponding to blocks to be free'd,
596 * and update on disk copy first.
597 */
598 copy = geteblk((int)fs->fs_bsize);
ec67a3ce
MK
599#ifdef SECSIZE
600 bp = bread(ip->i_dev, fsbtodb(fs, bn), (int)fs->fs_bsize,
601 fs->fs_dbsize);
602#else SECSIZE
9c03b2c0 603 bp = bread(ip->i_dev, fsbtodb(fs, bn), (int)fs->fs_bsize);
ec67a3ce 604#endif SECSIZE
9c03b2c0
SL
605 if (bp->b_flags&B_ERROR) {
606 brelse(copy);
607 brelse(bp);
9c03b2c0 608 return (0);
9c03b2c0
SL
609 }
610 bap = bp->b_un.b_daddr;
611 bcopy((caddr_t)bap, (caddr_t)copy->b_un.b_daddr, (u_int)fs->fs_bsize);
612 bzero((caddr_t)&bap[last + 1],
613 (u_int)(NINDIR(fs) - (last + 1)) * sizeof (daddr_t));
614 bwrite(bp);
615 bp = copy, bap = bp->b_un.b_daddr;
4f083fd7 616
9c03b2c0
SL
617 /*
618 * Recursively free totally unused blocks.
619 */
620 for (i = NINDIR(fs) - 1; i > last; i--) {
5d5124a1 621 nb = bap[i];
4f083fd7 622 if (nb == 0)
5d5124a1 623 continue;
9c03b2c0 624 if (level > SINGLE)
4f083fd7 625 blocksreleased +=
08d9a8ec 626 indirtrunc(ip, nb, (daddr_t)-1, level - 1);
8011f5df 627 free(ip, nb, (off_t)fs->fs_bsize);
4f083fd7 628 blocksreleased += nblocks;
4f083fd7 629 }
9c03b2c0
SL
630
631 /*
632 * Recursively free last partial block.
633 */
634 if (level > SINGLE && lastbn >= 0) {
635 last = lastbn % factor;
4f083fd7
SL
636 nb = bap[i];
637 if (nb != 0)
08d9a8ec 638 blocksreleased += indirtrunc(ip, nb, last, level - 1);
5d5124a1 639 }
9c03b2c0 640 brelse(bp);
4f083fd7 641 return (blocksreleased);
5d5124a1
BJ
642}
643
3ebac878 644/*
ec67a3ce 645 * Remove any inodes in the inode cache belonging to dev.
3ebac878
RE
646 *
647 * There should not be any active ones, return error if any are found
ec67a3ce 648 * (nb: this is a user error, not a system err).
3ebac878 649 */
b4567e9c 650#ifdef QUOTA
4147b3f6 651iflush(dev, iq)
89045c38 652 dev_t dev;
4147b3f6 653 struct inode *iq;
89045c38 654#else
3ebac878
RE
655iflush(dev)
656 dev_t dev;
89045c38 657#endif
3ebac878 658{
32dc2b7e 659 register struct inode *ip;
3ebac878
RE
660
661 for (ip = inode; ip < inodeNINODE; ip++) {
b4567e9c 662#ifdef QUOTA
89045c38
RE
663 if (ip != iq && ip->i_dev == dev)
664#else
3ebac878 665 if (ip->i_dev == dev)
89045c38 666#endif
3ebac878 667 if (ip->i_count)
ec67a3ce 668 return (EBUSY);
3ebac878 669 else {
32dc2b7e 670 remque(ip);
3ebac878
RE
671 ip->i_forw = ip;
672 ip->i_back = ip;
673 /*
674 * as i_count == 0, the inode was on the free
675 * list already, just leave it there, it will
676 * fall off the bottom eventually. We could
677 * perhaps move it to the head of the free
678 * list, but as umounts are done so
679 * infrequently, we would gain very little,
680 * while making the code bigger.
681 */
b4567e9c 682#ifdef QUOTA
89045c38
RE
683 dqrele(ip->i_dquot);
684 ip->i_dquot = NODQUOT;
685#endif
3ebac878 686 }
3ebac878 687 }
ec67a3ce 688 return (0);
3ebac878
RE
689}
690
d6a210b8 691/*
7494ef16 692 * Lock an inode. If its already locked, set the WANT bit and sleep.
d6a210b8 693 */
7494ef16
BJ
694ilock(ip)
695 register struct inode *ip;
d6a210b8
BJ
696{
697
5c2ba954 698 ILOCK(ip);
d6a210b8
BJ
699}
700
701/*
7494ef16 702 * Unlock an inode. If WANT bit is on, wakeup.
d6a210b8 703 */
ff56f48a 704iunlock(ip)
7494ef16 705 register struct inode *ip;
d6a210b8
BJ
706{
707
5c2ba954 708 IUNLOCK(ip);
d6a210b8 709}