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