]>
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_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_balloc.c 8.8 (Berkeley) 6/16/95
64 #include <rev_endian_fs.h>
65 #include <sys/param.h>
66 #include <sys/systm.h>
67 #include <sys/buf_internal.h>
69 #include <sys/kauth.h>
71 #include <sys/vnode_internal.h>
73 #include <sys/quota.h>
76 #include <sys/mount_internal.h>
77 #endif /* REV_ENDIAN_FS */
81 #include <ufs/ufs/quota.h>
82 #include <ufs/ufs/inode.h>
83 #include <ufs/ufs/ufs_extern.h>
85 #include <ufs/ffs/fs.h>
86 #include <ufs/ffs/ffs_extern.h>
89 #include <ufs/ufs/ufs_byte_order.h>
90 #include <libkern/OSByteOrder.h>
91 #endif /* REV_ENDIAN_FS */
94 * Balloc defines the structure of file system storage
95 * by allocating the physical blocks on a device given
96 * the inode and the logical block number in a file.
99 register struct inode
*ip
,
100 register ufs_daddr_t lbn
,
107 register struct fs
*fs
;
108 register ufs_daddr_t nb
;
109 struct buf
*bp
, *nbp
;
110 struct vnode
*vp
= ITOV(ip
);
111 struct indir indirs
[NIADDR
+ 2];
112 ufs_daddr_t newb
, *bap
, pref
;
113 int deallocated
, osize
, nsize
, num
, i
, error
;
114 ufs_daddr_t
*allocib
, *blkp
, *allocblk
, allociblk
[NIADDR
+ 1];
116 int alloc_buffer
= 1;
117 struct mount
*mp
=vp
->v_mount
;
119 int rev_endian
=(mp
->mnt_flag
& MNT_REVEND
);
120 #endif /* REV_ENDIAN_FS */
126 if (flags
& B_NOBUFF
)
133 * If the next write will extend the file into a new block,
134 * and the file is currently composed of a fragment
135 * this fragment has to be extended to be a full block.
137 nb
= lblkno(fs
, ip
->i_size
);
138 if (nb
< NDADDR
&& nb
< lbn
) {
139 /* the filesize prior to this write can fit in direct
140 * blocks (ie. fragmentaion is possibly done)
141 * we are now extending the file write beyond
142 * the block which has end of file prior to this write
144 osize
= blksize(fs
, ip
, nb
);
145 /* osize gives disk allocated size in the last block. It is
146 * either in fragments or a file system block size */
147 if (osize
< fs
->fs_bsize
&& osize
> 0) {
148 /* few fragments are already allocated,since the
149 * current extends beyond this block
150 * allocate the complete block as fragments are only
153 error
= ffs_realloccg(ip
, nb
,
154 ffs_blkpref(ip
, nb
, (int)nb
, &ip
->i_db
[0]),
155 osize
, (int)fs
->fs_bsize
, cred
, &bp
);
158 /* adjust the inode size we just grew */
159 /* it is in nb+1 as nb starts from 0 */
160 ip
->i_size
= (nb
+ 1) * fs
->fs_bsize
;
161 ubc_setsize(vp
, (off_t
)ip
->i_size
);
163 ip
->i_db
[nb
] = dbtofsb(fs
, (ufs_daddr_t
)buf_blkno(bp
));
164 ip
->i_flag
|= IN_CHANGE
| IN_UPDATE
;
166 if ((flags
& B_SYNC
) || (!alloc_buffer
)) {
168 buf_setflags(bp
, B_NOCACHE
);
172 /* note that bp is already released here */
176 * The first NDADDR blocks are direct blocks
180 if (nb
!= 0 && ip
->i_size
>= (lbn
+ 1) * fs
->fs_bsize
) {
182 error
= (int)buf_bread(vp
, (daddr64_t
)((unsigned)lbn
), fs
->fs_bsize
, NOCRED
, &bp
);
193 * Consider need to reallocate a fragment.
195 osize
= fragroundup(fs
, blkoff(fs
, ip
->i_size
));
196 nsize
= fragroundup(fs
, size
);
197 if (nsize
<= osize
) {
199 error
= (int)buf_bread(vp
, (daddr64_t
)((unsigned)lbn
), osize
, NOCRED
, &bp
);
204 ip
->i_flag
|= IN_CHANGE
| IN_UPDATE
;
209 ip
->i_flag
|= IN_CHANGE
| IN_UPDATE
;
213 error
= ffs_realloccg(ip
, lbn
,
214 ffs_blkpref(ip
, lbn
, (int)lbn
,
215 &ip
->i_db
[0]), osize
, nsize
, cred
, &bp
);
218 ip
->i_db
[lbn
] = dbtofsb(fs
, (ufs_daddr_t
)buf_blkno(bp
));
219 ip
->i_flag
|= IN_CHANGE
| IN_UPDATE
;
221 /* adjust the inode size we just grew */
222 ip
->i_size
= (lbn
* fs
->fs_bsize
) + size
;
223 ubc_setsize(vp
, (off_t
)ip
->i_size
);
226 buf_setflags(bp
, B_NOCACHE
);
237 if (ip
->i_size
< (lbn
+ 1) * fs
->fs_bsize
)
238 nsize
= fragroundup(fs
, size
);
240 nsize
= fs
->fs_bsize
;
241 error
= ffs_alloc(ip
, lbn
,
242 ffs_blkpref(ip
, lbn
, (int)lbn
, &ip
->i_db
[0]),
247 bp
= buf_getblk(vp
, (daddr64_t
)((unsigned)lbn
), nsize
, 0, 0, BLK_WRITE
);
248 buf_setblkno(bp
, (daddr64_t
)((unsigned)fsbtodb(fs
, newb
)));
250 if (flags
& B_CLRBUF
)
253 ip
->i_db
[lbn
] = newb
;
254 ip
->i_flag
|= IN_CHANGE
| IN_UPDATE
;
264 * Determine the number of levels of indirection.
267 if (error
= ufs_getlbns(vp
, lbn
, indirs
, &num
))
271 panic ("ffs_balloc: ufs_bmaparray returned indirect block");
274 * Fetch the first indirect block allocating if necessary.
277 nb
= ip
->i_ib
[indirs
[0].in_off
];
279 allocblk
= allociblk
;
281 pref
= ffs_blkpref(ip
, lbn
, 0, (ufs_daddr_t
*)0);
282 if (error
= ffs_alloc(ip
, lbn
, pref
, (int)fs
->fs_bsize
,
287 bp
= buf_getblk(vp
, (daddr64_t
)((unsigned)(indirs
[1].in_lbn
)), fs
->fs_bsize
, 0, 0, BLK_META
);
288 buf_setblkno(bp
, (daddr64_t
)((unsigned)fsbtodb(fs
, nb
)));
291 * Write synchronously conditional on mount flags.
293 if ((vp
)->v_mount
->mnt_flag
& MNT_ASYNC
) {
296 } else if ((error
= buf_bwrite(bp
)) != 0) {
299 allocib
= &ip
->i_ib
[indirs
[0].in_off
];
301 ip
->i_flag
|= IN_CHANGE
| IN_UPDATE
;
304 * Fetch through the indirect blocks, allocating as necessary.
307 error
= (int)buf_meta_bread(vp
, (daddr64_t
)((unsigned)(indirs
[i
].in_lbn
)), (int)fs
->fs_bsize
, NOCRED
, &bp
);
312 bap
= (ufs_daddr_t
*)buf_dataptr(bp
);
315 nb
= OSSwapInt32(bap
[indirs
[i
].in_off
]);
317 #endif /* REV_ENDIAN_FS */
318 nb
= bap
[indirs
[i
].in_off
];
321 #endif /* REV_ENDIAN_FS */
330 pref
= ffs_blkpref(ip
, lbn
, 0, (ufs_daddr_t
*)0);
332 ffs_alloc(ip
, lbn
, pref
, (int)fs
->fs_bsize
, cred
, &newb
)) {
338 nbp
= buf_getblk(vp
, (daddr64_t
)((unsigned)(indirs
[i
].in_lbn
)), fs
->fs_bsize
, 0, 0, BLK_META
);
339 buf_setblkno(nbp
, (daddr64_t
)((unsigned)fsbtodb(fs
, nb
)));
342 * Write synchronously conditional on mount flags.
344 if ((vp
)->v_mount
->mnt_flag
& MNT_ASYNC
) {
347 } else if (error
= buf_bwrite(nbp
)) {
353 bap
[indirs
[i
- 1].in_off
] = OSSwapInt32(nb
);
355 #endif /* REV_ENDIAN_FS */
356 bap
[indirs
[i
- 1].in_off
] = nb
;
359 #endif /* REV_ENDIAN_FS */
361 * If required, write synchronously, otherwise use
364 if (flags
& B_SYNC
) {
371 * Get the data block, allocating if necessary.
374 pref
= ffs_blkpref(ip
, lbn
, indirs
[i
].in_off
, &bap
[0]);
375 if (error
= ffs_alloc(ip
,
376 lbn
, pref
, (int)fs
->fs_bsize
, cred
, &newb
)) {
384 bap
[indirs
[i
].in_off
] = OSSwapInt32(nb
);
386 #endif /* REV_ENDIAN_FS */
387 bap
[indirs
[i
].in_off
] = nb
;
390 #endif /* REV_ENDIAN_FS */
392 * If required, write synchronously, otherwise use
395 if ((flags
& B_SYNC
)) {
401 nbp
= buf_getblk(vp
, (daddr64_t
)((unsigned)lbn
), fs
->fs_bsize
, 0, 0, BLK_WRITE
);
402 buf_setblkno(nbp
, (daddr64_t
)((unsigned)fsbtodb(fs
, nb
)));
404 if (flags
& B_CLRBUF
)
408 *blk_alloc
= fs
->fs_bsize
;
417 if (flags
& B_CLRBUF
) {
418 error
= (int)buf_bread(vp
, (daddr64_t
)((unsigned)lbn
), (int)fs
->fs_bsize
, NOCRED
, &nbp
);
424 nbp
= buf_getblk(vp
, (daddr64_t
)((unsigned)lbn
), fs
->fs_bsize
, 0, 0, BLK_WRITE
);
425 buf_setblkno(nbp
, (daddr64_t
)((unsigned)fsbtodb(fs
, nb
)));
432 * If we have failed part way through block allocation, we
433 * have to deallocate any indirect blocks that we have allocated.
435 for (deallocated
= 0, blkp
= allociblk
; blkp
< allocblk
; blkp
++) {
436 ffs_blkfree(ip
, *blkp
, fs
->fs_bsize
);
437 deallocated
+= fs
->fs_bsize
;
442 devBlockSize
= vfs_devblocksize(mp
);
445 * Restore user's disk quota because allocation failed.
447 (void) chkdq(ip
, (int64_t)-deallocated
, cred
, FORCE
);
449 ip
->i_blocks
-= btodb(deallocated
, devBlockSize
);
450 ip
->i_flag
|= IN_CHANGE
| IN_UPDATE
;
456 * ffs_blkalloc allocates a disk block for ffs_pageout(), as a consequence
457 * it does no buf_breads (that could lead to deadblock as the page may be already
458 * marked busy as it is being paged out. Also important to note that we are not
459 * growing the file in pageouts. So ip->i_size cannot increase by this call
460 * due to the way UBC works.
461 * This code is derived from ffs_balloc and many cases of that are dealt
462 * in ffs_balloc are not applicable here
463 * Do not call with B_CLRBUF flags as this should only be called only
473 register struct fs
*fs
;
474 register ufs_daddr_t nb
;
475 struct buf
*bp
, *nbp
;
476 struct vnode
*vp
= ITOV(ip
);
477 struct indir indirs
[NIADDR
+ 2];
478 ufs_daddr_t newb
, *bap
, pref
;
479 int deallocated
, osize
, nsize
, num
, i
, error
;
480 ufs_daddr_t
*allocib
, *blkp
, *allocblk
, allociblk
[NIADDR
+ 1];
482 struct mount
*mp
=vp
->v_mount
;
484 int rev_endian
=(mp
->mnt_flag
& MNT_REVEND
);
485 #endif /* REV_ENDIAN_FS */
489 if(size
> fs
->fs_bsize
)
490 panic("ffs_blkalloc: too large for allocation");
493 * If the next write will extend the file into a new block,
494 * and the file is currently composed of a fragment
495 * this fragment has to be extended to be a full block.
497 nb
= lblkno(fs
, ip
->i_size
);
498 if (nb
< NDADDR
&& nb
< lbn
) {
499 panic("ffs_blkalloc():cannot extend file: i_size %d, lbn %d", ip
->i_size
, lbn
);
502 * The first NDADDR blocks are direct blocks
506 if (nb
!= 0 && ip
->i_size
>= (lbn
+ 1) * fs
->fs_bsize
) {
507 /* TBD: trivial case; the block is already allocated */
512 * Consider need to reallocate a fragment.
514 osize
= fragroundup(fs
, blkoff(fs
, ip
->i_size
));
515 nsize
= fragroundup(fs
, size
);
517 panic("ffs_allocblk: trying to extend a fragment");
521 if (ip
->i_size
< (lbn
+ 1) * fs
->fs_bsize
)
522 nsize
= fragroundup(fs
, size
);
524 nsize
= fs
->fs_bsize
;
525 error
= ffs_alloc(ip
, lbn
,
526 ffs_blkpref(ip
, lbn
, (int)lbn
, &ip
->i_db
[0]),
530 ip
->i_db
[lbn
] = newb
;
531 ip
->i_flag
|= IN_CHANGE
| IN_UPDATE
;
536 * Determine the number of levels of indirection.
539 if (error
= ufs_getlbns(vp
, lbn
, indirs
, &num
))
543 panic("ffs_blkalloc: file with direct blocks only");
547 * Fetch the first indirect block allocating if necessary.
550 nb
= ip
->i_ib
[indirs
[0].in_off
];
552 allocblk
= allociblk
;
554 pref
= ffs_blkpref(ip
, lbn
, 0, (ufs_daddr_t
*)0);
555 if (error
= ffs_alloc(ip
, lbn
, pref
, (int)fs
->fs_bsize
,
560 bp
= buf_getblk(vp
, (daddr64_t
)((unsigned)(indirs
[1].in_lbn
)), fs
->fs_bsize
, 0, 0, BLK_META
);
561 buf_setblkno(bp
, (daddr64_t
)((unsigned)fsbtodb(fs
, nb
)));
564 * Write synchronously conditional on mount flags.
566 if ((vp
)->v_mount
->mnt_flag
& MNT_ASYNC
) {
569 } else if (error
= buf_bwrite(bp
)) {
572 allocib
= &ip
->i_ib
[indirs
[0].in_off
];
574 ip
->i_flag
|= IN_CHANGE
| IN_UPDATE
;
577 * Fetch through the indirect blocks, allocating as necessary.
580 error
= (int)buf_meta_bread(vp
, (daddr64_t
)((unsigned)(indirs
[i
].in_lbn
)), (int)fs
->fs_bsize
, NOCRED
, &bp
);
585 bap
= (ufs_daddr_t
*)buf_dataptr(bp
);
588 nb
= OSSwapInt32(bap
[indirs
[i
].in_off
]);
590 #endif /* REV_ENDIAN_FS */
591 nb
= bap
[indirs
[i
].in_off
];
594 #endif /* REV_ENDIAN_FS */
603 pref
= ffs_blkpref(ip
, lbn
, 0, (ufs_daddr_t
*)0);
605 ffs_alloc(ip
, lbn
, pref
, (int)fs
->fs_bsize
, cred
, &newb
)) {
611 nbp
= buf_getblk(vp
, (daddr64_t
)((unsigned)(indirs
[i
].in_lbn
)), fs
->fs_bsize
, 0, 0, BLK_META
);
612 buf_setblkno(nbp
, (daddr64_t
)((unsigned)fsbtodb(fs
, nb
)));
615 * Write synchronously conditional on mount flags.
617 if ((vp
)->v_mount
->mnt_flag
& MNT_ASYNC
) {
620 } else if (error
= buf_bwrite(nbp
)) {
626 bap
[indirs
[i
- 1].in_off
] = OSSwapInt32(nb
);
628 #endif /* REV_ENDIAN_FS */
629 bap
[indirs
[i
- 1].in_off
] = nb
;
632 #endif /* REV_ENDIAN_FS */
634 * If required, write synchronously, otherwise use
637 if (flags
& B_SYNC
) {
644 * Get the data block, allocating if necessary.
647 pref
= ffs_blkpref(ip
, lbn
, indirs
[i
].in_off
, &bap
[0]);
648 if (error
= ffs_alloc(ip
,
649 lbn
, pref
, (int)fs
->fs_bsize
, cred
, &newb
)) {
657 bap
[indirs
[i
].in_off
] = OSSwapInt32(nb
);
659 #endif /* REV_ENDIAN_FS */
660 bap
[indirs
[i
].in_off
] = nb
;
663 #endif /* REV_ENDIAN_FS */
665 * If required, write synchronously, otherwise use
668 if (flags
& B_SYNC
) {
679 * If we have failed part way through block allocation, we
680 * have to deallocate any indirect blocks that we have allocated.
682 for (deallocated
= 0, blkp
= allociblk
; blkp
< allocblk
; blkp
++) {
683 ffs_blkfree(ip
, *blkp
, fs
->fs_bsize
);
684 deallocated
+= fs
->fs_bsize
;
689 devBlockSize
= vfs_devblocksize(mp
);
692 * Restore user's disk quota because allocation failed.
694 (void) chkdq(ip
, (int64_t)-deallocated
, cred
, FORCE
);
696 ip
->i_blocks
-= btodb(deallocated
, devBlockSize
);
697 ip
->i_flag
|= IN_CHANGE
| IN_UPDATE
;