kernel: Move GPL'd kernel files to sys/gnu to have them all in one place.
[dragonfly.git] / sys / gnu / vfs / 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
1f1db49f
MD
50#include "quota.h"
51#include "inode.h"
1f2de5d4
MD
52#include "ext2_fs.h"
53#include "ext2_fs_sb.h"
54#include "fs.h"
55#include "ext2_extern.h"
984263bc
MD
56
57/*
58 * Balloc defines the structure of file system storage
59 * by allocating the physical blocks on a device given
60 * the inode and the logical block number in a file.
61 */
62int
0f7f7a49
CP
63ext2_balloc(struct inode *ip, daddr_t bn, int size, struct ucred *cred,
64 struct buf **bpp, int flags)
984263bc 65{
f7aae92f
RG
66 struct ext2_sb_info *fs;
67 daddr_t nb;
984263bc
MD
68 struct buf *bp, *nbp;
69 struct vnode *vp = ITOV(ip);
70 struct indir indirs[NIADDR + 2];
71 daddr_t newb, lbn, *bap, pref;
72 int osize, nsize, num, i, error;
73/*
b993bb87 74ext2_debug("ext2_balloc called (%d, %d, %d)\n",
984263bc
MD
75 ip->i_number, (int)bn, (int)size);
76*/
77 *bpp = NULL;
78 if (bn < 0)
79 return (EFBIG);
80 fs = ip->i_e2fs;
81 lbn = bn;
82
83 /*
b993bb87
SW
84 * check if this is a sequential block allocation.
85 * If so, increment next_alloc fields to allow ext2_blkpref
984263bc
MD
86 * to make a good guess
87 */
88 if (lbn == ip->i_next_alloc_block + 1) {
89 ip->i_next_alloc_block++;
90 ip->i_next_alloc_goal++;
91 }
92
93 /*
94 * The first NDADDR blocks are direct blocks
95 */
96 if (bn < NDADDR) {
97 nb = ip->i_db[bn];
98 /* no new block is to be allocated, and no need to expand
99 the file */
100 if (nb != 0 && ip->i_size >= (bn + 1) * fs->s_blocksize) {
b993bb87 101 error = bread(vp, lblktodoff(fs, bn),
54078292 102 fs->s_blocksize, &bp);
984263bc
MD
103 if (error) {
104 brelse(bp);
105 return (error);
106 }
107 *bpp = bp;
108 return (0);
109 }
110 if (nb != 0) {
111 /*
112 * Consider need to reallocate a fragment.
113 */
114 osize = fragroundup(fs, blkoff(fs, ip->i_size));
115 nsize = fragroundup(fs, size);
116 if (nsize <= osize) {
54078292
MD
117 error = bread(vp, lblktodoff(fs, bn),
118 osize, &bp);
984263bc
MD
119 if (error) {
120 brelse(bp);
121 return (error);
122 }
123 } else {
124 /* Godmar thinks: this shouldn't happen w/o fragments */
b993bb87
SW
125 kprintf("nsize %d(%d) > osize %d(%d) nb %d\n",
126 (int)nsize, (int)size, (int)osize,
984263bc
MD
127 (int)ip->i_size, (int)nb);
128 panic(
129 "ext2_balloc: Something is terribly wrong");
130/*
131 * please note there haven't been any changes from here on -
132 * FFS seems to work.
133 */
134 }
135 } else {
136 if (ip->i_size < (bn + 1) * fs->s_blocksize)
137 nsize = fragroundup(fs, size);
138 else
139 nsize = fs->s_blocksize;
140 error = ext2_alloc(ip, bn,
141 ext2_blkpref(ip, bn, (int)bn, &ip->i_db[0], 0),
142 nsize, cred, &newb);
143 if (error)
144 return (error);
54078292
MD
145 bp = getblk(vp, lblktodoff(fs, bn), nsize, 0, 0);
146 bp->b_bio2.bio_offset = fsbtodoff(fs, newb);
984263bc
MD
147 if (flags & B_CLRBUF)
148 vfs_bio_clrbuf(bp);
149 }
54078292 150 ip->i_db[bn] = dofftofsb(fs, bp->b_bio2.bio_offset);
984263bc
MD
151 ip->i_flag |= IN_CHANGE | IN_UPDATE;
152 *bpp = bp;
153 return (0);
154 }
155 /*
156 * Determine the number of levels of indirection.
157 */
158 pref = 0;
1f1db49f 159 if ((error = ext2_getlbns(vp, bn, indirs, &num)) != 0)
984263bc
MD
160 return(error);
161#if DIAGNOSTIC
162 if (num < 1)
1f1db49f 163 panic ("ext2_balloc: ext2_bmaparray returned indirect block");
984263bc
MD
164#endif
165 /*
166 * Fetch the first indirect block allocating if necessary.
167 */
168 --num;
169 nb = ip->i_ib[indirs[0].in_off];
170 if (nb == 0) {
171#if 0
60233e58 172 pref = ext2_blkpref(ip, lbn, 0, NULL, 0);
984263bc
MD
173#else
174 /* see the comment by ext2_blkpref. What we do here is
175 to pretend that it'd be good for a block holding indirect
b993bb87
SW
176 pointers to be allocated near its predecessor in terms
177 of indirection, or the last direct block.
984263bc 178 We shamelessly exploit the fact that i_ib immediately
b993bb87 179 follows i_db.
984263bc
MD
180 Godmar thinks it make sense to allocate i_ib[0] immediately
181 after i_db[11], but it's not utterly clear whether this also
182 applies to i_ib[1] and i_ib[0]
183 */
184
b993bb87 185 pref = ext2_blkpref(ip, lbn, indirs[0].in_off +
984263bc
MD
186 EXT2_NDIR_BLOCKS, &ip->i_db[0], 0);
187#endif
188 if ((error = ext2_alloc(ip, lbn, pref, (int)fs->s_blocksize,
189 cred, &newb)) != 0)
190 return (error);
191 nb = newb;
54078292
MD
192 bp = getblk(vp, lblktodoff(fs, indirs[1].in_lbn),
193 fs->s_blocksize, 0, 0);
194 bp->b_bio2.bio_offset = fsbtodoff(fs, newb);
984263bc
MD
195 vfs_bio_clrbuf(bp);
196 /*
197 * Write synchronously so that indirect blocks
198 * never point at garbage.
199 */
200 if ((error = bwrite(bp)) != 0) {
201 ext2_blkfree(ip, nb, fs->s_blocksize);
202 return (error);
203 }
204 ip->i_ib[indirs[0].in_off] = newb;
205 ip->i_flag |= IN_CHANGE | IN_UPDATE;
206 }
207 /*
208 * Fetch through the indirect blocks, allocating as necessary.
209 */
210 for (i = 1;;) {
211 error = bread(vp,
b993bb87 212 lblktodoff(fs, indirs[i].in_lbn),
54078292 213 (int)fs->s_blocksize, &bp);
984263bc
MD
214 if (error) {
215 brelse(bp);
216 return (error);
217 }
218 bap = (daddr_t *)bp->b_data;
219 nb = bap[indirs[i].in_off];
220 if (i == num)
221 break;
222 i += 1;
223 if (nb != 0) {
224 brelse(bp);
225 continue;
226 }
b993bb87 227 if (pref == 0)
984263bc
MD
228#if 1
229 /* see the comment above and by ext2_blkpref
230 * I think this implements Linux policy, but
231 * does it really make sense to allocate to
232 * block containing pointers together ?
233 * Also, will it ever succeed ?
234 */
235 pref = ext2_blkpref(ip, lbn, indirs[i].in_off, bap,
54078292 236 lblkno(fs, bp->b_loffset));
984263bc 237#else
60233e58 238 pref = ext2_blkpref(ip, lbn, 0, NULL, 0);
984263bc
MD
239#endif
240 if ((error =
241 ext2_alloc(ip, lbn, pref, (int)fs->s_blocksize, cred, &newb)) != 0) {
242 brelse(bp);
243 return (error);
244 }
245 nb = newb;
54078292
MD
246 nbp = getblk(vp, lblktodoff(fs, indirs[i].in_lbn),
247 fs->s_blocksize, 0, 0);
248 nbp->b_bio2.bio_offset = fsbtodoff(fs, nb);
984263bc
MD
249 vfs_bio_clrbuf(nbp);
250 /*
251 * Write synchronously so that indirect blocks
252 * never point at garbage.
253 */
254 if ((error = bwrite(nbp)) != 0) {
255 ext2_blkfree(ip, nb, fs->s_blocksize);
256 brelse(bp);
257 return (error);
258 }
259 bap[indirs[i - 1].in_off] = nb;
260 /*
261 * If required, write synchronously, otherwise use
262 * delayed write.
263 */
264 if (flags & B_SYNC) {
265 bwrite(bp);
266 } else {
267 bdwrite(bp);
268 }
269 }
270 /*
271 * Get the data block, allocating if necessary.
272 */
273 if (nb == 0) {
b993bb87 274 pref = ext2_blkpref(ip, lbn, indirs[i].in_off, &bap[0],
54078292 275 lblkno(fs, bp->b_loffset));
984263bc
MD
276 if ((error = ext2_alloc(ip,
277 lbn, pref, (int)fs->s_blocksize, cred, &newb)) != 0) {
278 brelse(bp);
279 return (error);
280 }
281 nb = newb;
54078292
MD
282 nbp = getblk(vp, lblktodoff(fs, lbn), fs->s_blocksize, 0, 0);
283 nbp->b_bio2.bio_offset = fsbtodoff(fs, nb);
984263bc
MD
284 if (flags & B_CLRBUF)
285 vfs_bio_clrbuf(nbp);
286 bap[indirs[i].in_off] = nb;
287 /*
288 * If required, write synchronously, otherwise use
289 * delayed write.
290 */
291 if (flags & B_SYNC) {
292 bwrite(bp);
293 } else {
294 bdwrite(bp);
295 }
296 *bpp = nbp;
297 return (0);
298 }
299 brelse(bp);
300 if (flags & B_CLRBUF) {
54078292
MD
301 error = bread(vp, lblktodoff(fs, lbn),
302 (int)fs->s_blocksize, &nbp);
984263bc
MD
303 if (error) {
304 brelse(nbp);
305 return (error);
306 }
307 } else {
54078292
MD
308 nbp = getblk(vp, lblktodoff(fs, lbn), fs->s_blocksize, 0, 0);
309 nbp->b_bio2.bio_offset = fsbtodoff(fs, nb);
984263bc
MD
310 }
311 *bpp = nbp;
312 return (0);
313}