Commit | Line | Data |
---|---|---|
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 |
30 | static struct dinode *lfs_ifind __P((struct lfs *, ino_t, struct dinode *)); |
31 | ||
0a0d4fba | 32 | int |
0b4d6502 | 33 | lfs_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 | 46 | int |
9342689a JH |
47 | lfs_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. */ |
149 | static struct dinode * | |
150 | lfs_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 | 168 | int |
9342689a JH |
169 | lfs_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 */ |
229 | int | |
9342689a JH |
230 | lfs_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 |