]>
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>
64 #include <sys/vnode.h>
66 #include <sys/quota.h>
69 #include <sys/mount.h>
70 #endif /* REV_ENDIAN_FS */
74 #include <ufs/ufs/quota.h>
75 #include <ufs/ufs/inode.h>
76 #include <ufs/ufs/ufs_extern.h>
78 #include <ufs/ffs/fs.h>
79 #include <ufs/ffs/ffs_extern.h>
82 #include <ufs/ufs/ufs_byte_order.h>
83 #include <architecture/byte_order.h>
84 #endif /* REV_ENDIAN_FS */
87 * Balloc defines the structure of file system storage
88 * by allocating the physical blocks on a device given
89 * the inode and the logical block number in a file.
91 ffs_balloc(ip
, lbn
, size
, cred
, bpp
, flags
, blk_alloc
)
92 register struct inode
*ip
;
93 register ufs_daddr_t lbn
;
100 register struct fs
*fs
;
101 register ufs_daddr_t nb
;
102 struct buf
*bp
, *nbp
;
103 struct vnode
*vp
= ITOV(ip
);
104 struct indir indirs
[NIADDR
+ 2];
105 ufs_daddr_t newb
, *bap
, pref
;
106 int deallocated
, osize
, nsize
, num
, i
, error
;
107 ufs_daddr_t
*allocib
, *blkp
, *allocblk
, allociblk
[NIADDR
+ 1];
109 int alloc_buffer
= 1;
111 struct mount
*mp
=vp
->v_mount
;
112 int rev_endian
=(mp
->mnt_flag
& MNT_REVEND
);
113 #endif /* REV_ENDIAN_FS */
119 if (flags
& B_NOBUFF
)
126 * If the next write will extend the file into a new block,
127 * and the file is currently composed of a fragment
128 * this fragment has to be extended to be a full block.
130 nb
= lblkno(fs
, ip
->i_size
);
131 if (nb
< NDADDR
&& nb
< lbn
) {
132 /* the filesize prior to this write can fit in direct
133 * blocks (ie. fragmentaion is possibly done)
134 * we are now extending the file write beyond
135 * the block which has end of file prior to this write
137 osize
= blksize(fs
, ip
, nb
);
138 /* osize gives disk allocated size in the last block. It is
139 * either in fragments or a file system block size */
140 if (osize
< fs
->fs_bsize
&& osize
> 0) {
141 /* few fragments are already allocated,since the
142 * current extends beyond this block
143 * allocate the complete block as fragments are only
146 error
= ffs_realloccg(ip
, nb
,
147 ffs_blkpref(ip
, nb
, (int)nb
, &ip
->i_db
[0]),
148 osize
, (int)fs
->fs_bsize
, cred
, &bp
);
151 /* adjust the innode size we just grew */
152 /* it is in nb+1 as nb starts from 0 */
153 ip
->i_size
= (nb
+ 1) * fs
->fs_bsize
;
155 ubc_setsize(vp
, (off_t
)ip
->i_size
); /* XXX check error */
156 ip
->i_db
[nb
] = dbtofsb(fs
, bp
->b_blkno
);
157 ip
->i_flag
|= IN_CHANGE
| IN_UPDATE
;
158 if ((flags
& B_SYNC
) || (!alloc_buffer
)) {
160 SET(bp
->b_flags
, B_NOCACHE
);
164 /* note that bp is already released here */
168 * The first NDADDR blocks are direct blocks
172 if (nb
!= 0 && ip
->i_size
>= (lbn
+ 1) * fs
->fs_bsize
) {
174 error
= bread(vp
, lbn
, fs
->fs_bsize
, NOCRED
, &bp
);
185 * Consider need to reallocate a fragment.
187 osize
= fragroundup(fs
, blkoff(fs
, ip
->i_size
));
188 nsize
= fragroundup(fs
, size
);
189 if (nsize
<= osize
) {
191 error
= bread(vp
, lbn
, osize
, NOCRED
, &bp
);
196 ip
->i_flag
|= IN_CHANGE
| IN_UPDATE
;
201 ip
->i_flag
|= IN_CHANGE
| IN_UPDATE
;
205 error
= ffs_realloccg(ip
, lbn
,
206 ffs_blkpref(ip
, lbn
, (int)lbn
,
207 &ip
->i_db
[0]), osize
, nsize
, cred
, &bp
);
210 ip
->i_db
[lbn
] = dbtofsb(fs
, bp
->b_blkno
);
211 ip
->i_flag
|= IN_CHANGE
| IN_UPDATE
;
213 SET(bp
->b_flags
, B_NOCACHE
);
224 if (ip
->i_size
< (lbn
+ 1) * fs
->fs_bsize
)
225 nsize
= fragroundup(fs
, size
);
227 nsize
= fs
->fs_bsize
;
228 error
= ffs_alloc(ip
, lbn
,
229 ffs_blkpref(ip
, lbn
, (int)lbn
, &ip
->i_db
[0]),
234 bp
= getblk(vp
, lbn
, nsize
, 0, 0, BLK_WRITE
);
235 bp
->b_blkno
= fsbtodb(fs
, newb
);
236 if (flags
& B_CLRBUF
)
239 ip
->i_db
[lbn
] = newb
;
240 ip
->i_flag
|= IN_CHANGE
| IN_UPDATE
;
250 * Determine the number of levels of indirection.
253 if (error
= ufs_getlbns(vp
, lbn
, indirs
, &num
))
257 panic ("ffs_balloc: ufs_bmaparray returned indirect block");
260 * Fetch the first indirect block allocating if necessary.
263 nb
= ip
->i_ib
[indirs
[0].in_off
];
265 allocblk
= allociblk
;
267 pref
= ffs_blkpref(ip
, lbn
, 0, (ufs_daddr_t
*)0);
268 if (error
= ffs_alloc(ip
, lbn
, pref
, (int)fs
->fs_bsize
,
273 bp
= getblk(vp
, indirs
[1].in_lbn
, fs
->fs_bsize
, 0, 0, BLK_META
);
274 bp
->b_blkno
= fsbtodb(fs
, nb
);
277 * Write synchronously conditional on mount flags.
279 if ((vp
)->v_mount
->mnt_flag
& MNT_ASYNC
) {
282 } else if ((error
= bwrite(bp
)) != 0) {
285 allocib
= &ip
->i_ib
[indirs
[0].in_off
];
287 ip
->i_flag
|= IN_CHANGE
| IN_UPDATE
;
290 * Fetch through the indirect blocks, allocating as necessary.
293 error
= meta_bread(vp
,
294 indirs
[i
].in_lbn
, (int)fs
->fs_bsize
, NOCRED
, &bp
);
299 bap
= (ufs_daddr_t
*)bp
->b_data
;
302 nb
= NXSwapLong(bap
[indirs
[i
].in_off
]);
304 #endif /* REV_ENDIAN_FS */
305 nb
= bap
[indirs
[i
].in_off
];
308 #endif /* REV_ENDIAN_FS */
317 pref
= ffs_blkpref(ip
, lbn
, 0, (ufs_daddr_t
*)0);
319 ffs_alloc(ip
, lbn
, pref
, (int)fs
->fs_bsize
, cred
, &newb
)) {
325 nbp
= getblk(vp
, indirs
[i
].in_lbn
, fs
->fs_bsize
, 0, 0, BLK_META
);
326 nbp
->b_blkno
= fsbtodb(fs
, nb
);
329 * Write synchronously conditional on mount flags.
331 if ((vp
)->v_mount
->mnt_flag
& MNT_ASYNC
) {
334 } else if (error
= bwrite(nbp
)) {
340 bap
[indirs
[i
- 1].in_off
] = NXSwapLong(nb
);
342 #endif /* REV_ENDIAN_FS */
343 bap
[indirs
[i
- 1].in_off
] = nb
;
346 #endif /* REV_ENDIAN_FS */
348 * If required, write synchronously, otherwise use
351 if (flags
& B_SYNC
) {
358 * Get the data block, allocating if necessary.
361 pref
= ffs_blkpref(ip
, lbn
, indirs
[i
].in_off
, &bap
[0]);
362 if (error
= ffs_alloc(ip
,
363 lbn
, pref
, (int)fs
->fs_bsize
, cred
, &newb
)) {
371 bap
[indirs
[i
].in_off
] = NXSwapLong(nb
);
373 #endif /* REV_ENDIAN_FS */
374 bap
[indirs
[i
].in_off
] = nb
;
377 #endif /* REV_ENDIAN_FS */
379 * If required, write synchronously, otherwise use
382 if ((flags
& B_SYNC
)) {
388 nbp
= getblk(vp
, lbn
, fs
->fs_bsize
, 0, 0, BLK_WRITE
);
389 nbp
->b_blkno
= fsbtodb(fs
, nb
);
390 if (flags
& B_CLRBUF
)
394 *blk_alloc
= fs
->fs_bsize
;
403 if (flags
& B_CLRBUF
) {
404 error
= bread(vp
, lbn
, (int)fs
->fs_bsize
, NOCRED
, &nbp
);
410 nbp
= getblk(vp
, lbn
, fs
->fs_bsize
, 0, 0, BLK_WRITE
);
411 nbp
->b_blkno
= fsbtodb(fs
, nb
);
418 * If we have failed part way through block allocation, we
419 * have to deallocate any indirect blocks that we have allocated.
421 for (deallocated
= 0, blkp
= allociblk
; blkp
< allocblk
; blkp
++) {
422 ffs_blkfree(ip
, *blkp
, fs
->fs_bsize
);
423 deallocated
+= fs
->fs_bsize
;
428 VOP_DEVBLOCKSIZE(ip
->i_devvp
,&devBlockSize
);
432 * Restore user's disk quota because allocation failed.
434 (void) chkdq(ip
, (int64_t)-deallocated
, cred
, FORCE
);
436 ip
->i_blocks
-= btodb(deallocated
, devBlockSize
);
437 ip
->i_flag
|= IN_CHANGE
| IN_UPDATE
;
443 * ffs_blkalloc allocates a disk block for ffs_pageout(), as a consequence
444 * it does no breads (that could lead to deadblock as the page may be already
445 * marked busy as it is being paged out. Also important to note that we are not
446 * growing the file in pageouts. So ip->i_size cannot increase by this call
447 * due to the way UBC works.
448 * This code is derived from ffs_balloc and many cases of that are dealt
449 * in ffs_balloc are not applicable here
450 * Do not call with B_CLRBUF flags as this should only be called only
453 ffs_blkalloc(ip
, lbn
, size
, cred
, flags
)
454 register struct inode
*ip
;
460 register struct fs
*fs
;
461 register ufs_daddr_t nb
;
462 struct buf
*bp
, *nbp
;
463 struct vnode
*vp
= ITOV(ip
);
464 struct indir indirs
[NIADDR
+ 2];
465 ufs_daddr_t newb
, *bap
, pref
;
466 int deallocated
, osize
, nsize
, num
, i
, error
;
467 ufs_daddr_t
*allocib
, *blkp
, *allocblk
, allociblk
[NIADDR
+ 1];
470 struct mount
*mp
=vp
->v_mount
;
471 int rev_endian
=(mp
->mnt_flag
& MNT_REVEND
);
472 #endif /* REV_ENDIAN_FS */
476 if(size
> fs
->fs_bsize
)
477 panic("ffs_blkalloc: too large for allocation");
480 * If the next write will extend the file into a new block,
481 * and the file is currently composed of a fragment
482 * this fragment has to be extended to be a full block.
484 nb
= lblkno(fs
, ip
->i_size
);
485 if (nb
< NDADDR
&& nb
< lbn
) {
486 panic("ffs_blkalloc():cannot extend file: i_size %d, lbn %d", ip
->i_size
, lbn
);
489 * The first NDADDR blocks are direct blocks
493 if (nb
!= 0 && ip
->i_size
>= (lbn
+ 1) * fs
->fs_bsize
) {
494 /* TBD: trivial case; the block is already allocated */
499 * Consider need to reallocate a fragment.
501 osize
= fragroundup(fs
, blkoff(fs
, ip
->i_size
));
502 nsize
= fragroundup(fs
, size
);
504 panic("ffs_allocblk: trying to extend a fragment");
508 if (ip
->i_size
< (lbn
+ 1) * fs
->fs_bsize
)
509 nsize
= fragroundup(fs
, size
);
511 nsize
= fs
->fs_bsize
;
512 error
= ffs_alloc(ip
, lbn
,
513 ffs_blkpref(ip
, lbn
, (int)lbn
, &ip
->i_db
[0]),
517 ip
->i_db
[lbn
] = newb
;
518 ip
->i_flag
|= IN_CHANGE
| IN_UPDATE
;
523 * Determine the number of levels of indirection.
526 if (error
= ufs_getlbns(vp
, lbn
, indirs
, &num
))
530 panic("ffs_blkalloc: file with direct blocks only");
534 * Fetch the first indirect block allocating if necessary.
537 nb
= ip
->i_ib
[indirs
[0].in_off
];
539 allocblk
= allociblk
;
541 pref
= ffs_blkpref(ip
, lbn
, 0, (ufs_daddr_t
*)0);
542 if (error
= ffs_alloc(ip
, lbn
, pref
, (int)fs
->fs_bsize
,
547 bp
= getblk(vp
, indirs
[1].in_lbn
, fs
->fs_bsize
, 0, 0, BLK_META
);
548 bp
->b_blkno
= fsbtodb(fs
, nb
);
551 * Write synchronously conditional on mount flags.
553 if ((vp
)->v_mount
->mnt_flag
& MNT_ASYNC
) {
556 } else if (error
= bwrite(bp
)) {
559 allocib
= &ip
->i_ib
[indirs
[0].in_off
];
561 ip
->i_flag
|= IN_CHANGE
| IN_UPDATE
;
564 * Fetch through the indirect blocks, allocating as necessary.
567 error
= meta_bread(vp
,
568 indirs
[i
].in_lbn
, (int)fs
->fs_bsize
, NOCRED
, &bp
);
573 bap
= (ufs_daddr_t
*)bp
->b_data
;
576 nb
= NXSwapLong(bap
[indirs
[i
].in_off
]);
578 #endif /* REV_ENDIAN_FS */
579 nb
= bap
[indirs
[i
].in_off
];
582 #endif /* REV_ENDIAN_FS */
591 pref
= ffs_blkpref(ip
, lbn
, 0, (ufs_daddr_t
*)0);
593 ffs_alloc(ip
, lbn
, pref
, (int)fs
->fs_bsize
, cred
, &newb
)) {
599 nbp
= getblk(vp
, indirs
[i
].in_lbn
, fs
->fs_bsize
, 0, 0, BLK_META
);
600 nbp
->b_blkno
= fsbtodb(fs
, nb
);
603 * Write synchronously conditional on mount flags.
605 if ((vp
)->v_mount
->mnt_flag
& MNT_ASYNC
) {
608 } else if (error
= bwrite(nbp
)) {
614 bap
[indirs
[i
- 1].in_off
] = NXSwapLong(nb
);
616 #endif /* REV_ENDIAN_FS */
617 bap
[indirs
[i
- 1].in_off
] = nb
;
620 #endif /* REV_ENDIAN_FS */
622 * If required, write synchronously, otherwise use
625 if (flags
& B_SYNC
) {
632 * Get the data block, allocating if necessary.
635 pref
= ffs_blkpref(ip
, lbn
, indirs
[i
].in_off
, &bap
[0]);
636 if (error
= ffs_alloc(ip
,
637 lbn
, pref
, (int)fs
->fs_bsize
, cred
, &newb
)) {
645 bap
[indirs
[i
].in_off
] = NXSwapLong(nb
);
647 #endif /* REV_ENDIAN_FS */
648 bap
[indirs
[i
].in_off
] = nb
;
651 #endif /* REV_ENDIAN_FS */
653 * If required, write synchronously, otherwise use
656 if (flags
& B_SYNC
) {
667 * If we have failed part way through block allocation, we
668 * have to deallocate any indirect blocks that we have allocated.
670 for (deallocated
= 0, blkp
= allociblk
; blkp
< allocblk
; blkp
++) {
671 ffs_blkfree(ip
, *blkp
, fs
->fs_bsize
);
672 deallocated
+= fs
->fs_bsize
;
677 VOP_DEVBLOCKSIZE(ip
->i_devvp
,&devBlockSize
);
681 * Restore user's disk quota because allocation failed.
683 (void) chkdq(ip
, (int64_t)-deallocated
, cred
, FORCE
);
685 ip
->i_blocks
-= btodb(deallocated
, devBlockSize
);
686 ip
->i_flag
|= IN_CHANGE
| IN_UPDATE
;