1 /* $OpenBSD: ext2fs_balloc.c,v 1.14 2007/06/02 00:45:50 pedro Exp $ */
2 /* $NetBSD: ext2fs_balloc.c,v 1.10 2001/07/04 21:16:01 chs Exp $ */
3
4 /*
5 * Copyright (c) 1997 Manuel Bouyer.
6 * Copyright (c) 1982, 1986, 1989, 1993
7 * The Regents of the University of California. All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 *
33 * @(#)ffs_balloc.c 8.4 (Berkeley) 9/23/93
34 * Modified for ext2fs by Manuel Bouyer.
35 */
36
37 #include <sys/param.h>
38 #include <sys/systm.h>
39 #include <sys/buf.h>
40 #include <sys/proc.h>
41 #include <sys/file.h>
42 #include <sys/vnode.h>
43
44 #include <uvm/uvm_extern.h>
45
46 #include <ufs/ufs/quota.h>
47 #include <ufs/ufs/inode.h>
48 #include <ufs/ufs/ufs_extern.h>
49
50 #include <ufs/ext2fs/ext2fs.h>
51 #include <ufs/ext2fs/ext2fs_extern.h>
52
53 /*
54 * Balloc defines the structure of file system storage
55 * by allocating the physical blocks on a device given
56 * the inode and the logical block number in a file.
57 */
58 int
59 ext2fs_buf_alloc(struct inode *ip, daddr_t bn, int size, struct ucred *cred,
60 struct buf **bpp, int flags)
61 {
62 struct m_ext2fs *fs;
63 int32_t nb;
64 struct buf *bp, *nbp;
65 struct vnode *vp = ITOV(ip);
66 struct indir indirs[NIADDR + 2];
67 int32_t newb, lbn, *bap, pref;
68 int num, i, error;
69 u_int deallocated;
70 int32_t *allocib, *blkp, *allocblk, allociblk[NIADDR + 1];
71 int unwindidx = -1;
72
73 *bpp = NULL;
74 if (bn < 0)
75 return (EFBIG);
76 fs = ip->i_e2fs;
77 lbn = bn;
78
79 /*
80 * The first NDADDR blocks are direct blocks
81 */
82 if (bn < NDADDR) {
83 nb = fs2h32(ip->i_e2fs_blocks[bn]);
84 if (nb != 0) {
85 error = bread(vp, bn, fs->e2fs_bsize, NOCRED, &bp);
86 if (error) {
87 brelse(bp);
88 return (error);
89 }
90 *bpp = bp;
91 return (0);
92 }
93
94 /*
95 * allocate a new direct block.
96 */
97 error = ext2fs_alloc(ip, bn,
98 ext2fs_blkpref(ip, bn, (int)bn, &ip->i_e2fs_blocks[0]),
99 cred, &newb);
100 if (error)
101 return (error);
102 ip->i_e2fs_last_lblk = lbn;
103 ip->i_e2fs_last_blk = newb;
104 ip->i_e2fs_blocks[bn] = h2fs32(newb);
105 ip->i_flag |= IN_CHANGE | IN_UPDATE;
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 *bpp = bp;
111 return (0);
112 }
113 /*
114 * Determine the number of levels of indirection.
115 */
116 pref = 0;
117 if ((error = ufs_getlbns(vp, bn, indirs, &num)) != 0)
118 return(error);
119 #ifdef DIAGNOSTIC
120 if (num < 1)
121 panic ("ext2fs_balloc: ufs_getlbns returned indirect block");
122 #endif
123 /*
124 * Fetch the first indirect block allocating if necessary.
125 */
126 --num;
127 nb = fs2h32(ip->i_e2fs_blocks[NDADDR + indirs[0].in_off]);
128 allocib = NULL;
129 allocblk = allociblk;
130 if (nb == 0) {
131 pref = ext2fs_blkpref(ip, lbn, 0, (int32_t *)0);
132 error = ext2fs_alloc(ip, lbn, pref, cred, &newb);
133 if (error)
134 return (error);
135 nb = newb;
136 *allocblk++ = nb;
137 ip->i_e2fs_last_blk = newb;
138 bp = getblk(vp, indirs[1].in_lbn, fs->e2fs_bsize, 0, 0);
139 bp->b_blkno = fsbtodb(fs, newb);
140 clrbuf(bp);
141 /*
142 * Write synchronously so that indirect blocks
143 * never point at garbage.
144 */
145 if ((error = bwrite(bp)) != 0)
146 goto fail;
147 unwindidx = 0;
148 allocib = &ip->i_e2fs_blocks[NDADDR + indirs[0].in_off];
149 *allocib = h2fs32(newb);
150 ip->i_flag |= IN_CHANGE | IN_UPDATE;
151 }
152 /*
153 * Fetch through the indirect blocks, allocating as necessary.
154 */
155 for (i = 1;;) {
156 error = bread(vp,
157 indirs[i].in_lbn, (int)fs->e2fs_bsize, NOCRED, &bp);
158 if (error) {
159 brelse(bp);
160 goto fail;
161 }
162 bap = (int32_t *)bp->b_data;
163 nb = fs2h32(bap[indirs[i].in_off]);
164 if (i == num)
165 break;
166 i++;
167 if (nb != 0) {
168 brelse(bp);
169 continue;
170 }
171 pref = ext2fs_blkpref(ip, lbn, 0, (int32_t *)0);
172 error = ext2fs_alloc(ip, lbn, pref, cred, &newb);
173 if (error) {
174 brelse(bp);
175 goto fail;
176 }
177 nb = newb;
178 *allocblk++ = nb;
179 ip->i_e2fs_last_blk = newb;
180 nbp = getblk(vp, indirs[i].in_lbn, fs->e2fs_bsize, 0, 0);
181 nbp->b_blkno = fsbtodb(fs, nb);
182 clrbuf(nbp);
183 /*
184 * Write synchronously so that indirect blocks
185 * never point at garbage.
186 */
187 if ((error = bwrite(nbp)) != 0) {
188 brelse(bp);
189 goto fail;
190 }
191 if (unwindidx < 0)
192 unwindidx = i - 1;
193 bap[indirs[i - 1].in_off] = h2fs32(nb);
194 /*
195 * If required, write synchronously, otherwise use
196 * delayed write.
197 */
198 if (flags & B_SYNC) {
199 bwrite(bp);
200 } else {
201 bdwrite(bp);
202 }
203 }
204 /*
205 * Get the data block, allocating if necessary.
206 */
207 if (nb == 0) {
208 pref = ext2fs_blkpref(ip, lbn, indirs[num].in_off, &bap[0]);
209 error = ext2fs_alloc(ip, lbn, pref, cred, &newb);
210 if (error) {
211 brelse(bp);
212 goto fail;
213 }
214 nb = newb;
215 *allocblk++ = nb;
216 ip->i_e2fs_last_lblk = lbn;
217 ip->i_e2fs_last_blk = newb;
218 bap[indirs[num].in_off] = h2fs32(nb);
219 /*
220 * If required, write synchronously, otherwise use
221 * delayed write.
222 */
223 if (flags & B_SYNC) {
224 bwrite(bp);
225 } else {
226 bdwrite(bp);
227 }
228 nbp = getblk(vp, lbn, fs->e2fs_bsize, 0, 0);
229 nbp->b_blkno = fsbtodb(fs, nb);
230 if (flags & B_CLRBUF)
231 clrbuf(nbp);
232 *bpp = nbp;
233 return (0);
234 }
235 brelse(bp);
236 if (flags & B_CLRBUF) {
237 error = bread(vp, lbn, (int)fs->e2fs_bsize, NOCRED, &nbp);
238 if (error) {
239 brelse(nbp);
240 goto fail;
241 }
242 } else {
243 nbp = getblk(vp, lbn, fs->e2fs_bsize, 0, 0);
244 nbp->b_blkno = fsbtodb(fs, nb);
245 }
246
247 *bpp = nbp;
248 return (0);
249 fail:
250 /*
251 * If we have failed part way through block allocation, we
252 * have to deallocate any indirect blocks that we have allocated.
253 */
254 for (deallocated = 0, blkp = allociblk; blkp < allocblk; blkp++) {
255 ext2fs_blkfree(ip, *blkp);
256 deallocated += fs->e2fs_bsize;
257 }
258 if (unwindidx >= 0) {
259 if (unwindidx == 0) {
260 *allocib = 0;
261 } else {
262 int r;
263
264 r = bread(vp, indirs[unwindidx].in_lbn,
265 (int)fs->e2fs_bsize, NOCRED, &bp);
266 if (r) {
267 panic("Could not unwind indirect block, error %d", r);
268 brelse(bp);
269 } else {
270 bap = (int32_t *)bp->b_data;
271 bap[indirs[unwindidx].in_off] = 0;
272 if (flags & B_SYNC)
273 bwrite(bp);
274 else
275 bdwrite(bp);
276 }
277 }
278 for (i = unwindidx + 1; i <= num; i++) {
279 bp = getblk(vp, indirs[i].in_lbn, (int)fs->e2fs_bsize,
280 0, 0);
281 bp->b_flags |= B_INVAL;
282 brelse(bp);
283 }
284 }
285 if (deallocated) {
286 ip->i_e2fs_nblock -= btodb(deallocated);
287 ip->i_e2fs_flags |= IN_CHANGE | IN_UPDATE;
288 }
289 return error;
290 }