1 /* $NetBSD: ffs_balloc.c,v 1.21 2015/03/29 05:52:59 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.21 2015/03/29 05:52:59 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
[UFS_NIADDR
+ 2];
94 int osize
, nsize
, num
, i
, error
;
95 int32_t *allocblk
, allociblk
[UFS_NIADDR
+ 1];
97 const int needswap
= UFS_FSNEEDSWAP(fs
);
99 lbn
= ffs_lblkno(fs
, offset
);
100 size
= ffs_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
= ffs_lblkno(fs
, ip
->i_ffs1_size
);
116 if (lastlbn
< UFS_NDADDR
&& lastlbn
< lbn
) {
118 osize
= ffs_blksize(fs
, ip
, nb
);
119 if (osize
< fs
->fs_bsize
&& osize
> 0) {
120 warnx("need to ffs_realloccg; not supported!");
126 * The first UFS_NDADDR blocks are direct blocks
129 if (lbn
< UFS_NDADDR
) {
130 nb
= ufs_rw32(ip
->i_ffs1_db
[lbn
], needswap
);
131 if (nb
!= 0 && ip
->i_ffs1_size
>= ffs_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_devvp
, lbn
, fs
->fs_bsize
,
153 * Consider need to reallocate a fragment.
156 osize
= ffs_fragroundup(fs
, ffs_blkoff(fs
, ip
->i_ffs1_size
));
157 nsize
= ffs_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_devvp
, lbn
, osize
,
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
< ffs_lblktosize(fs
, lbn
+ 1))
187 nsize
= ffs_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_devvp
, lbn
, nsize
, 0, 0);
198 bp
->b_blkno
= FFS_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_devvp
, indirs
[1].in_lbn
, fs
->fs_bsize
, 0, 0);
236 bp
->b_blkno
= FFS_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_devvp
, indirs
[i
].in_lbn
, fs
->fs_bsize
,
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_devvp
, indirs
[i
].in_lbn
, fs
->fs_bsize
, 0, 0);
278 nbp
->b_blkno
= FFS_FSBTODB(fs
, nb
);
281 * Write synchronously so that indirect blocks
282 * never point at garbage.
285 if ((error
= bwrite(nbp
)) != 0) {
289 bap
[indirs
[i
- 1].in_off
] = ufs_rw32(nb
, needswap
);
295 * Get the data block, allocating if necessary.
299 pref
= ffs_blkpref_ufs1(ip
, lbn
, indirs
[num
].in_off
, &bap
[0]);
300 error
= ffs_alloc(ip
, lbn
, pref
, (int)fs
->fs_bsize
, &newb
);
308 nbp
= getblk(ip
->i_devvp
, lbn
, fs
->fs_bsize
, 0, 0);
309 nbp
->b_blkno
= FFS_FSBTODB(fs
, nb
);
313 bap
[indirs
[num
].in_off
] = ufs_rw32(nb
, needswap
);
316 * If required, write synchronously, otherwise use
324 error
= bread(ip
->i_devvp
, lbn
, (int)fs
->fs_bsize
, 0, &nbp
);
335 ffs_balloc_ufs2(struct inode
*ip
, off_t offset
, int bufsize
, struct buf
**bpp
)
337 daddr_t lbn
, lastlbn
;
339 struct buf
*bp
, *nbp
;
340 struct fs
*fs
= ip
->i_fs
;
341 struct indir indirs
[UFS_NIADDR
+ 2];
342 daddr_t newb
, pref
, nb
;
344 int osize
, nsize
, num
, i
, error
;
345 int64_t *allocblk
, allociblk
[UFS_NIADDR
+ 1];
347 const int needswap
= UFS_FSNEEDSWAP(fs
);
349 lbn
= ffs_lblkno(fs
, offset
);
350 size
= ffs_blkoff(fs
, offset
) + bufsize
;
355 assert(size
<= fs
->fs_bsize
);
360 * If the next write will extend the file into a new block,
361 * and the file is currently composed of a fragment
362 * this fragment has to be extended to be a full block.
365 lastlbn
= ffs_lblkno(fs
, ip
->i_ffs2_size
);
366 if (lastlbn
< UFS_NDADDR
&& lastlbn
< lbn
) {
368 osize
= ffs_blksize(fs
, ip
, nb
);
369 if (osize
< fs
->fs_bsize
&& osize
> 0) {
370 warnx("need to ffs_realloccg; not supported!");
376 * The first UFS_NDADDR blocks are direct blocks
379 if (lbn
< UFS_NDADDR
) {
380 nb
= ufs_rw64(ip
->i_ffs2_db
[lbn
], needswap
);
381 if (nb
!= 0 && ip
->i_ffs2_size
>= ffs_lblktosize(fs
, lbn
+ 1)) {
384 * The block is an already-allocated direct block
385 * and the file already extends past this block,
386 * thus this must be a whole block.
387 * Just read the block (if requested).
391 error
= bread(ip
->i_devvp
, lbn
, fs
->fs_bsize
,
403 * Consider need to reallocate a fragment.
406 osize
= ffs_fragroundup(fs
, ffs_blkoff(fs
, ip
->i_ffs2_size
));
407 nsize
= ffs_fragroundup(fs
, size
);
408 if (nsize
<= osize
) {
411 * The existing block is already
412 * at least as big as we want.
413 * Just read the block (if requested).
417 error
= bread(ip
->i_devvp
, lbn
, osize
,
426 warnx("need to ffs_realloccg; not supported!");
432 * the block was not previously allocated,
433 * allocate a new block or fragment.
436 if (ip
->i_ffs2_size
< ffs_lblktosize(fs
, lbn
+ 1))
437 nsize
= ffs_fragroundup(fs
, size
);
439 nsize
= fs
->fs_bsize
;
440 error
= ffs_alloc(ip
, lbn
,
441 ffs_blkpref_ufs2(ip
, lbn
, (int)lbn
,
447 bp
= getblk(ip
->i_devvp
, lbn
, nsize
, 0, 0);
448 bp
->b_blkno
= FFS_FSBTODB(fs
, newb
);
453 ip
->i_ffs2_db
[lbn
] = ufs_rw64(newb
, needswap
);
458 * Determine the number of levels of indirection.
462 if ((error
= ufs_getlbns(ip
, lbn
, indirs
, &num
)) != 0)
466 warnx("ffs_balloc: ufs_getlbns returned indirect block");
471 * Fetch the first indirect block allocating if necessary.
475 nb
= ufs_rw64(ip
->i_ffs2_ib
[indirs
[0].in_off
], needswap
);
477 allocblk
= allociblk
;
479 pref
= ffs_blkpref_ufs2(ip
, lbn
, 0, (int64_t *)0);
480 error
= ffs_alloc(ip
, lbn
, pref
, (int)fs
->fs_bsize
, &newb
);
485 bp
= getblk(ip
->i_devvp
, indirs
[1].in_lbn
, fs
->fs_bsize
, 0, 0);
486 bp
->b_blkno
= FFS_FSBTODB(fs
, nb
);
489 * Write synchronously so that indirect blocks
490 * never point at garbage.
492 if ((error
= bwrite(bp
)) != 0)
494 allocib
= &ip
->i_ffs2_ib
[indirs
[0].in_off
];
495 *allocib
= ufs_rw64(nb
, needswap
);
499 * Fetch through the indirect blocks, allocating as necessary.
503 error
= bread(ip
->i_devvp
, indirs
[i
].in_lbn
, fs
->fs_bsize
,
509 bap
= (int64_t *)bp
->b_data
;
510 nb
= ufs_rw64(bap
[indirs
[i
].in_off
], needswap
);
519 pref
= ffs_blkpref_ufs2(ip
, lbn
, 0, (int64_t *)0);
520 error
= ffs_alloc(ip
, lbn
, pref
, (int)fs
->fs_bsize
, &newb
);
527 nbp
= getblk(ip
->i_devvp
, indirs
[i
].in_lbn
, fs
->fs_bsize
, 0, 0);
528 nbp
->b_blkno
= FFS_FSBTODB(fs
, nb
);
531 * Write synchronously so that indirect blocks
532 * never point at garbage.
535 if ((error
= bwrite(nbp
)) != 0) {
539 bap
[indirs
[i
- 1].in_off
] = ufs_rw64(nb
, needswap
);
545 * Get the data block, allocating if necessary.
549 pref
= ffs_blkpref_ufs2(ip
, lbn
, indirs
[num
].in_off
, &bap
[0]);
550 error
= ffs_alloc(ip
, lbn
, pref
, (int)fs
->fs_bsize
, &newb
);
558 nbp
= getblk(ip
->i_devvp
, lbn
, fs
->fs_bsize
, 0, 0);
559 nbp
->b_blkno
= FFS_FSBTODB(fs
, nb
);
563 bap
[indirs
[num
].in_off
] = ufs_rw64(nb
, needswap
);
566 * If required, write synchronously, otherwise use
574 error
= bread(ip
->i_devvp
, lbn
, (int)fs
->fs_bsize
, 0,