1 /* $NetBSD: ext2fs_balloc.c,v 1.33 2008/05/16 09:22:00 hannken Exp $ */
4 * Copyright (c) 1982, 1986, 1989, 1993
5 * The Regents of the University of California. All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the University nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * @(#)ffs_balloc.c 8.4 (Berkeley) 9/23/93
32 * Modified for ext2fs by Manuel Bouyer.
36 * Copyright (c) 1997 Manuel Bouyer.
38 * Redistribution and use in source and binary forms, with or without
39 * modification, are permitted provided that the following conditions
41 * 1. Redistributions of source code must retain the above copyright
42 * notice, this list of conditions and the following disclaimer.
43 * 2. Redistributions in binary form must reproduce the above copyright
44 * notice, this list of conditions and the following disclaimer in the
45 * documentation and/or other materials provided with the distribution.
47 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
48 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
49 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
50 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
51 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
52 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
53 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
54 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
55 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
56 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
58 * @(#)ffs_balloc.c 8.4 (Berkeley) 9/23/93
59 * Modified for ext2fs by Manuel Bouyer.
62 #include <sys/cdefs.h>
63 __KERNEL_RCSID(0, "$NetBSD: ext2fs_balloc.c,v 1.33 2008/05/16 09:22:00 hannken Exp $");
65 #if defined(_KERNEL_OPT)
66 #include "opt_uvmhist.h"
69 #include <sys/param.h>
70 #include <sys/systm.h>
74 #include <sys/vnode.h>
75 #include <sys/mount.h>
76 #include <sys/kauth.h>
80 #include <ufs/ufs/inode.h>
81 #include <ufs/ufs/ufs_extern.h>
83 #include <ufs/ext2fs/ext2fs.h>
84 #include <ufs/ext2fs/ext2fs_extern.h>
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.
92 ext2fs_balloc(struct inode
*ip
, daddr_t bn
, int size
,
93 kauth_cred_t cred
, struct buf
**bpp
, int flags
)
98 struct vnode
*vp
= ITOV(ip
);
99 struct indir indirs
[NIADDR
+ 2];
100 daddr_t newb
, lbn
, pref
;
101 int32_t *bap
; /* XXX ondisk32 */
104 daddr_t
*blkp
, *allocblk
, allociblk
[NIADDR
+ 1];
105 int32_t *allocib
; /* XXX ondisk32 */
107 UVMHIST_FUNC("ext2fs_balloc"); UVMHIST_CALLED(ubchist
);
109 UVMHIST_LOG(ubchist
, "bn 0x%x", bn
,0,0,0);
120 * The first NDADDR blocks are direct blocks
124 nb
= fs2h32(ip
->i_e2fs_blocks
[bn
]);
128 * the block is already allocated, just read it.
132 error
= bread(vp
, bn
, fs
->e2fs_bsize
, NOCRED
,
144 * allocate a new direct block.
147 error
= ext2fs_alloc(ip
, bn
,
148 ext2fs_blkpref(ip
, bn
, bn
, &ip
->i_e2fs_blocks
[0]),
152 ip
->i_e2fs_last_lblk
= lbn
;
153 ip
->i_e2fs_last_blk
= newb
;
155 ip
->i_e2fs_blocks
[bn
] = h2fs32((int32_t)newb
);
156 ip
->i_flag
|= IN_CHANGE
| IN_UPDATE
;
158 bp
= getblk(vp
, bn
, fs
->e2fs_bsize
, 0, 0);
159 bp
->b_blkno
= fsbtodb(fs
, newb
);
160 if (flags
& B_CLRBUF
)
167 * Determine the number of levels of indirection.
170 if ((error
= ufs_getlbns(vp
, bn
, indirs
, &num
)) != 0)
174 panic ("ext2fs_balloc: ufs_getlbns returned indirect block\n");
177 * Fetch the first indirect block allocating if necessary.
181 nb
= fs2h32(ip
->i_e2fs_blocks
[NDADDR
+ indirs
[0].in_off
]);
183 allocblk
= allociblk
;
185 pref
= ext2fs_blkpref(ip
, lbn
, 0, (int32_t *)0);
186 error
= ext2fs_alloc(ip
, lbn
, pref
, cred
, &newb
);
191 ip
->i_e2fs_last_blk
= newb
;
192 bp
= getblk(vp
, indirs
[1].in_lbn
, fs
->e2fs_bsize
, 0, 0);
193 bp
->b_blkno
= fsbtodb(fs
, newb
);
196 * Write synchronously so that indirect blocks
197 * never point at garbage.
199 if ((error
= bwrite(bp
)) != 0)
202 allocib
= &ip
->i_e2fs_blocks
[NDADDR
+ indirs
[0].in_off
];
204 *allocib
= h2fs32((int32_t)newb
);
205 ip
->i_flag
|= IN_CHANGE
| IN_UPDATE
;
208 * Fetch through the indirect blocks, allocating as necessary.
212 indirs
[i
].in_lbn
, (int)fs
->e2fs_bsize
, NOCRED
, 0, &bp
);
217 bap
= (int32_t *)bp
->b_data
; /* XXX ondisk32 */
218 nb
= fs2h32(bap
[indirs
[i
].in_off
]);
226 pref
= ext2fs_blkpref(ip
, lbn
, 0, (int32_t *)0);
227 error
= ext2fs_alloc(ip
, lbn
, pref
, cred
, &newb
);
234 ip
->i_e2fs_last_blk
= newb
;
235 nbp
= getblk(vp
, indirs
[i
].in_lbn
, fs
->e2fs_bsize
, 0, 0);
236 nbp
->b_blkno
= fsbtodb(fs
, nb
);
239 * Write synchronously so that indirect blocks
240 * never point at garbage.
242 if ((error
= bwrite(nbp
)) != 0) {
249 bap
[indirs
[i
- 1].in_off
] = h2fs32((int32_t)nb
);
251 * If required, write synchronously, otherwise use
254 if (flags
& B_SYNC
) {
261 * Get the data block, allocating if necessary.
264 pref
= ext2fs_blkpref(ip
, lbn
, indirs
[num
].in_off
, &bap
[0]);
265 error
= ext2fs_alloc(ip
, lbn
, pref
, cred
, &newb
);
272 ip
->i_e2fs_last_lblk
= lbn
;
273 ip
->i_e2fs_last_blk
= newb
;
275 bap
[indirs
[num
].in_off
] = h2fs32((int32_t)nb
);
277 * If required, write synchronously, otherwise use
280 if (flags
& B_SYNC
) {
286 nbp
= getblk(vp
, lbn
, fs
->e2fs_bsize
, 0, 0);
287 nbp
->b_blkno
= fsbtodb(fs
, nb
);
288 if (flags
& B_CLRBUF
)
296 if (flags
& B_CLRBUF
) {
297 error
= bread(vp
, lbn
, (int)fs
->e2fs_bsize
, NOCRED
,
304 nbp
= getblk(vp
, lbn
, fs
->e2fs_bsize
, 0, 0);
305 nbp
->b_blkno
= fsbtodb(fs
, nb
);
312 * If we have failed part way through block allocation, we
313 * have to deallocate any indirect blocks that we have allocated.
315 for (deallocated
= 0, blkp
= allociblk
; blkp
< allocblk
; blkp
++) {
316 ext2fs_blkfree(ip
, *blkp
);
317 deallocated
+= fs
->e2fs_bsize
;
319 if (unwindidx
>= 0) {
320 if (unwindidx
== 0) {
325 r
= bread(vp
, indirs
[unwindidx
].in_lbn
,
326 (int)fs
->e2fs_bsize
, NOCRED
, B_MODIFY
, &bp
);
328 panic("Could not unwind indirect block, error %d", r
);
331 bap
= (int32_t *)bp
->b_data
; /* XXX ondisk32 */
332 bap
[indirs
[unwindidx
].in_off
] = 0;
339 for (i
= unwindidx
+ 1; i
<= num
; i
++) {
340 bp
= getblk(vp
, indirs
[i
].in_lbn
, (int)fs
->e2fs_bsize
,
342 brelse(bp
, BC_INVAL
);
346 ip
->i_e2fs_nblock
-= btodb(deallocated
);
347 ip
->i_e2fs_flags
|= IN_CHANGE
| IN_UPDATE
;
353 ext2fs_gop_alloc(struct vnode
*vp
, off_t off
, off_t len
, int flags
,
356 struct inode
*ip
= VTOI(vp
);
357 struct m_ext2fs
*fs
= ip
->i_e2fs
;
358 int error
, delta
, bshift
, bsize
;
359 UVMHIST_FUNC("ext2fs_gop_alloc"); UVMHIST_CALLED(ubchist
);
361 bshift
= fs
->e2fs_bshift
;
364 delta
= off
& (bsize
- 1);
369 bsize
= min(bsize
, len
);
370 UVMHIST_LOG(ubchist
, "off 0x%x len 0x%x bsize 0x%x",
373 error
= ext2fs_balloc(ip
, lblkno(fs
, off
), bsize
, cred
,
376 UVMHIST_LOG(ubchist
, "error %d", error
, 0,0,0);
381 * increase file size now, ext2fs_balloc() requires that
382 * EOF be up-to-date before each call.
385 if (ext2fs_size(ip
) < off
+ bsize
) {
386 UVMHIST_LOG(ubchist
, "old 0x%lx%8lx new 0x%lx%8lx",
387 /* Note that arguments are always cast to u_long. */
388 ext2fs_size(ip
) >> 32,
389 ext2fs_size(ip
) & 0xffffffff,
391 (off
+ bsize
) & 0xffffffff);
392 error
= ext2fs_setsize(ip
, off
+ bsize
);
394 UVMHIST_LOG(ubchist
, "error %d", error
, 0,0,0);