registerized vnodeop ops after vnode interface conversion
[unix-history] / usr / src / sys / ufs / ffs / ffs_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 *
b702c21d 5 * %sccs.include.redist.c%
7188ac27 6 *
406c9a0d 7 * @(#)ffs_inode.c 7.53 (Berkeley) %G%
da7c5cc6 8 */
5d5124a1 9
0a52434b
KB
10#include <sys/param.h>
11#include <sys/systm.h>
12#include <sys/mount.h>
13#include <sys/proc.h>
14#include <sys/file.h>
15#include <sys/buf.h>
16#include <sys/vnode.h>
17#include <sys/kernel.h>
18#include <sys/malloc.h>
5d5124a1 19
8847a2f7
KM
20#include <vm/vm.h>
21
0a52434b
KB
22#include <ufs/ufs/quota.h>
23#include <ufs/ufs/inode.h>
24#include <ufs/ufs/ufsmount.h>
25#include <ufs/ufs/ufs_extern.h>
c6f5111d 26
0a52434b
KB
27#include <ufs/ffs/fs.h>
28#include <ufs/ffs/ffs_extern.h>
3ebac878 29
0a52434b 30static int ffs_indirtrunc __P((struct inode *, daddr_t, daddr_t, int, long *));
3ebac878 31
0a52434b 32extern u_long nextgennumber;
2bf2d153 33
0a52434b
KB
34int
35ffs_init()
5d5124a1 36{
0a52434b 37 return (ufs_init());
5d5124a1
BJ
38}
39
3ebac878 40/*
832eaef9
KM
41 * Look up a UFS dinode number to find its incore vnode.
42 * If it is not in core, read it in from the specified device.
43 * If it is in core, wait for the lock bit to clear, then
44 * return the inode locked. Detection and handling of mount
45 * points must be done by the calling routine.
5d5124a1 46 */
9342689a
JH
47ffs_vget (ap)
48 struct vop_vget_args *ap;
5d5124a1 49{
0a52434b
KB
50 register struct fs *fs;
51 register struct inode *ip;
a9013e03 52 struct ufsmount *ump;
7188ac27 53 struct buf *bp;
1259a9f9 54 struct dinode *dp;
0a52434b 55 struct vnode *vp;
4b61628b 56 union ihead *ih;
0a52434b 57 dev_t dev;
75e1b478 58 int i, type, error;
2e64ab65 59
e1b76915 60 ump = VFSTOUFS(ap->a_mp);
a9013e03 61 dev = ump->um_dev;
e1b76915 62 if ((*ap->a_vpp = ufs_ihashget(dev, ap->a_ino)) != NULL)
0a52434b
KB
63 return (0);
64
65 /* Allocate a new vnode/inode. */
e1b76915
JH
66 if (error = getnewvnode(VT_UFS, ap->a_mp, ffs_vnodeop_p, &vp)) {
67 *ap->a_vpp = NULL;
7188ac27
KM
68 return (error);
69 }
75e1b478
KM
70 type = ump->um_devvp->v_tag == VT_MFS ? M_MFSNODE : M_FFSNODE; /* XXX */
71 MALLOC(ip, struct inode *, sizeof(struct inode), type, M_WAITOK);
72 vp->v_data = ip;
0a52434b 73 ip->i_vnode = vp;
1259a9f9
KM
74 ip->i_flag = 0;
75 ip->i_devvp = 0;
1259a9f9 76 ip->i_mode = 0;
c9ad8afc 77 ip->i_diroff = 0;
4754ee14 78 ip->i_lockf = 0;
baaa0677 79 ip->i_fs = fs = ump->um_fs;
a9013e03 80 ip->i_dev = dev;
e1b76915 81 ip->i_number = ap->a_ino;
1259a9f9 82#ifdef QUOTA
4b61628b
KM
83 for (i = 0; i < MAXQUOTAS; i++)
84 ip->i_dquot[i] = NODQUOT;
1259a9f9
KM
85#endif
86 /*
87 * Put it onto its hash chain and lock it so that other requests for
88 * this inode will block if they arrive while we are sleeping waiting
89 * for old data structures to be purged or for the contents of the
90 * disk portion of this inode to be read.
91 */
0a52434b
KB
92 ufs_ihashins(ip);
93
94 /* Read in the disk contents for the inode, copy into the inode. */
e1b76915 95 if (error = bread(ump->um_devvp, fsbtodb(fs, itod(fs, ap->a_ino)),
a937f856 96 (int)fs->fs_bsize, NOCRED, &bp)) {
bd4160ab
KM
97 /*
98 * The inode does not contain anything useful, so it would
75e1b478
KM
99 * be misleading to leave it on its hash chain. It will be
100 * returned to the free list by ufs_iput().
bd4160ab
KM
101 */
102 remque(ip);
103 ip->i_forw = ip;
104 ip->i_back = ip;
0a52434b
KB
105
106 /* Unlock and discard unneeded inode. */
107 ufs_iput(ip);
7188ac27 108 brelse(bp);
e1b76915 109 *ap->a_vpp = NULL;
1259a9f9 110 return (error);
7188ac27 111 }
7188ac27 112 dp = bp->b_un.b_dino;
e1b76915 113 dp += itoo(fs, ap->a_ino);
1259a9f9
KM
114 ip->i_din = *dp;
115 brelse(bp);
0a52434b 116
1259a9f9 117 /*
75e1b478
KM
118 * Initialize the vnode from the inode, check for aliases.
119 * Note that the underlying vnode may have changed.
1259a9f9 120 */
e1b76915 121 if (error = ufs_vinit(ap->a_mp, ffs_specop_p, FFS_FIFOOPS, &vp)) {
0a52434b 122 ufs_iput(ip);
e1b76915 123 *ap->a_vpp = NULL;
0a52434b 124 return (error);
7188ac27 125 }
a9013e03
KM
126 /*
127 * Finish inode initialization now that aliasing has been resolved.
128 */
a9013e03
KM
129 ip->i_devvp = ump->um_devvp;
130 VREF(ip->i_devvp);
afd7e202
KM
131 /*
132 * Set up a generation number for this inode if it does not
133 * already have one. This should only happen on old filesystems.
134 */
135 if (ip->i_gen == 0) {
136 if (++nextgennumber < (u_long)time.tv_sec)
137 nextgennumber = time.tv_sec;
138 ip->i_gen = nextgennumber;
82161bc8 139 if ((vp->v_mount->mnt_flag & MNT_RDONLY) == 0)
afd7e202
KM
140 ip->i_flag |= IMOD;
141 }
9de329b9
KM
142 /*
143 * Ensure that uid and gid are correct. This is a temporary
144 * fix until fsck has been changed to do the update.
145 */
146 ip->i_uid = ip->i_din.di_ouid;
147 ip->i_gid = ip->i_din.di_ogid;
148
e1b76915 149 *ap->a_vpp = vp;
7188ac27
KM
150 return (0);
151}
3ebac878 152
a1e9dd57 153/*
832eaef9 154 * Update the access, modified, and inode change times as specified
a9013e03 155 * by the IACC, IUPD, and ICHG flags respectively. The IMOD flag
832eaef9
KM
156 * is used to specify that the inode needs to be updated but that
157 * the times have already been set. The access and modified times
158 * are taken from the second and third parameters; the inode change
159 * time is always taken from the current time. If waitfor is set,
160 * then wait for the disk write of the inode to complete.
5d5124a1 161 */
0a52434b 162int
9342689a
JH
163ffs_update (ap)
164 struct vop_update_args *ap;
5d5124a1 165{
7188ac27 166 struct buf *bp;
a9013e03 167 struct inode *ip;
5d5124a1 168 struct dinode *dp;
ec67a3ce 169 register struct fs *fs;
5d5124a1 170
e1b76915 171 if (ap->a_vp->v_mount->mnt_flag & MNT_RDONLY)
7188ac27 172 return (0);
e1b76915 173 ip = VTOI(ap->a_vp);
a9013e03
KM
174 if ((ip->i_flag & (IUPD|IACC|ICHG|IMOD)) == 0)
175 return (0);
7188ac27 176 if (ip->i_flag&IACC)
e1b76915 177 ip->i_atime.tv_sec = ap->a_ta->tv_sec;
baaa0677 178 if (ip->i_flag&IUPD) {
e1b76915 179 ip->i_mtime.tv_sec = ap->a_tm->tv_sec;
baaa0677
KM
180 INCRQUAD(ip->i_modrev);
181 }
7188ac27 182 if (ip->i_flag&ICHG)
8847a2f7 183 ip->i_ctime.tv_sec = time.tv_sec;
7188ac27 184 ip->i_flag &= ~(IUPD|IACC|ICHG|IMOD);
9de329b9
KM
185 /*
186 * Ensure that uid and gid are correct. This is a temporary
187 * fix until fsck has been changed to do the update.
188 */
189 ip->i_din.di_ouid = ip->i_uid;
190 ip->i_din.di_ogid = ip->i_gid;
a9013e03
KM
191
192 fs = ip->i_fs;
193 if (error = bread(ip->i_devvp, fsbtodb(fs, itod(fs, ip->i_number)),
194 (int)fs->fs_bsize, NOCRED, &bp)) {
195 brelse(bp);
196 return (error);
197 }
7188ac27 198 dp = bp->b_un.b_dino + itoo(fs, ip->i_number);
a1e9dd57 199 *dp = ip->i_din;
e1b76915 200 if (ap->a_waitfor)
7188ac27 201 return (bwrite(bp));
a9013e03 202 else {
7188ac27
KM
203 bdwrite(bp);
204 return (0);
5d5124a1
BJ
205 }
206}
207
9c03b2c0
SL
208#define SINGLE 0 /* index of single indirect block */
209#define DOUBLE 1 /* index of double indirect block */
210#define TRIPLE 2 /* index of triple indirect block */
5d5124a1 211/*
a1e9dd57
KM
212 * Truncate the inode ip to at most length size. Free affected disk
213 * blocks -- the blocks of the file are removed in reverse order.
9c03b2c0
SL
214 *
215 * NB: triple indirect blocks are untested.
5d5124a1 216 */
9342689a
JH
217ffs_truncate (ap)
218 struct vop_truncate_args *ap;
5d5124a1 219{
9342689a 220 USES_VOP_UPDATE;
406c9a0d 221 register struct vnode *ovp = ap->a_vp;
4f083fd7 222 register daddr_t lastblock;
a9013e03 223 register struct inode *oip;
a5e62f37 224 daddr_t bn, lbn, lastiblock[NIADDR];
6459ebe0 225 register struct fs *fs;
9c03b2c0 226 register struct inode *ip;
28821bc5 227 struct buf *bp;
0308fc84 228 int offset, size, level;
7188ac27 229 long count, nblocks, blocksreleased = 0;
28821bc5 230 register int i;
e038406d 231 int aflags, error, allerror;
9c03b2c0 232 struct inode tip;
0308fc84 233 off_t osize;
4f083fd7 234
406c9a0d
JH
235 vnode_pager_setsize(ovp, (u_long)ap->a_length);
236 oip = VTOI(ovp);
e1b76915 237 if (oip->i_size <= ap->a_length) {
7b2e4f05 238 oip->i_flag |= ICHG|IUPD;
406c9a0d 239 error = VOP_UPDATE(ovp, &time, &time, 1);
7188ac27 240 return (error);
7b2e4f05 241 }
c0bb1685 242 /*
9c03b2c0
SL
243 * Calculate index into inode's block list of
244 * last direct and indirect blocks (if any)
245 * which we want to keep. Lastblock is -1 when
246 * the file is truncated to 0.
c0bb1685 247 */
9c03b2c0 248 fs = oip->i_fs;
e1b76915 249 lastblock = lblkno(fs, ap->a_length + fs->fs_bsize - 1) - 1;
9c03b2c0
SL
250 lastiblock[SINGLE] = lastblock - NDADDR;
251 lastiblock[DOUBLE] = lastiblock[SINGLE] - NINDIR(fs);
252 lastiblock[TRIPLE] = lastiblock[DOUBLE] - NINDIR(fs) * NINDIR(fs);
08d9a8ec 253 nblocks = btodb(fs->fs_bsize);
6459ebe0 254 /*
28821bc5
KM
255 * Update the size of the file. If the file is not being
256 * truncated to a block boundry, the contents of the
257 * partial block following the end of the file must be
258 * zero'ed in case it ever become accessable again because
259 * of subsequent file growth.
260 */
261 osize = oip->i_size;
e1b76915 262 offset = blkoff(fs, ap->a_length);
28821bc5 263 if (offset == 0) {
e1b76915 264 oip->i_size = ap->a_length;
28821bc5 265 } else {
e1b76915 266 lbn = lblkno(fs, ap->a_length);
e038406d 267 aflags = B_CLRBUF;
e1b76915 268 if (ap->a_flags & IO_SYNC)
e038406d 269 aflags |= B_SYNC;
4b61628b
KM
270#ifdef QUOTA
271 if (error = getinoquota(oip))
272 return (error);
273#endif
e1b76915 274 if (error = ffs_balloc(oip, lbn, offset, ap->a_cred, &bp, aflags))
7188ac27 275 return (error);
e1b76915 276 oip->i_size = ap->a_length;
28821bc5 277 size = blksize(fs, oip, lbn);
406c9a0d 278 (void) vnode_pager_uncache(ovp);
a5e62f37 279 bzero(bp->b_un.b_addr + offset, (unsigned)(size - offset));
9cf42d55 280 allocbuf(bp, size);
e1b76915 281 if (ap->a_flags & IO_SYNC)
e038406d
KM
282 bwrite(bp);
283 else
284 bdwrite(bp);
28821bc5
KM
285 }
286 /*
0a52434b
KB
287 * Update file and block pointers on disk before we start freeing
288 * blocks. If we crash before free'ing blocks below, the blocks
289 * will be returned to the free list. lastiblock values are also
290 * normalized to -1 for calls to ffs_indirtrunc below.
6459ebe0 291 */
9c03b2c0 292 tip = *oip;
28821bc5 293 tip.i_size = osize;
9c03b2c0
SL
294 for (level = TRIPLE; level >= SINGLE; level--)
295 if (lastiblock[level] < 0) {
296 oip->i_ib[level] = 0;
297 lastiblock[level] = -1;
4f083fd7 298 }
9c03b2c0
SL
299 for (i = NDADDR - 1; i > lastblock; i--)
300 oip->i_db[i] = 0;
9c03b2c0 301 oip->i_flag |= ICHG|IUPD;
406c9a0d
JH
302 vinvalbuf(ovp, (ap->a_length > 0));
303 allerror = VOP_UPDATE(ovp, &time, &time, MNT_WAIT);
9c03b2c0 304
6459ebe0 305 /*
9c03b2c0 306 * Indirect blocks first.
6459ebe0 307 */
28821bc5 308 ip = &tip;
9c03b2c0
SL
309 for (level = TRIPLE; level >= SINGLE; level--) {
310 bn = ip->i_ib[level];
4f083fd7 311 if (bn != 0) {
0a52434b
KB
312 error = ffs_indirtrunc(ip,
313 bn, lastiblock[level], level, &count);
7188ac27
KM
314 if (error)
315 allerror = error;
316 blocksreleased += count;
9c03b2c0
SL
317 if (lastiblock[level] < 0) {
318 ip->i_ib[level] = 0;
0308fc84 319 ffs_blkfree(ip, bn, fs->fs_bsize);
9c03b2c0 320 blocksreleased += nblocks;
9c03b2c0
SL
321 }
322 }
323 if (lastiblock[level] >= 0)
324 goto done;
4f083fd7 325 }
9c03b2c0 326
6459ebe0 327 /*
9c03b2c0 328 * All whole direct blocks or frags.
6459ebe0 329 */
4f083fd7 330 for (i = NDADDR - 1; i > lastblock; i--) {
0308fc84 331 register long bsize;
4f083fd7 332
6459ebe0 333 bn = ip->i_db[i];
4f083fd7 334 if (bn == 0)
5d5124a1 335 continue;
4f083fd7 336 ip->i_db[i] = 0;
0308fc84 337 bsize = blksize(fs, ip, i);
0a52434b 338 ffs_blkfree(ip, bn, bsize);
0b355a6e 339 blocksreleased += btodb(bsize);
4f083fd7 340 }
9c03b2c0
SL
341 if (lastblock < 0)
342 goto done;
343
4f083fd7
SL
344 /*
345 * Finally, look for a change in size of the
346 * last direct block; release any frags.
347 */
9c03b2c0
SL
348 bn = ip->i_db[lastblock];
349 if (bn != 0) {
0308fc84 350 long oldspace, newspace;
9c03b2c0 351
4f083fd7
SL
352 /*
353 * Calculate amount of space we're giving
354 * back as old block size minus new block size.
355 */
9c03b2c0 356 oldspace = blksize(fs, ip, lastblock);
e1b76915 357 ip->i_size = ap->a_length;
9c03b2c0
SL
358 newspace = blksize(fs, ip, lastblock);
359 if (newspace == 0)
360 panic("itrunc: newspace");
361 if (oldspace - newspace > 0) {
4f083fd7
SL
362 /*
363 * Block number of space to be free'd is
364 * the old block # plus the number of frags
365 * required for the storage we're keeping.
366 */
9c03b2c0 367 bn += numfrags(fs, newspace);
0a52434b 368 ffs_blkfree(ip, bn, oldspace - newspace);
08d9a8ec 369 blocksreleased += btodb(oldspace - newspace);
4f083fd7 370 }
5d5124a1 371 }
4f083fd7 372done:
9c03b2c0
SL
373/* BEGIN PARANOIA */
374 for (level = SINGLE; level <= TRIPLE; level++)
375 if (ip->i_ib[level] != oip->i_ib[level])
376 panic("itrunc1");
377 for (i = 0; i < NDADDR; i++)
378 if (ip->i_db[i] != oip->i_db[i])
379 panic("itrunc2");
380/* END PARANOIA */
08d9a8ec
SL
381 oip->i_blocks -= blocksreleased;
382 if (oip->i_blocks < 0) /* sanity */
383 oip->i_blocks = 0;
384 oip->i_flag |= ICHG;
b4567e9c 385#ifdef QUOTA
4b61628b
KM
386 if (!getinoquota(oip))
387 (void) chkdq(oip, -blocksreleased, NOCRED, 0);
89045c38 388#endif
7188ac27 389 return (allerror);
5d5124a1
BJ
390}
391
4f083fd7 392/*
0a52434b
KB
393 * Release blocks associated with the inode ip and stored in the indirect
394 * block bn. Blocks are free'd in LIFO order up to (but not including)
395 * lastbn. If level is greater than SINGLE, the block is an indirect block
396 * and recursive calls to indirtrunc must be used to cleanse other indirect
397 * blocks.
9c03b2c0
SL
398 *
399 * NB: triple indirect blocks are untested.
4f083fd7 400 */
0a52434b
KB
401static int
402ffs_indirtrunc(ip, bn, lastbn, level, countp)
6459ebe0 403 register struct inode *ip;
4f083fd7 404 daddr_t bn, lastbn;
9c03b2c0 405 int level;
7188ac27 406 long *countp;
5d5124a1 407{
4f083fd7 408 register int i;
b30358ab 409 struct buf *bp;
9c03b2c0 410 register struct fs *fs = ip->i_fs;
b30358ab
KM
411 register daddr_t *bap;
412 daddr_t *copy, nb, last;
7188ac27
KM
413 long blkcount, factor;
414 int nblocks, blocksreleased = 0;
415 int error, allerror = 0;
5d5124a1 416
9c03b2c0
SL
417 /*
418 * Calculate index in current block of last
419 * block to be kept. -1 indicates the entire
420 * block so we need not calculate the index.
421 */
422 factor = 1;
423 for (i = SINGLE; i < level; i++)
424 factor *= NINDIR(fs);
4f083fd7 425 last = lastbn;
9c03b2c0
SL
426 if (lastbn > 0)
427 last /= factor;
08d9a8ec 428 nblocks = btodb(fs->fs_bsize);
9c03b2c0
SL
429 /*
430 * Get buffer of block pointers, zero those
431 * entries corresponding to blocks to be free'd,
432 * and update on disk copy first.
433 */
ec67a3ce
MK
434#ifdef SECSIZE
435 bp = bread(ip->i_dev, fsbtodb(fs, bn), (int)fs->fs_bsize,
436 fs->fs_dbsize);
437#else SECSIZE
a937f856
KM
438 error = bread(ip->i_devvp, fsbtodb(fs, bn), (int)fs->fs_bsize,
439 NOCRED, &bp);
7188ac27 440 if (error) {
9c03b2c0 441 brelse(bp);
7188ac27
KM
442 *countp = 0;
443 return (error);
9c03b2c0
SL
444 }
445 bap = bp->b_un.b_daddr;
b30358ab
KM
446 MALLOC(copy, daddr_t *, fs->fs_bsize, M_TEMP, M_WAITOK);
447 bcopy((caddr_t)bap, (caddr_t)copy, (u_int)fs->fs_bsize);
9c03b2c0
SL
448 bzero((caddr_t)&bap[last + 1],
449 (u_int)(NINDIR(fs) - (last + 1)) * sizeof (daddr_t));
e038406d
KM
450 if (last == -1)
451 bp->b_flags |= B_INVAL;
7188ac27
KM
452 error = bwrite(bp);
453 if (error)
454 allerror = error;
b30358ab 455 bap = copy;
4f083fd7 456
9c03b2c0
SL
457 /*
458 * Recursively free totally unused blocks.
459 */
460 for (i = NINDIR(fs) - 1; i > last; i--) {
5d5124a1 461 nb = bap[i];
4f083fd7 462 if (nb == 0)
5d5124a1 463 continue;
7188ac27 464 if (level > SINGLE) {
0a52434b
KB
465 if (error = ffs_indirtrunc(ip,
466 nb, (daddr_t)-1, level - 1, &blkcount))
7188ac27
KM
467 allerror = error;
468 blocksreleased += blkcount;
469 }
0308fc84 470 ffs_blkfree(ip, nb, fs->fs_bsize);
4f083fd7 471 blocksreleased += nblocks;
4f083fd7 472 }
9c03b2c0
SL
473
474 /*
475 * Recursively free last partial block.
476 */
477 if (level > SINGLE && lastbn >= 0) {
478 last = lastbn % factor;
4f083fd7 479 nb = bap[i];
7188ac27 480 if (nb != 0) {
0a52434b
KB
481 if (error =
482 ffs_indirtrunc(ip, nb, last, level - 1, &blkcount))
7188ac27
KM
483 allerror = error;
484 blocksreleased += blkcount;
485 }
5d5124a1 486 }
b30358ab 487 FREE(copy, M_TEMP);
7188ac27
KM
488 *countp = blocksreleased;
489 return (allerror);
5d5124a1 490}