ffs_balloc.c revision 1.7 1 /* $NetBSD: ffs_balloc.c,v 1.7 2002/01/07 16:56:27 lukem Exp $ */
2 /* From NetBSD: ffs_balloc.c,v 1.25 2001/08/08 08:36:36 lukem Exp */
3
4 /*
5 * Copyright (c) 1982, 1986, 1989, 1993
6 * The Regents of the University of California. All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
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. All advertising materials mentioning features or use of this software
17 * must display the following acknowledgement:
18 * This product includes software developed by the University of
19 * California, Berkeley and its contributors.
20 * 4. Neither the name of the University nor the names of its contributors
21 * may be used to endorse or promote products derived from this software
22 * without specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * SUCH DAMAGE.
35 *
36 * @(#)ffs_balloc.c 8.8 (Berkeley) 6/16/95
37 */
38
39 #include <sys/cdefs.h>
40 #ifndef __lint
41 __RCSID("$NetBSD: ffs_balloc.c,v 1.7 2002/01/07 16:56:27 lukem Exp $");
42 #endif /* !__lint */
43
44 #include <sys/param.h>
45 #include <sys/time.h>
46
47 #include <assert.h>
48 #include <err.h>
49 #include <errno.h>
50 #include <stdio.h>
51 #include <stdlib.h>
52 #include <string.h>
53
54 #include "makefs.h"
55
56 #include <ufs/ufs/ufs_bswap.h>
57 #include <ufs/ffs/fs.h>
58
59 #include "ffs/buf.h"
60 #include "ffs/ufs_inode.h"
61 #include "ffs/ffs_extern.h"
62
63 /*
64 * Balloc defines the structure of file system storage
65 * by allocating the physical blocks on a device given
66 * the inode and the logical block number in a file.
67 *
68 * Assume: flags == B_SYNC | B_CLRBUF
69 */
70 int
71 ffs_balloc(struct inode *ip, off_t offset, int bufsize, struct buf **bpp)
72 {
73 ufs_daddr_t lbn;
74 int size;
75 ufs_daddr_t nb;
76 struct buf *bp, *nbp;
77 struct fs *fs = ip->i_fs;
78 struct indir indirs[NIADDR + 2];
79 ufs_daddr_t newb, *bap, pref;
80 int osize, nsize, num, i, error;
81 ufs_daddr_t *allocib, *allocblk, allociblk[NIADDR + 1];
82 const int needswap = UFS_FSNEEDSWAP(fs);
83
84 lbn = lblkno(fs, offset);
85 size = blkoff(fs, offset) + bufsize;
86 if (bpp != NULL) {
87 *bpp = NULL;
88 }
89
90 assert(size <= fs->fs_bsize);
91 if (lbn < 0)
92 return (EFBIG);
93
94 /*
95 * If the next write will extend the file into a new block,
96 * and the file is currently composed of a fragment
97 * this fragment has to be extended to be a full block.
98 */
99
100 nb = lblkno(fs, ip->i_ffs_size);
101 if (nb < NDADDR && nb < lbn) {
102 osize = blksize(fs, ip, nb);
103 if (osize < fs->fs_bsize && osize > 0) {
104 warnx("need to ffs_realloccg; not supported!");
105 abort();
106 }
107 }
108
109 /*
110 * The first NDADDR blocks are direct blocks
111 */
112
113 if (lbn < NDADDR) {
114 nb = ufs_rw32(ip->i_ffs_db[lbn], needswap);
115 if (nb != 0 && ip->i_ffs_size >= lblktosize(fs, lbn + 1)) {
116
117 /*
118 * The block is an already-allocated direct block
119 * and the file already extends past this block,
120 * thus this must be a whole block.
121 * Just read the block (if requested).
122 */
123
124 if (bpp != NULL) {
125 error = bread(ip->i_fd, ip->i_fs, lbn,
126 fs->fs_bsize, bpp);
127 if (error) {
128 brelse(*bpp);
129 return (error);
130 }
131 }
132 return (0);
133 }
134 if (nb != 0) {
135
136 /*
137 * Consider need to reallocate a fragment.
138 */
139
140 osize = fragroundup(fs, blkoff(fs, ip->i_ffs_size));
141 nsize = fragroundup(fs, size);
142 if (nsize <= osize) {
143
144 /*
145 * The existing block is already
146 * at least as big as we want.
147 * Just read the block (if requested).
148 */
149
150 if (bpp != NULL) {
151 error = bread(ip->i_fd, ip->i_fs, lbn,
152 osize, bpp);
153 if (error) {
154 brelse(*bpp);
155 return (error);
156 }
157 }
158 return 0;
159 } else {
160 warnx("need to ffs_realloccg; not supported!");
161 abort();
162 }
163 } else {
164
165 /*
166 * the block was not previously allocated,
167 * allocate a new block or fragment.
168 */
169
170 if (ip->i_ffs_size < lblktosize(fs, lbn + 1))
171 nsize = fragroundup(fs, size);
172 else
173 nsize = fs->fs_bsize;
174 error = ffs_alloc(ip, lbn,
175 ffs_blkpref(ip, lbn, (int)lbn, &ip->i_ffs_db[0]),
176 nsize, &newb);
177 if (error)
178 return (error);
179 if (bpp != NULL) {
180 bp = getblk(ip->i_fd, ip->i_fs, lbn, nsize);
181 bp->b_blkno = fsbtodb(fs, newb);
182 clrbuf(bp);
183 *bpp = bp;
184 }
185 }
186 ip->i_ffs_db[lbn] = ufs_rw32(newb, needswap);
187 return (0);
188 }
189 /*
190 * Determine the number of levels of indirection.
191 */
192 pref = 0;
193 if ((error = ufs_getlbns(ip, lbn, indirs, &num)) != 0)
194 return(error);
195
196 if (num < 1) {
197 warnx("ffs_balloc: ufs_getlbns returned indirect block");
198 abort();
199 }
200 /*
201 * Fetch the first indirect block allocating if necessary.
202 */
203 --num;
204 nb = ufs_rw32(ip->i_ffs_ib[indirs[0].in_off], needswap);
205 allocib = NULL;
206 allocblk = allociblk;
207 if (nb == 0) {
208 pref = ffs_blkpref(ip, lbn, 0, (ufs_daddr_t *)0);
209 error = ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize, &newb);
210 if (error)
211 return (error);
212 nb = newb;
213 *allocblk++ = nb;
214 bp = getblk(ip->i_fd, ip->i_fs, indirs[1].in_lbn, fs->fs_bsize);
215 bp->b_blkno = fsbtodb(fs, nb);
216 clrbuf(bp);
217 /*
218 * Write synchronously so that indirect blocks
219 * never point at garbage.
220 */
221 if ((error = bwrite(bp)) != 0)
222 goto fail;
223 allocib = &ip->i_ffs_ib[indirs[0].in_off];
224 *allocib = ufs_rw32(nb, needswap);
225 }
226 /*
227 * Fetch through the indirect blocks, allocating as necessary.
228 */
229 for (i = 1;;) {
230 error = bread(ip->i_fd, ip->i_fs, indirs[i].in_lbn,
231 (int)fs->fs_bsize, &bp);
232 if (error) {
233 brelse(bp);
234 goto fail;
235 }
236 bap = (ufs_daddr_t *)bp->b_data;
237 nb = ufs_rw32(bap[indirs[i].in_off], needswap);
238 if (i == num)
239 break;
240 i++;
241 if (nb != 0) {
242 brelse(bp);
243 continue;
244 }
245 if (pref == 0)
246 pref = ffs_blkpref(ip, lbn, 0, (ufs_daddr_t *)0);
247 error = ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize, &newb);
248 if (error) {
249 brelse(bp);
250 goto fail;
251 }
252 nb = newb;
253 *allocblk++ = nb;
254 nbp = getblk(ip->i_fd, ip->i_fs, indirs[i].in_lbn,
255 fs->fs_bsize);
256 nbp->b_blkno = fsbtodb(fs, nb);
257 clrbuf(nbp);
258 /*
259 * Write synchronously so that indirect blocks
260 * never point at garbage.
261 */
262 if ((error = bwrite(nbp)) != 0) {
263 brelse(bp);
264 goto fail;
265 }
266 bap[indirs[i - 1].in_off] = ufs_rw32(nb, needswap);
267 /*
268 * If required, write synchronously, otherwise use
269 * delayed write.
270 */
271 bwrite(bp);
272 }
273 /*
274 * Get the data block, allocating if necessary.
275 */
276 if (nb == 0) {
277 pref = ffs_blkpref(ip, lbn, indirs[num].in_off, &bap[0]);
278 error = ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize, &newb);
279 if (error) {
280 brelse(bp);
281 goto fail;
282 }
283 nb = newb;
284 *allocblk++ = nb;
285 if (bpp != NULL) {
286 nbp = getblk(ip->i_fd, ip->i_fs, lbn, fs->fs_bsize);
287 nbp->b_blkno = fsbtodb(fs, nb);
288 clrbuf(nbp);
289 *bpp = nbp;
290 }
291 bap[indirs[num].in_off] = ufs_rw32(nb, needswap);
292 /*
293 * If required, write synchronously, otherwise use
294 * delayed write.
295 */
296 bwrite(bp);
297 return (0);
298 }
299 brelse(bp);
300 if (bpp != NULL) {
301 error = bread(ip->i_fd, ip->i_fs, lbn,
302 (int)fs->fs_bsize, &nbp);
303 if (error) {
304 brelse(nbp);
305 goto fail;
306 }
307 *bpp = nbp;
308 }
309 return (0);
310 fail:
311 return (error);
312 }
313