Initial import from FreeBSD RELENG_4:
[dragonfly.git] / sys / vfs / gnu / ext2fs / ext2_balloc.c
CommitLineData
984263bc
MD
1/*
2 * modified for Lites 1.1
3 *
4 * Aug 1995, Godmar Back (gback@cs.utah.edu)
5 * University of Utah, Department of Computer Science
6 */
7/*
8 * Copyright (c) 1982, 1986, 1989, 1993
9 * The Regents of the University of California. All rights reserved.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. All advertising materials mentioning features or use of this software
20 * must display the following acknowledgement:
21 * This product includes software developed by the University of
22 * California, Berkeley and its contributors.
23 * 4. Neither the name of the University nor the names of its contributors
24 * may be used to endorse or promote products derived from this software
25 * without specific prior written permission.
26 *
27 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
28 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
31 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
32 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
33 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
34 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
35 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
36 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
37 * SUCH DAMAGE.
38 *
39 * @(#)ffs_balloc.c 8.4 (Berkeley) 9/23/93
40 * $FreeBSD: src/sys/gnu/ext2fs/ext2_balloc.c,v 1.9.2.1 2000/08/03 00:52:57 peter Exp $
41 */
42
43#include <sys/param.h>
44#include <sys/systm.h>
45#include <sys/buf.h>
46#include <sys/lock.h>
47#include <sys/ucred.h>
48#include <sys/vnode.h>
49
50#include <ufs/ufs/quota.h>
51#include <ufs/ufs/inode.h>
52#include <ufs/ufs/ufs_extern.h>
53
54#include <gnu/ext2fs/ext2_fs.h>
55#include <gnu/ext2fs/ext2_fs_sb.h>
56#include <gnu/ext2fs/fs.h>
57#include <gnu/ext2fs/ext2_extern.h>
58
59/*
60 * Balloc defines the structure of file system storage
61 * by allocating the physical blocks on a device given
62 * the inode and the logical block number in a file.
63 */
64int
65ext2_balloc(ip, bn, size, cred, bpp, flags)
66 register struct inode *ip;
67 register daddr_t bn;
68 int size;
69 struct ucred *cred;
70 struct buf **bpp;
71 int flags;
72{
73 register struct ext2_sb_info *fs;
74 register daddr_t nb;
75 struct buf *bp, *nbp;
76 struct vnode *vp = ITOV(ip);
77 struct indir indirs[NIADDR + 2];
78 daddr_t newb, lbn, *bap, pref;
79 int osize, nsize, num, i, error;
80/*
81ext2_debug("ext2_balloc called (%d, %d, %d)\n",
82 ip->i_number, (int)bn, (int)size);
83*/
84 *bpp = NULL;
85 if (bn < 0)
86 return (EFBIG);
87 fs = ip->i_e2fs;
88 lbn = bn;
89
90 /*
91 * check if this is a sequential block allocation.
92 * If so, increment next_alloc fields to allow ext2_blkpref
93 * to make a good guess
94 */
95 if (lbn == ip->i_next_alloc_block + 1) {
96 ip->i_next_alloc_block++;
97 ip->i_next_alloc_goal++;
98 }
99
100 /*
101 * The first NDADDR blocks are direct blocks
102 */
103 if (bn < NDADDR) {
104 nb = ip->i_db[bn];
105 /* no new block is to be allocated, and no need to expand
106 the file */
107 if (nb != 0 && ip->i_size >= (bn + 1) * fs->s_blocksize) {
108 error = bread(vp, bn, fs->s_blocksize, NOCRED, &bp);
109 if (error) {
110 brelse(bp);
111 return (error);
112 }
113 *bpp = bp;
114 return (0);
115 }
116 if (nb != 0) {
117 /*
118 * Consider need to reallocate a fragment.
119 */
120 osize = fragroundup(fs, blkoff(fs, ip->i_size));
121 nsize = fragroundup(fs, size);
122 if (nsize <= osize) {
123 error = bread(vp, bn, osize, NOCRED, &bp);
124 if (error) {
125 brelse(bp);
126 return (error);
127 }
128 } else {
129 /* Godmar thinks: this shouldn't happen w/o fragments */
130 printf("nsize %d(%d) > osize %d(%d) nb %d\n",
131 (int)nsize, (int)size, (int)osize,
132 (int)ip->i_size, (int)nb);
133 panic(
134 "ext2_balloc: Something is terribly wrong");
135/*
136 * please note there haven't been any changes from here on -
137 * FFS seems to work.
138 */
139 }
140 } else {
141 if (ip->i_size < (bn + 1) * fs->s_blocksize)
142 nsize = fragroundup(fs, size);
143 else
144 nsize = fs->s_blocksize;
145 error = ext2_alloc(ip, bn,
146 ext2_blkpref(ip, bn, (int)bn, &ip->i_db[0], 0),
147 nsize, cred, &newb);
148 if (error)
149 return (error);
150 bp = getblk(vp, bn, nsize, 0, 0);
151 bp->b_blkno = fsbtodb(fs, newb);
152 if (flags & B_CLRBUF)
153 vfs_bio_clrbuf(bp);
154 }
155 ip->i_db[bn] = dbtofsb(fs, bp->b_blkno);
156 ip->i_flag |= IN_CHANGE | IN_UPDATE;
157 *bpp = bp;
158 return (0);
159 }
160 /*
161 * Determine the number of levels of indirection.
162 */
163 pref = 0;
164 if ((error = ufs_getlbns(vp, bn, indirs, &num)) != 0)
165 return(error);
166#if DIAGNOSTIC
167 if (num < 1)
168 panic ("ext2_balloc: ufs_bmaparray returned indirect block");
169#endif
170 /*
171 * Fetch the first indirect block allocating if necessary.
172 */
173 --num;
174 nb = ip->i_ib[indirs[0].in_off];
175 if (nb == 0) {
176#if 0
177 pref = ext2_blkpref(ip, lbn, 0, (daddr_t *)0, 0);
178#else
179 /* see the comment by ext2_blkpref. What we do here is
180 to pretend that it'd be good for a block holding indirect
181 pointers to be allocated near its predecessor in terms
182 of indirection, or the last direct block.
183 We shamelessly exploit the fact that i_ib immediately
184 follows i_db.
185 Godmar thinks it make sense to allocate i_ib[0] immediately
186 after i_db[11], but it's not utterly clear whether this also
187 applies to i_ib[1] and i_ib[0]
188 */
189
190 pref = ext2_blkpref(ip, lbn, indirs[0].in_off +
191 EXT2_NDIR_BLOCKS, &ip->i_db[0], 0);
192#endif
193 if ((error = ext2_alloc(ip, lbn, pref, (int)fs->s_blocksize,
194 cred, &newb)) != 0)
195 return (error);
196 nb = newb;
197 bp = getblk(vp, indirs[1].in_lbn, fs->s_blocksize, 0, 0);
198 bp->b_blkno = fsbtodb(fs, newb);
199 vfs_bio_clrbuf(bp);
200 /*
201 * Write synchronously so that indirect blocks
202 * never point at garbage.
203 */
204 if ((error = bwrite(bp)) != 0) {
205 ext2_blkfree(ip, nb, fs->s_blocksize);
206 return (error);
207 }
208 ip->i_ib[indirs[0].in_off] = newb;
209 ip->i_flag |= IN_CHANGE | IN_UPDATE;
210 }
211 /*
212 * Fetch through the indirect blocks, allocating as necessary.
213 */
214 for (i = 1;;) {
215 error = bread(vp,
216 indirs[i].in_lbn, (int)fs->s_blocksize, NOCRED, &bp);
217 if (error) {
218 brelse(bp);
219 return (error);
220 }
221 bap = (daddr_t *)bp->b_data;
222 nb = bap[indirs[i].in_off];
223 if (i == num)
224 break;
225 i += 1;
226 if (nb != 0) {
227 brelse(bp);
228 continue;
229 }
230 if (pref == 0)
231#if 1
232 /* see the comment above and by ext2_blkpref
233 * I think this implements Linux policy, but
234 * does it really make sense to allocate to
235 * block containing pointers together ?
236 * Also, will it ever succeed ?
237 */
238 pref = ext2_blkpref(ip, lbn, indirs[i].in_off, bap,
239 bp->b_lblkno);
240#else
241 pref = ext2_blkpref(ip, lbn, 0, (daddr_t *)0, 0);
242#endif
243 if ((error =
244 ext2_alloc(ip, lbn, pref, (int)fs->s_blocksize, cred, &newb)) != 0) {
245 brelse(bp);
246 return (error);
247 }
248 nb = newb;
249 nbp = getblk(vp, indirs[i].in_lbn, fs->s_blocksize, 0, 0);
250 nbp->b_blkno = fsbtodb(fs, nb);
251 vfs_bio_clrbuf(nbp);
252 /*
253 * Write synchronously so that indirect blocks
254 * never point at garbage.
255 */
256 if ((error = bwrite(nbp)) != 0) {
257 ext2_blkfree(ip, nb, fs->s_blocksize);
258 brelse(bp);
259 return (error);
260 }
261 bap[indirs[i - 1].in_off] = nb;
262 /*
263 * If required, write synchronously, otherwise use
264 * delayed write.
265 */
266 if (flags & B_SYNC) {
267 bwrite(bp);
268 } else {
269 bdwrite(bp);
270 }
271 }
272 /*
273 * Get the data block, allocating if necessary.
274 */
275 if (nb == 0) {
276 pref = ext2_blkpref(ip, lbn, indirs[i].in_off, &bap[0],
277 bp->b_lblkno);
278 if ((error = ext2_alloc(ip,
279 lbn, pref, (int)fs->s_blocksize, cred, &newb)) != 0) {
280 brelse(bp);
281 return (error);
282 }
283 nb = newb;
284 nbp = getblk(vp, lbn, fs->s_blocksize, 0, 0);
285 nbp->b_blkno = fsbtodb(fs, nb);
286 if (flags & B_CLRBUF)
287 vfs_bio_clrbuf(nbp);
288 bap[indirs[i].in_off] = nb;
289 /*
290 * If required, write synchronously, otherwise use
291 * delayed write.
292 */
293 if (flags & B_SYNC) {
294 bwrite(bp);
295 } else {
296 bdwrite(bp);
297 }
298 *bpp = nbp;
299 return (0);
300 }
301 brelse(bp);
302 if (flags & B_CLRBUF) {
303 error = bread(vp, lbn, (int)fs->s_blocksize, NOCRED, &nbp);
304 if (error) {
305 brelse(nbp);
306 return (error);
307 }
308 } else {
309 nbp = getblk(vp, lbn, fs->s_blocksize, 0, 0);
310 nbp->b_blkno = fsbtodb(fs, nb);
311 }
312 *bpp = nbp;
313 return (0);
314}