ext2fs_balloc.c revision 1.3.14.1 1 /* $NetBSD: ext2fs_balloc.c,v 1.3.14.1 2000/11/20 18:11:41 bouyer Exp $ */
2
3 /*
4 * Copyright (c) 1997 Manuel Bouyer.
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.4 (Berkeley) 9/23/93
37 * Modified for ext2fs by Manuel Bouyer.
38 */
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
47 #include <ufs/ufs/quota.h>
48 #include <ufs/ufs/inode.h>
49 #include <ufs/ufs/ufs_extern.h>
50
51 #include <ufs/ext2fs/ext2fs.h>
52 #include <ufs/ext2fs/ext2fs_extern.h>
53
54 /*
55 * Balloc defines the structure of file system storage
56 * by allocating the physical blocks on a device given
57 * the inode and the logical block number in a file.
58 */
59 int
60 ext2fs_balloc(ip, bn, size, cred, bpp, flags)
61 struct inode *ip;
62 ufs_daddr_t bn;
63 int size;
64 struct ucred *cred;
65 struct buf **bpp;
66 int flags;
67 {
68 struct m_ext2fs *fs;
69 ufs_daddr_t nb;
70 struct buf *bp, *nbp;
71 struct vnode *vp = ITOV(ip);
72 struct indir indirs[NIADDR + 2];
73 ufs_daddr_t newb, lbn, *bap, pref;
74 int num, i, error;
75 u_int deallocated;
76 ufs_daddr_t *allocib, *blkp, *allocblk, allociblk[NIADDR + 1];
77 int unwindidx = -1;
78
79 *bpp = NULL;
80 if (bn < 0)
81 return (EFBIG);
82 fs = ip->i_e2fs;
83 lbn = bn;
84
85 /*
86 * The first NDADDR blocks are direct blocks
87 */
88 if (bn < NDADDR) {
89 nb = fs2h32(ip->i_e2fs_blocks[bn]);
90 if (nb != 0) {
91 error = bread(vp, bn, fs->e2fs_bsize, NOCRED, &bp);
92 if (error) {
93 brelse(bp);
94 return (error);
95 }
96 *bpp = bp;
97 return (0);
98 } else {
99 error = ext2fs_alloc(ip, bn,
100 ext2fs_blkpref(ip, bn, (int)bn, &ip->i_e2fs_blocks[0]),
101 cred, &newb);
102 if (error)
103 return (error);
104 ip->i_e2fs_last_lblk = lbn;
105 ip->i_e2fs_last_blk = newb;
106 bp = getblk(vp, bn, fs->e2fs_bsize, 0, 0);
107 bp->b_blkno = fsbtodb(fs, newb);
108 if (flags & B_CLRBUF)
109 clrbuf(bp);
110 }
111 ip->i_e2fs_blocks[bn] = h2fs32(dbtofsb(fs, bp->b_blkno));
112 ip->i_flag |= IN_CHANGE | IN_UPDATE;
113 *bpp = bp;
114 return (0);
115 }
116 /*
117 * Determine the number of levels of indirection.
118 */
119 pref = 0;
120 if ((error = ufs_getlbns(vp, bn, indirs, &num)) != 0)
121 return(error);
122 #ifdef DIAGNOSTIC
123 if (num < 1)
124 panic ("ext2fs_balloc: ufs_getlbns returned indirect block\n");
125 #endif
126 /*
127 * Fetch the first indirect block allocating if necessary.
128 */
129 --num;
130 nb = fs2h32(ip->i_e2fs_blocks[NDADDR + indirs[0].in_off]);
131 allocib = NULL;
132 allocblk = allociblk;
133 if (nb == 0) {
134 pref = ext2fs_blkpref(ip, lbn, 0, (ufs_daddr_t *)0);
135 error = ext2fs_alloc(ip, lbn, pref, cred, &newb);
136 if (error)
137 return (error);
138 nb = newb;
139 *allocblk++ = nb;
140 ip->i_e2fs_last_blk = newb;
141 bp = getblk(vp, indirs[1].in_lbn, fs->e2fs_bsize, 0, 0);
142 bp->b_blkno = fsbtodb(fs, newb);
143 clrbuf(bp);
144 /*
145 * Write synchronously so that indirect blocks
146 * never point at garbage.
147 */
148 if ((error = bwrite(bp)) != 0)
149 goto fail;
150 unwindidx = 0;
151 allocib = &ip->i_e2fs_blocks[NDADDR + indirs[0].in_off];
152 *allocib = h2fs32(newb);
153 ip->i_flag |= IN_CHANGE | IN_UPDATE;
154 }
155 /*
156 * Fetch through the indirect blocks, allocating as necessary.
157 */
158 for (i = 1;;) {
159 error = bread(vp,
160 indirs[i].in_lbn, (int)fs->e2fs_bsize, NOCRED, &bp);
161 if (error) {
162 brelse(bp);
163 goto fail;
164 }
165 bap = (ufs_daddr_t *)bp->b_data;
166 nb = fs2h32(bap[indirs[i].in_off]);
167 if (i == num)
168 break;
169 i++;
170 if (nb != 0) {
171 brelse(bp);
172 continue;
173 }
174 pref = ext2fs_blkpref(ip, lbn, 0, (ufs_daddr_t *)0);
175 error = ext2fs_alloc(ip, lbn, pref, cred, &newb);
176 if (error) {
177 brelse(bp);
178 goto fail;
179 }
180 nb = newb;
181 *allocblk++ = nb;
182 ip->i_e2fs_last_blk = newb;
183 nbp = getblk(vp, indirs[i].in_lbn, fs->e2fs_bsize, 0, 0);
184 nbp->b_blkno = fsbtodb(fs, nb);
185 clrbuf(nbp);
186 /*
187 * Write synchronously so that indirect blocks
188 * never point at garbage.
189 */
190 if ((error = bwrite(nbp)) != 0) {
191 brelse(bp);
192 goto fail;
193 }
194 if (unwindidx < 0)
195 unwindidx = i - 1;
196 bap[indirs[i - 1].in_off] = h2fs32(nb);
197 /*
198 * If required, write synchronously, otherwise use
199 * delayed write.
200 */
201 if (flags & B_SYNC) {
202 bwrite(bp);
203 } else {
204 bdwrite(bp);
205 }
206 }
207 /*
208 * Get the data block, allocating if necessary.
209 */
210 if (nb == 0) {
211 pref = ext2fs_blkpref(ip, lbn, indirs[num].in_off, &bap[0]);
212 error = ext2fs_alloc(ip, lbn, pref, cred, &newb);
213 if (error) {
214 brelse(bp);
215 goto fail;
216 }
217 nb = newb;
218 *allocblk++ = nb;
219 ip->i_e2fs_last_lblk = lbn;
220 ip->i_e2fs_last_blk = newb;
221 nbp = getblk(vp, lbn, fs->e2fs_bsize, 0, 0);
222 nbp->b_blkno = fsbtodb(fs, nb);
223 if (flags & B_CLRBUF)
224 clrbuf(nbp);
225 bap[indirs[num].in_off] = h2fs32(nb);
226 /*
227 * If required, write synchronously, otherwise use
228 * delayed write.
229 */
230 if (flags & B_SYNC) {
231 bwrite(bp);
232 } else {
233 bdwrite(bp);
234 }
235 *bpp = nbp;
236 return (0);
237 }
238 brelse(bp);
239 if (flags & B_CLRBUF) {
240 error = bread(vp, lbn, (int)fs->e2fs_bsize, NOCRED, &nbp);
241 if (error) {
242 brelse(nbp);
243 goto fail;
244 }
245 } else {
246 nbp = getblk(vp, lbn, fs->e2fs_bsize, 0, 0);
247 nbp->b_blkno = fsbtodb(fs, nb);
248 }
249 *bpp = nbp;
250 return (0);
251 fail:
252 /*
253 * If we have failed part way through block allocation, we
254 * have to deallocate any indirect blocks that we have allocated.
255 */
256 for (deallocated = 0, blkp = allociblk; blkp < allocblk; blkp++) {
257 ext2fs_blkfree(ip, *blkp);
258 deallocated += fs->e2fs_bsize;
259 }
260 if (unwindidx >= 0) {
261 if (unwindidx == 0) {
262 *allocib = 0;
263 } else {
264 int r;
265
266 r = bread(vp, indirs[unwindidx].in_lbn,
267 (int)fs->e2fs_bsize, NOCRED, &bp);
268 if (r) {
269 panic("Could not unwind indirect block, error %d", r);
270 brelse(bp);
271 } else {
272 bap = (ufs_daddr_t *)bp->b_data;
273 bap[indirs[unwindidx].in_off] = 0;
274 if (flags & B_SYNC)
275 bwrite(bp);
276 else
277 bdwrite(bp);
278 }
279 }
280 for (i = unwindidx + 1; i <= num; i++) {
281 bp = getblk(vp, indirs[i].in_lbn, (int)fs->e2fs_bsize,
282 0, 0);
283 bp->b_flags |= B_INVAL;
284 brelse(bp);
285 }
286 }
287 if (deallocated) {
288 ip->i_e2fs_nblock -= btodb(deallocated);
289 ip->i_e2fs_flags |= IN_CHANGE | IN_UPDATE;
290 }
291 return (error);
292 }
293