]>
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_LICENSE_HEADER_START@
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
20 * @APPLE_LICENSE_HEADER_END@
22 /* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */
24 * Copyright (c) 1982, 1986, 1989, 1993
25 * The Regents of the University of California. All rights reserved.
27 * Redistribution and use in source and binary forms, with or without
28 * modification, are permitted provided that the following conditions
30 * 1. Redistributions of source code must retain the above copyright
31 * notice, this list of conditions and the following disclaimer.
32 * 2. Redistributions in binary form must reproduce the above copyright
33 * notice, this list of conditions and the following disclaimer in the
34 * documentation and/or other materials provided with the distribution.
35 * 3. All advertising materials mentioning features or use of this software
36 * must display the following acknowledgement:
37 * This product includes software developed by the University of
38 * California, Berkeley and its contributors.
39 * 4. Neither the name of the University nor the names of its contributors
40 * may be used to endorse or promote products derived from this software
41 * without specific prior written permission.
43 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
44 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
45 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
46 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
47 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
48 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
49 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
50 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
51 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
52 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
55 * @(#)ffs_inode.c 8.13 (Berkeley) 4/21/95
58 #include <rev_endian_fs.h>
59 #include <vm/vm_pager.h>
61 #include <sys/param.h>
62 #include <sys/systm.h>
63 #include <sys/mount.h>
67 #include <sys/vnode.h>
68 #include <sys/kernel.h>
69 #include <sys/malloc.h>
70 #include <sys/trace.h>
71 #include <sys/resourcevar.h>
73 #include <sys/quota.h>
77 #include <ufs/ufs/quota.h>
78 #include <ufs/ufs/inode.h>
79 #include <ufs/ufs/ufsmount.h>
80 #include <ufs/ufs/ufs_extern.h>
82 #include <ufs/ffs/fs.h>
83 #include <ufs/ffs/ffs_extern.h>
86 #include <ufs/ufs/ufs_byte_order.h>
87 #include <architecture/byte_order.h>
88 #endif /* REV_ENDIAN_FS */
90 static int ffs_indirtrunc
__P((struct inode
*, ufs_daddr_t
, ufs_daddr_t
,
91 ufs_daddr_t
, int, long *));
94 * Update the access, modified, and inode change times as specified by the
95 * IACCESS, IUPDATE, and ICHANGE flags respectively. The IMODIFIED flag is
96 * used to specify that the inode needs to be updated but that the times have
97 * already been set. The access and modified times are taken from the second
98 * and third parameters; the inode change time is always taken from the current
99 * time. If waitfor is set, then wait for the disk write of the inode to
104 struct vop_update_args
/* {
106 struct timeval *a_access;
107 struct timeval *a_modify;
111 register struct fs
*fs
;
116 struct mount
*mp
=(ap
->a_vp
)->v_mount
;
117 int rev_endian
=(mp
->mnt_flag
& MNT_REVEND
);
118 #endif /* REV_ENDIAN_FS */
121 if (ap
->a_vp
->v_mount
->mnt_flag
& MNT_RDONLY
) {
123 ~(IN_ACCESS
| IN_CHANGE
| IN_MODIFIED
| IN_UPDATE
);
127 (IN_ACCESS
| IN_CHANGE
| IN_MODIFIED
| IN_UPDATE
)) == 0)
129 if (ip
->i_flag
& IN_ACCESS
)
130 ip
->i_atime
= ap
->a_access
->tv_sec
;
131 if (ip
->i_flag
& IN_UPDATE
) {
132 ip
->i_mtime
= ap
->a_modify
->tv_sec
;
135 if (ip
->i_flag
& IN_CHANGE
)
136 ip
->i_ctime
= time
.tv_sec
;
137 ip
->i_flag
&= ~(IN_ACCESS
| IN_CHANGE
| IN_MODIFIED
| IN_UPDATE
);
140 * Ensure that uid and gid are correct. This is a temporary
141 * fix until fsck has been changed to do the update.
143 if (fs
->fs_inodefmt
< FS_44INODEFMT
) { /* XXX */
144 ip
->i_din
.di_ouid
= ip
->i_uid
; /* XXX */
145 ip
->i_din
.di_ogid
= ip
->i_gid
; /* XXX */
147 if (error
= bread(ip
->i_devvp
,
148 fsbtodb(fs
, ino_to_fsba(fs
, ip
->i_number
)),
149 (int)fs
->fs_bsize
, NOCRED
, &bp
)) {
155 byte_swap_inode_out(ip
, ((struct dinode
*)bp
->b_data
+ ino_to_fsbo(fs
, ip
->i_number
)));
157 #endif /* REV_ENDIAN_FS */
158 *((struct dinode
*)bp
->b_data
+
159 ino_to_fsbo(fs
, ip
->i_number
)) = ip
->i_din
;
162 #endif /* REV_ENDIAN_FS */
164 if (ap
->a_waitfor
&& (ap
->a_vp
->v_mount
->mnt_flag
& MNT_ASYNC
) == 0)
172 #define SINGLE 0 /* index of single indirect block */
173 #define DOUBLE 1 /* index of double indirect block */
174 #define TRIPLE 2 /* index of triple indirect block */
176 * Truncate the inode oip to at most length size, freeing the
180 struct vop_truncate_args
/* {
184 struct ucred *a_cred;
188 register struct vnode
*ovp
= ap
->a_vp
;
189 ufs_daddr_t lastblock
;
190 register struct inode
*oip
;
191 ufs_daddr_t bn
, lbn
, lastiblock
[NIADDR
], indir_lbn
[NIADDR
];
192 ufs_daddr_t oldblks
[NDADDR
+ NIADDR
], newblks
[NDADDR
+ NIADDR
];
193 off_t length
= ap
->a_length
;
194 register struct fs
*fs
;
196 int offset
, size
, level
;
197 long count
, nblocks
, vflags
, blocksreleased
= 0;
200 int aflags
, error
, allerror
;
204 int64_t change
; /* in bytes */
213 if (length
> fs
->fs_maxfilesize
)
217 if (ovp
->v_type
== VLNK
&&
218 oip
->i_size
< ovp
->v_mount
->mnt_maxsymlinklen
) {
221 panic("ffs_truncate: partial truncate of symlink");
223 bzero((char *)&oip
->i_shortlink
, (u_int
)oip
->i_size
);
225 oip
->i_flag
|= IN_CHANGE
| IN_UPDATE
;
226 return (VOP_UPDATE(ovp
, &tv
, &tv
, 1));
229 if (oip
->i_size
== length
) {
230 oip
->i_flag
|= IN_CHANGE
| IN_UPDATE
;
231 return (VOP_UPDATE(ovp
, &tv
, &tv
, 0));
234 if (error
= getinoquota(oip
))
240 * Lengthen the size of the file. We must ensure that the
241 * last byte of the file is allocated. Since the smallest
242 * value of osize is 0, length will be at least 1.
244 if (osize
< length
) {
245 offset
= blkoff(fs
, length
- 1);
246 lbn
= lblkno(fs
, length
- 1);
248 if (ap
->a_flags
& IO_SYNC
)
250 if (error
= ffs_balloc(oip
, lbn
, offset
+ 1, ap
->a_cred
, &bp
,
253 oip
->i_size
= length
;
255 if (UBCINFOEXISTS(ovp
)) {
256 bp
->b_flags
|= B_INVAL
;
258 ubc_setsize(ovp
, (off_t
)length
);
265 oip
->i_flag
|= IN_CHANGE
| IN_UPDATE
;
266 return (VOP_UPDATE(ovp
, &tv
, &tv
, 1));
269 * Shorten the size of the file. If the file is not being
270 * truncated to a block boundry, the contents of the
271 * partial block following the end of the file must be
272 * zero'ed in case it ever become accessable again because
273 * of subsequent file growth.
275 if (UBCINFOEXISTS(ovp
))
276 ubc_setsize(ovp
, (off_t
)length
);
278 vflags
= ((length
> 0) ? V_SAVE
: 0) | V_SAVEMETA
;
279 allerror
= vinvalbuf(ovp
, vflags
, ap
->a_cred
, ap
->a_p
, 0, 0);
282 offset
= blkoff(fs
, length
);
284 oip
->i_size
= length
;
286 lbn
= lblkno(fs
, length
);
288 if (ap
->a_flags
& IO_SYNC
)
290 if (error
= ffs_balloc(oip
, lbn
, offset
, ap
->a_cred
, &bp
,
293 oip
->i_size
= length
;
294 size
= blksize(fs
, oip
, lbn
);
295 bzero((char *)bp
->b_data
+ offset
, (u_int
)(size
- offset
));
297 if (UBCINFOEXISTS(ovp
)) {
298 bp
->b_flags
|= B_INVAL
;
308 * Calculate index into inode's block list of
309 * last direct and indirect blocks (if any)
310 * which we want to keep. Lastblock is -1 when
311 * the file is truncated to 0.
313 lastblock
= lblkno(fs
, length
+ fs
->fs_bsize
- 1) - 1;
314 lastiblock
[SINGLE
] = lastblock
- NDADDR
;
315 lastiblock
[DOUBLE
] = lastiblock
[SINGLE
] - NINDIR(fs
);
316 lastiblock
[TRIPLE
] = lastiblock
[DOUBLE
] - NINDIR(fs
) * NINDIR(fs
);
317 VOP_DEVBLOCKSIZE(oip
->i_devvp
,&devBlockSize
);
318 nblocks
= btodb(fs
->fs_bsize
, devBlockSize
);
321 * Update file and block pointers on disk before we start freeing
322 * blocks. If we crash before free'ing blocks below, the blocks
323 * will be returned to the free list. lastiblock values are also
324 * normalized to -1 for calls to ffs_indirtrunc below.
326 bcopy((caddr_t
)&oip
->i_db
[0], (caddr_t
)oldblks
, sizeof oldblks
);
327 for (level
= TRIPLE
; level
>= SINGLE
; level
--)
328 if (lastiblock
[level
] < 0) {
329 oip
->i_ib
[level
] = 0;
330 lastiblock
[level
] = -1;
332 for (i
= NDADDR
- 1; i
> lastblock
; i
--)
334 oip
->i_flag
|= IN_CHANGE
| IN_UPDATE
;
335 if (error
= VOP_UPDATE(ovp
, &tv
, &tv
, MNT_WAIT
))
338 * Having written the new inode to disk, save its new configuration
339 * and put back the old block pointers long enough to process them.
340 * Note that we save the new block configuration so we can check it
343 bcopy((caddr_t
)&oip
->i_db
[0], (caddr_t
)newblks
, sizeof newblks
);
344 bcopy((caddr_t
)oldblks
, (caddr_t
)&oip
->i_db
[0], sizeof oldblks
);
346 vflags
= ((length
> 0) ? V_SAVE
: 0) | V_SAVEMETA
;
347 allerror
= vinvalbuf(ovp
, vflags
, ap
->a_cred
, ap
->a_p
, 0, 0);
350 * Indirect blocks first.
352 indir_lbn
[SINGLE
] = -NDADDR
;
353 indir_lbn
[DOUBLE
] = indir_lbn
[SINGLE
] - NINDIR(fs
) - 1;
354 indir_lbn
[TRIPLE
] = indir_lbn
[DOUBLE
] - NINDIR(fs
) * NINDIR(fs
) - 1;
355 for (level
= TRIPLE
; level
>= SINGLE
; level
--) {
356 bn
= oip
->i_ib
[level
];
358 error
= ffs_indirtrunc(oip
, indir_lbn
[level
],
359 fsbtodb(fs
, bn
), lastiblock
[level
], level
, &count
);
362 blocksreleased
+= count
;
363 if (lastiblock
[level
] < 0) {
364 oip
->i_ib
[level
] = 0;
365 ffs_blkfree(oip
, bn
, fs
->fs_bsize
);
366 blocksreleased
+= nblocks
;
369 if (lastiblock
[level
] >= 0)
374 * All whole direct blocks or frags.
376 for (i
= NDADDR
- 1; i
> lastblock
; i
--) {
383 bsize
= blksize(fs
, oip
, i
);
384 ffs_blkfree(oip
, bn
, bsize
);
385 blocksreleased
+= btodb(bsize
, devBlockSize
);
391 * Finally, look for a change in size of the
392 * last direct block; release any frags.
394 bn
= oip
->i_db
[lastblock
];
396 long oldspace
, newspace
;
399 * Calculate amount of space we're giving
400 * back as old block size minus new block size.
402 oldspace
= blksize(fs
, oip
, lastblock
);
403 oip
->i_size
= length
;
404 newspace
= blksize(fs
, oip
, lastblock
);
406 panic("itrunc: newspace");
407 if (oldspace
- newspace
> 0) {
409 * Block number of space to be free'd is
410 * the old block # plus the number of frags
411 * required for the storage we're keeping.
413 bn
+= numfrags(fs
, newspace
);
414 ffs_blkfree(oip
, bn
, oldspace
- newspace
);
415 blocksreleased
+= btodb(oldspace
- newspace
, devBlockSize
);
420 for (level
= SINGLE
; level
<= TRIPLE
; level
++)
421 if (newblks
[NDADDR
+ level
] != oip
->i_ib
[level
])
423 for (i
= 0; i
< NDADDR
; i
++)
424 if (newblks
[i
] != oip
->i_db
[i
])
427 (ovp
->v_dirtyblkhd
.lh_first
|| ovp
->v_cleanblkhd
.lh_first
))
429 #endif /* DIAGNOSTIC */
431 * Put back the real size.
433 oip
->i_size
= length
;
434 oip
->i_blocks
-= blocksreleased
;
435 if (oip
->i_blocks
< 0) /* sanity */
437 oip
->i_flag
|= IN_CHANGE
;
439 change
= dbtob((int64_t)blocksreleased
,devBlockSize
);
440 (void) chkdq(oip
, -change
, NOCRED
, 0);
446 * Release blocks associated with the inode ip and stored in the indirect
447 * block bn. Blocks are free'd in LIFO order up to (but not including)
448 * lastbn. If level is greater than SINGLE, the block is an indirect block
449 * and recursive calls to indirtrunc must be used to cleanse other indirect
452 * NB: triple indirect blocks are untested.
455 ffs_indirtrunc(ip
, lbn
, dbn
, lastbn
, level
, countp
)
456 register struct inode
*ip
;
457 ufs_daddr_t lbn
, lastbn
;
465 register struct fs
*fs
= ip
->i_fs
;
466 register ufs_daddr_t
*bap
;
467 struct vnode
*vp
=ITOV(ip
);
468 ufs_daddr_t
*copy
, nb
, nlbn
, last
;
469 long blkcount
, factor
;
470 int nblocks
, blocksreleased
= 0;
471 int error
= 0, allerror
= 0;
474 struct mount
*mp
=vp
->v_mount
;
475 int rev_endian
=(mp
->mnt_flag
& MNT_REVEND
);
476 #endif /* REV_ENDIAN_FS */
479 * Calculate index in current block of last
480 * block to be kept. -1 indicates the entire
481 * block so we need not calculate the index.
484 for (i
= SINGLE
; i
< level
; i
++)
485 factor
*= NINDIR(fs
);
489 VOP_DEVBLOCKSIZE(ip
->i_devvp
,&devBlockSize
);
490 nblocks
= btodb(fs
->fs_bsize
, devBlockSize
);
492 /* Doing a MALLOC here is asking for trouble. We can still
493 * deadlock on pagerfile lock, in case we are running
494 * low on memory and block in MALLOC
497 tbp
= geteblk(fs
->fs_bsize
);
498 copy
= (ufs_daddr_t
*)tbp
->b_data
;
501 * Get buffer of block pointers, zero those entries corresponding
502 * to blocks to be free'd, and update on disk copy first. Since
503 * double(triple) indirect before single(double) indirect, calls
504 * to bmap on these blocks will fail. However, we already have
505 * the on disk address, so we have to set the b_blkno field
506 * explicitly instead of letting bread do everything for us.
510 bp
= getblk(vp
, lbn
, (int)fs
->fs_bsize
, 0, 0, BLK_META
);
511 if (bp
->b_flags
& (B_DONE
| B_DELWRI
)) {
512 /* Braces must be here in case trace evaluates to nothing. */
513 trace(TR_BREADHIT
, pack(vp
, fs
->fs_bsize
), lbn
);
515 trace(TR_BREADMISS
, pack(vp
, fs
->fs_bsize
), lbn
);
516 current_proc()->p_stats
->p_ru
.ru_inblock
++; /* pay for read */
517 bp
->b_flags
|= B_READ
;
518 if (bp
->b_bcount
> bp
->b_bufsize
)
519 panic("ffs_indirtrunc: bad buffer size");
531 bap
= (ufs_daddr_t
*)bp
->b_data
;
532 bcopy((caddr_t
)bap
, (caddr_t
)copy
, (u_int
)fs
->fs_bsize
);
533 bzero((caddr_t
)&bap
[last
+ 1],
534 (u_int
)(NINDIR(fs
) - (last
+ 1)) * sizeof (ufs_daddr_t
));
536 bp
->b_flags
|= B_INVAL
;
543 * Recursively free totally unused blocks.
545 for (i
= NINDIR(fs
) - 1, nlbn
= lbn
+ 1 - i
* factor
; i
> last
;
546 i
--, nlbn
+= factor
) {
549 nb
= NXSwapLong(bap
[i
]);
551 #endif /* REV_ENDIAN_FS */
555 #endif /* REV_ENDIAN_FS */
558 if (level
> SINGLE
) {
559 if (error
= ffs_indirtrunc(ip
, nlbn
, fsbtodb(fs
, nb
),
560 (ufs_daddr_t
)-1, level
- 1, &blkcount
))
562 blocksreleased
+= blkcount
;
564 ffs_blkfree(ip
, nb
, fs
->fs_bsize
);
565 blocksreleased
+= nblocks
;
569 * Recursively free last partial block.
571 if (level
> SINGLE
&& lastbn
>= 0) {
572 last
= lastbn
% factor
;
575 nb
= NXSwapLong(bap
[i
]);
577 #endif /* REV_ENDIAN_FS */
581 #endif /* REV_ENDIAN_FS */
583 if (error
= ffs_indirtrunc(ip
, nlbn
, fsbtodb(fs
, nb
),
584 last
, level
- 1, &blkcount
))
586 blocksreleased
+= blkcount
;
590 *countp
= blocksreleased
;