vnode interface conversion
[unix-history] / usr / src / sys / ufs / lfs / lfs_inode.c
CommitLineData
da7c5cc6 1/*
7795cb4d 2 * Copyright (c) 1986, 1989, 1991 Regents of the University of California.
7188ac27 3 * All rights reserved.
da7c5cc6 4 *
b702c21d 5 * %sccs.include.redist.c%
7188ac27 6 *
091d1501 7 * @(#)lfs_inode.c 7.64 (Berkeley) %G%
da7c5cc6 8 */
5d5124a1 9
29ad237c
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
89663819
KM
20#include <vm/vm.h>
21
7795cb4d
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
7795cb4d
KB
27#include <ufs/lfs/lfs.h>
28#include <ufs/lfs/lfs_extern.h>
2bf2d153 29
841fa75e
KB
30static struct dinode *lfs_ifind __P((struct lfs *, ino_t, struct dinode *));
31
0a0d4fba 32int
0b4d6502 33lfs_init()
5d5124a1 34{
a79b7b81
KB
35#ifdef VERBOSE
36 printf("lfs_init\n");
37#endif
29ad237c 38 return (ufs_init());
5d5124a1
BJ
39}
40
3ebac878 41/*
29ad237c
KB
42 * Look up an LFS dinode number to find its incore vnode. If not already
43 * in core, read it in from the specified device. Return the inode locked.
44 * Detection and handling of mount points must be done by the calling routine.
5d5124a1 45 */
0a0d4fba 46int
9342689a
JH
47lfs_vget (ap)
48 struct vop_vget_args *ap;
49#define mntp (ap->a_mp)
50#define ino (ap->a_ino)
51#define vpp (ap->a_vpp)
5d5124a1 52{
7795cb4d 53 register struct lfs *fs;
29ad237c 54 register struct inode *ip;
7188ac27 55 struct buf *bp;
99a575da 56 struct ifile *ifp;
7795cb4d 57 struct vnode *vp;
ffcee610 58 struct ufsmount *ump;
99a575da 59 daddr_t daddr;
29ad237c 60 dev_t dev;
0a0d4fba 61 int error;
2e64ab65 62
a79b7b81
KB
63#ifdef VERBOSE
64 printf("lfs_vget\n");
65#endif
ffcee610
KM
66 ump = VFSTOUFS(mntp);
67 dev = ump->um_dev;
68 if ((*vpp = ufs_ihashget(dev, ino)) != NULL)
29ad237c 69 return (0);
0b4d6502 70
99a575da
KB
71 /* Translate the inode number to a disk address. */
72 fs = ump->um_lfs;
73 if (ino == LFS_IFILE_INUM)
74 daddr = fs->lfs_idaddr;
75 else {
76 LFS_IENTRY(ifp, fs, ino, bp);
77 daddr = ifp->if_daddr;
78 brelse(bp);
79 if (daddr == LFS_UNUSED_DADDR)
80 return (ENOENT);
81 }
82
0b4d6502 83 /* Allocate new vnode/inode. */
7795cb4d 84 if (error = lfs_vcreate(mntp, ino, &vp)) {
ffcee610 85 *vpp = NULL;
7188ac27
KM
86 return (error);
87 }
99a575da 88
1259a9f9
KM
89 /*
90 * Put it onto its hash chain and lock it so that other requests for
91 * this inode will block if they arrive while we are sleeping waiting
92 * for old data structures to be purged or for the contents of the
93 * disk portion of this inode to be read.
94 */
ffcee610 95 ip = VTOI(vp);
29ad237c 96 ufs_ihashins(ip);
0b4d6502 97
99a575da
KB
98 /*
99 * XXX
100 * This may not need to be here, logically it should go down with
101 * the i_devvp initialization.
102 * Ask Kirk.
103 */
104 ip->i_lfs = ump->um_lfs;
105
29ad237c 106 /* Read in the disk contents for the inode, copy into the inode. */
99a575da
KB
107 if (error =
108 bread(ump->um_devvp, daddr, (int)fs->lfs_bsize, NOCRED, &bp)) {
bd4160ab 109 /*
a79b7b81
KB
110 * The inode does not contain anything useful, so it
111 * would be misleading to leave it on its hash chain.
112 * Iput() will return it to the free list.
bd4160ab
KM
113 */
114 remque(ip);
115 ip->i_forw = ip;
116 ip->i_back = ip;
29ad237c
KB
117
118 /* Unlock and discard unneeded inode. */
119 ufs_iput(ip);
7188ac27 120 brelse(bp);
ffcee610 121 *vpp = NULL;
1259a9f9 122 return (error);
7188ac27 123 }
0b4d6502 124 ip->i_din = *lfs_ifind(fs, ino, bp->b_un.b_dino);
1259a9f9 125 brelse(bp);
0b4d6502 126
7795cb4d
KB
127 /*
128 * Initialize the vnode from the inode, check for aliases. In all
129 * cases re-init ip, the underlying vnode/inode may have changed.
130 */
9342689a 131 if (error = ufs_vinit(mntp, lfs_specop_p, LFS_FIFOOPS, &vp)) {
29ad237c 132 ufs_iput(ip);
ffcee610 133 *vpp = NULL;
29ad237c 134 return (error);
7188ac27 135 }
ffcee610
KM
136 /*
137 * Finish inode initialization now that aliasing has been resolved.
138 */
ffcee610
KM
139 ip->i_devvp = ump->um_devvp;
140 VREF(ip->i_devvp);
141 *vpp = vp;
7188ac27
KM
142 return (0);
143}
9342689a
JH
144#undef mntp
145#undef ino
146#undef vpp
3ebac878 147
841fa75e
KB
148/* Search a block for a specific dinode. */
149static struct dinode *
150lfs_ifind(fs, ino, dip)
151 struct lfs *fs;
152 ino_t ino;
153 register struct dinode *dip;
154{
155 register int cnt;
156
157#ifdef VERBOSE
158 printf("lfs_ifind: inode %d\n", ino);
159#endif
160 for (cnt = INOPB(fs); cnt--; ++dip)
161 if (dip->di_inum == ino)
162 return (dip);
163
164 panic("lfs_ifind: dinode %u not found", ino);
165 /* NOTREACHED */
166}
167
0a0d4fba 168int
9342689a
JH
169lfs_update (ap)
170 struct vop_update_args *ap;
171#define vp (ap->a_vp)
172#define ta (ap->a_ta)
173#define tm (ap->a_tm)
174#define waitfor (ap->a_waitfor)
ff56f48a 175{
ffcee610
KM
176 struct inode *ip;
177
a79b7b81
KB
178#ifdef VERBOSE
179 printf("lfs_update\n");
180#endif
ffcee610
KM
181 if (vp->v_mount->mnt_flag & MNT_RDONLY)
182 return (0);
183 ip = VTOI(vp);
184 if ((ip->i_flag & (IUPD|IACC|ICHG|IMOD)) == 0)
185 return (0);
186 if (ip->i_flag&IACC)
89663819 187 ip->i_atime.tv_sec = ta->tv_sec;
5b51b344 188 if (ip->i_flag&IUPD) {
89663819 189 ip->i_mtime.tv_sec = tm->tv_sec;
5b51b344
KM
190 INCRQUAD((ip)->i_modrev);
191 }
ffcee610 192 if (ip->i_flag&ICHG)
89663819 193 ip->i_ctime.tv_sec = time.tv_sec;
ffcee610
KM
194 ip->i_flag &= ~(IUPD|IACC|ICHG|IMOD);
195
b3071295
KB
196 /* Push back the vnode and any dirty blocks it may have. */
197 return (waitfor ? lfs_vflush(vp) : 0);
5d5124a1 198}
9342689a
JH
199#undef vp
200#undef ta
201#undef tm
202#undef waitfor
5d5124a1 203
2c68aab8 204/* Update segment usage information when removing a block. */
4ee2ad24
KB
205#define UPDATE_SEGUSE \
206 if (lastseg != -1) { \
207 LFS_SEGENTRY(sup, fs, lastseg, sup_bp); \
5b792b30 208 sup->su_nbytes -= num << fs->lfs_bshift; \
4ee2ad24
KB
209 LFS_UBWRITE(sup_bp); \
210 blocksreleased += num; \
211 }
2c68aab8
KB
212
213#define SEGDEC { \
214 if (daddr != UNASSIGNED) { \
215 if (lastseg != (seg = datosn(fs, daddr))) { \
216 UPDATE_SEGUSE; \
217 num = 1; \
218 lastseg = seg; \
219 } else \
220 ++num; \
221 } \
222}
223
5d5124a1 224/*
2c68aab8
KB
225 * Truncate the inode ip to at most length size. Update segment usage
226 * table information.
5d5124a1 227 */
29ad237c
KB
228/* ARGSUSED */
229int
9342689a
JH
230lfs_truncate (ap)
231 struct vop_truncate_args *ap;
232#define vp (ap->a_vp)
233#define length (ap->a_length)
234#define flags (ap->a_flags)
235#define cred (ap->a_cred)
5d5124a1 236{
9342689a 237 USES_VOP_UPDATE;
8f42dbe0 238 register INDIR *inp;
2c68aab8
KB
239 register int i;
240 register daddr_t *daddrp;
4ee2ad24 241 struct buf *bp, *sup_bp;
b3071295 242 struct ifile *ifp;
2c68aab8
KB
243 struct inode *ip;
244 struct lfs *fs;
245 INDIR a[NIADDR + 2], a_end[NIADDR + 2];
246 SEGUSE *sup;
247 daddr_t daddr, lastblock, lbn, olastblock;
0308fc84 248 long off, blocksreleased;
2c68aab8 249 int error, depth, lastseg, num, offset, seg, size;
4f083fd7 250
a79b7b81
KB
251#ifdef VERBOSE
252 printf("lfs_truncate\n");
253#endif
89663819 254 vnode_pager_setsize(vp, (u_long)length);
b3071295 255
2c68aab8 256 ip = VTOI(vp);
b3071295
KB
257 fs = ip->i_lfs;
258
259 /* If truncating the file to 0, update the version number. */
260 if (length == 0) {
261 LFS_IENTRY(ifp, fs, ip->i_number, bp);
262 ++ifp->if_version;
263 LFS_UBWRITE(bp);
264 }
265
29ad237c 266 /* If length is larger than the file, just update the times. */
2c68aab8
KB
267 if (ip->i_size <= length) {
268 ip->i_flag |= ICHG|IUPD;
9342689a 269 return (VOP_UPDATE(vp, &time, &time, 1));
7b2e4f05 270 }
b3071295 271
2c68aab8
KB
272 /*
273 * Calculate index into inode's block list of last direct and indirect
274 * blocks (if any) which we want to keep. Lastblock is 0 when the
275 * file is truncated to 0.
276 */
2c68aab8
KB
277 lastblock = lblkno(fs, length + fs->lfs_bsize - 1);
278 olastblock = lblkno(fs, ip->i_size + fs->lfs_bsize - 1) - 1;
29ad237c 279
c0bb1685 280 /*
29ad237c
KB
281 * Update the size of the file. If the file is not being truncated to
282 * a block boundry, the contents of the partial block following the end
283 * of the file must be zero'ed in case it ever become accessable again
284 * because of subsequent file growth.
28821bc5 285 */
28821bc5 286 offset = blkoff(fs, length);
29ad237c 287 if (offset == 0)
2c68aab8 288 ip->i_size = length;
29ad237c 289 else {
28821bc5 290 lbn = lblkno(fs, length);
4b61628b 291#ifdef QUOTA
2c68aab8 292 if (error = getinoquota(ip))
4b61628b 293 return (error);
d5075120 294#endif
2c68aab8 295 if (error = bread(vp, lbn, fs->lfs_bsize, NOCRED, &bp))
7188ac27 296 return (error);
2c68aab8 297 ip->i_size = length;
a79b7b81 298 size = blksize(fs);
2c68aab8 299 (void)vnode_pager_uncache(vp);
a5e62f37 300 bzero(bp->b_un.b_addr + offset, (unsigned)(size - offset));
9cf42d55 301 allocbuf(bp, size);
f28a1334 302 LFS_UBWRITE(bp);
5d5124a1 303 }
f28a1334 304 /*
2c68aab8
KB
305 * Modify sup->su_nbyte counters for each deleted block; keep track
306 * of number of blocks removed for ip->i_blocks.
307 */
308 blocksreleased = 0;
309 num = 0;
310 lastseg = -1;
311
312 for (lbn = olastblock; lbn >= lastblock;) {
313 lfs_bmaparray(vp, lbn, &daddr, a, &depth);
314 if (lbn == olastblock)
315 for (i = NIADDR + 2; i--;)
316 a_end[i] = a[i];
317 switch (depth) {
318 case 0: /* Direct block. */
319 daddr = ip->i_db[lbn];
320 SEGDEC;
321 ip->i_db[lbn] = 0;
322 --lbn;
323 break;
324#ifdef DIAGNOSTIC
325 case 1: /* An indirect block. */
326 panic("lfs_truncate: lfs_bmaparray returned depth 1");
327 /* NOTREACHED */
328#endif
329 default: /* Chain of indirect blocks. */
8f42dbe0
JH
330 inp = a + --depth;
331 if (inp->in_off > 0 && lbn != lastblock) {
332 lbn -= inp->in_off < lbn - lastblock ?
333 inp->in_off : lbn - lastblock;
2c68aab8
KB
334 break;
335 }
8f42dbe0
JH
336 for (; depth && (inp->in_off == 0 || lbn == lastblock);
337 --inp, --depth) {
2c68aab8
KB
338 /*
339 * XXX
340 * The indirect block may not yet exist, so
341 * bread will create one just so we can free
342 * it.
343 */
344 if (bread(vp,
8f42dbe0 345 inp->in_lbn, fs->lfs_bsize, NOCRED, &bp))
2c68aab8 346 panic("lfs_truncate: bread bno %d",
8f42dbe0
JH
347 inp->in_lbn);
348 daddrp = bp->b_un.b_daddr + inp->in_off;
349 for (i = inp->in_off;
2c68aab8
KB
350 i++ <= a_end[depth].in_off;) {
351 daddr = *daddrp++;
352 SEGDEC;
353 }
c86ca11e 354 a_end[depth].in_off = NINDIR(fs) - 1;
8f42dbe0 355 if (inp->in_off == 0)
c86ca11e
CS
356 brelse (bp);
357 else {
8f42dbe0 358 bzero(bp->b_un.b_daddr + inp->in_off,
2c68aab8 359 fs->lfs_bsize -
8f42dbe0 360 inp->in_off * sizeof(daddr_t));
2c68aab8 361 LFS_UBWRITE(bp);
c86ca11e 362 }
2c68aab8 363 }
c86ca11e 364 if (depth == 0 && a[1].in_off == 0) {
2c68aab8
KB
365 off = a[0].in_off;
366 daddr = ip->i_ib[off];
367 SEGDEC;
368 ip->i_ib[off] = 0;
369 }
5b792b30 370 if (lbn == lastblock || lbn <= NDADDR)
2c68aab8
KB
371 --lbn;
372 else {
373 lbn -= NINDIR(fs);
374 if (lbn < lastblock)
375 lbn = lastblock;
376 }
377 }
378 }
4ee2ad24 379 UPDATE_SEGUSE;
2c68aab8
KB
380 ip->i_blocks -= blocksreleased;
381 /*
f28a1334 382 * XXX
2c68aab8
KB
383 * Currently, we don't know when we allocate an indirect block, so
384 * ip->i_blocks isn't getting incremented appropriately. As a result,
385 * when we delete any indirect blocks, we get a bad number here.
f28a1334 386 */
2c68aab8
KB
387 if (ip->i_blocks < 0)
388 ip->i_blocks = 0;
389 ip->i_flag |= ICHG|IUPD;
390 (void)vinvalbuf(vp, length > 0);
9342689a 391 error = VOP_UPDATE(vp, &time, &time, MNT_WAIT);
a79b7b81 392 return (0);
7188ac27 393}
9342689a
JH
394#undef vp
395#undef length
396#undef flags
397#undef cred