try to flush all inodes when unmounting;
[unix-history] / usr / src / sys / ufs / lfs / lfs_inode.c
CommitLineData
da7c5cc6 1/*
7188ac27
KM
2 * Copyright (c) 1982, 1986, 1989 Regents of the University of California.
3 * All rights reserved.
da7c5cc6 4 *
7188ac27
KM
5 * Redistribution and use in source and binary forms are permitted
6 * provided that the above copyright notice and this paragraph are
7 * duplicated in all such forms and that any documentation,
8 * advertising materials, and other materials related to such
9 * distribution and use acknowledge that the software was developed
10 * by the University of California, Berkeley. The name of the
11 * University may not be used to endorse or promote products derived
12 * from this software without specific prior written permission.
13 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
16 *
0d73cd0c 17 * @(#)lfs_inode.c 7.13 (Berkeley) %G%
da7c5cc6 18 */
5d5124a1 19
94368568
JB
20#include "param.h"
21#include "systm.h"
22#include "mount.h"
94368568 23#include "user.h"
7188ac27 24#include "file.h"
94368568 25#include "buf.h"
0b355a6e 26#include "cmap.h"
7188ac27
KM
27#include "vnode.h"
28#include "../ufs/inode.h"
29#include "../ufs/fs.h"
30#include "../ufs/ufsmount.h"
b4567e9c 31#ifdef QUOTA
7188ac27 32#include "../ufs/quota.h"
4147b3f6 33#endif
94368568 34#include "kernel.h"
b30358ab 35#include "malloc.h"
5d5124a1 36
c22c66ff 37#define INOHSZ 512
3ebac878
RE
38#if ((INOHSZ&(INOHSZ-1)) == 0)
39#define INOHASH(dev,ino) (((dev)+(ino))&(INOHSZ-1))
40#else
a3a9487d 41#define INOHASH(dev,ino) (((unsigned)((dev)+(ino)))%INOHSZ)
3ebac878
RE
42#endif
43
7188ac27
KM
44#define INSFREE(ip) {\
45 if (ifreeh) { \
46 *ifreet = (ip); \
47 (ip)->i_freeb = ifreet; \
48 } else { \
49 ifreeh = (ip); \
50 (ip)->i_freeb = &ifreeh; \
51 } \
52 (ip)->i_freef = NULL; \
53 ifreet = &(ip)->i_freef; \
54}
55
3ebac878
RE
56union ihead { /* inode LRU cache, Chris Maltby */
57 union ihead *ih_head[2];
58 struct inode *ih_chain[2];
59} ihead[INOHSZ];
60
7188ac27 61struct inode *ifreeh, **ifreet, *bdevlisth;
5d5124a1
BJ
62
63/*
64 * Initialize hash links for inodes
65 * and build inode free list.
66 */
67ihinit()
68{
69 register int i;
75105cf0 70 register struct inode *ip = inode;
3ebac878 71 register union ihead *ih = ihead;
5d5124a1 72
3ebac878
RE
73 for (i = INOHSZ; --i >= 0; ih++) {
74 ih->ih_head[0] = ih;
75 ih->ih_head[1] = ih;
76 }
77 ifreeh = ip;
78 ifreet = &ip->i_freef;
79 ip->i_freeb = &ifreeh;
80 ip->i_forw = ip;
81 ip->i_back = ip;
7188ac27 82 ITOV(ip)->v_data = (qaddr_t)ip;
3ebac878
RE
83 for (i = ninode; --i > 0; ) {
84 ++ip;
85 ip->i_forw = ip;
86 ip->i_back = ip;
7188ac27 87 ITOV(ip)->v_data = (qaddr_t)ip;
3ebac878
RE
88 *ifreet = ip;
89 ip->i_freeb = ifreet;
90 ifreet = &ip->i_freef;
91 }
92 ip->i_freef = NULL;
5d5124a1
BJ
93}
94
3ebac878 95/*
7188ac27 96 * Look up an vnode/inode by device,inumber.
5d5124a1
BJ
97 * If it is in core (in the inode structure),
98 * honor the locking protocol.
99 * If it is not in core, read it in from the
100 * specified device.
7188ac27 101 * Callers must check for mount points!!
5d5124a1
BJ
102 * In all cases, a pointer to a locked
103 * inode structure is returned.
5d5124a1 104 */
7188ac27
KM
105iget(xp, ino, ipp)
106 struct inode *xp;
7494ef16 107 ino_t ino;
7188ac27 108 struct inode **ipp;
5d5124a1 109{
7188ac27
KM
110 dev_t dev = xp->i_dev;
111 struct mount *mntp = ITOV(xp)->v_mount;
112 register struct fs *fs = VFSTOUFS(mntp)->um_fs;
113 register struct inode *ip, *iq;
114 register struct vnode *vp;
115 struct inode *nip;
116 struct buf *bp;
117 struct dinode tdip, *dp;
118 union ihead *ih;
119 int error;
2e64ab65 120
5d5124a1 121loop:
3ebac878
RE
122 ih = &ihead[INOHASH(dev, ino)];
123 for (ip = ih->ih_chain[0]; ip != (struct inode *)ih; ip = ip->i_forw)
7494ef16 124 if (ino == ip->i_number && dev == ip->i_dev) {
8ac1234a
SL
125 /*
126 * Following is essentially an inline expanded
127 * copy of igrab(), expanded inline for speed,
128 * and so that the test for a mounted on inode
129 * can be deferred until after we are sure that
130 * the inode isn't busy.
131 */
5c2ba954 132 if ((ip->i_flag&ILOCKED) != 0) {
5d5124a1
BJ
133 ip->i_flag |= IWANT;
134 sleep((caddr_t)ip, PINOD);
135 goto loop;
136 }
7188ac27
KM
137 vp = ITOV(ip);
138 if (vp->v_count == 0) { /* ino on free list */
3ebac878
RE
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 }
aed86454 147 ILOCK(ip);
8fe1c702 148 VREF(vp);
7188ac27
KM
149 *ipp = ip;
150 return(0);
151 }
152 if (error = getnewino(dev, ino, &nip)) {
153 *ipp = 0;
154 return (error);
155 }
156 ip = nip;
157 /*
158 * Read in the disk contents for the inode.
159 */
160 if (error = bread(VFSTOUFS(mntp)->um_devvp, fsbtodb(fs, itod(fs, ino)),
a937f856 161 (int)fs->fs_bsize, NOCRED, &bp)) {
7188ac27
KM
162 /*
163 * The inode doesn't contain anything useful, so it would
164 * be misleading to leave it on its hash chain. Iput() will
165 * take care of putting it back on the free list. We also
166 * lose its inumber, just in case.
167 */
168 remque(ip);
169 ip->i_forw = ip;
170 ip->i_back = ip;
171 ip->i_number = 0;
9b651315 172 ITOV(ip)->v_type = VNON;
7188ac27 173 INSFREE(ip);
aed86454 174 iunlock(ip);
7188ac27
KM
175 ip->i_flag = 0;
176 brelse(bp);
177 *ipp = 0;
178 return(error);
179 }
180 /*
181 * Check to see if the new inode represents a block device
182 * for which we already have an inode (either because of
183 * bdevvp() or because of a different inode representing
184 * the same block device). If such an alias exists, put the
185 * just allocated inode back on the free list, and replace
186 * the contents of the existing inode with the contents of
187 * the new inode.
188 */
189 dp = bp->b_un.b_dino;
190 dp += itoo(fs, ino);
191 if ((dp->di_mode & IFMT) != IFBLK) {
192 ip->i_ic = dp->di_ic;
193 brelse(bp);
194 } else {
195again:
196 for (iq = bdevlisth; iq; iq = iq->i_devlst) {
9b651315
KM
197 vp = ITOV(iq);
198 if (dp->di_rdev != vp->v_rdev)
7188ac27
KM
199 continue;
200 igrab(iq);
9b651315 201 if (dp->di_rdev != vp->v_rdev) {
7188ac27
KM
202 iput(iq);
203 goto again;
204 }
205 /*
206 * Discard unneeded inode.
207 */
208 remque(ip);
209 ip->i_forw = ip;
210 ip->i_back = ip;
211 ip->i_number = 0;
9b651315 212 ITOV(ip)->v_type = VNON;
7188ac27 213 INSFREE(ip);
aed86454 214 iunlock(ip);
7188ac27
KM
215 ip->i_flag = 0;
216 /*
217 * Reinitialize aliased inode.
218 * We must release the buffer that we just read
219 * before doing the iupdat() to avoid a possible
220 * deadlock with updating an inode in the same
221 * disk block.
222 */
223 ip = iq;
7188ac27
KM
224 tdip.di_ic = dp->di_ic;
225 brelse(bp);
226 error = iupdat(ip, &time, &time, 1);
227 ip->i_ic = tdip.di_ic;
228 remque(ip);
229 insque(ip, ih);
230 ip->i_dev = dev;
231 ip->i_number = ino;
232 if (ip->i_devvp) {
233 vrele(ip->i_devvp);
234 ip->i_devvp = 0;
235 }
236 cache_purge(vp);
237 break;
238 }
239 if (iq == 0) {
240 ip->i_ic = dp->di_ic;
241 brelse(bp);
242 ip->i_devlst = bdevlisth;
243 bdevlisth = ip;
5d5124a1 244 }
7188ac27
KM
245 }
246 /*
247 * Finish inode initialization.
248 */
249 ip->i_fs = fs;
250 ip->i_devvp = VFSTOUFS(mntp)->um_devvp;
8fe1c702 251 VREF(ip->i_devvp);
7188ac27
KM
252 /*
253 * Initialize the associated vnode
254 */
255 vp = ITOV(ip);
256 vinit(vp, mntp, IFTOVT(ip->i_mode), &ufs_vnodeops);
257 if (vp->v_type == VCHR || vp->v_type == VBLK) {
258 vp->v_rdev = ip->i_rdev;
259 vp->v_op = &blk_vnodeops;
260 }
261 if (ino == ROOTINO)
262 vp->v_flag |= VROOT;
263#ifdef QUOTA
264 if (ip->i_mode != 0)
265 ip->i_dquot = inoquota(ip);
266#endif
afd7e202
KM
267 /*
268 * Set up a generation number for this inode if it does not
269 * already have one. This should only happen on old filesystems.
270 */
271 if (ip->i_gen == 0) {
272 if (++nextgennumber < (u_long)time.tv_sec)
273 nextgennumber = time.tv_sec;
274 ip->i_gen = nextgennumber;
275 if ((vp->v_mount->m_flag & M_RDONLY) == 0)
276 ip->i_flag |= IMOD;
277 }
7188ac27
KM
278 *ipp = ip;
279 return (0);
280}
3ebac878 281
7188ac27
KM
282/*
283 * Allocate a new inode.
284 *
285 * Put it onto its hash chain and lock it so that other requests for
286 * this inode will block if they arrive while we are sleeping waiting
287 * for old data structures to be purged or for the contents of the disk
288 * portion of this inode to be read.
289 */
290getnewino(dev, ino, ipp)
291 dev_t dev;
292 ino_t ino;
293 struct inode **ipp;
294{
295 union ihead *ih;
296 register struct inode *ip, *iq;
297 register struct vnode *vp;
298
299 /*
300 * Remove the next inode from the free list.
301 */
3ebac878 302 if ((ip = ifreeh) == NULL) {
945fbb1b 303 tablefull("inode");
7188ac27
KM
304 *ipp = 0;
305 return(ENFILE);
5d5124a1 306 }
7188ac27
KM
307 vp = ITOV(ip);
308 if (vp->v_count)
bed1bb6e 309 panic("free inode isn't");
3ebac878
RE
310 if (iq = ip->i_freef)
311 iq->i_freeb = &ifreeh;
312 ifreeh = iq;
313 ip->i_freef = NULL;
314 ip->i_freeb = NULL;
315 /*
316 * Now to take inode off the hash chain it was on
317 * (initially, or after an iflush, it is on a "hash chain"
7188ac27
KM
318 * consisting entirely of itself, and pointed to by no-one)
319 * and put it on the chain for its new (ino, dev) pair.
3ebac878 320 */
32dc2b7e 321 remque(ip);
5d5124a1
BJ
322 ip->i_dev = dev;
323 ip->i_number = ino;
7188ac27
KM
324 if (dev != NODEV) {
325 ih = &ihead[INOHASH(dev, ino)];
326 insque(ip, ih);
327 }
aed86454
KM
328 ip->i_flag = 0;
329 ILOCK(ip);
6459ebe0 330 ip->i_lastr = 0;
ec67a3ce 331#endif SECSIZE
5d5124a1 332 /*
7188ac27 333 * Purge old data structures associated with the inode.
5d5124a1 334 */
7188ac27
KM
335 cache_purge(vp);
336 if (ip->i_devvp) {
337 vrele(ip->i_devvp);
338 ip->i_devvp = 0;
5d5124a1 339 }
b4567e9c 340#ifdef QUOTA
7188ac27
KM
341 dqrele(ip->i_dquot);
342 ip->i_dquot = NODQUOT;
89045c38 343#endif
7188ac27
KM
344 if (vp->v_type == VBLK) {
345 if (bdevlisth == ip) {
346 bdevlisth = ip->i_devlst;
347 } else {
348 for (iq = bdevlisth; iq; iq = iq->i_devlst) {
349 if (iq->i_devlst != ip)
350 continue;
351 iq->i_devlst = ip->i_devlst;
352 break;
353 }
354 if (iq == NULL)
355 panic("missing bdev");
356 }
357 }
358 *ipp = ip;
359 return (0);
5d5124a1
BJ
360}
361
8ac1234a
SL
362/*
363 * Convert a pointer to an inode into a reference to an inode.
364 *
365 * This is basically the internal piece of iget (after the
366 * inode pointer is located) but without the test for mounted
367 * filesystems. It is caller's responsibility to check that
368 * the inode pointer is valid.
369 */
370igrab(ip)
371 register struct inode *ip;
372{
7188ac27
KM
373 register struct vnode *vp = ITOV(ip);
374
8ac1234a
SL
375 while ((ip->i_flag&ILOCKED) != 0) {
376 ip->i_flag |= IWANT;
377 sleep((caddr_t)ip, PINOD);
378 }
7188ac27 379 if (vp->v_count == 0) { /* ino on free list */
8ac1234a
SL
380 register struct inode *iq;
381
382 if (iq = ip->i_freef)
383 iq->i_freeb = ip->i_freeb;
384 else
385 ifreet = ip->i_freeb;
386 *ip->i_freeb = iq;
387 ip->i_freef = NULL;
388 ip->i_freeb = NULL;
389 }
8fe1c702 390 VREF(vp);
aed86454 391 ILOCK(ip);
8ac1234a
SL
392}
393
7188ac27
KM
394/*
395 * Create a vnode for a block device.
396 * Used for root filesystem, argdev, and swap areas.
397 */
398bdevvp(dev, vpp)
399 dev_t dev;
400 struct vnode **vpp;
401{
402 register struct inode *ip;
403 register struct vnode *vp;
404 struct inode *nip;
405 int error;
406
407 /*
408 * Check for the existence of an existing vnode.
409 */
410again:
411 for (ip = bdevlisth; ip; ip = ip->i_devlst) {
412 vp = ITOV(ip);
413 if (dev != vp->v_rdev)
414 continue;
415 igrab(ip);
416 if (dev != vp->v_rdev) {
417 iput(ip);
418 goto again;
419 }
420 IUNLOCK(ip);
421 *vpp = vp;
422 return (0);
423 }
424 if (error = getnewino(NODEV, (ino_t)0, &nip)) {
425 *vpp = 0;
426 return (error);
427 }
428 ip = nip;
429 ip->i_fs = 0;
430 ip->i_devlst = bdevlisth;
431 bdevlisth = ip;
432 vp = ITOV(ip);
433 vinit(vp, 0, VBLK, &blk_vnodeops);
434 vp->v_rdev = dev;
435 IUNLOCK(ip);
436 *vpp = vp;
437 return (0);
438}
439
5d5124a1
BJ
440/*
441 * Decrement reference count of
442 * an inode structure.
443 * On the last reference,
444 * write the inode out and if necessary,
445 * truncate and deallocate the file.
446 */
447iput(ip)
7494ef16 448 register struct inode *ip;
5d5124a1 449{
ff56f48a 450
5c2ba954 451 if ((ip->i_flag & ILOCKED) == 0)
ff56f48a 452 panic("iput");
a388503d 453 IUNLOCK(ip);
7188ac27 454 vrele(ITOV(ip));
ff56f48a
KM
455}
456
7188ac27
KM
457
458ufs_inactive(vp)
459 struct vnode *vp;
ff56f48a 460{
7188ac27
KM
461 register struct inode *ip = VTOI(vp);
462 int mode, error;
463
464 if (ITOV(ip)->v_count != 0)
465 panic("ufs_inactive: not inactive");
b5ea418e
KM
466 /*
467 * Get rid of inodes related to stale file handles.
468 */
469 if (ip->i_mode == 0)
470 goto freeit;
aed86454 471 ILOCK(ip);
7188ac27
KM
472 if (ip->i_nlink <= 0 && (ITOV(ip)->v_mount->m_flag&M_RDONLY) == 0) {
473 error = itrunc(ip, (u_long)0);
474 mode = ip->i_mode;
475 ip->i_mode = 0;
476 ip->i_rdev = 0;
477 ip->i_flag |= IUPD|ICHG;
478 ifree(ip, ip->i_number, mode);
b4567e9c 479#ifdef QUOTA
7188ac27
KM
480 (void) chkiq(ip->i_dev, ip, ip->i_uid, 0);
481 dqrele(ip->i_dquot);
482 ip->i_dquot = NODQUOT;
89045c38 483#endif
7188ac27
KM
484 }
485 IUPDAT(ip, &time, &time, 0);
486 IUNLOCK(ip);
b5ea418e 487freeit:
7188ac27
KM
488 ip->i_flag = 0;
489 /*
490 * Put the inode on the end of the free list.
491 * Possibly in some cases it would be better to
492 * put the inode at the head of the free list,
493 * (eg: where i_mode == 0 || i_number == 0).
494 */
495 INSFREE(ip);
496 return (error);
5d5124a1
BJ
497}
498
499/*
500 * Check accessed and update flags on
501 * an inode structure.
502 * If any is on, update the inode
503 * with the current time.
c0bb1685
BJ
504 * If waitfor is given, then must insure
505 * i/o order so wait for write to complete.
5d5124a1 506 */
c0bb1685 507iupdat(ip, ta, tm, waitfor)
7494ef16 508 register struct inode *ip;
b32450f4 509 struct timeval *ta, *tm;
7494ef16 510 int waitfor;
5d5124a1 511{
7188ac27
KM
512 struct buf *bp;
513 struct vnode *vp = ITOV(ip);
5d5124a1 514 struct dinode *dp;
ec67a3ce 515 register struct fs *fs;
5d5124a1 516
ec67a3ce 517 fs = ip->i_fs;
7188ac27
KM
518 if ((ip->i_flag & (IUPD|IACC|ICHG|IMOD)) == 0)
519 return (0);
520 if (vp->v_mount->m_flag & M_RDONLY)
521 return (0);
522 error = bread(ip->i_devvp, fsbtodb(fs, itod(fs, ip->i_number)),
a937f856 523 (int)fs->fs_bsize, NOCRED, &bp);
7188ac27
KM
524 if (error) {
525 brelse(bp);
526 return (error);
527 }
528 if (ip->i_flag&IACC)
529 ip->i_atime = ta->tv_sec;
530 if (ip->i_flag&IUPD)
531 ip->i_mtime = tm->tv_sec;
532 if (ip->i_flag&ICHG)
533 ip->i_ctime = time.tv_sec;
534 ip->i_flag &= ~(IUPD|IACC|ICHG|IMOD);
535 dp = bp->b_un.b_dino + itoo(fs, ip->i_number);
536 dp->di_ic = ip->i_ic;
537 if (waitfor) {
538 return (bwrite(bp));
539 } else {
540 bdwrite(bp);
541 return (0);
5d5124a1
BJ
542 }
543}
544
9c03b2c0
SL
545#define SINGLE 0 /* index of single indirect block */
546#define DOUBLE 1 /* index of double indirect block */
547#define TRIPLE 2 /* index of triple indirect block */
5d5124a1 548/*
528f664c
SL
549 * Truncate the inode ip to at most
550 * length size. Free affected disk
551 * blocks -- the blocks of the file
552 * are removed in reverse order.
9c03b2c0
SL
553 *
554 * NB: triple indirect blocks are untested.
5d5124a1 555 */
9c03b2c0 556itrunc(oip, length)
28821bc5 557 register struct inode *oip;
4f083fd7 558 u_long length;
5d5124a1 559{
4f083fd7 560 register daddr_t lastblock;
a5e62f37 561 daddr_t bn, lbn, lastiblock[NIADDR];
6459ebe0 562 register struct fs *fs;
9c03b2c0 563 register struct inode *ip;
28821bc5 564 struct buf *bp;
7188ac27
KM
565 int offset, osize, size, level;
566 long count, nblocks, blocksreleased = 0;
28821bc5 567 register int i;
7188ac27 568 int error, allerror = 0;
9c03b2c0 569 struct inode tip;
4f083fd7 570
7b2e4f05
SL
571 if (oip->i_size <= length) {
572 oip->i_flag |= ICHG|IUPD;
7188ac27
KM
573 error = iupdat(oip, &time, &time, 1);
574 return (error);
7b2e4f05 575 }
c0bb1685 576 /*
9c03b2c0
SL
577 * Calculate index into inode's block list of
578 * last direct and indirect blocks (if any)
579 * which we want to keep. Lastblock is -1 when
580 * the file is truncated to 0.
c0bb1685 581 */
9c03b2c0 582 fs = oip->i_fs;
4f083fd7 583 lastblock = lblkno(fs, length + fs->fs_bsize - 1) - 1;
9c03b2c0
SL
584 lastiblock[SINGLE] = lastblock - NDADDR;
585 lastiblock[DOUBLE] = lastiblock[SINGLE] - NINDIR(fs);
586 lastiblock[TRIPLE] = lastiblock[DOUBLE] - NINDIR(fs) * NINDIR(fs);
08d9a8ec 587 nblocks = btodb(fs->fs_bsize);
6459ebe0 588 /*
28821bc5
KM
589 * Update the size of the file. If the file is not being
590 * truncated to a block boundry, the contents of the
591 * partial block following the end of the file must be
592 * zero'ed in case it ever become accessable again because
593 * of subsequent file growth.
594 */
595 osize = oip->i_size;
596 offset = blkoff(fs, length);
597 if (offset == 0) {
598 oip->i_size = length;
599 } else {
600 lbn = lblkno(fs, length);
7188ac27
KM
601 error = balloc(oip, lbn, offset, &bn, B_CLRBUF);
602 if (error)
603 return (error);
604 if ((long)bn < 0)
605 panic("itrunc: hole");
28821bc5
KM
606 oip->i_size = length;
607 size = blksize(fs, oip, lbn);
ec67a3ce 608 count = howmany(size, CLBYTES);
7188ac27 609 munhash(oip->i_devvp, bn + i * CLBYTES / DEV_BSIZE);
a937f856 610 error = bread(oip->i_devvp, bn, size, NOCRED, &bp);
7188ac27 611 if (error) {
28821bc5
KM
612 oip->i_size = osize;
613 brelse(bp);
7188ac27 614 return (error);
28821bc5 615 }
a5e62f37 616 bzero(bp->b_un.b_addr + offset, (unsigned)(size - offset));
28821bc5
KM
617 bdwrite(bp);
618 }
619 /*
620 * Update file and block pointers
9c03b2c0
SL
621 * on disk before we start freeing blocks.
622 * If we crash before free'ing blocks below,
623 * the blocks will be returned to the free list.
624 * lastiblock values are also normalized to -1
625 * for calls to indirtrunc below.
6459ebe0 626 */
9c03b2c0 627 tip = *oip;
28821bc5 628 tip.i_size = osize;
9c03b2c0
SL
629 for (level = TRIPLE; level >= SINGLE; level--)
630 if (lastiblock[level] < 0) {
631 oip->i_ib[level] = 0;
632 lastiblock[level] = -1;
4f083fd7 633 }
9c03b2c0
SL
634 for (i = NDADDR - 1; i > lastblock; i--)
635 oip->i_db[i] = 0;
9c03b2c0 636 oip->i_flag |= ICHG|IUPD;
7188ac27 637 allerror = syncip(oip);
9c03b2c0 638
6459ebe0 639 /*
9c03b2c0 640 * Indirect blocks first.
6459ebe0 641 */
28821bc5 642 ip = &tip;
9c03b2c0
SL
643 for (level = TRIPLE; level >= SINGLE; level--) {
644 bn = ip->i_ib[level];
4f083fd7 645 if (bn != 0) {
7188ac27
KM
646 error = indirtrunc(ip, bn, lastiblock[level], level,
647 &count);
648 if (error)
649 allerror = error;
650 blocksreleased += count;
9c03b2c0
SL
651 if (lastiblock[level] < 0) {
652 ip->i_ib[level] = 0;
ced3a252 653 blkfree(ip, bn, (off_t)fs->fs_bsize);
9c03b2c0 654 blocksreleased += nblocks;
9c03b2c0
SL
655 }
656 }
657 if (lastiblock[level] >= 0)
658 goto done;
4f083fd7 659 }
9c03b2c0 660
6459ebe0 661 /*
9c03b2c0 662 * All whole direct blocks or frags.
6459ebe0 663 */
4f083fd7 664 for (i = NDADDR - 1; i > lastblock; i--) {
8011f5df 665 register off_t bsize;
4f083fd7 666
6459ebe0 667 bn = ip->i_db[i];
4f083fd7 668 if (bn == 0)
5d5124a1 669 continue;
4f083fd7 670 ip->i_db[i] = 0;
0b355a6e 671 bsize = (off_t)blksize(fs, ip, i);
ced3a252 672 blkfree(ip, bn, bsize);
0b355a6e 673 blocksreleased += btodb(bsize);
4f083fd7 674 }
9c03b2c0
SL
675 if (lastblock < 0)
676 goto done;
677
4f083fd7
SL
678 /*
679 * Finally, look for a change in size of the
680 * last direct block; release any frags.
681 */
9c03b2c0
SL
682 bn = ip->i_db[lastblock];
683 if (bn != 0) {
8011f5df 684 off_t oldspace, newspace;
9c03b2c0 685
4f083fd7
SL
686 /*
687 * Calculate amount of space we're giving
688 * back as old block size minus new block size.
689 */
9c03b2c0 690 oldspace = blksize(fs, ip, lastblock);
4f083fd7 691 ip->i_size = length;
9c03b2c0
SL
692 newspace = blksize(fs, ip, lastblock);
693 if (newspace == 0)
694 panic("itrunc: newspace");
695 if (oldspace - newspace > 0) {
4f083fd7
SL
696 /*
697 * Block number of space to be free'd is
698 * the old block # plus the number of frags
699 * required for the storage we're keeping.
700 */
9c03b2c0 701 bn += numfrags(fs, newspace);
ced3a252 702 blkfree(ip, bn, oldspace - newspace);
08d9a8ec 703 blocksreleased += btodb(oldspace - newspace);
4f083fd7 704 }
5d5124a1 705 }
4f083fd7 706done:
9c03b2c0
SL
707/* BEGIN PARANOIA */
708 for (level = SINGLE; level <= TRIPLE; level++)
709 if (ip->i_ib[level] != oip->i_ib[level])
710 panic("itrunc1");
711 for (i = 0; i < NDADDR; i++)
712 if (ip->i_db[i] != oip->i_db[i])
713 panic("itrunc2");
714/* END PARANOIA */
08d9a8ec
SL
715 oip->i_blocks -= blocksreleased;
716 if (oip->i_blocks < 0) /* sanity */
717 oip->i_blocks = 0;
718 oip->i_flag |= ICHG;
b4567e9c 719#ifdef QUOTA
08d9a8ec 720 (void) chkdq(oip, -blocksreleased, 0);
89045c38 721#endif
7188ac27 722 return (allerror);
5d5124a1
BJ
723}
724
4f083fd7
SL
725/*
726 * Release blocks associated with the inode ip and
727 * stored in the indirect block bn. Blocks are free'd
728 * in LIFO order up to (but not including) lastbn. If
9c03b2c0
SL
729 * level is greater than SINGLE, the block is an indirect
730 * block and recursive calls to indirtrunc must be used to
731 * cleanse other indirect blocks.
732 *
733 * NB: triple indirect blocks are untested.
4f083fd7 734 */
7188ac27 735indirtrunc(ip, bn, lastbn, level, countp)
6459ebe0 736 register struct inode *ip;
4f083fd7 737 daddr_t bn, lastbn;
9c03b2c0 738 int level;
7188ac27 739 long *countp;
5d5124a1 740{
4f083fd7 741 register int i;
b30358ab 742 struct buf *bp;
9c03b2c0 743 register struct fs *fs = ip->i_fs;
b30358ab
KM
744 register daddr_t *bap;
745 daddr_t *copy, nb, last;
7188ac27
KM
746 long blkcount, factor;
747 int nblocks, blocksreleased = 0;
748 int error, allerror = 0;
5d5124a1 749
9c03b2c0
SL
750 /*
751 * Calculate index in current block of last
752 * block to be kept. -1 indicates the entire
753 * block so we need not calculate the index.
754 */
755 factor = 1;
756 for (i = SINGLE; i < level; i++)
757 factor *= NINDIR(fs);
4f083fd7 758 last = lastbn;
9c03b2c0
SL
759 if (lastbn > 0)
760 last /= factor;
08d9a8ec 761 nblocks = btodb(fs->fs_bsize);
9c03b2c0
SL
762 /*
763 * Get buffer of block pointers, zero those
764 * entries corresponding to blocks to be free'd,
765 * and update on disk copy first.
766 */
ec67a3ce
MK
767#ifdef SECSIZE
768 bp = bread(ip->i_dev, fsbtodb(fs, bn), (int)fs->fs_bsize,
769 fs->fs_dbsize);
770#else SECSIZE
a937f856
KM
771 error = bread(ip->i_devvp, fsbtodb(fs, bn), (int)fs->fs_bsize,
772 NOCRED, &bp);
7188ac27 773 if (error) {
9c03b2c0 774 brelse(bp);
7188ac27
KM
775 *countp = 0;
776 return (error);
9c03b2c0
SL
777 }
778 bap = bp->b_un.b_daddr;
b30358ab
KM
779 MALLOC(copy, daddr_t *, fs->fs_bsize, M_TEMP, M_WAITOK);
780 bcopy((caddr_t)bap, (caddr_t)copy, (u_int)fs->fs_bsize);
9c03b2c0
SL
781 bzero((caddr_t)&bap[last + 1],
782 (u_int)(NINDIR(fs) - (last + 1)) * sizeof (daddr_t));
7188ac27
KM
783 error = bwrite(bp);
784 if (error)
785 allerror = error;
b30358ab 786 bap = copy;
4f083fd7 787
9c03b2c0
SL
788 /*
789 * Recursively free totally unused blocks.
790 */
791 for (i = NINDIR(fs) - 1; i > last; i--) {
5d5124a1 792 nb = bap[i];
4f083fd7 793 if (nb == 0)
5d5124a1 794 continue;
7188ac27
KM
795 if (level > SINGLE) {
796 error = indirtrunc(ip, nb, (daddr_t)-1, level - 1,
797 &blkcount);
798 if (error)
799 allerror = error;
800 blocksreleased += blkcount;
801 }
ced3a252 802 blkfree(ip, nb, (off_t)fs->fs_bsize);
4f083fd7 803 blocksreleased += nblocks;
4f083fd7 804 }
9c03b2c0
SL
805
806 /*
807 * Recursively free last partial block.
808 */
809 if (level > SINGLE && lastbn >= 0) {
810 last = lastbn % factor;
4f083fd7 811 nb = bap[i];
7188ac27
KM
812 if (nb != 0) {
813 error = indirtrunc(ip, nb, last, level - 1, &blkcount);
814 if (error)
815 allerror = error;
816 blocksreleased += blkcount;
817 }
5d5124a1 818 }
b30358ab 819 FREE(copy, M_TEMP);
7188ac27
KM
820 *countp = blocksreleased;
821 return (allerror);
5d5124a1
BJ
822}
823
3ebac878 824/*
ec67a3ce 825 * Remove any inodes in the inode cache belonging to dev.
3ebac878
RE
826 *
827 * There should not be any active ones, return error if any are found
ec67a3ce 828 * (nb: this is a user error, not a system err).
3ebac878 829 */
0d73cd0c
KM
830int busyprt = 0; /* patch to print out busy inodes */
831
b4567e9c 832#ifdef QUOTA
4147b3f6 833iflush(dev, iq)
89045c38 834 dev_t dev;
4147b3f6 835 struct inode *iq;
89045c38 836#else
3ebac878
RE
837iflush(dev)
838 dev_t dev;
89045c38 839#endif
3ebac878 840{
32dc2b7e 841 register struct inode *ip;
0d73cd0c 842 int busy = 0;
3ebac878
RE
843
844 for (ip = inode; ip < inodeNINODE; ip++) {
b4567e9c 845#ifdef QUOTA
0d73cd0c
KM
846 if (ip == iq || ip->i_dev != dev)
847 continue;
89045c38 848#else
0d73cd0c
KM
849 if (ip->i_dev != dev)
850 continue;
89045c38 851#endif
0d73cd0c
KM
852 if (ITOV(ip)->v_count) {
853 busy++;
854 if (!busyprt)
855 continue;
856 printf("%s %d on dev 0x%x count %d type %d\n",
857 "iflush: busy inode ", ip->i_number, ip->i_dev,
858 ITOV(ip)->v_count, ITOV(ip)->v_type);
859 continue;
860 }
861 remque(ip);
862 ip->i_forw = ip;
863 ip->i_back = ip;
864 /*
865 * As v_count == 0, the inode was on the free list already,
866 * just leave it there, it will fall off the bottom eventually.
867 * We could perhaps move it to the head of the free list,
868 * but as umounts are done so infrequently, we would gain
869 * very little, while making the code bigger.
870 */
b4567e9c 871#ifdef QUOTA
0d73cd0c
KM
872 dqrele(ip->i_dquot);
873 ip->i_dquot = NODQUOT;
89045c38 874#endif
0d73cd0c
KM
875 if (ip->i_devvp) {
876 vrele(ip->i_devvp);
877 ip->i_devvp = 0;
878 }
3ebac878 879 }
0d73cd0c
KM
880 if (busy)
881 return (EBUSY);
ec67a3ce 882 return (0);
3ebac878
RE
883}
884
d6a210b8 885/*
7494ef16 886 * Lock an inode. If its already locked, set the WANT bit and sleep.
d6a210b8 887 */
7494ef16
BJ
888ilock(ip)
889 register struct inode *ip;
d6a210b8
BJ
890{
891
7188ac27
KM
892 while (ip->i_flag & ILOCKED) {
893 ip->i_flag |= IWANT;
894 (void) sleep((caddr_t)ip, PINOD);
895 }
896 ip->i_flag |= ILOCKED;
d6a210b8
BJ
897}
898
899/*
7494ef16 900 * Unlock an inode. If WANT bit is on, wakeup.
d6a210b8 901 */
ff56f48a 902iunlock(ip)
7494ef16 903 register struct inode *ip;
d6a210b8
BJ
904{
905
7188ac27
KM
906 if ((ip->i_flag & ILOCKED) == 0)
907 printf("unlocking unlocked inode %d on dev 0x%x\n",
908 ip->i_number, ip->i_dev);
909 ip->i_flag &= ~ILOCKED;
910 if (ip->i_flag&IWANT) {
911 ip->i_flag &= ~IWANT;
912 wakeup((caddr_t)ip);
913 }
914}
915
916/*
917 * Check mode permission on inode pointer. Mode is READ, WRITE or EXEC.
918 * The mode is shifted to select the owner/group/other fields. The
919 * super user is granted all permissions.
920 *
921 * NB: Called from vnode op table. It seems this could all be done
922 * using vattr's but...
923 */
924iaccess(ip, mode, cred)
925 register struct inode *ip;
926 register int mode;
927 struct ucred *cred;
928{
929 register gid_t *gp;
930 register struct vnode *vp = ITOV(ip);
931 int i;
932
933 /*
934 * If you're the super-user,
935 * you always get access.
936 */
937 if (cred->cr_uid == 0)
938 return (0);
939 /*
940 * Access check is based on only one of owner, group, public.
941 * If not owner, then check group. If not a member of the
942 * group, then check public access.
943 */
944 if (cred->cr_uid != ip->i_uid) {
945 mode >>= 3;
946 gp = cred->cr_groups;
947 for (i = 0; i < cred->cr_ngroups; i++, gp++)
948 if (ip->i_gid == *gp)
949 goto found;
950 mode >>= 3;
951found:
952 ;
953 }
954 if ((ip->i_mode & mode) != 0)
955 return (0);
956 return (EACCES);
d6a210b8 957}