]>
git.saurik.com Git - apple/xnu.git/blob - bsd/ufs/ffs/ffs_inode.c
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
28 /* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */
30 * Copyright (c) 1982, 1986, 1989, 1993
31 * The Regents of the University of California. All rights reserved.
33 * Redistribution and use in source and binary forms, with or without
34 * modification, are permitted provided that the following conditions
36 * 1. Redistributions of source code must retain the above copyright
37 * notice, this list of conditions and the following disclaimer.
38 * 2. Redistributions in binary form must reproduce the above copyright
39 * notice, this list of conditions and the following disclaimer in the
40 * documentation and/or other materials provided with the distribution.
41 * 3. All advertising materials mentioning features or use of this software
42 * must display the following acknowledgement:
43 * This product includes software developed by the University of
44 * California, Berkeley and its contributors.
45 * 4. Neither the name of the University nor the names of its contributors
46 * may be used to endorse or promote products derived from this software
47 * without specific prior written permission.
49 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
50 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
51 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
52 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
53 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
54 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
55 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
56 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
57 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
58 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
61 * @(#)ffs_inode.c 8.13 (Berkeley) 4/21/95
64 #include <rev_endian_fs.h>
65 #include <vm/vm_pager.h>
67 #include <sys/param.h>
68 #include <sys/systm.h>
69 #include <sys/mount_internal.h>
70 #include <sys/proc_internal.h> /* for accessing p_stats */
72 #include <sys/buf_internal.h>
73 #include <sys/vnode_internal.h>
74 #include <sys/kernel.h>
75 #include <sys/malloc.h>
76 #include <sys/trace.h>
77 #include <sys/resourcevar.h>
79 #include <sys/quota.h>
83 #include <ufs/ufs/quota.h>
84 #include <ufs/ufs/inode.h>
85 #include <ufs/ufs/ufsmount.h>
86 #include <ufs/ufs/ufs_extern.h>
88 #include <ufs/ffs/fs.h>
89 #include <ufs/ffs/ffs_extern.h>
92 #include <ufs/ufs/ufs_byte_order.h>
93 #include <libkern/OSByteOrder.h>
94 #endif /* REV_ENDIAN_FS */
95 #include <libkern/OSAtomic.h>
97 static int ffs_indirtrunc(struct inode
*, ufs_daddr_t
, ufs_daddr_t
,
98 ufs_daddr_t
, int, long *);
101 * Update the access, modified, and inode change times as specified by the
102 * IACCESS, IUPDATE, and ICHANGE flags respectively. The IMODIFIED flag is
103 * used to specify that the inode needs to be updated but that the times have
104 * already been set. The access and modified times are taken from the second
105 * and third parameters; the inode change time is always taken from the current
106 * time. If waitfor is set, then wait for the disk write of the inode to
110 ffs_update(struct vnode
*vp
, struct timeval
*access
, struct timeval
*modify
, int waitfor
)
112 register struct fs
*fs
;
118 struct mount
*mp
=(vp
)->v_mount
;
119 int rev_endian
=(mp
->mnt_flag
& MNT_REVEND
);
120 #endif /* REV_ENDIAN_FS */
123 if (vp
->v_mount
->mnt_flag
& MNT_RDONLY
) {
125 ~(IN_ACCESS
| IN_CHANGE
| IN_MODIFIED
| IN_UPDATE
);
129 (IN_ACCESS
| IN_CHANGE
| IN_MODIFIED
| IN_UPDATE
)) == 0)
131 if (ip
->i_flag
& IN_ACCESS
)
132 ip
->i_atime
= access
->tv_sec
;
133 if (ip
->i_flag
& IN_UPDATE
) {
134 ip
->i_mtime
= modify
->tv_sec
;
137 if (ip
->i_flag
& IN_CHANGE
) {
139 ip
->i_ctime
= tv
.tv_sec
;
141 ip
->i_flag
&= ~(IN_ACCESS
| IN_CHANGE
| IN_MODIFIED
| IN_UPDATE
);
144 * Ensure that uid and gid are correct. This is a temporary
145 * fix until fsck has been changed to do the update.
147 if (fs
->fs_inodefmt
< FS_44INODEFMT
) { /* XXX */
148 ip
->i_din
.di_ouid
= ip
->i_uid
; /* XXX */
149 ip
->i_din
.di_ogid
= ip
->i_gid
; /* XXX */
151 if (error
= buf_bread(ip
->i_devvp
,
152 (daddr64_t
)((unsigned)fsbtodb(fs
, ino_to_fsba(fs
, ip
->i_number
))),
153 (int)fs
->fs_bsize
, NOCRED
, &bp
)) {
159 byte_swap_inode_out(ip
, ((struct dinode
*)buf_dataptr(bp
) + ino_to_fsbo(fs
, ip
->i_number
)));
161 #endif /* REV_ENDIAN_FS */
162 *((struct dinode
*)buf_dataptr(bp
) + ino_to_fsbo(fs
, ip
->i_number
)) = ip
->i_din
;
165 #endif /* REV_ENDIAN_FS */
167 if (waitfor
&& (vp
->v_mount
->mnt_flag
& MNT_ASYNC
) == 0)
168 return ((int)buf_bwrite(bp
));
176 #define SINGLE 0 /* index of single indirect block */
177 #define DOUBLE 1 /* index of double indirect block */
178 #define TRIPLE 2 /* index of triple indirect block */
181 ffs_truncate_internal(vnode_t ovp
, off_t length
, int flags
, ucred_t cred
)
185 ufs_daddr_t lastblock
;
186 ufs_daddr_t bn
, lbn
, lastiblock
[NIADDR
], indir_lbn
[NIADDR
];
187 ufs_daddr_t oldblks
[NDADDR
+ NIADDR
], newblks
[NDADDR
+ NIADDR
];
189 int offset
, size
, level
, i
;
190 long count
, nblocks
, vflags
, blocksreleased
= 0;
192 int aflags
, error
, allerror
;
196 int64_t change
; /* in bytes */
205 if (length
> fs
->fs_maxfilesize
)
209 if (ovp
->v_type
== VLNK
&&
210 oip
->i_size
< ovp
->v_mount
->mnt_maxsymlinklen
) {
213 panic("ffs_truncate: partial truncate of symlink");
215 bzero((char *)&oip
->i_shortlink
, (u_int
)oip
->i_size
);
217 oip
->i_flag
|= IN_CHANGE
| IN_UPDATE
;
218 return (ffs_update(ovp
, &tv
, &tv
, 1));
221 if (oip
->i_size
== length
) {
222 oip
->i_flag
|= IN_CHANGE
| IN_UPDATE
;
223 return (ffs_update(ovp
, &tv
, &tv
, 0));
226 if (error
= getinoquota(oip
))
232 * Lengthen the size of the file. We must ensure that the
233 * last byte of the file is allocated. Since the smallest
234 * value of osize is 0, length will be at least 1.
236 if (osize
< length
) {
237 offset
= blkoff(fs
, length
- 1);
238 lbn
= lblkno(fs
, length
- 1);
242 if (error
= ffs_balloc(oip
, lbn
, offset
+ 1, cred
, &bp
, aflags
, 0))
244 oip
->i_size
= length
;
246 if (UBCINFOEXISTS(ovp
)) {
249 ubc_setsize(ovp
, (off_t
)length
);
256 oip
->i_flag
|= IN_CHANGE
| IN_UPDATE
;
257 return (ffs_update(ovp
, &tv
, &tv
, 1));
260 * Shorten the size of the file. If the file is not being
261 * truncated to a block boundry, the contents of the
262 * partial block following the end of the file must be
263 * zero'ed in case it ever become accessable again because
264 * of subsequent file growth.
266 if (UBCINFOEXISTS(ovp
))
267 ubc_setsize(ovp
, (off_t
)length
);
269 vflags
= ((length
> 0) ? BUF_WRITE_DATA
: 0) | BUF_SKIP_META
;
271 if (vflags
& BUF_WRITE_DATA
)
272 ffs_fsync_internal(ovp
, MNT_WAIT
);
273 allerror
= buf_invalidateblks(ovp
, vflags
, 0, 0);
275 offset
= blkoff(fs
, length
);
277 oip
->i_size
= length
;
279 lbn
= lblkno(fs
, length
);
283 if (error
= ffs_balloc(oip
, lbn
, offset
, cred
, &bp
, aflags
, 0))
285 oip
->i_size
= length
;
286 size
= blksize(fs
, oip
, lbn
);
287 bzero((char *)buf_dataptr(bp
) + offset
, (u_int
)(size
- offset
));
289 if (UBCINFOEXISTS(ovp
)) {
300 * Calculate index into inode's block list of
301 * last direct and indirect blocks (if any)
302 * which we want to keep. Lastblock is -1 when
303 * the file is truncated to 0.
305 lastblock
= lblkno(fs
, length
+ fs
->fs_bsize
- 1) - 1;
306 lastiblock
[SINGLE
] = lastblock
- NDADDR
;
307 lastiblock
[DOUBLE
] = lastiblock
[SINGLE
] - NINDIR(fs
);
308 lastiblock
[TRIPLE
] = lastiblock
[DOUBLE
] - NINDIR(fs
) * NINDIR(fs
);
310 devBlockSize
= vfs_devblocksize(vnode_mount(ovp
));
311 nblocks
= btodb(fs
->fs_bsize
, devBlockSize
);
314 * Update file and block pointers on disk before we start freeing
315 * blocks. If we crash before free'ing blocks below, the blocks
316 * will be returned to the free list. lastiblock values are also
317 * normalized to -1 for calls to ffs_indirtrunc below.
319 bcopy((caddr_t
)&oip
->i_db
[0], (caddr_t
)oldblks
, sizeof oldblks
);
320 for (level
= TRIPLE
; level
>= SINGLE
; level
--)
321 if (lastiblock
[level
] < 0) {
322 oip
->i_ib
[level
] = 0;
323 lastiblock
[level
] = -1;
325 for (i
= NDADDR
- 1; i
> lastblock
; i
--)
327 oip
->i_flag
|= IN_CHANGE
| IN_UPDATE
;
328 if (error
= ffs_update(ovp
, &tv
, &tv
, MNT_WAIT
))
331 * Having written the new inode to disk, save its new configuration
332 * and put back the old block pointers long enough to process them.
333 * Note that we save the new block configuration so we can check it
336 bcopy((caddr_t
)&oip
->i_db
[0], (caddr_t
)newblks
, sizeof newblks
);
337 bcopy((caddr_t
)oldblks
, (caddr_t
)&oip
->i_db
[0], sizeof oldblks
);
340 vflags
= ((length
> 0) ? BUF_WRITE_DATA
: 0) | BUF_SKIP_META
;
342 if (vflags
& BUF_WRITE_DATA
)
343 ffs_fsync_internal(ovp
, MNT_WAIT
);
344 allerror
= buf_invalidateblks(ovp
, vflags
, 0, 0);
347 * Indirect blocks first.
349 indir_lbn
[SINGLE
] = -NDADDR
;
350 indir_lbn
[DOUBLE
] = indir_lbn
[SINGLE
] - NINDIR(fs
) - 1;
351 indir_lbn
[TRIPLE
] = indir_lbn
[DOUBLE
] - NINDIR(fs
) * NINDIR(fs
) - 1;
352 for (level
= TRIPLE
; level
>= SINGLE
; level
--) {
353 bn
= oip
->i_ib
[level
];
355 error
= ffs_indirtrunc(oip
, indir_lbn
[level
],
356 fsbtodb(fs
, bn
), lastiblock
[level
], level
, &count
);
359 blocksreleased
+= count
;
360 if (lastiblock
[level
] < 0) {
361 oip
->i_ib
[level
] = 0;
362 ffs_blkfree(oip
, bn
, fs
->fs_bsize
);
363 blocksreleased
+= nblocks
;
366 if (lastiblock
[level
] >= 0)
371 * All whole direct blocks or frags.
373 for (i
= NDADDR
- 1; i
> lastblock
; i
--) {
380 bsize
= blksize(fs
, oip
, i
);
381 ffs_blkfree(oip
, bn
, bsize
);
382 blocksreleased
+= btodb(bsize
, devBlockSize
);
388 * Finally, look for a change in size of the
389 * last direct block; release any frags.
391 bn
= oip
->i_db
[lastblock
];
393 long oldspace
, newspace
;
396 * Calculate amount of space we're giving
397 * back as old block size minus new block size.
399 oldspace
= blksize(fs
, oip
, lastblock
);
400 oip
->i_size
= length
;
401 newspace
= blksize(fs
, oip
, lastblock
);
403 panic("itrunc: newspace");
404 if (oldspace
- newspace
> 0) {
406 * Block number of space to be free'd is
407 * the old block # plus the number of frags
408 * required for the storage we're keeping.
410 bn
+= numfrags(fs
, newspace
);
411 ffs_blkfree(oip
, bn
, oldspace
- newspace
);
412 blocksreleased
+= btodb(oldspace
- newspace
, devBlockSize
);
417 for (level
= SINGLE
; level
<= TRIPLE
; level
++)
418 if (newblks
[NDADDR
+ level
] != oip
->i_ib
[level
])
420 for (i
= 0; i
< NDADDR
; i
++)
421 if (newblks
[i
] != oip
->i_db
[i
])
424 (vnode_hasdirtyblks(ovp
) || vnode_hascleanblks(ovp
)))
426 #endif /* DIAGNOSTIC */
428 * Put back the real size.
430 oip
->i_size
= length
;
431 oip
->i_blocks
-= blocksreleased
;
432 if (oip
->i_blocks
< 0) /* sanity */
434 oip
->i_flag
|= IN_CHANGE
;
436 change
= dbtob((int64_t)blocksreleased
,devBlockSize
);
437 (void) chkdq(oip
, -change
, NOCRED
, 0);
443 * Release blocks associated with the inode ip and stored in the indirect
444 * block bn. Blocks are free'd in LIFO order up to (but not including)
445 * lastbn. If level is greater than SINGLE, the block is an indirect block
446 * and recursive calls to indirtrunc must be used to cleanse other indirect
449 * NB: triple indirect blocks are untested.
452 ffs_indirtrunc(ip
, lbn
, dbn
, lastbn
, level
, countp
)
453 register struct inode
*ip
;
454 ufs_daddr_t lbn
, lastbn
;
462 register struct fs
*fs
= ip
->i_fs
;
463 register ufs_daddr_t
*bap
;
464 struct vnode
*vp
=ITOV(ip
);
465 ufs_daddr_t
*copy
, nb
, nlbn
, last
;
466 long blkcount
, factor
;
467 int nblocks
, blocksreleased
= 0;
468 errno_t error
= 0, allerror
= 0;
470 struct mount
*mp
=vp
->v_mount
;
472 int rev_endian
=(mp
->mnt_flag
& MNT_REVEND
);
473 #endif /* REV_ENDIAN_FS */
476 * Calculate index in current block of last
477 * block to be kept. -1 indicates the entire
478 * block so we need not calculate the index.
481 for (i
= SINGLE
; i
< level
; i
++)
482 factor
*= NINDIR(fs
);
487 devBlockSize
= vfs_devblocksize(mp
);
488 nblocks
= btodb(fs
->fs_bsize
, devBlockSize
);
490 /* Doing a MALLOC here is asking for trouble. We can still
491 * deadlock on pagerfile lock, in case we are running
492 * low on memory and block in MALLOC
495 tbp
= buf_geteblk(fs
->fs_bsize
);
496 copy
= (ufs_daddr_t
*)buf_dataptr(tbp
);
499 * Get buffer of block pointers, zero those entries corresponding
500 * to blocks to be free'd, and update on disk copy first. Since
501 * double(triple) indirect before single(double) indirect, calls
502 * to bmap on these blocks will fail. However, we already have
503 * the on disk address, so we have to set the blkno field
504 * explicitly instead of letting buf_bread do everything for us.
508 bp
= buf_getblk(vp
, (daddr64_t
)((unsigned)lbn
), (int)fs
->fs_bsize
, 0, 0, BLK_META
);
511 /* Braces must be here in case trace evaluates to nothing. */
512 trace(TR_BREADHIT
, pack(vp
, fs
->fs_bsize
), lbn
);
514 trace(TR_BREADMISS
, pack(vp
, fs
->fs_bsize
), lbn
);
515 OSIncrementAtomic(¤t_proc()->p_stats
->p_ru
.ru_inblock
); /* pay for read */
516 buf_setflags(bp
, B_READ
);
517 if (buf_count(bp
) > buf_size(bp
))
518 panic("ffs_indirtrunc: bad buffer size");
519 buf_setblkno(bp
, (daddr64_t
)((unsigned)dbn
));
521 error
= buf_biowait(bp
);
530 bap
= (ufs_daddr_t
*)buf_dataptr(bp
);
531 bcopy((caddr_t
)bap
, (caddr_t
)copy
, (u_int
)fs
->fs_bsize
);
532 bzero((caddr_t
)&bap
[last
+ 1],
533 (u_int
)(NINDIR(fs
) - (last
+ 1)) * sizeof (ufs_daddr_t
));
536 if (last
!= -1 && (vp
)->v_mount
->mnt_flag
& MNT_ASYNC
) {
540 error
= buf_bwrite(bp
);
547 * Recursively free totally unused blocks.
549 for (i
= NINDIR(fs
) - 1, nlbn
= lbn
+ 1 - i
* factor
; i
> last
;
550 i
--, nlbn
+= factor
) {
553 nb
= OSSwapInt32(bap
[i
]);
555 #endif /* REV_ENDIAN_FS */
559 #endif /* REV_ENDIAN_FS */
562 if (level
> SINGLE
) {
563 if (error
= ffs_indirtrunc(ip
, nlbn
, fsbtodb(fs
, nb
),
564 (ufs_daddr_t
)-1, level
- 1, &blkcount
))
566 blocksreleased
+= blkcount
;
568 ffs_blkfree(ip
, nb
, fs
->fs_bsize
);
569 blocksreleased
+= nblocks
;
573 * Recursively free last partial block.
575 if (level
> SINGLE
&& lastbn
>= 0) {
576 last
= lastbn
% factor
;
579 nb
= OSSwapInt32(bap
[i
]);
581 #endif /* REV_ENDIAN_FS */
585 #endif /* REV_ENDIAN_FS */
587 if (error
= ffs_indirtrunc(ip
, nlbn
, fsbtodb(fs
, nb
),
588 last
, level
- 1, &blkcount
))
590 blocksreleased
+= blkcount
;
594 *countp
= blocksreleased
;
595 return ((int)allerror
);