1 /* $NetBSD: ext2fs_inode.c,v 1.74 2011/06/16 09:21:03 hannken Exp $ */
4 * Copyright (c) 1982, 1986, 1989, 1993
5 * The Regents of the University of California. All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the University nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * @(#)ffs_inode.c 8.8 (Berkeley) 10/19/94
32 * Modified for ext2fs by Manuel Bouyer.
36 * Copyright (c) 1997 Manuel Bouyer.
38 * Redistribution and use in source and binary forms, with or without
39 * modification, are permitted provided that the following conditions
41 * 1. Redistributions of source code must retain the above copyright
42 * notice, this list of conditions and the following disclaimer.
43 * 2. Redistributions in binary form must reproduce the above copyright
44 * notice, this list of conditions and the following disclaimer in the
45 * documentation and/or other materials provided with the distribution.
47 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
48 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
49 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
50 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
51 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
52 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
53 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
54 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
55 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
56 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
58 * @(#)ffs_inode.c 8.8 (Berkeley) 10/19/94
59 * Modified for ext2fs by Manuel Bouyer.
62 #include <sys/cdefs.h>
63 __KERNEL_RCSID(0, "$NetBSD: ext2fs_inode.c,v 1.74 2011/06/16 09:21:03 hannken Exp $");
65 #include <sys/param.h>
66 #include <sys/systm.h>
67 #include <sys/mount.h>
71 #include <sys/vnode.h>
72 #include <sys/kernel.h>
73 #include <sys/malloc.h>
74 #include <sys/trace.h>
75 #include <sys/resourcevar.h>
76 #include <sys/kauth.h>
78 #include <ufs/ufs/inode.h>
79 #include <ufs/ufs/ufsmount.h>
80 #include <ufs/ufs/ufs_extern.h>
82 #include <ufs/ext2fs/ext2fs.h>
83 #include <ufs/ext2fs/ext2fs_extern.h>
87 static int ext2fs_indirtrunc(struct inode
*, daddr_t
, daddr_t
,
88 daddr_t
, int, long *);
91 * Get the size of an inode.
94 ext2fs_size(struct inode
*ip
)
96 uint64_t size
= ip
->i_e2fs_size
;
98 if ((ip
->i_e2fs_mode
& IFMT
) == IFREG
)
99 size
|= (uint64_t)ip
->i_e2fs_dacl
<< 32;
104 ext2fs_setsize(struct inode
*ip
, uint64_t size
)
106 if ((ip
->i_e2fs_mode
& IFMT
) == IFREG
||
107 ip
->i_e2fs_mode
== 0) {
108 ip
->i_e2fs_dacl
= size
>> 32;
109 if (size
>= 0x80000000U
) {
110 struct m_ext2fs
*fs
= ip
->i_e2fs
;
112 if (fs
->e2fs
.e2fs_rev
<= E2FS_REV0
) {
113 /* Linux automagically upgrades to REV1 here! */
116 if (!(fs
->e2fs
.e2fs_features_rocompat
117 & EXT2F_ROCOMPAT_LARGEFILE
)) {
118 fs
->e2fs
.e2fs_features_rocompat
|=
119 EXT2F_ROCOMPAT_LARGEFILE
;
123 } else if (size
>= 0x80000000U
)
126 ip
->i_e2fs_size
= size
;
132 * Last reference to an inode. If necessary, write or delete it.
135 ext2fs_inactive(void *v
)
137 struct vop_inactive_args
/* {
141 struct vnode
*vp
= ap
->a_vp
;
142 struct inode
*ip
= VTOI(vp
);
145 if (prtactive
&& vp
->v_usecount
!= 0)
146 vprint("ext2fs_inactive: pushing active", vp
);
147 /* Get rid of inodes related to stale file handles. */
148 if (ip
->i_e2fs_mode
== 0 || ip
->i_e2fs_dtime
!= 0)
152 if (ip
->i_e2fs_nlink
== 0 && (vp
->v_mount
->mnt_flag
& MNT_RDONLY
) == 0) {
153 /* Defer final inode free and update to reclaim.*/
154 if (ext2fs_size(ip
) != 0) {
155 error
= ext2fs_truncate(vp
, (off_t
)0, 0, NOCRED
);
157 ip
->i_e2fs_dtime
= time_second
;
158 ip
->i_flag
|= IN_CHANGE
| IN_UPDATE
;
161 if (ip
->i_flag
& (IN_CHANGE
| IN_UPDATE
| IN_MODIFIED
)) {
162 ext2fs_update(vp
, NULL
, NULL
, 0);
166 * If we are done with the inode, reclaim it
167 * so that it can be reused immediately.
169 *ap
->a_recycle
= (ip
->i_e2fs_dtime
!= 0);
176 * Update the access, modified, and inode change times as specified by the
177 * IACCESS, IUPDATE, and ICHANGE flags respectively. The IMODIFIED flag is
178 * used to specify that the inode needs to be updated but that the times have
179 * already been set. The access and modified times are taken from the second
180 * and third parameters; the inode change time is always taken from the current
181 * time. If UPDATE_WAIT or UPDATE_DIROP is set, then wait for the disk
182 * write of the inode to complete.
185 ext2fs_update(struct vnode
*vp
, const struct timespec
*acc
,
186 const struct timespec
*mod
, int updflags
)
195 if (vp
->v_mount
->mnt_flag
& MNT_RDONLY
)
198 EXT2FS_ITIMES(ip
, acc
, mod
, NULL
);
199 if (updflags
& UPDATE_CLOSE
)
200 flags
= ip
->i_flag
& (IN_MODIFIED
| IN_ACCESSED
);
202 flags
= ip
->i_flag
& IN_MODIFIED
;
207 error
= bread(ip
->i_devvp
,
208 fsbtodb(fs
, ino_to_fsba(fs
, ip
->i_number
)),
209 (int)fs
->e2fs_bsize
, NOCRED
, B_MODIFY
, &bp
);
214 ip
->i_flag
&= ~(IN_MODIFIED
| IN_ACCESSED
);
215 cp
= (char *)bp
->b_data
+
216 (ino_to_fsbo(fs
, ip
->i_number
) * EXT2_DINODE_SIZE(fs
));
217 e2fs_isave(ip
->i_din
.e2fs_din
, (struct ext2fs_dinode
*)cp
);
218 if ((updflags
& (UPDATE_WAIT
|UPDATE_DIROP
)) != 0 &&
219 (flags
& IN_MODIFIED
) != 0 &&
220 (vp
->v_mount
->mnt_flag
& MNT_ASYNC
) == 0)
228 #define SINGLE 0 /* index of single indirect block */
229 #define DOUBLE 1 /* index of double indirect block */
230 #define TRIPLE 2 /* index of triple indirect block */
232 * Truncate the inode oip to at most length size, freeing the
236 ext2fs_truncate(struct vnode
*ovp
, off_t length
, int ioflag
,
240 struct inode
*oip
= VTOI(ovp
);
241 daddr_t bn
, lastiblock
[NIADDR
], indir_lbn
[NIADDR
];
243 int32_t oldblks
[NDADDR
+ NIADDR
], newblks
[NDADDR
+ NIADDR
];
245 int offset
, size
, level
;
246 long count
, blocksreleased
= 0;
248 int error
, allerror
= 0;
251 struct ufsmount
*ump
= oip
->i_ump
;
253 if (ovp
->v_type
== VCHR
|| ovp
->v_type
== VBLK
||
254 ovp
->v_type
== VFIFO
|| ovp
->v_type
== VSOCK
) {
261 if (ovp
->v_type
== VLNK
&&
262 (ext2fs_size(oip
) < ump
->um_maxsymlinklen
||
263 (ump
->um_maxsymlinklen
== 0 && oip
->i_e2fs_nblock
== 0))) {
264 KDASSERT(length
== 0);
265 memset((char *)&oip
->i_din
.e2fs_din
->e2di_shortlink
, 0,
266 (u_int
)ext2fs_size(oip
));
267 (void)ext2fs_setsize(oip
, 0);
268 oip
->i_flag
|= IN_CHANGE
| IN_UPDATE
;
269 return (ext2fs_update(ovp
, NULL
, NULL
, 0));
271 if (ext2fs_size(oip
) == length
) {
272 /* still do a uvm_vnp_setsize() as writesize may be larger */
273 uvm_vnp_setsize(ovp
, length
);
274 oip
->i_flag
|= IN_CHANGE
| IN_UPDATE
;
275 return (ext2fs_update(ovp
, NULL
, NULL
, 0));
278 if (length
> ump
->um_maxfilesize
)
281 osize
= ext2fs_size(oip
);
284 * Lengthen the size of the file. We must ensure that the
285 * last byte of the file is allocated. Since the smallest
286 * value of osize is 0, length will be at least 1.
288 if (osize
< length
) {
289 uvm_vnp_setwritesize(ovp
, length
);
290 error
= ufs_balloc_range(ovp
, length
- 1, 1, cred
,
291 ioflag
& IO_SYNC
? B_SYNC
: 0);
293 (void) ext2fs_truncate(ovp
, osize
, ioflag
& IO_SYNC
,
297 uvm_vnp_setsize(ovp
, length
);
298 oip
->i_flag
|= IN_CHANGE
| IN_UPDATE
;
299 KASSERT(error
|| ovp
->v_size
== ext2fs_size(oip
));
300 return (ext2fs_update(ovp
, NULL
, NULL
, 0));
303 * Shorten the size of the file. If the file is not being
304 * truncated to a block boundry, the contents of the
305 * partial block following the end of the file must be
306 * zero'ed in case it ever become accessible again because
307 * of subsequent file growth.
309 offset
= blkoff(fs
, length
);
311 size
= fs
->e2fs_bsize
;
313 /* XXXUBC we should handle more than just VREG */
314 ubc_zerorange(&ovp
->v_uobj
, length
, size
- offset
,
315 UBC_UNMAP_FLAG(ovp
));
317 (void)ext2fs_setsize(oip
, length
);
318 uvm_vnp_setsize(ovp
, length
);
320 * Calculate index into inode's block list of
321 * last direct and indirect blocks (if any)
322 * which we want to keep. Lastblock is -1 when
323 * the file is truncated to 0.
325 lastblock
= lblkno(fs
, length
+ fs
->e2fs_bsize
- 1) - 1;
326 lastiblock
[SINGLE
] = lastblock
- NDADDR
;
327 lastiblock
[DOUBLE
] = lastiblock
[SINGLE
] - NINDIR(fs
);
328 lastiblock
[TRIPLE
] = lastiblock
[DOUBLE
] - NINDIR(fs
) * NINDIR(fs
);
329 nblocks
= btodb(fs
->e2fs_bsize
);
331 * Update file and block pointers on disk before we start freeing
332 * blocks. If we crash before free'ing blocks below, the blocks
333 * will be returned to the free list. lastiblock values are also
334 * normalized to -1 for calls to ext2fs_indirtrunc below.
336 memcpy((void *)oldblks
, (void *)&oip
->i_e2fs_blocks
[0], sizeof oldblks
);
338 for (level
= TRIPLE
; level
>= SINGLE
; level
--) {
339 if (lastiblock
[level
] < 0 && oldblks
[NDADDR
+ level
] != 0) {
341 oip
->i_e2fs_blocks
[NDADDR
+ level
] = 0;
342 lastiblock
[level
] = -1;
345 for (i
= 0; i
< NDADDR
; i
++) {
346 if (i
> lastblock
&& oldblks
[i
] != 0) {
348 oip
->i_e2fs_blocks
[i
] = 0;
351 oip
->i_flag
|= IN_CHANGE
| IN_UPDATE
;
353 error
= ext2fs_update(ovp
, NULL
, NULL
, UPDATE_WAIT
);
354 if (error
&& !allerror
)
359 * Having written the new inode to disk, save its new configuration
360 * and put back the old block pointers long enough to process them.
361 * Note that we save the new block configuration so we can check it
364 memcpy((void *)newblks
, (void *)&oip
->i_e2fs_blocks
[0], sizeof newblks
);
365 memcpy((void *)&oip
->i_e2fs_blocks
[0], (void *)oldblks
, sizeof oldblks
);
367 (void)ext2fs_setsize(oip
, osize
);
368 error
= vtruncbuf(ovp
, lastblock
+ 1, 0, 0);
369 if (error
&& !allerror
)
373 * Indirect blocks first.
375 indir_lbn
[SINGLE
] = -NDADDR
;
376 indir_lbn
[DOUBLE
] = indir_lbn
[SINGLE
] - NINDIR(fs
) -1;
377 indir_lbn
[TRIPLE
] = indir_lbn
[DOUBLE
] - NINDIR(fs
) * NINDIR(fs
) - 1;
378 for (level
= TRIPLE
; level
>= SINGLE
; level
--) {
380 bn
= fs2h32(oip
->i_e2fs_blocks
[NDADDR
+ level
]);
382 error
= ext2fs_indirtrunc(oip
, indir_lbn
[level
],
383 fsbtodb(fs
, bn
), lastiblock
[level
], level
, &count
);
386 blocksreleased
+= count
;
387 if (lastiblock
[level
] < 0) {
388 oip
->i_e2fs_blocks
[NDADDR
+ level
] = 0;
389 ext2fs_blkfree(oip
, bn
);
390 blocksreleased
+= nblocks
;
393 if (lastiblock
[level
] >= 0)
398 * All whole direct blocks or frags.
400 for (i
= NDADDR
- 1; i
> lastblock
; i
--) {
402 bn
= fs2h32(oip
->i_e2fs_blocks
[i
]);
405 oip
->i_e2fs_blocks
[i
] = 0;
406 ext2fs_blkfree(oip
, bn
);
407 blocksreleased
+= btodb(fs
->e2fs_bsize
);
412 for (level
= SINGLE
; level
<= TRIPLE
; level
++)
413 if (newblks
[NDADDR
+ level
] !=
414 oip
->i_e2fs_blocks
[NDADDR
+ level
])
415 panic("ext2fs_truncate1");
416 for (i
= 0; i
< NDADDR
; i
++)
417 if (newblks
[i
] != oip
->i_e2fs_blocks
[i
])
418 panic("ext2fs_truncate2");
420 (!LIST_EMPTY(&ovp
->v_cleanblkhd
) ||
421 !LIST_EMPTY(&ovp
->v_dirtyblkhd
)))
422 panic("ext2fs_truncate3");
423 #endif /* DIAGNOSTIC */
425 * Put back the real size.
427 (void)ext2fs_setsize(oip
, length
);
428 oip
->i_e2fs_nblock
-= blocksreleased
;
429 oip
->i_flag
|= IN_CHANGE
;
430 KASSERT(ovp
->v_type
!= VREG
|| ovp
->v_size
== ext2fs_size(oip
));
435 * Release blocks associated with the inode ip and stored in the indirect
436 * block bn. Blocks are free'd in LIFO order up to (but not including)
437 * lastbn. If level is greater than SINGLE, the block is an indirect block
438 * and recursive calls to indirtrunc must be used to cleanse other indirect
441 * NB: triple indirect blocks are untested.
444 ext2fs_indirtrunc(struct inode
*ip
, daddr_t lbn
, daddr_t dbn
, daddr_t lastbn
,
445 int level
, long *countp
)
449 struct m_ext2fs
*fs
= ip
->i_e2fs
;
450 int32_t *bap
; /* XXX ondisk32 */
452 daddr_t nb
, nlbn
, last
;
453 int32_t *copy
= NULL
; /* XXX ondisk32 */
454 long blkcount
, factor
;
455 int nblocks
, blocksreleased
= 0;
456 int error
= 0, allerror
= 0;
459 * Calculate index in current block of last
460 * block to be kept. -1 indicates the entire
461 * block so we need not calculate the index.
464 for (i
= SINGLE
; i
< level
; i
++)
465 factor
*= NINDIR(fs
);
469 nblocks
= btodb(fs
->e2fs_bsize
);
471 * Get buffer of block pointers, zero those entries corresponding
472 * to blocks to be free'd, and update on disk copy first. Since
473 * double(triple) indirect before single(double) indirect, calls
474 * to bmap on these blocks will fail. However, we already have
475 * the on disk address, so we have to set the b_blkno field
476 * explicitly instead of letting bread do everything for us.
479 bp
= getblk(vp
, lbn
, (int)fs
->e2fs_bsize
, 0, 0);
480 if (bp
->b_oflags
& (BO_DONE
| BO_DELWRI
)) {
481 /* Braces must be here in case trace evaluates to nothing. */
482 trace(TR_BREADHIT
, pack(vp
, fs
->e2fs_bsize
), lbn
);
484 trace(TR_BREADMISS
, pack(vp
, fs
->e2fs_bsize
), lbn
);
485 curlwp
->l_ru
.ru_inblock
++; /* pay for read */
486 bp
->b_flags
|= B_READ
;
487 if (bp
->b_bcount
> bp
->b_bufsize
)
488 panic("ext2fs_indirtrunc: bad buffer size");
490 VOP_STRATEGY(vp
, bp
);
499 bap
= (int32_t *)bp
->b_data
; /* XXX ondisk32 */
502 copy
= malloc(fs
->e2fs_bsize
, M_TEMP
, M_WAITOK
);
503 memcpy((void *)copy
, (void *)bap
, (u_int
)fs
->e2fs_bsize
);
504 memset((void *)&bap
[last
+ 1], 0,
505 (u_int
)(NINDIR(fs
) - (last
+ 1)) * sizeof (uint32_t));
513 * Recursively free totally unused blocks.
515 for (i
= NINDIR(fs
) - 1,
516 nlbn
= lbn
+ 1 - i
* factor
; i
> last
;
517 i
--, nlbn
+= factor
) {
522 if (level
> SINGLE
) {
523 error
= ext2fs_indirtrunc(ip
, nlbn
, fsbtodb(fs
, nb
),
524 (daddr_t
)-1, level
- 1,
528 blocksreleased
+= blkcount
;
530 ext2fs_blkfree(ip
, nb
);
531 blocksreleased
+= nblocks
;
535 * Recursively free last partial block.
537 if (level
> SINGLE
&& lastbn
>= 0) {
538 last
= lastbn
% factor
;
542 error
= ext2fs_indirtrunc(ip
, nlbn
, fsbtodb(fs
, nb
),
543 last
, level
- 1, &blkcount
);
546 blocksreleased
+= blkcount
;
553 brelse(bp
, BC_INVAL
);
556 *countp
= blocksreleased
;