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