2 * modified for Lites 1.1
4 * Aug 1995, Godmar Back (gback@cs.utah.edu)
5 * University of Utah, Department of Computer Science
8 * Copyright (c) 1982, 1986, 1989, 1993
9 * The Regents of the University of California. All rights reserved.
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
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 * 3. All advertising materials mentioning features or use of this software
20 * must display the following acknowledgement:
21 * This product includes software developed by the University of
22 * California, Berkeley and its contributors.
23 * 4. Neither the name of the University nor the names of its contributors
24 * may be used to endorse or promote products derived from this software
25 * without specific prior written permission.
27 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
28 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
31 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
32 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
33 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
34 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
35 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
36 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
39 * @(#)ext2_inode.c 8.5 (Berkeley) 12/30/93
40 * $FreeBSD: src/sys/gnu/ext2fs/ext2_inode.c,v 1.24.2.1 2000/08/03 00:52:57 peter Exp $
41 * $DragonFly: src/sys/vfs/gnu/ext2fs/ext2_inode.c,v 1.21 2007/05/06 19:23:33 dillon Exp $
44 #include "opt_quota.h"
46 #include <sys/param.h>
47 #include <sys/systm.h>
48 #include <sys/mount.h>
50 #include <sys/vnode.h>
51 #include <sys/malloc.h>
54 #include <vm/vm_extern.h>
58 #include "ext2mount.h"
61 #include "ext2_fs_sb.h"
63 #include "ext2_extern.h"
65 static int ext2_indirtrunc (struct inode
*, daddr_t
, off_t
, daddr_t
,
69 * Update the access, modified, and inode change times as specified by the
70 * IN_ACCESS, IN_UPDATE, and IN_CHANGE flags respectively. Write the inode
71 * to disk if the IN_MODIFIED flag is set (it may be set initially, or by
72 * the timestamp update). The IN_LAZYMOD flag is set to force a write
73 * later if not now. If we write now, then clear both IN_MODIFIED and
74 * IN_LAZYMOD to reflect the presumably successful write, and if waitfor is
75 * set, then wait for the write to complete.
78 ext2_update(struct vnode
*vp
, int waitfor
)
80 struct ext2_sb_info
*fs
;
87 if ((ip
->i_flag
& IN_MODIFIED
) == 0)
89 ip
->i_flag
&= ~(IN_LAZYMOD
| IN_MODIFIED
);
90 if (vp
->v_mount
->mnt_flag
& MNT_RDONLY
)
93 error
= bread(ip
->i_devvp
,
94 fsbtodoff(fs
, ino_to_fsba(fs
, ip
->i_number
)),
95 (int)fs
->s_blocksize
, &bp
);
100 ext2_di2ei( &ip
->i_din
, (struct ext2_inode
*) ((char *)bp
->b_data
+ EXT2_INODE_SIZE(fs
) *
101 ino_to_fsbo(fs
, ip
->i_number
)));
103 if (waitfor && (vp->v_mount->mnt_flag & MNT_ASYNC) == 0)
114 #define SINGLE 0 /* index of single indirect block */
115 #define DOUBLE 1 /* index of double indirect block */
116 #define TRIPLE 2 /* index of triple indirect block */
118 * Truncate the inode oip to at most length size, freeing the
122 ext2_truncate(struct vnode
*vp
, off_t length
, int flags
, struct ucred
*cred
)
124 struct vnode
*ovp
= vp
;
127 daddr_t bn
, lbn
, lastiblock
[NIADDR
], indir_lbn
[NIADDR
];
128 daddr_t oldblks
[NDADDR
+ NIADDR
], newblks
[NDADDR
+ NIADDR
];
129 struct ext2_sb_info
*fs
;
131 int offset
, size
, level
;
132 long count
, nblocks
, blocksreleased
= 0;
134 int aflags
, error
, allerror
;
137 kprintf("ext2_truncate called %d to %d\n", VTOI(ovp)->i_number, length);
139 * negative file sizes will totally break the code below and
140 * are not meaningful anyways.
146 if (ovp
->v_type
== VLNK
&&
147 oip
->i_size
< ovp
->v_mount
->mnt_maxsymlinklen
) {
150 panic("ext2_truncate: partial truncate of symlink");
152 bzero((char *)&oip
->i_shortlink
, (u_int
)oip
->i_size
);
154 oip
->i_flag
|= IN_CHANGE
| IN_UPDATE
;
155 return (EXT2_UPDATE(ovp
, 1));
157 if (oip
->i_size
== length
) {
158 oip
->i_flag
|= IN_CHANGE
| IN_UPDATE
;
159 return (EXT2_UPDATE(ovp
, 0));
162 if ((error
= ext2_getinoquota(oip
)) != 0)
167 ext2_discard_prealloc(oip
);
169 * Lengthen the size of the file. We must ensure that the
170 * last byte of the file is allocated. Since the smallest
171 * value of osize is 0, length will be at least 1.
173 if (osize
< length
) {
174 offset
= blkoff(fs
, length
- 1);
175 lbn
= lblkno(fs
, length
- 1);
179 vnode_pager_setsize(ovp
, length
);
180 error
= ext2_balloc(oip
, lbn
, offset
+ 1, cred
, &bp
, aflags
);
182 vnode_pager_setsize(ovp
, osize
);
185 oip
->i_size
= length
;
186 if (aflags
& IO_SYNC
)
190 oip
->i_flag
|= IN_CHANGE
| IN_UPDATE
;
191 return (EXT2_UPDATE(ovp
, 1));
194 * Shorten the size of the file. If the file is not being
195 * truncated to a block boundry, the contents of the
196 * partial block following the end of the file must be
197 * zero'ed in case it ever become accessable again because
198 * of subsequent file growth.
200 /* I don't understand the comment above */
201 offset
= blkoff(fs
, length
);
203 oip
->i_size
= length
;
205 lbn
= lblkno(fs
, length
);
209 error
= ext2_balloc(oip
, lbn
, offset
, cred
, &bp
, aflags
);
212 oip
->i_size
= length
;
213 size
= blksize(fs
, oip
, lbn
);
214 bzero((char *)bp
->b_data
+ offset
, (u_int
)(size
- offset
));
216 if (aflags
& IO_SYNC
)
222 * Calculate index into inode's block list of
223 * last direct and indirect blocks (if any)
224 * which we want to keep. Lastblock is -1 when
225 * the file is truncated to 0.
227 lastblock
= lblkno(fs
, length
+ fs
->s_blocksize
- 1) - 1;
228 lastiblock
[SINGLE
] = lastblock
- NDADDR
;
229 lastiblock
[DOUBLE
] = lastiblock
[SINGLE
] - NINDIR(fs
);
230 lastiblock
[TRIPLE
] = lastiblock
[DOUBLE
] - NINDIR(fs
) * NINDIR(fs
);
231 nblocks
= btodb(fs
->s_blocksize
);
233 * Update file and block pointers on disk before we start freeing
234 * blocks. If we crash before free'ing blocks below, the blocks
235 * will be returned to the free list. lastiblock values are also
236 * normalized to -1 for calls to ext2_indirtrunc below.
238 bcopy((caddr_t
)&oip
->i_db
[0], (caddr_t
)oldblks
, sizeof oldblks
);
239 for (level
= TRIPLE
; level
>= SINGLE
; level
--)
240 if (lastiblock
[level
] < 0) {
241 oip
->i_ib
[level
] = 0;
242 lastiblock
[level
] = -1;
244 for (i
= NDADDR
- 1; i
> lastblock
; i
--)
246 oip
->i_flag
|= IN_CHANGE
| IN_UPDATE
;
247 allerror
= EXT2_UPDATE(ovp
, 1);
250 * Having written the new inode to disk, save its new configuration
251 * and put back the old block pointers long enough to process them.
252 * Note that we save the new block configuration so we can check it
255 bcopy((caddr_t
)&oip
->i_db
[0], (caddr_t
)newblks
, sizeof newblks
);
256 bcopy((caddr_t
)oldblks
, (caddr_t
)&oip
->i_db
[0], sizeof oldblks
);
258 error
= vtruncbuf(ovp
, length
, (int)fs
->s_blocksize
);
259 if (error
&& (allerror
== 0))
263 * Indirect blocks first.
265 indir_lbn
[SINGLE
] = -NDADDR
;
266 indir_lbn
[DOUBLE
] = indir_lbn
[SINGLE
] - NINDIR(fs
) - 1;
267 indir_lbn
[TRIPLE
] = indir_lbn
[DOUBLE
] - NINDIR(fs
) * NINDIR(fs
) - 1;
268 for (level
= TRIPLE
; level
>= SINGLE
; level
--) {
269 bn
= oip
->i_ib
[level
];
271 error
= ext2_indirtrunc(oip
, indir_lbn
[level
],
272 fsbtodoff(fs
, bn
), lastiblock
[level
], level
, &count
);
275 blocksreleased
+= count
;
276 if (lastiblock
[level
] < 0) {
277 oip
->i_ib
[level
] = 0;
278 ext2_blkfree(oip
, bn
, fs
->s_frag_size
);
279 blocksreleased
+= nblocks
;
282 if (lastiblock
[level
] >= 0)
287 * All whole direct blocks or frags.
289 for (i
= NDADDR
- 1; i
> lastblock
; i
--) {
296 bsize
= blksize(fs
, oip
, i
);
297 ext2_blkfree(oip
, bn
, bsize
);
298 blocksreleased
+= btodb(bsize
);
304 * Finally, look for a change in size of the
305 * last direct block; release any frags.
307 bn
= oip
->i_db
[lastblock
];
309 long oldspace
, newspace
;
312 * Calculate amount of space we're giving
313 * back as old block size minus new block size.
315 oldspace
= blksize(fs
, oip
, lastblock
);
316 oip
->i_size
= length
;
317 newspace
= blksize(fs
, oip
, lastblock
);
319 panic("itrunc: newspace");
320 if (oldspace
- newspace
> 0) {
322 * Block number of space to be free'd is
323 * the old block # plus the number of frags
324 * required for the storage we're keeping.
326 bn
+= numfrags(fs
, newspace
);
327 ext2_blkfree(oip
, bn
, oldspace
- newspace
);
328 blocksreleased
+= btodb(oldspace
- newspace
);
333 for (level
= SINGLE
; level
<= TRIPLE
; level
++)
334 if (newblks
[NDADDR
+ level
] != oip
->i_ib
[level
])
336 for (i
= 0; i
< NDADDR
; i
++)
337 if (newblks
[i
] != oip
->i_db
[i
])
339 if (length
== 0 && (!RB_EMPTY(&ovp
->v_rbdirty_tree
) ||
340 !RB_EMPTY(&ovp
->v_rbclean_tree
)))
342 #endif /* DIAGNOSTIC */
344 * Put back the real size.
346 oip
->i_size
= length
;
347 oip
->i_blocks
-= blocksreleased
;
348 if (oip
->i_blocks
< 0) /* sanity */
350 oip
->i_flag
|= IN_CHANGE
;
351 vnode_pager_setsize(ovp
, length
);
353 ext2_chkdq(oip
, -blocksreleased
, NOCRED
, 0);
359 * Release blocks associated with the inode ip and stored in the indirect
360 * block bn. Blocks are free'd in LIFO order up to (but not including)
361 * lastbn. If level is greater than SINGLE, the block is an indirect block
362 * and recursive calls to indirtrunc must be used to cleanse other indirect
365 * NB: triple indirect blocks are untested.
369 ext2_indirtrunc(struct inode
*ip
, daddr_t lbn
, off_t doffset
, daddr_t lastbn
,
370 int level
, long *countp
)
374 struct ext2_sb_info
*fs
= ip
->i_e2fs
;
377 daddr_t
*copy
, nb
, nlbn
, last
;
378 long blkcount
, factor
;
379 int nblocks
, blocksreleased
= 0;
380 int error
= 0, allerror
= 0;
383 * Calculate index in current block of last
384 * block to be kept. -1 indicates the entire
385 * block so we need not calculate the index.
388 for (i
= SINGLE
; i
< level
; i
++)
389 factor
*= NINDIR(fs
);
393 nblocks
= btodb(fs
->s_blocksize
);
395 * Get buffer of block pointers, zero those entries corresponding
396 * to blocks to be free'd, and update on disk copy first. Since
397 * double(triple) indirect before single(double) indirect, calls
398 * to bmap on these blocks will fail. However, we already have
399 * the on disk address, so we have to set the bio_offset field
400 * explicitly instead of letting bread do everything for us.
403 bp
= getblk(vp
, lblktodoff(fs
, lbn
), (int)fs
->s_blocksize
, 0, 0);
404 if ((bp
->b_flags
& B_CACHE
) == 0) {
405 bp
->b_flags
&= ~(B_ERROR
| B_INVAL
);
406 bp
->b_cmd
= BUF_CMD_READ
;
407 if (bp
->b_bcount
> bp
->b_bufsize
)
408 panic("ext2_indirtrunc: bad buffer size");
409 bp
->b_bio2
.bio_offset
= doffset
;
410 bp
->b_bio1
.bio_done
= biodone_sync
;
411 bp
->b_bio1
.bio_flags
|= BIO_SYNC
;
412 vfs_busy_pages(bp
->b_vp
, bp
);
413 vn_strategy(vp
, &bp
->b_bio1
);
414 error
= biowait(&bp
->b_bio1
, "biord");
422 bap
= (daddr_t
*)bp
->b_data
;
423 MALLOC(copy
, daddr_t
*, fs
->s_blocksize
, M_TEMP
, M_WAITOK
);
424 bcopy((caddr_t
)bap
, (caddr_t
)copy
, (u_int
)fs
->s_blocksize
);
425 bzero((caddr_t
)&bap
[last
+ 1],
426 (u_int
)(NINDIR(fs
) - (last
+ 1)) * sizeof (daddr_t
));
428 bp
->b_flags
|= B_INVAL
;
435 * Recursively free totally unused blocks.
437 for (i
= NINDIR(fs
) - 1, nlbn
= lbn
+ 1 - i
* factor
; i
> last
;
438 i
--, nlbn
+= factor
) {
442 if (level
> SINGLE
) {
443 if ((error
= ext2_indirtrunc(ip
, nlbn
,
444 fsbtodoff(fs
, nb
), (daddr_t
)-1, level
- 1, &blkcount
)) != 0)
446 blocksreleased
+= blkcount
;
448 ext2_blkfree(ip
, nb
, fs
->s_blocksize
);
449 blocksreleased
+= nblocks
;
453 * Recursively free last partial block.
455 if (level
> SINGLE
&& lastbn
>= 0) {
456 last
= lastbn
% factor
;
459 error
= ext2_indirtrunc(ip
, nlbn
, fsbtodoff(fs
, nb
),
460 last
, level
- 1, &blkcount
);
463 blocksreleased
+= blkcount
;
467 *countp
= blocksreleased
;
472 * Last reference to an inode. If necessary, write or delete it.
474 * ext2_inactive(struct vnode *a_vp)
477 ext2_inactive(struct vop_inactive_args
*ap
)
479 struct vnode
*vp
= ap
->a_vp
;
480 struct inode
*ip
= VTOI(vp
);
483 ext2_discard_prealloc(ip
);
484 if (prtactive
&& vp
->v_sysref
.refcnt
> 1)
485 vprint("ext2_inactive: pushing active", vp
);
488 * Ignore inodes related to stale file handles.
490 if (ip
== NULL
|| ip
->i_mode
== 0)
492 if (ip
->i_nlink
<= 0 && (vp
->v_mount
->mnt_flag
& MNT_RDONLY
) == 0) {
494 if (!ext2_getinoquota(ip
))
495 (void)ext2_chkiq(ip
, -1, NOCRED
, FORCE
);
497 error
= EXT2_TRUNCATE(vp
, (off_t
)0, 0, NOCRED
);
501 ip
->i_flag
|= IN_CHANGE
| IN_UPDATE
;
502 EXT2_VFREE(vp
, ip
->i_number
, mode
);
504 if (ip
->i_flag
& (IN_ACCESS
| IN_CHANGE
| IN_MODIFIED
| IN_UPDATE
))
508 * If we are done with the inode, reclaim it
509 * so that it can be reused immediately.
511 if (ip
== NULL
|| ip
->i_mode
== 0)
517 * Reclaim an inode so that it can be used for other purposes.
519 * ext2_reclaim(struct vnode *a_vp)
522 ext2_reclaim(struct vop_reclaim_args
*ap
)
525 struct vnode
*vp
= ap
->a_vp
;
530 if (prtactive
&& vp
->v_sysref
.refcnt
> 1)
531 vprint("ext2_reclaim: pushing active", vp
);
538 if (ip
->i_flag
& IN_LAZYMOD
) {
539 ip
->i_flag
|= IN_MODIFIED
;
544 if (ip
&& (ip
->i_flag
& (IN_ACCESS
| IN_CHANGE
| IN_MODIFIED
| IN_UPDATE
))) {
545 kprintf("WARNING: INODE %ld flags %08x: modified inode being released!\n", (long)ip
->i_number
, (int)ip
->i_flag
);
546 ip
->i_flag
|= IN_MODIFIED
;
551 * Remove the inode from its hash chain and purge namecache
552 * data associated with the vnode.
562 for (i
= 0; i
< MAXQUOTAS
; i
++) {
563 if (ip
->i_dquot
[i
] != NODQUOT
) {
564 ext2_dqrele(vp
, ip
->i_dquot
[i
]);
565 ip
->i_dquot
[i
] = NODQUOT
;
570 if (ip
->i_dirhash
!= NULL
)
571 ext2dirhash_free(ip
);
573 kfree(ip
, VFSTOEXT2(vp
->v_mount
)->um_malloctype
);