1 /*-
2 * modified for Lites 1.1
3 *
4 * Aug 1995, Godmar Back (gback@cs.utah.edu)
5 * University of Utah, Department of Computer Science
6 */
7 /*-
8 * Copyright (c) 1982, 1986, 1989, 1993
9 * The Regents of the University of California. All rights reserved.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 4. Neither the name of the University nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 *
35 * @(#)ffs_inode.c 8.5 (Berkeley) 12/30/93
36 * $FreeBSD$
37 */
38
39 #include <sys/param.h>
40 #include <sys/systm.h>
41 #include <sys/mount.h>
42 #include <sys/bio.h>
43 #include <sys/buf.h>
44 #include <sys/vnode.h>
45 #include <sys/malloc.h>
46 #include <sys/rwlock.h>
47
48 #include <vm/vm.h>
49 #include <vm/vm_extern.h>
50
51 #include <fs/ext2fs/inode.h>
52 #include <fs/ext2fs/ext2_mount.h>
53 #include <fs/ext2fs/ext2fs.h>
54 #include <fs/ext2fs/fs.h>
55 #include <fs/ext2fs/ext2_extern.h>
56 #include <fs/ext2fs/ext2_extattr.h>
57
58 static int ext2_indirtrunc(struct inode *, daddr_t, daddr_t,
59 daddr_t, int, e4fs_daddr_t *);
60
61 /*
62 * Update the access, modified, and inode change times as specified by the
63 * IN_ACCESS, IN_UPDATE, and IN_CHANGE flags respectively. Write the inode
64 * to disk if the IN_MODIFIED flag is set (it may be set initially, or by
65 * the timestamp update). The IN_LAZYMOD flag is set to force a write
66 * later if not now. If we write now, then clear both IN_MODIFIED and
67 * IN_LAZYMOD to reflect the presumably successful write, and if waitfor is
68 * set, then wait for the write to complete.
69 */
70 int
71 ext2_update(struct vnode *vp, int waitfor)
72 {
73 struct m_ext2fs *fs;
74 struct buf *bp;
75 struct inode *ip;
76 int error;
77
78 ASSERT_VOP_ELOCKED(vp, "ext2_update");
79 ext2_itimes(vp);
80 ip = VTOI(vp);
81 if ((ip->i_flag & IN_MODIFIED) == 0 && waitfor == 0)
82 return (0);
83 ip->i_flag &= ~(IN_LAZYACCESS | IN_LAZYMOD | IN_MODIFIED);
84 fs = ip->i_e2fs;
85 if (fs->e2fs_ronly)
86 return (0);
87 if ((error = bread(ip->i_devvp,
88 fsbtodb(fs, ino_to_fsba(fs, ip->i_number)),
89 (int)fs->e2fs_bsize, NOCRED, &bp)) != 0) {
90 brelse(bp);
91 return (error);
92 }
93 error = ext2_i2ei(ip, (struct ext2fs_dinode *)((char *)bp->b_data +
94 EXT2_INODE_SIZE(fs) * ino_to_fsbo(fs, ip->i_number)));
95 if (error) {
96 brelse(bp);
97 return (error);
98 }
99 if (waitfor && !DOINGASYNC(vp))
100 return (bwrite(bp));
101 else {
102 bdwrite(bp);
103 return (0);
104 }
105 }
106
107 #define SINGLE 0 /* index of single indirect block */
108 #define DOUBLE 1 /* index of double indirect block */
109 #define TRIPLE 2 /* index of triple indirect block */
110 /*
111 * Truncate the inode oip to at most length size, freeing the
112 * disk blocks.
113 */
114 int
115 ext2_truncate(struct vnode *vp, off_t length, int flags, struct ucred *cred,
116 struct thread *td)
117 {
118 struct vnode *ovp = vp;
119 int32_t lastblock;
120 struct inode *oip;
121 int32_t bn, lbn, lastiblock[NIADDR], indir_lbn[NIADDR];
122 uint32_t oldblks[NDADDR + NIADDR], newblks[NDADDR + NIADDR];
123 struct m_ext2fs *fs;
124 struct buf *bp;
125 int offset, size, level;
126 e4fs_daddr_t count, nblocks, blocksreleased = 0;
127 int error, i, allerror;
128 off_t osize;
129 #ifdef INVARIANTS
130 struct bufobj *bo;
131 #endif
132
133 oip = VTOI(ovp);
134 #ifdef INVARIANTS
135 bo = &ovp->v_bufobj;
136 #endif
137
138 ASSERT_VOP_LOCKED(vp, "ext2_truncate");
139
140 if (length < 0)
141 return (EINVAL);
142
143 if (ovp->v_type == VLNK &&
144 oip->i_size < ovp->v_mount->mnt_maxsymlinklen) {
145 #ifdef INVARIANTS
146 if (length != 0)
147 panic("ext2_truncate: partial truncate of symlink");
148 #endif
149 bzero((char *)&oip->i_shortlink, (u_int)oip->i_size);
150 oip->i_size = 0;
151 oip->i_flag |= IN_CHANGE | IN_UPDATE;
152 return (ext2_update(ovp, 1));
153 }
154 if (oip->i_size == length) {
155 oip->i_flag |= IN_CHANGE | IN_UPDATE;
156 return (ext2_update(ovp, 0));
157 }
158 fs = oip->i_e2fs;
159 osize = oip->i_size;
160 /*
161 * Lengthen the size of the file. We must ensure that the
162 * last byte of the file is allocated. Since the smallest
163 * value of osize is 0, length will be at least 1.
164 */
165 if (osize < length) {
166 if (length > oip->i_e2fs->e2fs_maxfilesize)
167 return (EFBIG);
168 vnode_pager_setsize(ovp, length);
169 offset = blkoff(fs, length - 1);
170 lbn = lblkno(fs, length - 1);
171 flags |= BA_CLRBUF;
172 error = ext2_balloc(oip, lbn, offset + 1, cred, &bp, flags);
173 if (error) {
174 vnode_pager_setsize(vp, osize);
175 return (error);
176 }
177 oip->i_size = length;
178 if (bp->b_bufsize == fs->e2fs_bsize)
179 bp->b_flags |= B_CLUSTEROK;
180 if (flags & IO_SYNC)
181 bwrite(bp);
182 else if (DOINGASYNC(ovp))
183 bdwrite(bp);
184 else
185 bawrite(bp);
186 oip->i_flag |= IN_CHANGE | IN_UPDATE;
187 return (ext2_update(ovp, !DOINGASYNC(ovp)));
188 }
189 /*
190 * Shorten the size of the file. If the file is not being
191 * truncated to a block boundary, the contents of the
192 * partial block following the end of the file must be
193 * zero'ed in case it ever become accessible again because
194 * of subsequent file growth.
195 */
196 /* I don't understand the comment above */
197 offset = blkoff(fs, length);
198 if (offset == 0) {
199 oip->i_size = length;
200 } else {
201 lbn = lblkno(fs, length);
202 flags |= BA_CLRBUF;
203 error = ext2_balloc(oip, lbn, offset, cred, &bp, flags);
204 if (error)
205 return (error);
206 oip->i_size = length;
207 size = blksize(fs, oip, lbn);
208 bzero((char *)bp->b_data + offset, (u_int)(size - offset));
209 allocbuf(bp, size);
210 if (bp->b_bufsize == fs->e2fs_bsize)
211 bp->b_flags |= B_CLUSTEROK;
212 if (flags & IO_SYNC)
213 bwrite(bp);
214 else if (DOINGASYNC(ovp))
215 bdwrite(bp);
216 else
217 bawrite(bp);
218 }
219 /*
220 * Calculate index into inode's block list of
221 * last direct and indirect blocks (if any)
222 * which we want to keep. Lastblock is -1 when
223 * the file is truncated to 0.
224 */
225 lastblock = lblkno(fs, length + fs->e2fs_bsize - 1) - 1;
226 lastiblock[SINGLE] = lastblock - NDADDR;
227 lastiblock[DOUBLE] = lastiblock[SINGLE] - NINDIR(fs);
228 lastiblock[TRIPLE] = lastiblock[DOUBLE] - NINDIR(fs) * NINDIR(fs);
229 nblocks = btodb(fs->e2fs_bsize);
230 /*
231 * Update file and block pointers on disk before we start freeing
232 * blocks. If we crash before free'ing blocks below, the blocks
233 * will be returned to the free list. lastiblock values are also
234 * normalized to -1 for calls to ext2_indirtrunc below.
235 */
236 for (level = TRIPLE; level >= SINGLE; level--) {
237 oldblks[NDADDR + level] = oip->i_ib[level];
238 if (lastiblock[level] < 0) {
239 oip->i_ib[level] = 0;
240 lastiblock[level] = -1;
241 }
242 }
243 for (i = 0; i < NDADDR; i++) {
244 oldblks[i] = oip->i_db[i];
245 if (i > lastblock)
246 oip->i_db[i] = 0;
247 }
248 oip->i_flag |= IN_CHANGE | IN_UPDATE;
249 allerror = ext2_update(ovp, !DOINGASYNC(ovp));
250
251 /*
252 * Having written the new inode to disk, save its new configuration
253 * and put back the old block pointers long enough to process them.
254 * Note that we save the new block configuration so we can check it
255 * when we are done.
256 */
257 for (i = 0; i < NDADDR; i++) {
258 newblks[i] = oip->i_db[i];
259 oip->i_db[i] = oldblks[i];
260 }
261 for (i = 0; i < NIADDR; i++) {
262 newblks[NDADDR + i] = oip->i_ib[i];
263 oip->i_ib[i] = oldblks[NDADDR + i];
264 }
265 oip->i_size = osize;
266 error = vtruncbuf(ovp, length, (int)fs->e2fs_bsize);
267 if (error && (allerror == 0))
268 allerror = error;
269 vnode_pager_setsize(ovp, length);
270
271 /*
272 * Indirect blocks first.
273 */
274 indir_lbn[SINGLE] = -NDADDR;
275 indir_lbn[DOUBLE] = indir_lbn[SINGLE] - NINDIR(fs) - 1;
276 indir_lbn[TRIPLE] = indir_lbn[DOUBLE] - NINDIR(fs) * NINDIR(fs) - 1;
277 for (level = TRIPLE; level >= SINGLE; level--) {
278 bn = oip->i_ib[level];
279 if (bn != 0) {
280 error = ext2_indirtrunc(oip, indir_lbn[level],
281 fsbtodb(fs, bn), lastiblock[level], level, &count);
282 if (error)
283 allerror = error;
284 blocksreleased += count;
285 if (lastiblock[level] < 0) {
286 oip->i_ib[level] = 0;
287 ext2_blkfree(oip, bn, fs->e2fs_fsize);
288 blocksreleased += nblocks;
289 }
290 }
291 if (lastiblock[level] >= 0)
292 goto done;
293 }
294
295 /*
296 * All whole direct blocks or frags.
297 */
298 for (i = NDADDR - 1; i > lastblock; i--) {
299 long bsize;
300
301 bn = oip->i_db[i];
302 if (bn == 0)
303 continue;
304 oip->i_db[i] = 0;
305 bsize = blksize(fs, oip, i);
306 ext2_blkfree(oip, bn, bsize);
307 blocksreleased += btodb(bsize);
308 }
309 if (lastblock < 0)
310 goto done;
311
312 /*
313 * Finally, look for a change in size of the
314 * last direct block; release any frags.
315 */
316 bn = oip->i_db[lastblock];
317 if (bn != 0) {
318 long oldspace, newspace;
319
320 /*
321 * Calculate amount of space we're giving
322 * back as old block size minus new block size.
323 */
324 oldspace = blksize(fs, oip, lastblock);
325 oip->i_size = length;
326 newspace = blksize(fs, oip, lastblock);
327 if (newspace == 0)
328 panic("ext2_truncate: newspace");
329 if (oldspace - newspace > 0) {
330 /*
331 * Block number of space to be free'd is
332 * the old block # plus the number of frags
333 * required for the storage we're keeping.
334 */
335 bn += numfrags(fs, newspace);
336 ext2_blkfree(oip, bn, oldspace - newspace);
337 blocksreleased += btodb(oldspace - newspace);
338 }
339 }
340 done:
341 #ifdef INVARIANTS
342 for (level = SINGLE; level <= TRIPLE; level++)
343 if (newblks[NDADDR + level] != oip->i_ib[level])
344 panic("itrunc1");
345 for (i = 0; i < NDADDR; i++)
346 if (newblks[i] != oip->i_db[i])
347 panic("itrunc2");
348 BO_LOCK(bo);
349 if (length == 0 && (bo->bo_dirty.bv_cnt != 0 ||
350 bo->bo_clean.bv_cnt != 0))
351 panic("itrunc3");
352 BO_UNLOCK(bo);
353 #endif /* INVARIANTS */
354 /*
355 * Put back the real size.
356 */
357 oip->i_size = length;
358 if (oip->i_blocks >= blocksreleased)
359 oip->i_blocks -= blocksreleased;
360 else /* sanity */
361 oip->i_blocks = 0;
362 oip->i_flag |= IN_CHANGE;
363 vnode_pager_setsize(ovp, length);
364 return (allerror);
365 }
366
367 /*
368 * Release blocks associated with the inode ip and stored in the indirect
369 * block bn. Blocks are free'd in LIFO order up to (but not including)
370 * lastbn. If level is greater than SINGLE, the block is an indirect block
371 * and recursive calls to indirtrunc must be used to cleanse other indirect
372 * blocks.
373 *
374 * NB: triple indirect blocks are untested.
375 */
376
377 static int
378 ext2_indirtrunc(struct inode *ip, daddr_t lbn, daddr_t dbn,
379 daddr_t lastbn, int level, e4fs_daddr_t *countp)
380 {
381 struct buf *bp;
382 struct m_ext2fs *fs = ip->i_e2fs;
383 struct vnode *vp;
384 e2fs_daddr_t *bap, *copy;
385 int i, nblocks, error = 0, allerror = 0;
386 e2fs_lbn_t nb, nlbn, last;
387 e4fs_daddr_t blkcount, factor, blocksreleased = 0;
388
389 /*
390 * Calculate index in current block of last
391 * block to be kept. -1 indicates the entire
392 * block so we need not calculate the index.
393 */
394 factor = 1;
395 for (i = SINGLE; i < level; i++)
396 factor *= NINDIR(fs);
397 last = lastbn;
398 if (lastbn > 0)
399 last /= factor;
400 nblocks = btodb(fs->e2fs_bsize);
401 /*
402 * Get buffer of block pointers, zero those entries corresponding
403 * to blocks to be free'd, and update on disk copy first. Since
404 * double(triple) indirect before single(double) indirect, calls
405 * to bmap on these blocks will fail. However, we already have
406 * the on disk address, so we have to set the b_blkno field
407 * explicitly instead of letting bread do everything for us.
408 */
409 vp = ITOV(ip);
410 bp = getblk(vp, lbn, (int)fs->e2fs_bsize, 0, 0, 0);
411 if ((bp->b_flags & (B_DONE | B_DELWRI)) == 0) {
412 bp->b_iocmd = BIO_READ;
413 if (bp->b_bcount > bp->b_bufsize)
414 panic("ext2_indirtrunc: bad buffer size");
415 bp->b_blkno = dbn;
416 vfs_busy_pages(bp, 0);
417 bp->b_iooffset = dbtob(bp->b_blkno);
418 bstrategy(bp);
419 error = bufwait(bp);
420 }
421 if (error) {
422 brelse(bp);
423 *countp = 0;
424 return (error);
425 }
426 bap = (e2fs_daddr_t *)bp->b_data;
427 copy = malloc(fs->e2fs_bsize, M_TEMP, M_WAITOK);
428 bcopy((caddr_t)bap, (caddr_t)copy, (u_int)fs->e2fs_bsize);
429 bzero((caddr_t)&bap[last + 1],
430 (NINDIR(fs) - (last + 1)) * sizeof(e2fs_daddr_t));
431 if (last == -1)
432 bp->b_flags |= B_INVAL;
433 if (DOINGASYNC(vp)) {
434 bdwrite(bp);
435 } else {
436 error = bwrite(bp);
437 if (error)
438 allerror = error;
439 }
440 bap = copy;
441
442 /*
443 * Recursively free totally unused blocks.
444 */
445 for (i = NINDIR(fs) - 1, nlbn = lbn + 1 - i * factor; i > last;
446 i--, nlbn += factor) {
447 nb = bap[i];
448 if (nb == 0)
449 continue;
450 if (level > SINGLE) {
451 if ((error = ext2_indirtrunc(ip, nlbn,
452 fsbtodb(fs, nb), (int32_t)-1, level - 1, &blkcount)) != 0)
453 allerror = error;
454 blocksreleased += blkcount;
455 }
456 ext2_blkfree(ip, nb, fs->e2fs_bsize);
457 blocksreleased += nblocks;
458 }
459
460 /*
461 * Recursively free last partial block.
462 */
463 if (level > SINGLE && lastbn >= 0) {
464 last = lastbn % factor;
465 nb = bap[i];
466 if (nb != 0) {
467 if ((error = ext2_indirtrunc(ip, nlbn, fsbtodb(fs, nb),
468 last, level - 1, &blkcount)) != 0)
469 allerror = error;
470 blocksreleased += blkcount;
471 }
472 }
473 free(copy, M_TEMP);
474 *countp = blocksreleased;
475 return (allerror);
476 }
477
478 /*
479 * discard preallocated blocks
480 */
481 int
482 ext2_inactive(struct vop_inactive_args *ap)
483 {
484 struct vnode *vp = ap->a_vp;
485 struct inode *ip = VTOI(vp);
486 struct thread *td = ap->a_td;
487 int mode, error = 0;
488
489 /*
490 * Ignore inodes related to stale file handles.
491 */
492 if (ip->i_mode == 0)
493 goto out;
494 if (ip->i_nlink <= 0) {
495 ext2_extattr_free(ip);
496 error = ext2_truncate(vp, (off_t)0, 0, NOCRED, td);
497 ip->i_rdev = 0;
498 mode = ip->i_mode;
499 ip->i_mode = 0;
500 ip->i_flag |= IN_CHANGE | IN_UPDATE;
501 ext2_vfree(vp, ip->i_number, mode);
502 }
503 if (ip->i_flag & (IN_ACCESS | IN_CHANGE | IN_MODIFIED | IN_UPDATE))
504 ext2_update(vp, 0);
505 out:
506 /*
507 * If we are done with the inode, reclaim it
508 * so that it can be reused immediately.
509 */
510 if (ip->i_mode == 0)
511 vrecycle(vp);
512 return (error);
513 }
514
515 /*
516 * Reclaim an inode so that it can be used for other purposes.
517 */
518 int
519 ext2_reclaim(struct vop_reclaim_args *ap)
520 {
521 struct inode *ip;
522 struct vnode *vp = ap->a_vp;
523
524 ip = VTOI(vp);
525 if (ip->i_flag & IN_LAZYMOD) {
526 ip->i_flag |= IN_MODIFIED;
527 ext2_update(vp, 0);
528 }
529 vfs_hash_remove(vp);
530 free(vp->v_data, M_EXT2NODE);
531 vp->v_data = 0;
532 vnode_destroy_vobject(vp);
533 return (0);
534 }
Cache object: b50813f8598aa561cbec6e457ab06944
|