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