]>
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 * 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_balloc.c 8.8 (Berkeley) 6/16/95
58 #include <rev_endian_fs.h>
59 #include <sys/param.h>
60 #include <sys/systm.h>
61 #include <sys/buf_internal.h>
63 #include <sys/kauth.h>
65 #include <sys/vnode_internal.h>
67 #include <sys/quota.h>
70 #include <sys/mount_internal.h>
71 #endif /* REV_ENDIAN_FS */
75 #include <ufs/ufs/quota.h>
76 #include <ufs/ufs/inode.h>
77 #include <ufs/ufs/ufs_extern.h>
79 #include <ufs/ffs/fs.h>
80 #include <ufs/ffs/ffs_extern.h>
83 #include <ufs/ufs/ufs_byte_order.h>
84 #include <architecture/byte_order.h>
85 #endif /* REV_ENDIAN_FS */
88 * Balloc defines the structure of file system storage
89 * by allocating the physical blocks on a device given
90 * the inode and the logical block number in a file.
93 register struct inode
*ip
,
94 register ufs_daddr_t lbn
,
101 register struct fs
*fs
;
102 register ufs_daddr_t nb
;
103 struct buf
*bp
, *nbp
;
104 struct vnode
*vp
= ITOV(ip
);
105 struct indir indirs
[NIADDR
+ 2];
106 ufs_daddr_t newb
, *bap
, pref
;
107 int deallocated
, osize
, nsize
, num
, i
, error
;
108 ufs_daddr_t
*allocib
, *blkp
, *allocblk
, allociblk
[NIADDR
+ 1];
110 int alloc_buffer
= 1;
111 struct mount
*mp
=vp
->v_mount
;
113 int rev_endian
=(mp
->mnt_flag
& MNT_REVEND
);
114 #endif /* REV_ENDIAN_FS */
120 if (flags
& B_NOBUFF
)
127 * If the next write will extend the file into a new block,
128 * and the file is currently composed of a fragment
129 * this fragment has to be extended to be a full block.
131 nb
= lblkno(fs
, ip
->i_size
);
132 if (nb
< NDADDR
&& nb
< lbn
) {
133 /* the filesize prior to this write can fit in direct
134 * blocks (ie. fragmentaion is possibly done)
135 * we are now extending the file write beyond
136 * the block which has end of file prior to this write
138 osize
= blksize(fs
, ip
, nb
);
139 /* osize gives disk allocated size in the last block. It is
140 * either in fragments or a file system block size */
141 if (osize
< fs
->fs_bsize
&& osize
> 0) {
142 /* few fragments are already allocated,since the
143 * current extends beyond this block
144 * allocate the complete block as fragments are only
147 error
= ffs_realloccg(ip
, nb
,
148 ffs_blkpref(ip
, nb
, (int)nb
, &ip
->i_db
[0]),
149 osize
, (int)fs
->fs_bsize
, cred
, &bp
);
152 /* adjust the inode size we just grew */
153 /* it is in nb+1 as nb starts from 0 */
154 ip
->i_size
= (nb
+ 1) * fs
->fs_bsize
;
155 ubc_setsize(vp
, (off_t
)ip
->i_size
);
157 ip
->i_db
[nb
] = dbtofsb(fs
, (ufs_daddr_t
)buf_blkno(bp
));
158 ip
->i_flag
|= IN_CHANGE
| IN_UPDATE
;
160 if ((flags
& B_SYNC
) || (!alloc_buffer
)) {
162 buf_setflags(bp
, B_NOCACHE
);
166 /* note that bp is already released here */
170 * The first NDADDR blocks are direct blocks
174 if (nb
!= 0 && ip
->i_size
>= (lbn
+ 1) * fs
->fs_bsize
) {
176 error
= (int)buf_bread(vp
, (daddr64_t
)((unsigned)lbn
), fs
->fs_bsize
, NOCRED
, &bp
);
187 * Consider need to reallocate a fragment.
189 osize
= fragroundup(fs
, blkoff(fs
, ip
->i_size
));
190 nsize
= fragroundup(fs
, size
);
191 if (nsize
<= osize
) {
193 error
= (int)buf_bread(vp
, (daddr64_t
)((unsigned)lbn
), osize
, NOCRED
, &bp
);
198 ip
->i_flag
|= IN_CHANGE
| IN_UPDATE
;
203 ip
->i_flag
|= IN_CHANGE
| IN_UPDATE
;
207 error
= ffs_realloccg(ip
, lbn
,
208 ffs_blkpref(ip
, lbn
, (int)lbn
,
209 &ip
->i_db
[0]), osize
, nsize
, cred
, &bp
);
212 ip
->i_db
[lbn
] = dbtofsb(fs
, (ufs_daddr_t
)buf_blkno(bp
));
213 ip
->i_flag
|= IN_CHANGE
| IN_UPDATE
;
215 /* adjust the inode size we just grew */
216 ip
->i_size
= (lbn
* fs
->fs_bsize
) + size
;
217 ubc_setsize(vp
, (off_t
)ip
->i_size
);
220 buf_setflags(bp
, B_NOCACHE
);
231 if (ip
->i_size
< (lbn
+ 1) * fs
->fs_bsize
)
232 nsize
= fragroundup(fs
, size
);
234 nsize
= fs
->fs_bsize
;
235 error
= ffs_alloc(ip
, lbn
,
236 ffs_blkpref(ip
, lbn
, (int)lbn
, &ip
->i_db
[0]),
241 bp
= buf_getblk(vp
, (daddr64_t
)((unsigned)lbn
), nsize
, 0, 0, BLK_WRITE
);
242 buf_setblkno(bp
, (daddr64_t
)((unsigned)fsbtodb(fs
, newb
)));
244 if (flags
& B_CLRBUF
)
247 ip
->i_db
[lbn
] = newb
;
248 ip
->i_flag
|= IN_CHANGE
| IN_UPDATE
;
258 * Determine the number of levels of indirection.
261 if (error
= ufs_getlbns(vp
, lbn
, indirs
, &num
))
265 panic ("ffs_balloc: ufs_bmaparray returned indirect block");
268 * Fetch the first indirect block allocating if necessary.
271 nb
= ip
->i_ib
[indirs
[0].in_off
];
273 allocblk
= allociblk
;
275 pref
= ffs_blkpref(ip
, lbn
, 0, (ufs_daddr_t
*)0);
276 if (error
= ffs_alloc(ip
, lbn
, pref
, (int)fs
->fs_bsize
,
281 bp
= buf_getblk(vp
, (daddr64_t
)((unsigned)(indirs
[1].in_lbn
)), fs
->fs_bsize
, 0, 0, BLK_META
);
282 buf_setblkno(bp
, (daddr64_t
)((unsigned)fsbtodb(fs
, nb
)));
285 * Write synchronously conditional on mount flags.
287 if ((vp
)->v_mount
->mnt_flag
& MNT_ASYNC
) {
290 } else if ((error
= buf_bwrite(bp
)) != 0) {
293 allocib
= &ip
->i_ib
[indirs
[0].in_off
];
295 ip
->i_flag
|= IN_CHANGE
| IN_UPDATE
;
298 * Fetch through the indirect blocks, allocating as necessary.
301 error
= (int)buf_meta_bread(vp
, (daddr64_t
)((unsigned)(indirs
[i
].in_lbn
)), (int)fs
->fs_bsize
, NOCRED
, &bp
);
306 bap
= (ufs_daddr_t
*)buf_dataptr(bp
);
309 nb
= NXSwapLong(bap
[indirs
[i
].in_off
]);
311 #endif /* REV_ENDIAN_FS */
312 nb
= bap
[indirs
[i
].in_off
];
315 #endif /* REV_ENDIAN_FS */
324 pref
= ffs_blkpref(ip
, lbn
, 0, (ufs_daddr_t
*)0);
326 ffs_alloc(ip
, lbn
, pref
, (int)fs
->fs_bsize
, cred
, &newb
)) {
332 nbp
= buf_getblk(vp
, (daddr64_t
)((unsigned)(indirs
[i
].in_lbn
)), fs
->fs_bsize
, 0, 0, BLK_META
);
333 buf_setblkno(nbp
, (daddr64_t
)((unsigned)fsbtodb(fs
, nb
)));
336 * Write synchronously conditional on mount flags.
338 if ((vp
)->v_mount
->mnt_flag
& MNT_ASYNC
) {
341 } else if (error
= buf_bwrite(nbp
)) {
347 bap
[indirs
[i
- 1].in_off
] = NXSwapLong(nb
);
349 #endif /* REV_ENDIAN_FS */
350 bap
[indirs
[i
- 1].in_off
] = nb
;
353 #endif /* REV_ENDIAN_FS */
355 * If required, write synchronously, otherwise use
358 if (flags
& B_SYNC
) {
365 * Get the data block, allocating if necessary.
368 pref
= ffs_blkpref(ip
, lbn
, indirs
[i
].in_off
, &bap
[0]);
369 if (error
= ffs_alloc(ip
,
370 lbn
, pref
, (int)fs
->fs_bsize
, cred
, &newb
)) {
378 bap
[indirs
[i
].in_off
] = NXSwapLong(nb
);
380 #endif /* REV_ENDIAN_FS */
381 bap
[indirs
[i
].in_off
] = nb
;
384 #endif /* REV_ENDIAN_FS */
386 * If required, write synchronously, otherwise use
389 if ((flags
& B_SYNC
)) {
395 nbp
= buf_getblk(vp
, (daddr64_t
)((unsigned)lbn
), fs
->fs_bsize
, 0, 0, BLK_WRITE
);
396 buf_setblkno(nbp
, (daddr64_t
)((unsigned)fsbtodb(fs
, nb
)));
398 if (flags
& B_CLRBUF
)
402 *blk_alloc
= fs
->fs_bsize
;
411 if (flags
& B_CLRBUF
) {
412 error
= (int)buf_bread(vp
, (daddr64_t
)((unsigned)lbn
), (int)fs
->fs_bsize
, NOCRED
, &nbp
);
418 nbp
= buf_getblk(vp
, (daddr64_t
)((unsigned)lbn
), fs
->fs_bsize
, 0, 0, BLK_WRITE
);
419 buf_setblkno(nbp
, (daddr64_t
)((unsigned)fsbtodb(fs
, nb
)));
426 * If we have failed part way through block allocation, we
427 * have to deallocate any indirect blocks that we have allocated.
429 for (deallocated
= 0, blkp
= allociblk
; blkp
< allocblk
; blkp
++) {
430 ffs_blkfree(ip
, *blkp
, fs
->fs_bsize
);
431 deallocated
+= fs
->fs_bsize
;
436 devBlockSize
= vfs_devblocksize(mp
);
439 * Restore user's disk quota because allocation failed.
441 (void) chkdq(ip
, (int64_t)-deallocated
, cred
, FORCE
);
443 ip
->i_blocks
-= btodb(deallocated
, devBlockSize
);
444 ip
->i_flag
|= IN_CHANGE
| IN_UPDATE
;
450 * ffs_blkalloc allocates a disk block for ffs_pageout(), as a consequence
451 * it does no buf_breads (that could lead to deadblock as the page may be already
452 * marked busy as it is being paged out. Also important to note that we are not
453 * growing the file in pageouts. So ip->i_size cannot increase by this call
454 * due to the way UBC works.
455 * This code is derived from ffs_balloc and many cases of that are dealt
456 * in ffs_balloc are not applicable here
457 * Do not call with B_CLRBUF flags as this should only be called only
467 register struct fs
*fs
;
468 register ufs_daddr_t nb
;
469 struct buf
*bp
, *nbp
;
470 struct vnode
*vp
= ITOV(ip
);
471 struct indir indirs
[NIADDR
+ 2];
472 ufs_daddr_t newb
, *bap
, pref
;
473 int deallocated
, osize
, nsize
, num
, i
, error
;
474 ufs_daddr_t
*allocib
, *blkp
, *allocblk
, allociblk
[NIADDR
+ 1];
476 struct mount
*mp
=vp
->v_mount
;
478 int rev_endian
=(mp
->mnt_flag
& MNT_REVEND
);
479 #endif /* REV_ENDIAN_FS */
483 if(size
> fs
->fs_bsize
)
484 panic("ffs_blkalloc: too large for allocation");
487 * If the next write will extend the file into a new block,
488 * and the file is currently composed of a fragment
489 * this fragment has to be extended to be a full block.
491 nb
= lblkno(fs
, ip
->i_size
);
492 if (nb
< NDADDR
&& nb
< lbn
) {
493 panic("ffs_blkalloc():cannot extend file: i_size %d, lbn %d", ip
->i_size
, lbn
);
496 * The first NDADDR blocks are direct blocks
500 if (nb
!= 0 && ip
->i_size
>= (lbn
+ 1) * fs
->fs_bsize
) {
501 /* TBD: trivial case; the block is already allocated */
506 * Consider need to reallocate a fragment.
508 osize
= fragroundup(fs
, blkoff(fs
, ip
->i_size
));
509 nsize
= fragroundup(fs
, size
);
511 panic("ffs_allocblk: trying to extend a fragment");
515 if (ip
->i_size
< (lbn
+ 1) * fs
->fs_bsize
)
516 nsize
= fragroundup(fs
, size
);
518 nsize
= fs
->fs_bsize
;
519 error
= ffs_alloc(ip
, lbn
,
520 ffs_blkpref(ip
, lbn
, (int)lbn
, &ip
->i_db
[0]),
524 ip
->i_db
[lbn
] = newb
;
525 ip
->i_flag
|= IN_CHANGE
| IN_UPDATE
;
530 * Determine the number of levels of indirection.
533 if (error
= ufs_getlbns(vp
, lbn
, indirs
, &num
))
537 panic("ffs_blkalloc: file with direct blocks only");
541 * Fetch the first indirect block allocating if necessary.
544 nb
= ip
->i_ib
[indirs
[0].in_off
];
546 allocblk
= allociblk
;
548 pref
= ffs_blkpref(ip
, lbn
, 0, (ufs_daddr_t
*)0);
549 if (error
= ffs_alloc(ip
, lbn
, pref
, (int)fs
->fs_bsize
,
554 bp
= buf_getblk(vp
, (daddr64_t
)((unsigned)(indirs
[1].in_lbn
)), fs
->fs_bsize
, 0, 0, BLK_META
);
555 buf_setblkno(bp
, (daddr64_t
)((unsigned)fsbtodb(fs
, nb
)));
558 * Write synchronously conditional on mount flags.
560 if ((vp
)->v_mount
->mnt_flag
& MNT_ASYNC
) {
563 } else if (error
= buf_bwrite(bp
)) {
566 allocib
= &ip
->i_ib
[indirs
[0].in_off
];
568 ip
->i_flag
|= IN_CHANGE
| IN_UPDATE
;
571 * Fetch through the indirect blocks, allocating as necessary.
574 error
= (int)buf_meta_bread(vp
, (daddr64_t
)((unsigned)(indirs
[i
].in_lbn
)), (int)fs
->fs_bsize
, NOCRED
, &bp
);
579 bap
= (ufs_daddr_t
*)buf_dataptr(bp
);
582 nb
= NXSwapLong(bap
[indirs
[i
].in_off
]);
584 #endif /* REV_ENDIAN_FS */
585 nb
= bap
[indirs
[i
].in_off
];
588 #endif /* REV_ENDIAN_FS */
597 pref
= ffs_blkpref(ip
, lbn
, 0, (ufs_daddr_t
*)0);
599 ffs_alloc(ip
, lbn
, pref
, (int)fs
->fs_bsize
, cred
, &newb
)) {
605 nbp
= buf_getblk(vp
, (daddr64_t
)((unsigned)(indirs
[i
].in_lbn
)), fs
->fs_bsize
, 0, 0, BLK_META
);
606 buf_setblkno(nbp
, (daddr64_t
)((unsigned)fsbtodb(fs
, nb
)));
609 * Write synchronously conditional on mount flags.
611 if ((vp
)->v_mount
->mnt_flag
& MNT_ASYNC
) {
614 } else if (error
= buf_bwrite(nbp
)) {
620 bap
[indirs
[i
- 1].in_off
] = NXSwapLong(nb
);
622 #endif /* REV_ENDIAN_FS */
623 bap
[indirs
[i
- 1].in_off
] = nb
;
626 #endif /* REV_ENDIAN_FS */
628 * If required, write synchronously, otherwise use
631 if (flags
& B_SYNC
) {
638 * Get the data block, allocating if necessary.
641 pref
= ffs_blkpref(ip
, lbn
, indirs
[i
].in_off
, &bap
[0]);
642 if (error
= ffs_alloc(ip
,
643 lbn
, pref
, (int)fs
->fs_bsize
, cred
, &newb
)) {
651 bap
[indirs
[i
].in_off
] = NXSwapLong(nb
);
653 #endif /* REV_ENDIAN_FS */
654 bap
[indirs
[i
].in_off
] = nb
;
657 #endif /* REV_ENDIAN_FS */
659 * If required, write synchronously, otherwise use
662 if (flags
& B_SYNC
) {
673 * If we have failed part way through block allocation, we
674 * have to deallocate any indirect blocks that we have allocated.
676 for (deallocated
= 0, blkp
= allociblk
; blkp
< allocblk
; blkp
++) {
677 ffs_blkfree(ip
, *blkp
, fs
->fs_bsize
);
678 deallocated
+= fs
->fs_bsize
;
683 devBlockSize
= vfs_devblocksize(mp
);
686 * Restore user's disk quota because allocation failed.
688 (void) chkdq(ip
, (int64_t)-deallocated
, cred
, FORCE
);
690 ip
->i_blocks
-= btodb(deallocated
, devBlockSize
);
691 ip
->i_flag
|= IN_CHANGE
| IN_UPDATE
;