]>
git.saurik.com Git - apple/xnu.git/blob - bsd/ufs/ffs/ffs_balloc.c
2 * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
23 * @APPLE_LICENSE_HEADER_END@
25 /* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */
27 * Copyright (c) 1982, 1986, 1989, 1993
28 * The Regents of the University of California. All rights reserved.
30 * Redistribution and use in source and binary forms, with or without
31 * modification, are permitted provided that the following conditions
33 * 1. Redistributions of source code must retain the above copyright
34 * notice, this list of conditions and the following disclaimer.
35 * 2. Redistributions in binary form must reproduce the above copyright
36 * notice, this list of conditions and the following disclaimer in the
37 * documentation and/or other materials provided with the distribution.
38 * 3. All advertising materials mentioning features or use of this software
39 * must display the following acknowledgement:
40 * This product includes software developed by the University of
41 * California, Berkeley and its contributors.
42 * 4. Neither the name of the University nor the names of its contributors
43 * may be used to endorse or promote products derived from this software
44 * without specific prior written permission.
46 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
47 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
48 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
49 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
50 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
51 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
52 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
53 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
54 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
55 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
58 * @(#)ffs_balloc.c 8.8 (Berkeley) 6/16/95
61 #include <rev_endian_fs.h>
62 #include <sys/param.h>
63 #include <sys/systm.h>
67 #include <sys/vnode.h>
69 #include <sys/quota.h>
72 #include <sys/mount.h>
73 #endif /* REV_ENDIAN_FS */
77 #include <ufs/ufs/quota.h>
78 #include <ufs/ufs/inode.h>
79 #include <ufs/ufs/ufs_extern.h>
81 #include <ufs/ffs/fs.h>
82 #include <ufs/ffs/ffs_extern.h>
85 #include <ufs/ufs/ufs_byte_order.h>
86 #include <architecture/byte_order.h>
87 #endif /* REV_ENDIAN_FS */
90 * Balloc defines the structure of file system storage
91 * by allocating the physical blocks on a device given
92 * the inode and the logical block number in a file.
94 ffs_balloc(ip
, lbn
, size
, cred
, bpp
, flags
, blk_alloc
)
95 register struct inode
*ip
;
96 register ufs_daddr_t lbn
;
103 register struct fs
*fs
;
104 register ufs_daddr_t nb
;
105 struct buf
*bp
, *nbp
;
106 struct vnode
*vp
= ITOV(ip
);
107 struct indir indirs
[NIADDR
+ 2];
108 ufs_daddr_t newb
, *bap
, pref
;
109 int deallocated
, osize
, nsize
, num
, i
, error
;
110 ufs_daddr_t
*allocib
, *blkp
, *allocblk
, allociblk
[NIADDR
+ 1];
112 int alloc_buffer
= 1;
114 struct mount
*mp
=vp
->v_mount
;
115 int rev_endian
=(mp
->mnt_flag
& MNT_REVEND
);
116 #endif /* REV_ENDIAN_FS */
122 if (flags
& B_NOBUFF
)
129 * If the next write will extend the file into a new block,
130 * and the file is currently composed of a fragment
131 * this fragment has to be extended to be a full block.
133 nb
= lblkno(fs
, ip
->i_size
);
134 if (nb
< NDADDR
&& nb
< lbn
) {
135 /* the filesize prior to this write can fit in direct
136 * blocks (ie. fragmentaion is possibly done)
137 * we are now extending the file write beyond
138 * the block which has end of file prior to this write
140 osize
= blksize(fs
, ip
, nb
);
141 /* osize gives disk allocated size in the last block. It is
142 * either in fragments or a file system block size */
143 if (osize
< fs
->fs_bsize
&& osize
> 0) {
144 /* few fragments are already allocated,since the
145 * current extends beyond this block
146 * allocate the complete block as fragments are only
149 error
= ffs_realloccg(ip
, nb
,
150 ffs_blkpref(ip
, nb
, (int)nb
, &ip
->i_db
[0]),
151 osize
, (int)fs
->fs_bsize
, cred
, &bp
);
154 /* adjust the innode size we just grew */
155 /* it is in nb+1 as nb starts from 0 */
156 ip
->i_size
= (nb
+ 1) * fs
->fs_bsize
;
158 ubc_setsize(vp
, (off_t
)ip
->i_size
); /* XXX check error */
159 ip
->i_db
[nb
] = dbtofsb(fs
, bp
->b_blkno
);
160 ip
->i_flag
|= IN_CHANGE
| IN_UPDATE
;
161 if ((flags
& B_SYNC
) || (!alloc_buffer
)) {
163 SET(bp
->b_flags
, B_NOCACHE
);
167 /* note that bp is already released here */
171 * The first NDADDR blocks are direct blocks
175 if (nb
!= 0 && ip
->i_size
>= (lbn
+ 1) * fs
->fs_bsize
) {
177 error
= bread(vp
, lbn
, fs
->fs_bsize
, NOCRED
, &bp
);
188 * Consider need to reallocate a fragment.
190 osize
= fragroundup(fs
, blkoff(fs
, ip
->i_size
));
191 nsize
= fragroundup(fs
, size
);
192 if (nsize
<= osize
) {
194 error
= bread(vp
, lbn
, osize
, NOCRED
, &bp
);
199 ip
->i_flag
|= IN_CHANGE
| IN_UPDATE
;
204 ip
->i_flag
|= IN_CHANGE
| IN_UPDATE
;
208 error
= ffs_realloccg(ip
, lbn
,
209 ffs_blkpref(ip
, lbn
, (int)lbn
,
210 &ip
->i_db
[0]), osize
, nsize
, cred
, &bp
);
213 ip
->i_db
[lbn
] = dbtofsb(fs
, bp
->b_blkno
);
214 ip
->i_flag
|= IN_CHANGE
| IN_UPDATE
;
216 SET(bp
->b_flags
, B_NOCACHE
);
227 if (ip
->i_size
< (lbn
+ 1) * fs
->fs_bsize
)
228 nsize
= fragroundup(fs
, size
);
230 nsize
= fs
->fs_bsize
;
231 error
= ffs_alloc(ip
, lbn
,
232 ffs_blkpref(ip
, lbn
, (int)lbn
, &ip
->i_db
[0]),
237 bp
= getblk(vp
, lbn
, nsize
, 0, 0, BLK_WRITE
);
238 bp
->b_blkno
= fsbtodb(fs
, newb
);
239 if (flags
& B_CLRBUF
)
242 ip
->i_db
[lbn
] = newb
;
243 ip
->i_flag
|= IN_CHANGE
| IN_UPDATE
;
253 * Determine the number of levels of indirection.
256 if (error
= ufs_getlbns(vp
, lbn
, indirs
, &num
))
260 panic ("ffs_balloc: ufs_bmaparray returned indirect block");
263 * Fetch the first indirect block allocating if necessary.
266 nb
= ip
->i_ib
[indirs
[0].in_off
];
268 allocblk
= allociblk
;
270 pref
= ffs_blkpref(ip
, lbn
, 0, (ufs_daddr_t
*)0);
271 if (error
= ffs_alloc(ip
, lbn
, pref
, (int)fs
->fs_bsize
,
276 bp
= getblk(vp
, indirs
[1].in_lbn
, fs
->fs_bsize
, 0, 0, BLK_META
);
277 bp
->b_blkno
= fsbtodb(fs
, nb
);
280 * Write synchronously conditional on mount flags.
282 if ((vp
)->v_mount
->mnt_flag
& MNT_ASYNC
) {
285 } else if ((error
= bwrite(bp
)) != 0) {
288 allocib
= &ip
->i_ib
[indirs
[0].in_off
];
290 ip
->i_flag
|= IN_CHANGE
| IN_UPDATE
;
293 * Fetch through the indirect blocks, allocating as necessary.
296 error
= meta_bread(vp
,
297 indirs
[i
].in_lbn
, (int)fs
->fs_bsize
, NOCRED
, &bp
);
302 bap
= (ufs_daddr_t
*)bp
->b_data
;
305 nb
= NXSwapLong(bap
[indirs
[i
].in_off
]);
307 #endif /* REV_ENDIAN_FS */
308 nb
= bap
[indirs
[i
].in_off
];
311 #endif /* REV_ENDIAN_FS */
320 pref
= ffs_blkpref(ip
, lbn
, 0, (ufs_daddr_t
*)0);
322 ffs_alloc(ip
, lbn
, pref
, (int)fs
->fs_bsize
, cred
, &newb
)) {
328 nbp
= getblk(vp
, indirs
[i
].in_lbn
, fs
->fs_bsize
, 0, 0, BLK_META
);
329 nbp
->b_blkno
= fsbtodb(fs
, nb
);
332 * Write synchronously conditional on mount flags.
334 if ((vp
)->v_mount
->mnt_flag
& MNT_ASYNC
) {
337 } else if (error
= bwrite(nbp
)) {
343 bap
[indirs
[i
- 1].in_off
] = NXSwapLong(nb
);
345 #endif /* REV_ENDIAN_FS */
346 bap
[indirs
[i
- 1].in_off
] = nb
;
349 #endif /* REV_ENDIAN_FS */
351 * If required, write synchronously, otherwise use
354 if (flags
& B_SYNC
) {
361 * Get the data block, allocating if necessary.
364 pref
= ffs_blkpref(ip
, lbn
, indirs
[i
].in_off
, &bap
[0]);
365 if (error
= ffs_alloc(ip
,
366 lbn
, pref
, (int)fs
->fs_bsize
, cred
, &newb
)) {
374 bap
[indirs
[i
].in_off
] = NXSwapLong(nb
);
376 #endif /* REV_ENDIAN_FS */
377 bap
[indirs
[i
].in_off
] = nb
;
380 #endif /* REV_ENDIAN_FS */
382 * If required, write synchronously, otherwise use
385 if ((flags
& B_SYNC
)) {
391 nbp
= getblk(vp
, lbn
, fs
->fs_bsize
, 0, 0, BLK_WRITE
);
392 nbp
->b_blkno
= fsbtodb(fs
, nb
);
393 if (flags
& B_CLRBUF
)
397 *blk_alloc
= fs
->fs_bsize
;
406 if (flags
& B_CLRBUF
) {
407 error
= bread(vp
, lbn
, (int)fs
->fs_bsize
, NOCRED
, &nbp
);
413 nbp
= getblk(vp
, lbn
, fs
->fs_bsize
, 0, 0, BLK_WRITE
);
414 nbp
->b_blkno
= fsbtodb(fs
, nb
);
421 * If we have failed part way through block allocation, we
422 * have to deallocate any indirect blocks that we have allocated.
424 for (deallocated
= 0, blkp
= allociblk
; blkp
< allocblk
; blkp
++) {
425 ffs_blkfree(ip
, *blkp
, fs
->fs_bsize
);
426 deallocated
+= fs
->fs_bsize
;
431 VOP_DEVBLOCKSIZE(ip
->i_devvp
,&devBlockSize
);
435 * Restore user's disk quota because allocation failed.
437 (void) chkdq(ip
, (int64_t)-deallocated
, cred
, FORCE
);
439 ip
->i_blocks
-= btodb(deallocated
, devBlockSize
);
440 ip
->i_flag
|= IN_CHANGE
| IN_UPDATE
;
446 * ffs_blkalloc allocates a disk block for ffs_pageout(), as a consequence
447 * it does no breads (that could lead to deadblock as the page may be already
448 * marked busy as it is being paged out. Also important to note that we are not
449 * growing the file in pageouts. So ip->i_size cannot increase by this call
450 * due to the way UBC works.
451 * This code is derived from ffs_balloc and many cases of that are dealt
452 * in ffs_balloc are not applicable here
453 * Do not call with B_CLRBUF flags as this should only be called only
456 ffs_blkalloc(ip
, lbn
, size
, cred
, flags
)
457 register struct inode
*ip
;
463 register struct fs
*fs
;
464 register ufs_daddr_t nb
;
465 struct buf
*bp
, *nbp
;
466 struct vnode
*vp
= ITOV(ip
);
467 struct indir indirs
[NIADDR
+ 2];
468 ufs_daddr_t newb
, *bap
, pref
;
469 int deallocated
, osize
, nsize
, num
, i
, error
;
470 ufs_daddr_t
*allocib
, *blkp
, *allocblk
, allociblk
[NIADDR
+ 1];
473 struct mount
*mp
=vp
->v_mount
;
474 int rev_endian
=(mp
->mnt_flag
& MNT_REVEND
);
475 #endif /* REV_ENDIAN_FS */
479 if(size
> fs
->fs_bsize
)
480 panic("ffs_blkalloc: too large for allocation");
483 * If the next write will extend the file into a new block,
484 * and the file is currently composed of a fragment
485 * this fragment has to be extended to be a full block.
487 nb
= lblkno(fs
, ip
->i_size
);
488 if (nb
< NDADDR
&& nb
< lbn
) {
489 panic("ffs_blkalloc():cannot extend file: i_size %d, lbn %d", ip
->i_size
, lbn
);
492 * The first NDADDR blocks are direct blocks
496 if (nb
!= 0 && ip
->i_size
>= (lbn
+ 1) * fs
->fs_bsize
) {
497 /* TBD: trivial case; the block is already allocated */
502 * Consider need to reallocate a fragment.
504 osize
= fragroundup(fs
, blkoff(fs
, ip
->i_size
));
505 nsize
= fragroundup(fs
, size
);
507 panic("ffs_allocblk: trying to extend a fragment");
511 if (ip
->i_size
< (lbn
+ 1) * fs
->fs_bsize
)
512 nsize
= fragroundup(fs
, size
);
514 nsize
= fs
->fs_bsize
;
515 error
= ffs_alloc(ip
, lbn
,
516 ffs_blkpref(ip
, lbn
, (int)lbn
, &ip
->i_db
[0]),
520 ip
->i_db
[lbn
] = newb
;
521 ip
->i_flag
|= IN_CHANGE
| IN_UPDATE
;
526 * Determine the number of levels of indirection.
529 if (error
= ufs_getlbns(vp
, lbn
, indirs
, &num
))
533 panic("ffs_blkalloc: file with direct blocks only");
537 * Fetch the first indirect block allocating if necessary.
540 nb
= ip
->i_ib
[indirs
[0].in_off
];
542 allocblk
= allociblk
;
544 pref
= ffs_blkpref(ip
, lbn
, 0, (ufs_daddr_t
*)0);
545 if (error
= ffs_alloc(ip
, lbn
, pref
, (int)fs
->fs_bsize
,
550 bp
= getblk(vp
, indirs
[1].in_lbn
, fs
->fs_bsize
, 0, 0, BLK_META
);
551 bp
->b_blkno
= fsbtodb(fs
, nb
);
554 * Write synchronously conditional on mount flags.
556 if ((vp
)->v_mount
->mnt_flag
& MNT_ASYNC
) {
559 } else if (error
= bwrite(bp
)) {
562 allocib
= &ip
->i_ib
[indirs
[0].in_off
];
564 ip
->i_flag
|= IN_CHANGE
| IN_UPDATE
;
567 * Fetch through the indirect blocks, allocating as necessary.
570 error
= meta_bread(vp
,
571 indirs
[i
].in_lbn
, (int)fs
->fs_bsize
, NOCRED
, &bp
);
576 bap
= (ufs_daddr_t
*)bp
->b_data
;
579 nb
= NXSwapLong(bap
[indirs
[i
].in_off
]);
581 #endif /* REV_ENDIAN_FS */
582 nb
= bap
[indirs
[i
].in_off
];
585 #endif /* REV_ENDIAN_FS */
594 pref
= ffs_blkpref(ip
, lbn
, 0, (ufs_daddr_t
*)0);
596 ffs_alloc(ip
, lbn
, pref
, (int)fs
->fs_bsize
, cred
, &newb
)) {
602 nbp
= getblk(vp
, indirs
[i
].in_lbn
, fs
->fs_bsize
, 0, 0, BLK_META
);
603 nbp
->b_blkno
= fsbtodb(fs
, nb
);
606 * Write synchronously conditional on mount flags.
608 if ((vp
)->v_mount
->mnt_flag
& MNT_ASYNC
) {
611 } else if (error
= bwrite(nbp
)) {
617 bap
[indirs
[i
- 1].in_off
] = NXSwapLong(nb
);
619 #endif /* REV_ENDIAN_FS */
620 bap
[indirs
[i
- 1].in_off
] = nb
;
623 #endif /* REV_ENDIAN_FS */
625 * If required, write synchronously, otherwise use
628 if (flags
& B_SYNC
) {
635 * Get the data block, allocating if necessary.
638 pref
= ffs_blkpref(ip
, lbn
, indirs
[i
].in_off
, &bap
[0]);
639 if (error
= ffs_alloc(ip
,
640 lbn
, pref
, (int)fs
->fs_bsize
, cred
, &newb
)) {
648 bap
[indirs
[i
].in_off
] = NXSwapLong(nb
);
650 #endif /* REV_ENDIAN_FS */
651 bap
[indirs
[i
].in_off
] = nb
;
654 #endif /* REV_ENDIAN_FS */
656 * If required, write synchronously, otherwise use
659 if (flags
& B_SYNC
) {
670 * If we have failed part way through block allocation, we
671 * have to deallocate any indirect blocks that we have allocated.
673 for (deallocated
= 0, blkp
= allociblk
; blkp
< allocblk
; blkp
++) {
674 ffs_blkfree(ip
, *blkp
, fs
->fs_bsize
);
675 deallocated
+= fs
->fs_bsize
;
680 VOP_DEVBLOCKSIZE(ip
->i_devvp
,&devBlockSize
);
684 * Restore user's disk quota because allocation failed.
686 (void) chkdq(ip
, (int64_t)-deallocated
, cred
, FORCE
);
688 ip
->i_blocks
-= btodb(deallocated
, devBlockSize
);
689 ip
->i_flag
|= IN_CHANGE
| IN_UPDATE
;