ffs_balloc.c revision 1.9 1 /* $NetBSD: ffs_balloc.c,v 1.9 1998/03/18 15:57:27 bouyer Exp $ */
2
3 /*
4 * Copyright (c) 1982, 1986, 1989, 1993
5 * The Regents of the University of California. All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
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. All advertising materials mentioning features or use of this software
16 * must display the following acknowledgement:
17 * This product includes software developed by the University of
18 * California, Berkeley and its contributors.
19 * 4. Neither the name of the University nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 *
35 * @(#)ffs_balloc.c 8.8 (Berkeley) 6/16/95
36 */
37
38 #include "opt_uvm.h"
39
40 #include <sys/param.h>
41 #include <sys/systm.h>
42 #include <sys/buf.h>
43 #include <sys/proc.h>
44 #include <sys/file.h>
45 #include <sys/vnode.h>
46 #include <sys/mount.h>
47
48 #include <vm/vm.h>
49
50 #if defined(UVM)
51 #include <uvm/uvm_extern.h>
52 #endif
53
54 #include <ufs/ufs/quota.h>
55 #include <ufs/ufs/ufsmount.h>
56 #include <ufs/ufs/inode.h>
57 #include <ufs/ufs/ufs_extern.h>
58 #include <ufs/ufs/ufs_bswap.h>
59
60 #include <ufs/ffs/fs.h>
61 #include <ufs/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 int
69 ffs_balloc(ip, lbn, size, cred, bpp, flags)
70 register struct inode *ip;
71 register ufs_daddr_t lbn;
72 int size;
73 struct ucred *cred;
74 struct buf **bpp;
75 int flags;
76 {
77 register struct fs *fs;
78 register ufs_daddr_t nb;
79 struct buf *bp, *nbp;
80 struct vnode *vp = ITOV(ip);
81 struct indir indirs[NIADDR + 2];
82 ufs_daddr_t newb, *bap, pref;
83 int deallocated, osize, nsize, num, i, error;
84 ufs_daddr_t *allocib, *blkp, *allocblk, allociblk[NIADDR + 1];
85
86 *bpp = NULL;
87 if (lbn < 0)
88 return (EFBIG);
89 fs = ip->i_fs;
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 nb = lblkno(fs, ip->i_ffs_size);
97 if (nb < NDADDR && nb < lbn) {
98 osize = blksize(fs, ip, nb);
99 if (osize < fs->fs_bsize && osize > 0) {
100 error = ffs_realloccg(ip, nb,
101 ffs_blkpref(ip, nb, (int)nb, &ip->i_ffs_db[0]),
102 osize, (int)fs->fs_bsize, cred, &bp);
103 if (error)
104 return (error);
105 ip->i_ffs_size = (nb + 1) * fs->fs_bsize;
106 #if defined(UVM)
107 uvm_vnp_setsize(vp, ip->i_ffs_size);
108 #else
109 vnode_pager_setsize(vp, ip->i_ffs_size);
110 #endif
111 ip->i_ffs_db[nb] = ufs_rw32(dbtofsb(fs, bp->b_blkno),
112 UFS_MPNEEDSWAP(vp->v_mount));
113 ip->i_flag |= IN_CHANGE | IN_UPDATE;
114 if (flags & B_SYNC)
115 bwrite(bp);
116 else
117 bawrite(bp);
118 }
119 }
120 /*
121 * The first NDADDR blocks are direct blocks
122 */
123 if (lbn < NDADDR) {
124 nb = ufs_rw32(ip->i_ffs_db[lbn], UFS_MPNEEDSWAP(vp->v_mount));
125 if (nb != 0 && ip->i_ffs_size >= (lbn + 1) * fs->fs_bsize) {
126 error = bread(vp, lbn, fs->fs_bsize, NOCRED, &bp);
127 if (error) {
128 brelse(bp);
129 return (error);
130 }
131 *bpp = bp;
132 return (0);
133 }
134 if (nb != 0) {
135 /*
136 * Consider need to reallocate a fragment.
137 */
138 osize = fragroundup(fs, blkoff(fs, ip->i_ffs_size));
139 nsize = fragroundup(fs, size);
140 if (nsize <= osize) {
141 error = bread(vp, lbn, osize, NOCRED, &bp);
142 if (error) {
143 brelse(bp);
144 return (error);
145 }
146 } else {
147 error = ffs_realloccg(ip, lbn,
148 ffs_blkpref(ip, lbn, (int)lbn,
149 &ip->i_ffs_db[0]), osize, nsize, cred,
150 &bp);
151 if (error)
152 return (error);
153 }
154 } else {
155 if (ip->i_ffs_size < (lbn + 1) * fs->fs_bsize)
156 nsize = fragroundup(fs, size);
157 else
158 nsize = fs->fs_bsize;
159 error = ffs_alloc(ip, lbn,
160 ffs_blkpref(ip, lbn, (int)lbn, &ip->i_ffs_db[0]),
161 nsize, cred, &newb);
162 if (error)
163 return (error);
164 bp = getblk(vp, lbn, nsize, 0, 0);
165 bp->b_blkno = fsbtodb(fs, newb);
166 if (flags & B_CLRBUF)
167 clrbuf(bp);
168 }
169 ip->i_ffs_db[lbn] = ufs_rw32(dbtofsb(fs, bp->b_blkno),
170 UFS_MPNEEDSWAP(vp->v_mount));
171 ip->i_flag |= IN_CHANGE | IN_UPDATE;
172 *bpp = bp;
173 return (0);
174 }
175 /*
176 * Determine the number of levels of indirection.
177 */
178 pref = 0;
179 if ((error = ufs_getlbns(vp, lbn, indirs, &num)) != 0)
180 return(error);
181 #ifdef DIAGNOSTIC
182 if (num < 1)
183 panic ("ffs_balloc: ufs_bmaparray returned indirect block\n");
184 #endif
185 /*
186 * Fetch the first indirect block allocating if necessary.
187 */
188 --num;
189 nb = ufs_rw32(ip->i_ffs_ib[indirs[0].in_off],
190 UFS_MPNEEDSWAP(vp->v_mount));
191 allocib = NULL;
192 allocblk = allociblk;
193 if (nb == 0) {
194 pref = ffs_blkpref(ip, lbn, 0, (ufs_daddr_t *)0);
195 error = ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize,
196 cred, &newb);
197 if (error)
198 return (error);
199 nb = newb;
200 *allocblk++ = nb;
201 bp = getblk(vp, indirs[1].in_lbn, fs->fs_bsize, 0, 0);
202 bp->b_blkno = fsbtodb(fs, nb);
203 clrbuf(bp);
204 /*
205 * Write synchronously so that indirect blocks
206 * never point at garbage.
207 */
208 if ((error = bwrite(bp)) != 0)
209 goto fail;
210 allocib = &ip->i_ffs_ib[indirs[0].in_off];
211 *allocib = ufs_rw32(nb, UFS_MPNEEDSWAP(vp->v_mount));
212 ip->i_flag |= IN_CHANGE | IN_UPDATE;
213 }
214 /*
215 * Fetch through the indirect blocks, allocating as necessary.
216 */
217 for (i = 1;;) {
218 error = bread(vp,
219 indirs[i].in_lbn, (int)fs->fs_bsize, NOCRED, &bp);
220 if (error) {
221 brelse(bp);
222 goto fail;
223 }
224 bap = (ufs_daddr_t *)bp->b_data;
225 nb = ufs_rw32(bap[indirs[i].in_off], UFS_MPNEEDSWAP(vp->v_mount));
226 if (i == num)
227 break;
228 i += 1;
229 if (nb != 0) {
230 brelse(bp);
231 continue;
232 }
233 if (pref == 0)
234 pref = ffs_blkpref(ip, lbn, 0, (ufs_daddr_t *)0);
235 error = ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize, cred,
236 &newb);
237 if (error) {
238 brelse(bp);
239 goto fail;
240 }
241 nb = newb;
242 *allocblk++ = nb;
243 nbp = getblk(vp, indirs[i].in_lbn, fs->fs_bsize, 0, 0);
244 nbp->b_blkno = fsbtodb(fs, nb);
245 clrbuf(nbp);
246 /*
247 * Write synchronously so that indirect blocks
248 * never point at garbage.
249 */
250 if ((error = bwrite(nbp)) != 0) {
251 brelse(bp);
252 goto fail;
253 }
254 bap[indirs[i - 1].in_off] = ufs_rw32(nb,
255 UFS_MPNEEDSWAP(vp->v_mount));
256 /*
257 * If required, write synchronously, otherwise use
258 * delayed write.
259 */
260 if (flags & B_SYNC) {
261 bwrite(bp);
262 } else {
263 bdwrite(bp);
264 }
265 }
266 /*
267 * Get the data block, allocating if necessary.
268 */
269 if (nb == 0) {
270 pref = ffs_blkpref(ip, lbn, indirs[i].in_off, &bap[0]);
271 error = ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize, cred,
272 &newb);
273 if (error) {
274 brelse(bp);
275 goto fail;
276 }
277 nb = newb;
278 *allocblk++ = nb;
279 nbp = getblk(vp, lbn, fs->fs_bsize, 0, 0);
280 nbp->b_blkno = fsbtodb(fs, nb);
281 if (flags & B_CLRBUF)
282 clrbuf(nbp);
283 bap[indirs[i].in_off] = ufs_rw32(nb, UFS_MPNEEDSWAP(vp->v_mount));
284 /*
285 * If required, write synchronously, otherwise use
286 * delayed write.
287 */
288 if (flags & B_SYNC) {
289 bwrite(bp);
290 } else {
291 bdwrite(bp);
292 }
293 *bpp = nbp;
294 return (0);
295 }
296 brelse(bp);
297 if (flags & B_CLRBUF) {
298 error = bread(vp, lbn, (int)fs->fs_bsize, NOCRED, &nbp);
299 if (error) {
300 brelse(nbp);
301 goto fail;
302 }
303 } else {
304 nbp = getblk(vp, lbn, fs->fs_bsize, 0, 0);
305 nbp->b_blkno = fsbtodb(fs, nb);
306 }
307 *bpp = nbp;
308 return (0);
309 fail:
310 /*
311 * If we have failed part way through block allocation, we
312 * have to deallocate any indirect blocks that we have allocated.
313 */
314 for (deallocated = 0, blkp = allociblk; blkp < allocblk; blkp++) {
315 ffs_blkfree(ip, *blkp, fs->fs_bsize);
316 deallocated += fs->fs_bsize;
317 }
318 if (allocib != NULL)
319 *allocib = 0;
320 if (deallocated) {
321 #ifdef QUOTA
322 /*
323 * Restore user's disk quota because allocation failed.
324 */
325 (void)chkdq(ip, (long)-btodb(deallocated), cred, FORCE);
326 #endif
327 ip->i_ffs_blocks -= btodb(deallocated);
328 ip->i_ffs_flags |= IN_CHANGE | IN_UPDATE;
329 }
330 return (error);
331 }
332