]>
git.saurik.com Git - apple/xnu.git/blob - bsd/ufs/ffs/ffs_balloc.c
8a1908418e8a95ed684e309fe2fe31338e989bca
2 * Copyright (c) 2006 Apple Computer, Inc. All Rights Reserved.
4 * @APPLE_LICENSE_OSREFERENCE_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
10 * License may not be used to create, or enable the creation or
11 * redistribution of, unlawful or unlicensed copies of an Apple operating
12 * system, or to circumvent, violate, or enable the circumvention or
13 * violation of, any terms of an Apple operating system software license
16 * Please obtain a copy of the License at
17 * http://www.opensource.apple.com/apsl/ and read it before using this
20 * The Original Code and all software distributed under the License are
21 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
22 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
23 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
24 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
25 * Please see the License for the specific language governing rights and
26 * limitations under the License.
28 * @APPLE_LICENSE_OSREFERENCE_HEADER_END@
30 /* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */
32 * Copyright (c) 1982, 1986, 1989, 1993
33 * The Regents of the University of California. All rights reserved.
35 * Redistribution and use in source and binary forms, with or without
36 * modification, are permitted provided that the following conditions
38 * 1. Redistributions of source code must retain the above copyright
39 * notice, this list of conditions and the following disclaimer.
40 * 2. Redistributions in binary form must reproduce the above copyright
41 * notice, this list of conditions and the following disclaimer in the
42 * documentation and/or other materials provided with the distribution.
43 * 3. All advertising materials mentioning features or use of this software
44 * must display the following acknowledgement:
45 * This product includes software developed by the University of
46 * California, Berkeley and its contributors.
47 * 4. Neither the name of the University nor the names of its contributors
48 * may be used to endorse or promote products derived from this software
49 * without specific prior written permission.
51 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
52 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
53 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
54 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
55 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
56 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
57 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
58 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
59 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
60 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
63 * @(#)ffs_balloc.c 8.8 (Berkeley) 6/16/95
66 #include <rev_endian_fs.h>
67 #include <sys/param.h>
68 #include <sys/systm.h>
69 #include <sys/buf_internal.h>
71 #include <sys/kauth.h>
73 #include <sys/vnode_internal.h>
75 #include <sys/quota.h>
78 #include <sys/mount_internal.h>
79 #endif /* REV_ENDIAN_FS */
83 #include <ufs/ufs/quota.h>
84 #include <ufs/ufs/inode.h>
85 #include <ufs/ufs/ufs_extern.h>
87 #include <ufs/ffs/fs.h>
88 #include <ufs/ffs/ffs_extern.h>
91 #include <ufs/ufs/ufs_byte_order.h>
92 #include <architecture/byte_order.h>
93 #endif /* REV_ENDIAN_FS */
96 * Balloc defines the structure of file system storage
97 * by allocating the physical blocks on a device given
98 * the inode and the logical block number in a file.
101 register struct inode
*ip
,
102 register ufs_daddr_t lbn
,
109 register struct fs
*fs
;
110 register ufs_daddr_t nb
;
111 struct buf
*bp
, *nbp
;
112 struct vnode
*vp
= ITOV(ip
);
113 struct indir indirs
[NIADDR
+ 2];
114 ufs_daddr_t newb
, *bap
, pref
;
115 int deallocated
, osize
, nsize
, num
, i
, error
;
116 ufs_daddr_t
*allocib
, *blkp
, *allocblk
, allociblk
[NIADDR
+ 1];
118 int alloc_buffer
= 1;
119 struct mount
*mp
=vp
->v_mount
;
121 int rev_endian
=(mp
->mnt_flag
& MNT_REVEND
);
122 #endif /* REV_ENDIAN_FS */
128 if (flags
& B_NOBUFF
)
135 * If the next write will extend the file into a new block,
136 * and the file is currently composed of a fragment
137 * this fragment has to be extended to be a full block.
139 nb
= lblkno(fs
, ip
->i_size
);
140 if (nb
< NDADDR
&& nb
< lbn
) {
141 /* the filesize prior to this write can fit in direct
142 * blocks (ie. fragmentaion is possibly done)
143 * we are now extending the file write beyond
144 * the block which has end of file prior to this write
146 osize
= blksize(fs
, ip
, nb
);
147 /* osize gives disk allocated size in the last block. It is
148 * either in fragments or a file system block size */
149 if (osize
< fs
->fs_bsize
&& osize
> 0) {
150 /* few fragments are already allocated,since the
151 * current extends beyond this block
152 * allocate the complete block as fragments are only
155 error
= ffs_realloccg(ip
, nb
,
156 ffs_blkpref(ip
, nb
, (int)nb
, &ip
->i_db
[0]),
157 osize
, (int)fs
->fs_bsize
, cred
, &bp
);
160 /* adjust the inode size we just grew */
161 /* it is in nb+1 as nb starts from 0 */
162 ip
->i_size
= (nb
+ 1) * fs
->fs_bsize
;
163 ubc_setsize(vp
, (off_t
)ip
->i_size
);
165 ip
->i_db
[nb
] = dbtofsb(fs
, (ufs_daddr_t
)buf_blkno(bp
));
166 ip
->i_flag
|= IN_CHANGE
| IN_UPDATE
;
168 if ((flags
& B_SYNC
) || (!alloc_buffer
)) {
170 buf_setflags(bp
, B_NOCACHE
);
174 /* note that bp is already released here */
178 * The first NDADDR blocks are direct blocks
182 if (nb
!= 0 && ip
->i_size
>= (lbn
+ 1) * fs
->fs_bsize
) {
184 error
= (int)buf_bread(vp
, (daddr64_t
)((unsigned)lbn
), fs
->fs_bsize
, NOCRED
, &bp
);
195 * Consider need to reallocate a fragment.
197 osize
= fragroundup(fs
, blkoff(fs
, ip
->i_size
));
198 nsize
= fragroundup(fs
, size
);
199 if (nsize
<= osize
) {
201 error
= (int)buf_bread(vp
, (daddr64_t
)((unsigned)lbn
), osize
, NOCRED
, &bp
);
206 ip
->i_flag
|= IN_CHANGE
| IN_UPDATE
;
211 ip
->i_flag
|= IN_CHANGE
| IN_UPDATE
;
215 error
= ffs_realloccg(ip
, lbn
,
216 ffs_blkpref(ip
, lbn
, (int)lbn
,
217 &ip
->i_db
[0]), osize
, nsize
, cred
, &bp
);
220 ip
->i_db
[lbn
] = dbtofsb(fs
, (ufs_daddr_t
)buf_blkno(bp
));
221 ip
->i_flag
|= IN_CHANGE
| IN_UPDATE
;
223 /* adjust the inode size we just grew */
224 ip
->i_size
= (lbn
* fs
->fs_bsize
) + size
;
225 ubc_setsize(vp
, (off_t
)ip
->i_size
);
228 buf_setflags(bp
, B_NOCACHE
);
239 if (ip
->i_size
< (lbn
+ 1) * fs
->fs_bsize
)
240 nsize
= fragroundup(fs
, size
);
242 nsize
= fs
->fs_bsize
;
243 error
= ffs_alloc(ip
, lbn
,
244 ffs_blkpref(ip
, lbn
, (int)lbn
, &ip
->i_db
[0]),
249 bp
= buf_getblk(vp
, (daddr64_t
)((unsigned)lbn
), nsize
, 0, 0, BLK_WRITE
);
250 buf_setblkno(bp
, (daddr64_t
)((unsigned)fsbtodb(fs
, newb
)));
252 if (flags
& B_CLRBUF
)
255 ip
->i_db
[lbn
] = newb
;
256 ip
->i_flag
|= IN_CHANGE
| IN_UPDATE
;
266 * Determine the number of levels of indirection.
269 if (error
= ufs_getlbns(vp
, lbn
, indirs
, &num
))
273 panic ("ffs_balloc: ufs_bmaparray returned indirect block");
276 * Fetch the first indirect block allocating if necessary.
279 nb
= ip
->i_ib
[indirs
[0].in_off
];
281 allocblk
= allociblk
;
283 pref
= ffs_blkpref(ip
, lbn
, 0, (ufs_daddr_t
*)0);
284 if (error
= ffs_alloc(ip
, lbn
, pref
, (int)fs
->fs_bsize
,
289 bp
= buf_getblk(vp
, (daddr64_t
)((unsigned)(indirs
[1].in_lbn
)), fs
->fs_bsize
, 0, 0, BLK_META
);
290 buf_setblkno(bp
, (daddr64_t
)((unsigned)fsbtodb(fs
, nb
)));
293 * Write synchronously conditional on mount flags.
295 if ((vp
)->v_mount
->mnt_flag
& MNT_ASYNC
) {
298 } else if ((error
= buf_bwrite(bp
)) != 0) {
301 allocib
= &ip
->i_ib
[indirs
[0].in_off
];
303 ip
->i_flag
|= IN_CHANGE
| IN_UPDATE
;
306 * Fetch through the indirect blocks, allocating as necessary.
309 error
= (int)buf_meta_bread(vp
, (daddr64_t
)((unsigned)(indirs
[i
].in_lbn
)), (int)fs
->fs_bsize
, NOCRED
, &bp
);
314 bap
= (ufs_daddr_t
*)buf_dataptr(bp
);
317 nb
= NXSwapLong(bap
[indirs
[i
].in_off
]);
319 #endif /* REV_ENDIAN_FS */
320 nb
= bap
[indirs
[i
].in_off
];
323 #endif /* REV_ENDIAN_FS */
332 pref
= ffs_blkpref(ip
, lbn
, 0, (ufs_daddr_t
*)0);
334 ffs_alloc(ip
, lbn
, pref
, (int)fs
->fs_bsize
, cred
, &newb
)) {
340 nbp
= buf_getblk(vp
, (daddr64_t
)((unsigned)(indirs
[i
].in_lbn
)), fs
->fs_bsize
, 0, 0, BLK_META
);
341 buf_setblkno(nbp
, (daddr64_t
)((unsigned)fsbtodb(fs
, nb
)));
344 * Write synchronously conditional on mount flags.
346 if ((vp
)->v_mount
->mnt_flag
& MNT_ASYNC
) {
349 } else if (error
= buf_bwrite(nbp
)) {
355 bap
[indirs
[i
- 1].in_off
] = NXSwapLong(nb
);
357 #endif /* REV_ENDIAN_FS */
358 bap
[indirs
[i
- 1].in_off
] = nb
;
361 #endif /* REV_ENDIAN_FS */
363 * If required, write synchronously, otherwise use
366 if (flags
& B_SYNC
) {
373 * Get the data block, allocating if necessary.
376 pref
= ffs_blkpref(ip
, lbn
, indirs
[i
].in_off
, &bap
[0]);
377 if (error
= ffs_alloc(ip
,
378 lbn
, pref
, (int)fs
->fs_bsize
, cred
, &newb
)) {
386 bap
[indirs
[i
].in_off
] = NXSwapLong(nb
);
388 #endif /* REV_ENDIAN_FS */
389 bap
[indirs
[i
].in_off
] = nb
;
392 #endif /* REV_ENDIAN_FS */
394 * If required, write synchronously, otherwise use
397 if ((flags
& B_SYNC
)) {
403 nbp
= buf_getblk(vp
, (daddr64_t
)((unsigned)lbn
), fs
->fs_bsize
, 0, 0, BLK_WRITE
);
404 buf_setblkno(nbp
, (daddr64_t
)((unsigned)fsbtodb(fs
, nb
)));
406 if (flags
& B_CLRBUF
)
410 *blk_alloc
= fs
->fs_bsize
;
419 if (flags
& B_CLRBUF
) {
420 error
= (int)buf_bread(vp
, (daddr64_t
)((unsigned)lbn
), (int)fs
->fs_bsize
, NOCRED
, &nbp
);
426 nbp
= buf_getblk(vp
, (daddr64_t
)((unsigned)lbn
), fs
->fs_bsize
, 0, 0, BLK_WRITE
);
427 buf_setblkno(nbp
, (daddr64_t
)((unsigned)fsbtodb(fs
, nb
)));
434 * If we have failed part way through block allocation, we
435 * have to deallocate any indirect blocks that we have allocated.
437 for (deallocated
= 0, blkp
= allociblk
; blkp
< allocblk
; blkp
++) {
438 ffs_blkfree(ip
, *blkp
, fs
->fs_bsize
);
439 deallocated
+= fs
->fs_bsize
;
444 devBlockSize
= vfs_devblocksize(mp
);
447 * Restore user's disk quota because allocation failed.
449 (void) chkdq(ip
, (int64_t)-deallocated
, cred
, FORCE
);
451 ip
->i_blocks
-= btodb(deallocated
, devBlockSize
);
452 ip
->i_flag
|= IN_CHANGE
| IN_UPDATE
;
458 * ffs_blkalloc allocates a disk block for ffs_pageout(), as a consequence
459 * it does no buf_breads (that could lead to deadblock as the page may be already
460 * marked busy as it is being paged out. Also important to note that we are not
461 * growing the file in pageouts. So ip->i_size cannot increase by this call
462 * due to the way UBC works.
463 * This code is derived from ffs_balloc and many cases of that are dealt
464 * in ffs_balloc are not applicable here
465 * Do not call with B_CLRBUF flags as this should only be called only
475 register struct fs
*fs
;
476 register ufs_daddr_t nb
;
477 struct buf
*bp
, *nbp
;
478 struct vnode
*vp
= ITOV(ip
);
479 struct indir indirs
[NIADDR
+ 2];
480 ufs_daddr_t newb
, *bap
, pref
;
481 int deallocated
, osize
, nsize
, num
, i
, error
;
482 ufs_daddr_t
*allocib
, *blkp
, *allocblk
, allociblk
[NIADDR
+ 1];
484 struct mount
*mp
=vp
->v_mount
;
486 int rev_endian
=(mp
->mnt_flag
& MNT_REVEND
);
487 #endif /* REV_ENDIAN_FS */
491 if(size
> fs
->fs_bsize
)
492 panic("ffs_blkalloc: too large for allocation");
495 * If the next write will extend the file into a new block,
496 * and the file is currently composed of a fragment
497 * this fragment has to be extended to be a full block.
499 nb
= lblkno(fs
, ip
->i_size
);
500 if (nb
< NDADDR
&& nb
< lbn
) {
501 panic("ffs_blkalloc():cannot extend file: i_size %d, lbn %d", ip
->i_size
, lbn
);
504 * The first NDADDR blocks are direct blocks
508 if (nb
!= 0 && ip
->i_size
>= (lbn
+ 1) * fs
->fs_bsize
) {
509 /* TBD: trivial case; the block is already allocated */
514 * Consider need to reallocate a fragment.
516 osize
= fragroundup(fs
, blkoff(fs
, ip
->i_size
));
517 nsize
= fragroundup(fs
, size
);
519 panic("ffs_allocblk: trying to extend a fragment");
523 if (ip
->i_size
< (lbn
+ 1) * fs
->fs_bsize
)
524 nsize
= fragroundup(fs
, size
);
526 nsize
= fs
->fs_bsize
;
527 error
= ffs_alloc(ip
, lbn
,
528 ffs_blkpref(ip
, lbn
, (int)lbn
, &ip
->i_db
[0]),
532 ip
->i_db
[lbn
] = newb
;
533 ip
->i_flag
|= IN_CHANGE
| IN_UPDATE
;
538 * Determine the number of levels of indirection.
541 if (error
= ufs_getlbns(vp
, lbn
, indirs
, &num
))
545 panic("ffs_blkalloc: file with direct blocks only");
549 * Fetch the first indirect block allocating if necessary.
552 nb
= ip
->i_ib
[indirs
[0].in_off
];
554 allocblk
= allociblk
;
556 pref
= ffs_blkpref(ip
, lbn
, 0, (ufs_daddr_t
*)0);
557 if (error
= ffs_alloc(ip
, lbn
, pref
, (int)fs
->fs_bsize
,
562 bp
= buf_getblk(vp
, (daddr64_t
)((unsigned)(indirs
[1].in_lbn
)), fs
->fs_bsize
, 0, 0, BLK_META
);
563 buf_setblkno(bp
, (daddr64_t
)((unsigned)fsbtodb(fs
, nb
)));
566 * Write synchronously conditional on mount flags.
568 if ((vp
)->v_mount
->mnt_flag
& MNT_ASYNC
) {
571 } else if (error
= buf_bwrite(bp
)) {
574 allocib
= &ip
->i_ib
[indirs
[0].in_off
];
576 ip
->i_flag
|= IN_CHANGE
| IN_UPDATE
;
579 * Fetch through the indirect blocks, allocating as necessary.
582 error
= (int)buf_meta_bread(vp
, (daddr64_t
)((unsigned)(indirs
[i
].in_lbn
)), (int)fs
->fs_bsize
, NOCRED
, &bp
);
587 bap
= (ufs_daddr_t
*)buf_dataptr(bp
);
590 nb
= NXSwapLong(bap
[indirs
[i
].in_off
]);
592 #endif /* REV_ENDIAN_FS */
593 nb
= bap
[indirs
[i
].in_off
];
596 #endif /* REV_ENDIAN_FS */
605 pref
= ffs_blkpref(ip
, lbn
, 0, (ufs_daddr_t
*)0);
607 ffs_alloc(ip
, lbn
, pref
, (int)fs
->fs_bsize
, cred
, &newb
)) {
613 nbp
= buf_getblk(vp
, (daddr64_t
)((unsigned)(indirs
[i
].in_lbn
)), fs
->fs_bsize
, 0, 0, BLK_META
);
614 buf_setblkno(nbp
, (daddr64_t
)((unsigned)fsbtodb(fs
, nb
)));
617 * Write synchronously conditional on mount flags.
619 if ((vp
)->v_mount
->mnt_flag
& MNT_ASYNC
) {
622 } else if (error
= buf_bwrite(nbp
)) {
628 bap
[indirs
[i
- 1].in_off
] = NXSwapLong(nb
);
630 #endif /* REV_ENDIAN_FS */
631 bap
[indirs
[i
- 1].in_off
] = nb
;
634 #endif /* REV_ENDIAN_FS */
636 * If required, write synchronously, otherwise use
639 if (flags
& B_SYNC
) {
646 * Get the data block, allocating if necessary.
649 pref
= ffs_blkpref(ip
, lbn
, indirs
[i
].in_off
, &bap
[0]);
650 if (error
= ffs_alloc(ip
,
651 lbn
, pref
, (int)fs
->fs_bsize
, cred
, &newb
)) {
659 bap
[indirs
[i
].in_off
] = NXSwapLong(nb
);
661 #endif /* REV_ENDIAN_FS */
662 bap
[indirs
[i
].in_off
] = nb
;
665 #endif /* REV_ENDIAN_FS */
667 * If required, write synchronously, otherwise use
670 if (flags
& B_SYNC
) {
681 * If we have failed part way through block allocation, we
682 * have to deallocate any indirect blocks that we have allocated.
684 for (deallocated
= 0, blkp
= allociblk
; blkp
< allocblk
; blkp
++) {
685 ffs_blkfree(ip
, *blkp
, fs
->fs_bsize
);
686 deallocated
+= fs
->fs_bsize
;
691 devBlockSize
= vfs_devblocksize(mp
);
694 * Restore user's disk quota because allocation failed.
696 (void) chkdq(ip
, (int64_t)-deallocated
, cred
, FORCE
);
698 ip
->i_blocks
-= btodb(deallocated
, devBlockSize
);
699 ip
->i_flag
|= IN_CHANGE
| IN_UPDATE
;