1 /* $NetBSD: ffs_balloc.c,v 1.12 2003/08/07 11:25:33 agc Exp $ */
2 /* From NetBSD: ffs_balloc.c,v 1.25 2001/08/08 08:36:36 lukem Exp */
5 * Copyright (c) 1982, 1986, 1989, 1993
6 * The Regents of the University of California. All rights reserved.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. Neither the name of the University nor the names of its contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * @(#)ffs_balloc.c 8.8 (Berkeley) 6/16/95
35 #if HAVE_NBTOOL_CONFIG_H
36 #include "nbtool_config.h"
39 #include <sys/cdefs.h>
40 #if defined(__RCSID) && !defined(__lint)
41 __RCSID("$NetBSD: ffs_balloc.c,v 1.12 2003/08/07 11:25:33 agc Exp $");
44 #include <sys/param.h>
55 #include <ufs/ufs/dinode.h>
56 #include <ufs/ufs/ufs_bswap.h>
57 #include <ufs/ffs/fs.h>
60 #include "ffs/ufs_inode.h"
61 #include "ffs/ffs_extern.h"
63 static int ffs_balloc_ufs1(struct inode
*, off_t
, int, struct buf
**);
64 static int ffs_balloc_ufs2(struct inode
*, off_t
, int, struct buf
**);
67 * Balloc defines the structure of file system storage
68 * by allocating the physical blocks on a device given
69 * the inode and the logical block number in a file.
71 * Assume: flags == B_SYNC | B_CLRBUF
75 ffs_balloc(struct inode
*ip
, off_t offset
, int bufsize
, struct buf
**bpp
)
77 if (ip
->i_fs
->fs_magic
== FS_UFS2_MAGIC
)
78 return ffs_balloc_ufs2(ip
, offset
, bufsize
, bpp
);
80 return ffs_balloc_ufs1(ip
, offset
, bufsize
, bpp
);
84 ffs_balloc_ufs1(struct inode
*ip
, off_t offset
, int bufsize
, struct buf
**bpp
)
90 struct fs
*fs
= ip
->i_fs
;
91 struct indir indirs
[NIADDR
+ 2];
94 int osize
, nsize
, num
, i
, error
;
95 int32_t *allocblk
, allociblk
[NIADDR
+ 1];
97 const int needswap
= UFS_FSNEEDSWAP(fs
);
99 lbn
= lblkno(fs
, offset
);
100 size
= blkoff(fs
, offset
) + bufsize
;
105 assert(size
<= fs
->fs_bsize
);
110 * If the next write will extend the file into a new block,
111 * and the file is currently composed of a fragment
112 * this fragment has to be extended to be a full block.
115 lastlbn
= lblkno(fs
, ip
->i_ffs1_size
);
116 if (lastlbn
< NDADDR
&& lastlbn
< lbn
) {
118 osize
= blksize(fs
, ip
, nb
);
119 if (osize
< fs
->fs_bsize
&& osize
> 0) {
120 warnx("need to ffs_realloccg; not supported!");
126 * The first NDADDR blocks are direct blocks
130 nb
= ufs_rw32(ip
->i_ffs1_db
[lbn
], needswap
);
131 if (nb
!= 0 && ip
->i_ffs1_size
>= lblktosize(fs
, lbn
+ 1)) {
134 * The block is an already-allocated direct block
135 * and the file already extends past this block,
136 * thus this must be a whole block.
137 * Just read the block (if requested).
141 error
= bread(ip
->i_fd
, ip
->i_fs
, lbn
,
153 * Consider need to reallocate a fragment.
156 osize
= fragroundup(fs
, blkoff(fs
, ip
->i_ffs1_size
));
157 nsize
= fragroundup(fs
, size
);
158 if (nsize
<= osize
) {
161 * The existing block is already
162 * at least as big as we want.
163 * Just read the block (if requested).
167 error
= bread(ip
->i_fd
, ip
->i_fs
, lbn
,
176 warnx("need to ffs_realloccg; not supported!");
182 * the block was not previously allocated,
183 * allocate a new block or fragment.
186 if (ip
->i_ffs1_size
< lblktosize(fs
, lbn
+ 1))
187 nsize
= fragroundup(fs
, size
);
189 nsize
= fs
->fs_bsize
;
190 error
= ffs_alloc(ip
, lbn
,
191 ffs_blkpref_ufs1(ip
, lbn
, (int)lbn
,
197 bp
= getblk(ip
->i_fd
, ip
->i_fs
, lbn
, nsize
);
198 bp
->b_blkno
= fsbtodb(fs
, newb
);
203 ip
->i_ffs1_db
[lbn
] = ufs_rw32((int32_t)newb
, needswap
);
208 * Determine the number of levels of indirection.
212 if ((error
= ufs_getlbns(ip
, lbn
, indirs
, &num
)) != 0)
216 warnx("ffs_balloc: ufs_getlbns returned indirect block");
221 * Fetch the first indirect block allocating if necessary.
225 nb
= ufs_rw32(ip
->i_ffs1_ib
[indirs
[0].in_off
], needswap
);
227 allocblk
= allociblk
;
229 pref
= ffs_blkpref_ufs1(ip
, lbn
, 0, (int32_t *)0);
230 error
= ffs_alloc(ip
, lbn
, pref
, (int)fs
->fs_bsize
, &newb
);
235 bp
= getblk(ip
->i_fd
, ip
->i_fs
, indirs
[1].in_lbn
, fs
->fs_bsize
);
236 bp
->b_blkno
= fsbtodb(fs
, nb
);
239 * Write synchronously so that indirect blocks
240 * never point at garbage.
242 if ((error
= bwrite(bp
)) != 0)
244 allocib
= &ip
->i_ffs1_ib
[indirs
[0].in_off
];
245 *allocib
= ufs_rw32((int32_t)nb
, needswap
);
249 * Fetch through the indirect blocks, allocating as necessary.
253 error
= bread(ip
->i_fd
, ip
->i_fs
, indirs
[i
].in_lbn
,
259 bap
= (int32_t *)bp
->b_data
;
260 nb
= ufs_rw32(bap
[indirs
[i
].in_off
], needswap
);
269 pref
= ffs_blkpref_ufs1(ip
, lbn
, 0, (int32_t *)0);
270 error
= ffs_alloc(ip
, lbn
, pref
, (int)fs
->fs_bsize
, &newb
);
277 nbp
= getblk(ip
->i_fd
, ip
->i_fs
, indirs
[i
].in_lbn
,
279 nbp
->b_blkno
= fsbtodb(fs
, nb
);
282 * Write synchronously so that indirect blocks
283 * never point at garbage.
286 if ((error
= bwrite(nbp
)) != 0) {
290 bap
[indirs
[i
- 1].in_off
] = ufs_rw32(nb
, needswap
);
296 * Get the data block, allocating if necessary.
300 pref
= ffs_blkpref_ufs1(ip
, lbn
, indirs
[num
].in_off
, &bap
[0]);
301 error
= ffs_alloc(ip
, lbn
, pref
, (int)fs
->fs_bsize
, &newb
);
309 nbp
= getblk(ip
->i_fd
, ip
->i_fs
, lbn
, fs
->fs_bsize
);
310 nbp
->b_blkno
= fsbtodb(fs
, nb
);
314 bap
[indirs
[num
].in_off
] = ufs_rw32(nb
, needswap
);
317 * If required, write synchronously, otherwise use
325 error
= bread(ip
->i_fd
, ip
->i_fs
, lbn
, (int)fs
->fs_bsize
, &nbp
);
336 ffs_balloc_ufs2(struct inode
*ip
, off_t offset
, int bufsize
, struct buf
**bpp
)
338 daddr_t lbn
, lastlbn
;
340 struct buf
*bp
, *nbp
;
341 struct fs
*fs
= ip
->i_fs
;
342 struct indir indirs
[NIADDR
+ 2];
343 daddr_t newb
, pref
, nb
;
345 int osize
, nsize
, num
, i
, error
;
346 int64_t *allocblk
, allociblk
[NIADDR
+ 1];
348 const int needswap
= UFS_FSNEEDSWAP(fs
);
350 lbn
= lblkno(fs
, offset
);
351 size
= blkoff(fs
, offset
) + bufsize
;
356 assert(size
<= fs
->fs_bsize
);
361 * If the next write will extend the file into a new block,
362 * and the file is currently composed of a fragment
363 * this fragment has to be extended to be a full block.
366 lastlbn
= lblkno(fs
, ip
->i_ffs2_size
);
367 if (lastlbn
< NDADDR
&& lastlbn
< lbn
) {
369 osize
= blksize(fs
, ip
, nb
);
370 if (osize
< fs
->fs_bsize
&& osize
> 0) {
371 warnx("need to ffs_realloccg; not supported!");
377 * The first NDADDR blocks are direct blocks
381 nb
= ufs_rw64(ip
->i_ffs2_db
[lbn
], needswap
);
382 if (nb
!= 0 && ip
->i_ffs2_size
>= lblktosize(fs
, lbn
+ 1)) {
385 * The block is an already-allocated direct block
386 * and the file already extends past this block,
387 * thus this must be a whole block.
388 * Just read the block (if requested).
392 error
= bread(ip
->i_fd
, ip
->i_fs
, lbn
,
404 * Consider need to reallocate a fragment.
407 osize
= fragroundup(fs
, blkoff(fs
, ip
->i_ffs2_size
));
408 nsize
= fragroundup(fs
, size
);
409 if (nsize
<= osize
) {
412 * The existing block is already
413 * at least as big as we want.
414 * Just read the block (if requested).
418 error
= bread(ip
->i_fd
, ip
->i_fs
, lbn
,
427 warnx("need to ffs_realloccg; not supported!");
433 * the block was not previously allocated,
434 * allocate a new block or fragment.
437 if (ip
->i_ffs2_size
< lblktosize(fs
, lbn
+ 1))
438 nsize
= fragroundup(fs
, size
);
440 nsize
= fs
->fs_bsize
;
441 error
= ffs_alloc(ip
, lbn
,
442 ffs_blkpref_ufs2(ip
, lbn
, (int)lbn
,
448 bp
= getblk(ip
->i_fd
, ip
->i_fs
, lbn
, nsize
);
449 bp
->b_blkno
= fsbtodb(fs
, newb
);
454 ip
->i_ffs2_db
[lbn
] = ufs_rw64(newb
, needswap
);
459 * Determine the number of levels of indirection.
463 if ((error
= ufs_getlbns(ip
, lbn
, indirs
, &num
)) != 0)
467 warnx("ffs_balloc: ufs_getlbns returned indirect block");
472 * Fetch the first indirect block allocating if necessary.
476 nb
= ufs_rw64(ip
->i_ffs2_ib
[indirs
[0].in_off
], needswap
);
478 allocblk
= allociblk
;
480 pref
= ffs_blkpref_ufs2(ip
, lbn
, 0, (int64_t *)0);
481 error
= ffs_alloc(ip
, lbn
, pref
, (int)fs
->fs_bsize
, &newb
);
486 bp
= getblk(ip
->i_fd
, ip
->i_fs
, indirs
[1].in_lbn
, fs
->fs_bsize
);
487 bp
->b_blkno
= fsbtodb(fs
, nb
);
490 * Write synchronously so that indirect blocks
491 * never point at garbage.
493 if ((error
= bwrite(bp
)) != 0)
495 allocib
= &ip
->i_ffs2_ib
[indirs
[0].in_off
];
496 *allocib
= ufs_rw64(nb
, needswap
);
500 * Fetch through the indirect blocks, allocating as necessary.
504 error
= bread(ip
->i_fd
, ip
->i_fs
, indirs
[i
].in_lbn
,
510 bap
= (int64_t *)bp
->b_data
;
511 nb
= ufs_rw64(bap
[indirs
[i
].in_off
], needswap
);
520 pref
= ffs_blkpref_ufs2(ip
, lbn
, 0, (int64_t *)0);
521 error
= ffs_alloc(ip
, lbn
, pref
, (int)fs
->fs_bsize
, &newb
);
528 nbp
= getblk(ip
->i_fd
, ip
->i_fs
, indirs
[i
].in_lbn
,
530 nbp
->b_blkno
= fsbtodb(fs
, nb
);
533 * Write synchronously so that indirect blocks
534 * never point at garbage.
537 if ((error
= bwrite(nbp
)) != 0) {
541 bap
[indirs
[i
- 1].in_off
] = ufs_rw64(nb
, needswap
);
547 * Get the data block, allocating if necessary.
551 pref
= ffs_blkpref_ufs2(ip
, lbn
, indirs
[num
].in_off
, &bap
[0]);
552 error
= ffs_alloc(ip
, lbn
, pref
, (int)fs
->fs_bsize
, &newb
);
560 nbp
= getblk(ip
->i_fd
, ip
->i_fs
, lbn
, fs
->fs_bsize
);
561 nbp
->b_blkno
= fsbtodb(fs
, nb
);
565 bap
[indirs
[num
].in_off
] = ufs_rw64(nb
, needswap
);
568 * If required, write synchronously, otherwise use
576 error
= bread(ip
->i_fd
, ip
->i_fs
, lbn
, (int)fs
->fs_bsize
, &nbp
);