386BSD 0.1 development
[unix-history] / usr / src / sys.386bsd / ufs / ufs_bmap.c
CommitLineData
b688fc87
WJ
1/*
2 * Copyright (c) 1982, 1986, 1989 Regents of the University of California.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by the University of
16 * California, Berkeley and its contributors.
17 * 4. 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 * @(#)ufs_bmap.c 7.13 (Berkeley) 5/8/91
34 */
35
36#include "param.h"
37#include "systm.h"
38#include "buf.h"
39#include "proc.h"
40#include "file.h"
41#include "vnode.h"
42
43#include "quota.h"
44#include "inode.h"
45#include "fs.h"
46
47/*
48 * Bmap converts a the logical block number of a file
49 * to its physical block number on the disk. The conversion
50 * is done by using the logical block number to index into
51 * the array of block pointers described by the dinode.
52 */
53bmap(ip, bn, bnp)
54 register struct inode *ip;
55 register daddr_t bn;
56 daddr_t *bnp;
57{
58 register struct fs *fs;
59 register daddr_t nb;
60 struct buf *bp;
61 daddr_t *bap;
62 int i, j, sh;
63 int error;
64
65 if (bn < 0)
66 return (EFBIG);
67 fs = ip->i_fs;
68
69 /*
70 * The first NDADDR blocks are direct blocks
71 */
72 if (bn < NDADDR) {
73 nb = ip->i_db[bn];
74 if (nb == 0) {
75 *bnp = (daddr_t)-1;
76 return (0);
77 }
78 *bnp = fsbtodb(fs, nb);
79 return (0);
80 }
81 /*
82 * Determine the number of levels of indirection.
83 */
84 sh = 1;
85 bn -= NDADDR;
86 for (j = NIADDR; j > 0; j--) {
87 sh *= NINDIR(fs);
88 if (bn < sh)
89 break;
90 bn -= sh;
91 }
92 if (j == 0)
93 return (EFBIG);
94 /*
95 * Fetch through the indirect blocks.
96 */
97 nb = ip->i_ib[NIADDR - j];
98 if (nb == 0) {
99 *bnp = (daddr_t)-1;
100 return (0);
101 }
102 for (; j <= NIADDR; j++) {
103 if (error = bread(ip->i_devvp, fsbtodb(fs, nb),
104 (int)fs->fs_bsize, NOCRED, &bp)) {
105 brelse(bp);
106 return (error);
107 }
108 bap = bp->b_un.b_daddr;
109 sh /= NINDIR(fs);
110 i = (bn / sh) % NINDIR(fs);
111 nb = bap[i];
112 if (nb == 0) {
113 *bnp = (daddr_t)-1;
114 brelse(bp);
115 return (0);
116 }
117 brelse(bp);
118 }
119 *bnp = fsbtodb(fs, nb);
120 return (0);
121}
122
123/*
124 * Balloc defines the structure of file system storage
125 * by allocating the physical blocks on a device given
126 * the inode and the logical block number in a file.
127 */
128balloc(ip, bn, size, bpp, flags)
129 register struct inode *ip;
130 register daddr_t bn;
131 int size;
132 struct buf **bpp;
133 int flags;
134{
135 register struct fs *fs;
136 register daddr_t nb;
137 struct buf *bp, *nbp;
138 struct vnode *vp = ITOV(ip);
139 int osize, nsize, i, j, sh, error;
140 daddr_t newb, lbn, *bap, pref, blkpref();
141
142 *bpp = (struct buf *)0;
143 if (bn < 0)
144 return (EFBIG);
145 fs = ip->i_fs;
146
147 /*
148 * If the next write will extend the file into a new block,
149 * and the file is currently composed of a fragment
150 * this fragment has to be extended to be a full block.
151 */
152 nb = lblkno(fs, ip->i_size);
153 if (nb < NDADDR && nb < bn) {
154 osize = blksize(fs, ip, nb);
155 if (osize < fs->fs_bsize && osize > 0) {
156 error = realloccg(ip, nb,
157 blkpref(ip, nb, (int)nb, &ip->i_db[0]),
158 osize, (int)fs->fs_bsize, &bp);
159 if (error)
160 return (error);
161 ip->i_size = (nb + 1) * fs->fs_bsize;
162 vnode_pager_setsize(ITOV(ip), (u_long)ip->i_size);
163 ip->i_db[nb] = dbtofsb(fs, bp->b_blkno);
164 ip->i_flag |= IUPD|ICHG;
165 if (flags & B_SYNC)
166 bwrite(bp);
167 else
168 bawrite(bp);
169 }
170 }
171 /*
172 * The first NDADDR blocks are direct blocks
173 */
174 if (bn < NDADDR) {
175 nb = ip->i_db[bn];
176 if (nb != 0 && ip->i_size >= (bn + 1) * fs->fs_bsize) {
177 error = bread(vp, bn, fs->fs_bsize, NOCRED, &bp);
178 if (error) {
179 brelse(bp);
180 return (error);
181 }
182 *bpp = bp;
183 return (0);
184 }
185 if (nb != 0) {
186 /*
187 * Consider need to reallocate a fragment.
188 */
189 osize = fragroundup(fs, blkoff(fs, ip->i_size));
190 nsize = fragroundup(fs, size);
191 if (nsize <= osize) {
192 error = bread(vp, bn, osize, NOCRED, &bp);
193 if (error) {
194 brelse(bp);
195 return (error);
196 }
197 } else {
198 error = realloccg(ip, bn,
199 blkpref(ip, bn, (int)bn, &ip->i_db[0]),
200 osize, nsize, &bp);
201 if (error)
202 return (error);
203 }
204 } else {
205 if (ip->i_size < (bn + 1) * fs->fs_bsize)
206 nsize = fragroundup(fs, size);
207 else
208 nsize = fs->fs_bsize;
209 error = alloc(ip, bn,
210 blkpref(ip, bn, (int)bn, &ip->i_db[0]),
211 nsize, &newb);
212 if (error)
213 return (error);
214 bp = getblk(vp, bn, nsize);
215 bp->b_blkno = fsbtodb(fs, newb);
216 if (flags & B_CLRBUF)
217 clrbuf(bp);
218 }
219 ip->i_db[bn] = dbtofsb(fs, bp->b_blkno);
220 ip->i_flag |= IUPD|ICHG;
221 *bpp = bp;
222 return (0);
223 }
224 /*
225 * Determine the number of levels of indirection.
226 */
227 pref = 0;
228 sh = 1;
229 lbn = bn;
230 bn -= NDADDR;
231 for (j = NIADDR; j > 0; j--) {
232 sh *= NINDIR(fs);
233 if (bn < sh)
234 break;
235 bn -= sh;
236 }
237 if (j == 0)
238 return (EFBIG);
239 /*
240 * Fetch the first indirect block allocating if necessary.
241 */
242 nb = ip->i_ib[NIADDR - j];
243 if (nb == 0) {
244 pref = blkpref(ip, lbn, 0, (daddr_t *)0);
245 if (error = alloc(ip, lbn, pref, (int)fs->fs_bsize, &newb))
246 return (error);
247 nb = newb;
248 bp = getblk(ip->i_devvp, fsbtodb(fs, nb), fs->fs_bsize);
249 clrbuf(bp);
250 /*
251 * Write synchronously so that indirect blocks
252 * never point at garbage.
253 */
254 if (error = bwrite(bp)) {
255 blkfree(ip, nb, fs->fs_bsize);
256 return (error);
257 }
258 ip->i_ib[NIADDR - j] = nb;
259 ip->i_flag |= IUPD|ICHG;
260 }
261 /*
262 * Fetch through the indirect blocks, allocating as necessary.
263 */
264 for (; ; j++) {
265 error = bread(ip->i_devvp, fsbtodb(fs, nb),
266 (int)fs->fs_bsize, NOCRED, &bp);
267 if (error) {
268 brelse(bp);
269 return (error);
270 }
271 bap = bp->b_un.b_daddr;
272 sh /= NINDIR(fs);
273 i = (bn / sh) % NINDIR(fs);
274 nb = bap[i];
275 if (j == NIADDR)
276 break;
277 if (nb != 0) {
278 brelse(bp);
279 continue;
280 }
281 if (pref == 0)
282 pref = blkpref(ip, lbn, 0, (daddr_t *)0);
283 if (error = alloc(ip, lbn, pref, (int)fs->fs_bsize, &newb)) {
284 brelse(bp);
285 return (error);
286 }
287 nb = newb;
288 nbp = getblk(ip->i_devvp, fsbtodb(fs, nb), fs->fs_bsize);
289 clrbuf(nbp);
290 /*
291 * Write synchronously so that indirect blocks
292 * never point at garbage.
293 */
294 if (error = bwrite(nbp)) {
295 blkfree(ip, nb, fs->fs_bsize);
296 brelse(bp);
297 return (error);
298 }
299 bap[i] = nb;
300 /*
301 * If required, write synchronously, otherwise use
302 * delayed write. If this is the first instance of
303 * the delayed write, reassociate the buffer with the
304 * file so it will be written if the file is sync'ed.
305 */
306 if (flags & B_SYNC) {
307 bwrite(bp);
308 } else if (bp->b_flags & B_DELWRI) {
309 bdwrite(bp);
310 } else {
311 bdwrite(bp);
312 reassignbuf(bp, vp);
313 }
314 }
315 /*
316 * Get the data block, allocating if necessary.
317 */
318 if (nb == 0) {
319 pref = blkpref(ip, lbn, i, &bap[0]);
320 if (error = alloc(ip, lbn, pref, (int)fs->fs_bsize, &newb)) {
321 brelse(bp);
322 return (error);
323 }
324 nb = newb;
325 nbp = getblk(vp, lbn, fs->fs_bsize);
326 nbp->b_blkno = fsbtodb(fs, nb);
327 if (flags & B_CLRBUF)
328 clrbuf(nbp);
329 bap[i] = nb;
330 /*
331 * If required, write synchronously, otherwise use
332 * delayed write. If this is the first instance of
333 * the delayed write, reassociate the buffer with the
334 * file so it will be written if the file is sync'ed.
335 */
336 if (flags & B_SYNC) {
337 bwrite(bp);
338 } else if (bp->b_flags & B_DELWRI) {
339 bdwrite(bp);
340 } else {
341 bdwrite(bp);
342 reassignbuf(bp, vp);
343 }
344 *bpp = nbp;
345 return (0);
346 }
347 brelse(bp);
348 if (flags & B_CLRBUF) {
349 error = bread(vp, lbn, (int)fs->fs_bsize, NOCRED, &nbp);
350 if (error) {
351 brelse(nbp);
352 return (error);
353 }
354 } else {
355 nbp = getblk(vp, lbn, fs->fs_bsize);
356 nbp->b_blkno = fsbtodb(fs, nb);
357 }
358 *bpp = nbp;
359 return (0);
360}