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