1 /* $NetBSD: ext2fs_balloc.c,v 1.40 2015/03/28 19:24:04 maxv 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.40 2015/03/28 19:24:04 maxv 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
[EXT2FS_NIADDR
+ 2];
100 daddr_t newb
, lbn
, pref
;
101 int32_t *bap
; /* XXX ondisk32 */
104 daddr_t
*blkp
, *allocblk
, allociblk
[EXT2FS_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 EXT2FS_NDADDR blocks are direct blocks
122 if (bn
< EXT2FS_NDADDR
) {
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
,
143 * allocate a new direct block.
146 error
= ext2fs_alloc(ip
, bn
,
147 ext2fs_blkpref(ip
, bn
, bn
, &ip
->i_e2fs_blocks
[0]),
151 ip
->i_e2fs_last_lblk
= lbn
;
152 ip
->i_e2fs_last_blk
= newb
;
154 ip
->i_e2fs_blocks
[bn
] = h2fs32((int32_t)newb
);
155 ip
->i_flag
|= IN_CHANGE
| IN_UPDATE
;
157 bp
= getblk(vp
, bn
, fs
->e2fs_bsize
, 0, 0);
158 bp
->b_blkno
= EXT2_FSBTODB(fs
, newb
);
159 if (flags
& B_CLRBUF
)
166 * Determine the number of levels of indirection.
169 if ((error
= ufs_getlbns(vp
, bn
, indirs
, &num
)) != 0)
173 panic ("ext2fs_balloc: ufs_getlbns returned indirect block\n");
176 * Fetch the first indirect block allocating if necessary.
180 nb
= fs2h32(ip
->i_e2fs_blocks
[EXT2FS_NDADDR
+ indirs
[0].in_off
]);
182 allocblk
= allociblk
;
184 pref
= ext2fs_blkpref(ip
, lbn
, 0, (int32_t *)0);
185 error
= ext2fs_alloc(ip
, lbn
, pref
, cred
, &newb
);
190 ip
->i_e2fs_last_blk
= newb
;
191 bp
= getblk(vp
, indirs
[1].in_lbn
, fs
->e2fs_bsize
, 0, 0);
192 bp
->b_blkno
= EXT2_FSBTODB(fs
, newb
);
195 * Write synchronously so that indirect blocks
196 * never point at garbage.
198 if ((error
= bwrite(bp
)) != 0)
201 allocib
= &ip
->i_e2fs_blocks
[EXT2FS_NDADDR
+ indirs
[0].in_off
];
203 *allocib
= h2fs32((int32_t)newb
);
204 ip
->i_flag
|= IN_CHANGE
| IN_UPDATE
;
207 * Fetch through the indirect blocks, allocating as necessary.
211 indirs
[i
].in_lbn
, (int)fs
->e2fs_bsize
, 0, &bp
);
215 bap
= (int32_t *)bp
->b_data
; /* XXX ondisk32 */
216 nb
= fs2h32(bap
[indirs
[i
].in_off
]);
224 pref
= ext2fs_blkpref(ip
, lbn
, 0, (int32_t *)0);
225 error
= ext2fs_alloc(ip
, lbn
, pref
, cred
, &newb
);
232 ip
->i_e2fs_last_blk
= newb
;
233 nbp
= getblk(vp
, indirs
[i
].in_lbn
, fs
->e2fs_bsize
, 0, 0);
234 nbp
->b_blkno
= EXT2_FSBTODB(fs
, nb
);
237 * Write synchronously so that indirect blocks
238 * never point at garbage.
240 if ((error
= bwrite(nbp
)) != 0) {
247 bap
[indirs
[i
- 1].in_off
] = h2fs32((int32_t)nb
);
249 * If required, write synchronously, otherwise use
252 if (flags
& B_SYNC
) {
259 * Get the data block, allocating if necessary.
262 pref
= ext2fs_blkpref(ip
, lbn
, indirs
[num
].in_off
, &bap
[0]);
263 error
= ext2fs_alloc(ip
, lbn
, pref
, cred
, &newb
);
270 ip
->i_e2fs_last_lblk
= lbn
;
271 ip
->i_e2fs_last_blk
= newb
;
273 bap
[indirs
[num
].in_off
] = h2fs32((int32_t)nb
);
275 * If required, write synchronously, otherwise use
278 if (flags
& B_SYNC
) {
284 nbp
= getblk(vp
, lbn
, fs
->e2fs_bsize
, 0, 0);
285 nbp
->b_blkno
= EXT2_FSBTODB(fs
, nb
);
286 if (flags
& B_CLRBUF
)
294 if (flags
& B_CLRBUF
) {
295 error
= bread(vp
, lbn
, (int)fs
->e2fs_bsize
,
301 nbp
= getblk(vp
, lbn
, fs
->e2fs_bsize
, 0, 0);
302 nbp
->b_blkno
= EXT2_FSBTODB(fs
, nb
);
309 * If we have failed part way through block allocation, we
310 * have to deallocate any indirect blocks that we have allocated.
312 for (deallocated
= 0, blkp
= allociblk
; blkp
< allocblk
; blkp
++) {
313 ext2fs_blkfree(ip
, *blkp
);
314 deallocated
+= fs
->e2fs_bsize
;
316 if (unwindidx
>= 0) {
317 if (unwindidx
== 0) {
322 r
= bread(vp
, indirs
[unwindidx
].in_lbn
,
323 (int)fs
->e2fs_bsize
, B_MODIFY
, &bp
);
325 panic("Could not unwind indirect block, error %d", r
);
327 bap
= (int32_t *)bp
->b_data
; /* XXX ondisk32 */
328 bap
[indirs
[unwindidx
].in_off
] = 0;
335 for (i
= unwindidx
+ 1; i
<= num
; i
++) {
336 bp
= getblk(vp
, indirs
[i
].in_lbn
, (int)fs
->e2fs_bsize
,
338 brelse(bp
, BC_INVAL
);
342 ext2fs_setnblock(ip
, ext2fs_nblock(ip
) - btodb(deallocated
));
343 ip
->i_e2fs_flags
|= IN_CHANGE
| IN_UPDATE
;
349 ext2fs_gop_alloc(struct vnode
*vp
, off_t off
, off_t len
, int flags
,
352 struct inode
*ip
= VTOI(vp
);
353 struct m_ext2fs
*fs
= ip
->i_e2fs
;
354 int error
, delta
, bshift
, bsize
;
355 UVMHIST_FUNC("ext2fs_gop_alloc"); UVMHIST_CALLED(ubchist
);
357 bshift
= fs
->e2fs_bshift
;
360 delta
= off
& (bsize
- 1);
365 bsize
= min(bsize
, len
);
366 UVMHIST_LOG(ubchist
, "off 0x%x len 0x%x bsize 0x%x",
369 error
= ext2fs_balloc(ip
, ext2_lblkno(fs
, off
), bsize
, cred
,
372 UVMHIST_LOG(ubchist
, "error %d", error
, 0,0,0);
377 * increase file size now, ext2fs_balloc() requires that
378 * EOF be up-to-date before each call.
381 if (ext2fs_size(ip
) < off
+ bsize
) {
382 UVMHIST_LOG(ubchist
, "old 0x%lx%8lx new 0x%lx%8lx",
383 /* Note that arguments are always cast to u_long. */
384 ext2fs_size(ip
) >> 32,
385 ext2fs_size(ip
) & 0xffffffff,
387 (off
+ bsize
) & 0xffffffff);
388 error
= ext2fs_setsize(ip
, off
+ bsize
);
390 UVMHIST_LOG(ubchist
, "error %d", error
, 0,0,0);