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