ffs_balloc.c revision 1.3 1 /* $NetBSD: ffs_balloc.c,v 1.3 2001/11/22 02:47:26 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.3 2001/11/22 02:47:26 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 <string.h>
52
53 #include "ufs/ufs/ufs_bswap.h"
54 #include "ufs/ufs/inode.h"
55 #include "ufs/ffs/fs.h"
56
57 #include "ffs/buf.h"
58 #include "ffs/ffs_extern.h"
59
60 /*
61 * Balloc defines the structure of file system storage
62 * by allocating the physical blocks on a device given
63 * the inode and the logical block number in a file.
64 *
65 * Assume: flags == B_SYNC | B_CLRBUF
66 */
67 int
68 ffs_balloc(struct inode *ip, off_t offset, int bufsize, struct buf **bpp)
69 {
70 ufs_daddr_t lbn;
71 int size;
72 ufs_daddr_t nb;
73 struct buf *bp, *nbp;
74 struct fs *fs = ip->i_fs;
75 struct indir indirs[NIADDR + 2];
76 ufs_daddr_t newb, *bap, pref;
77 int osize, nsize, num, i, error;
78 ufs_daddr_t *allocib, *allocblk, allociblk[NIADDR + 1];
79 const int needswap = UFS_FSNEEDSWAP(fs);
80
81 lbn = lblkno(fs, offset);
82 size = blkoff(fs, offset) + bufsize;
83 if (bpp != NULL) {
84 *bpp = NULL;
85 }
86
87 assert(size <= fs->fs_bsize);
88 if (lbn < 0)
89 return (EFBIG);
90
91 /*
92 * If the next write will extend the file into a new block,
93 * and the file is currently composed of a fragment
94 * this fragment has to be extended to be a full block.
95 */
96
97 nb = lblkno(fs, ip->i_ffs_size);
98 if (nb < NDADDR && nb < lbn) {
99 osize = blksize(fs, ip, nb);
100 if (osize < fs->fs_bsize && osize > 0) {
101 warnx("need to ffs_realloccg; not supported!");
102 abort();
103 }
104 }
105
106 /*
107 * The first NDADDR blocks are direct blocks
108 */
109
110 if (lbn < NDADDR) {
111 nb = ufs_rw32(ip->i_ffs_db[lbn], needswap);
112 if (nb != 0 && ip->i_ffs_size >= lblktosize(fs, lbn + 1)) {
113
114 /*
115 * The block is an already-allocated direct block
116 * and the file already extends past this block,
117 * thus this must be a whole block.
118 * Just read the block (if requested).
119 */
120
121 if (bpp != NULL) {
122 error = bread(ip->i_fd, ip->i_fs, lbn,
123 fs->fs_bsize, bpp);
124 if (error) {
125 brelse(*bpp);
126 return (error);
127 }
128 }
129 return (0);
130 }
131 if (nb != 0) {
132
133 /*
134 * Consider need to reallocate a fragment.
135 */
136
137 osize = fragroundup(fs, blkoff(fs, ip->i_ffs_size));
138 nsize = fragroundup(fs, size);
139 if (nsize <= osize) {
140
141 /*
142 * The existing block is already
143 * at least as big as we want.
144 * Just read the block (if requested).
145 */
146
147 if (bpp != NULL) {
148 error = bread(ip->i_fd, ip->i_fs, lbn,
149 osize, bpp);
150 if (error) {
151 brelse(*bpp);
152 return (error);
153 }
154 }
155 return 0;
156 } else {
157 warnx("need to ffs_realloccg; not supported!");
158 abort();
159 }
160 } else {
161
162 /*
163 * the block was not previously allocated,
164 * allocate a new block or fragment.
165 */
166
167 if (ip->i_ffs_size < lblktosize(fs, lbn + 1))
168 nsize = fragroundup(fs, size);
169 else
170 nsize = fs->fs_bsize;
171 error = ffs_alloc(ip, lbn,
172 ffs_blkpref(ip, lbn, (int)lbn, &ip->i_ffs_db[0]),
173 nsize, &newb);
174 if (error)
175 return (error);
176 if (bpp != NULL) {
177 bp = getblk(ip->i_fd, ip->i_fs, lbn, nsize);
178 bp->b_blkno = fsbtodb(fs, newb);
179 clrbuf(bp);
180 *bpp = bp;
181 }
182 }
183 ip->i_ffs_db[lbn] = ufs_rw32(newb, needswap);
184 return (0);
185 }
186 /*
187 * Determine the number of levels of indirection.
188 */
189 pref = 0;
190 if ((error = ufs_getlbns(ip, lbn, indirs, &num)) != 0)
191 return(error);
192
193 if (num < 1) {
194 warnx("ffs_balloc: ufs_getlbns returned indirect block");
195 abort();
196 }
197 /*
198 * Fetch the first indirect block allocating if necessary.
199 */
200 --num;
201 nb = ufs_rw32(ip->i_ffs_ib[indirs[0].in_off], needswap);
202 allocib = NULL;
203 allocblk = allociblk;
204 if (nb == 0) {
205 pref = ffs_blkpref(ip, lbn, 0, (ufs_daddr_t *)0);
206 error = ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize, &newb);
207 if (error)
208 return (error);
209 nb = newb;
210 *allocblk++ = nb;
211 bp = getblk(ip->i_fd, ip->i_fs, indirs[1].in_lbn, fs->fs_bsize);
212 bp->b_blkno = fsbtodb(fs, nb);
213 clrbuf(bp);
214 /*
215 * Write synchronously so that indirect blocks
216 * never point at garbage.
217 */
218 if ((error = bwrite(bp)) != 0)
219 goto fail;
220 allocib = &ip->i_ffs_ib[indirs[0].in_off];
221 *allocib = ufs_rw32(nb, needswap);
222 }
223 /*
224 * Fetch through the indirect blocks, allocating as necessary.
225 */
226 for (i = 1;;) {
227 error = bread(ip->i_fd, ip->i_fs, indirs[i].in_lbn,
228 (int)fs->fs_bsize, &bp);
229 if (error) {
230 brelse(bp);
231 goto fail;
232 }
233 bap = (ufs_daddr_t *)bp->b_data;
234 nb = ufs_rw32(bap[indirs[i].in_off], needswap);
235 if (i == num)
236 break;
237 i++;
238 if (nb != 0) {
239 brelse(bp);
240 continue;
241 }
242 if (pref == 0)
243 pref = ffs_blkpref(ip, lbn, 0, (ufs_daddr_t *)0);
244 error = ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize, &newb);
245 if (error) {
246 brelse(bp);
247 goto fail;
248 }
249 nb = newb;
250 *allocblk++ = nb;
251 nbp = getblk(ip->i_fd, ip->i_fs, indirs[i].in_lbn,
252 fs->fs_bsize);
253 nbp->b_blkno = fsbtodb(fs, nb);
254 clrbuf(nbp);
255 /*
256 * Write synchronously so that indirect blocks
257 * never point at garbage.
258 */
259 if ((error = bwrite(nbp)) != 0) {
260 brelse(bp);
261 goto fail;
262 }
263 bap[indirs[i - 1].in_off] = ufs_rw32(nb, needswap);
264 /*
265 * If required, write synchronously, otherwise use
266 * delayed write.
267 */
268 bwrite(bp);
269 }
270 /*
271 * Get the data block, allocating if necessary.
272 */
273 if (nb == 0) {
274 pref = ffs_blkpref(ip, lbn, indirs[num].in_off, &bap[0]);
275 error = ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize, &newb);
276 if (error) {
277 brelse(bp);
278 goto fail;
279 }
280 nb = newb;
281 *allocblk++ = nb;
282 if (bpp != NULL) {
283 nbp = getblk(ip->i_fd, ip->i_fs, lbn, fs->fs_bsize);
284 nbp->b_blkno = fsbtodb(fs, nb);
285 clrbuf(nbp);
286 *bpp = nbp;
287 }
288 bap[indirs[num].in_off] = ufs_rw32(nb, needswap);
289 /*
290 * If required, write synchronously, otherwise use
291 * delayed write.
292 */
293 bwrite(bp);
294 return (0);
295 }
296 brelse(bp);
297 if (bpp != NULL) {
298 error = bread(ip->i_fd, ip->i_fs, lbn,
299 (int)fs->fs_bsize, &nbp);
300 if (error) {
301 brelse(nbp);
302 goto fail;
303 }
304 *bpp = nbp;
305 }
306 return (0);
307 fail:
308 return (error);
309 }
310