ffs_balloc.c revision 33108
1219820Sjeff/*
2219820Sjeff * Copyright (c) 1982, 1986, 1989, 1993
3219820Sjeff *	The Regents of the University of California.  All rights reserved.
4219820Sjeff *
5219820Sjeff * Redistribution and use in source and binary forms, with or without
6219820Sjeff * modification, are permitted provided that the following conditions
7219820Sjeff * are met:
8219820Sjeff * 1. Redistributions of source code must retain the above copyright
9219820Sjeff *    notice, this list of conditions and the following disclaimer.
10219820Sjeff * 2. Redistributions in binary form must reproduce the above copyright
11219820Sjeff *    notice, this list of conditions and the following disclaimer in the
12219820Sjeff *    documentation and/or other materials provided with the distribution.
13219820Sjeff * 3. All advertising materials mentioning features or use of this software
14219820Sjeff *    must display the following acknowledgement:
15219820Sjeff *	This product includes software developed by the University of
16219820Sjeff *	California, Berkeley and its contributors.
17219820Sjeff * 4. Neither the name of the University nor the names of its contributors
18219820Sjeff *    may be used to endorse or promote products derived from this software
19219820Sjeff *    without specific prior written permission.
20219820Sjeff *
21219820Sjeff * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22219820Sjeff * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23219820Sjeff * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24219820Sjeff * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25219820Sjeff * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26219820Sjeff * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27219820Sjeff * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28219820Sjeff * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29219820Sjeff * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30219820Sjeff * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31219820Sjeff * SUCH DAMAGE.
32219820Sjeff *
33219820Sjeff *	@(#)ffs_balloc.c	8.8 (Berkeley) 6/16/95
34219820Sjeff * $Id: ffs_balloc.c,v 1.17 1998/01/06 05:23:33 dyson Exp $
35219820Sjeff */
36219820Sjeff
37219820Sjeff#include "opt_diagnostic.h"
38219820Sjeff
39219820Sjeff#include <sys/param.h>
40219820Sjeff#include <sys/systm.h>
41219820Sjeff#include <sys/buf.h>
42219820Sjeff#include <sys/lock.h>
43219820Sjeff#include <sys/vnode.h>
44219820Sjeff
45219820Sjeff#include <ufs/ufs/quota.h>
46219820Sjeff#include <ufs/ufs/inode.h>
47219820Sjeff#include <ufs/ufs/ufs_extern.h>
48219820Sjeff
49219820Sjeff#include <ufs/ffs/fs.h>
50219820Sjeff#include <ufs/ffs/ffs_extern.h>
51219820Sjeff
52219820Sjeff/*
53219820Sjeff * Balloc defines the structure of file system storage
54219820Sjeff * by allocating the physical blocks on a device given
55219820Sjeff * the inode and the logical block number in a file.
56219820Sjeff */
57219820Sjeffint
58219820Sjeffffs_balloc(ip, lbn, size, cred, bpp, flags)
59219820Sjeff	register struct inode *ip;
60219820Sjeff	register ufs_daddr_t lbn;
61219820Sjeff	int size;
62219820Sjeff	struct ucred *cred;
63219820Sjeff	struct buf **bpp;
64219820Sjeff	int flags;
65219820Sjeff{
66219820Sjeff	register struct fs *fs;
67219820Sjeff	register ufs_daddr_t nb;
68219820Sjeff	struct buf *bp, *nbp;
69219820Sjeff	struct vnode *vp = ITOV(ip);
70219820Sjeff	struct indir indirs[NIADDR + 2];
71219820Sjeff	ufs_daddr_t newb, *bap, pref;
72219820Sjeff	int deallocated, osize, nsize, num, i, error;
73219820Sjeff	ufs_daddr_t *allocib, *blkp, *allocblk, allociblk[NIADDR + 1];
74219820Sjeff
75219820Sjeff	*bpp = NULL;
76219820Sjeff	if (lbn < 0)
77219820Sjeff		return (EFBIG);
78219820Sjeff	fs = ip->i_fs;
79219820Sjeff
80219820Sjeff	/*
81219820Sjeff	 * If the next write will extend the file into a new block,
82219820Sjeff	 * and the file is currently composed of a fragment
83219820Sjeff	 * this fragment has to be extended to be a full block.
84219820Sjeff	 */
85219820Sjeff	nb = lblkno(fs, ip->i_size);
86219820Sjeff	if (nb < NDADDR && nb < lbn) {
87219820Sjeff		osize = blksize(fs, ip, nb);
88219820Sjeff		if (osize < fs->fs_bsize && osize > 0) {
89219820Sjeff			error = ffs_realloccg(ip, nb,
90219820Sjeff				ffs_blkpref(ip, nb, (int)nb, &ip->i_db[0]),
91219820Sjeff				osize, (int)fs->fs_bsize, cred, &bp);
92219820Sjeff			if (error)
93219820Sjeff				return (error);
94219820Sjeff			ip->i_size = smalllblktosize(fs, nb + 1);
95219820Sjeff			ip->i_db[nb] = dbtofsb(fs, bp->b_blkno);
96219820Sjeff			ip->i_flag |= IN_CHANGE | IN_UPDATE;
97219820Sjeff			if (flags & B_SYNC)
98219820Sjeff				bwrite(bp);
99219820Sjeff			else
100219820Sjeff				bawrite(bp);
101219820Sjeff		}
102219820Sjeff	}
103219820Sjeff	/*
104219820Sjeff	 * The first NDADDR blocks are direct blocks
105219820Sjeff	 */
106219820Sjeff	if (lbn < NDADDR) {
107219820Sjeff		nb = ip->i_db[lbn];
108219820Sjeff		if (nb != 0 && ip->i_size >= smalllblktosize(fs, lbn + 1)) {
109219820Sjeff			error = bread(vp, lbn, fs->fs_bsize, NOCRED, &bp);
110219820Sjeff			if (error) {
111219820Sjeff				brelse(bp);
112219820Sjeff				return (error);
113219820Sjeff			}
114219820Sjeff			bp->b_blkno = fsbtodb(fs, nb);
115219820Sjeff			*bpp = bp;
116219820Sjeff			return (0);
117219820Sjeff		}
118219820Sjeff		if (nb != 0) {
119219820Sjeff			/*
120219820Sjeff			 * Consider need to reallocate a fragment.
121219820Sjeff			 */
122219820Sjeff			osize = fragroundup(fs, blkoff(fs, ip->i_size));
123219820Sjeff			nsize = fragroundup(fs, size);
124219820Sjeff			if (nsize <= osize) {
125219820Sjeff				error = bread(vp, lbn, osize, NOCRED, &bp);
126219820Sjeff				if (error) {
127219820Sjeff					brelse(bp);
128219820Sjeff					return (error);
129219820Sjeff				}
130219820Sjeff				bp->b_blkno = fsbtodb(fs, nb);
131219820Sjeff			} else {
132219820Sjeff				error = ffs_realloccg(ip, lbn,
133219820Sjeff				    ffs_blkpref(ip, lbn, (int)lbn,
134219820Sjeff					&ip->i_db[0]), osize, nsize, cred, &bp);
135219820Sjeff				if (error)
136219820Sjeff					return (error);
137219820Sjeff			}
138219820Sjeff		} else {
139219820Sjeff			if (ip->i_size < smalllblktosize(fs, lbn + 1))
140219820Sjeff				nsize = fragroundup(fs, size);
141219820Sjeff			else
142219820Sjeff				nsize = fs->fs_bsize;
143219820Sjeff			error = ffs_alloc(ip, lbn,
144219820Sjeff			    ffs_blkpref(ip, lbn, (int)lbn, &ip->i_db[0]),
145219820Sjeff			    nsize, cred, &newb);
146219820Sjeff			if (error)
147219820Sjeff				return (error);
148219820Sjeff			bp = getblk(vp, lbn, nsize, 0, 0);
149219820Sjeff			bp->b_blkno = fsbtodb(fs, newb);
150219820Sjeff			if (flags & B_CLRBUF)
151219820Sjeff				vfs_bio_clrbuf(bp);
152219820Sjeff		}
153219820Sjeff		ip->i_db[lbn] = dbtofsb(fs, bp->b_blkno);
154219820Sjeff		ip->i_flag |= IN_CHANGE | IN_UPDATE;
155219820Sjeff		*bpp = bp;
156219820Sjeff		return (0);
157219820Sjeff	}
158219820Sjeff	/*
159219820Sjeff	 * Determine the number of levels of indirection.
160219820Sjeff	 */
161219820Sjeff	pref = 0;
162219820Sjeff	if (error = ufs_getlbns(vp, lbn, indirs, &num))
163219820Sjeff		return(error);
164219820Sjeff#ifdef DIAGNOSTIC
165219820Sjeff	if (num < 1)
166219820Sjeff		panic ("ffs_balloc: ufs_bmaparray returned indirect block");
167219820Sjeff#endif
168219820Sjeff	/*
169219820Sjeff	 * Fetch the first indirect block allocating if necessary.
170219820Sjeff	 */
171219820Sjeff	--num;
172219820Sjeff	nb = ip->i_ib[indirs[0].in_off];
173219820Sjeff	allocib = NULL;
174219820Sjeff	allocblk = allociblk;
175219820Sjeff	if (nb == 0) {
176219820Sjeff		pref = ffs_blkpref(ip, lbn, 0, (ufs_daddr_t *)0);
177219820Sjeff	        if (error = ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize,
178219820Sjeff		    cred, &newb))
179219820Sjeff			return (error);
180219820Sjeff		nb = newb;
181219820Sjeff		*allocblk++ = nb;
182219820Sjeff		bp = getblk(vp, indirs[1].in_lbn, fs->fs_bsize, 0, 0);
183219820Sjeff		bp->b_blkno = fsbtodb(fs, nb);
184219820Sjeff		vfs_bio_clrbuf(bp);
185219820Sjeff		/*
186219820Sjeff		 * Write synchronously so that indirect blocks
187219820Sjeff		 * never point at garbage.
188219820Sjeff		 */
189219820Sjeff		if (error = bwrite(bp))
190219820Sjeff			goto fail;
191219820Sjeff		allocib = &ip->i_ib[indirs[0].in_off];
192219820Sjeff		*allocib = nb;
193219820Sjeff		ip->i_flag |= IN_CHANGE | IN_UPDATE;
194219820Sjeff	}
195219820Sjeff	/*
196219820Sjeff	 * Fetch through the indirect blocks, allocating as necessary.
197219820Sjeff	 */
198219820Sjeff	for (i = 1;;) {
199219820Sjeff		error = bread(vp,
200219820Sjeff		    indirs[i].in_lbn, (int)fs->fs_bsize, NOCRED, &bp);
201219820Sjeff		if (error) {
202219820Sjeff			brelse(bp);
203219820Sjeff			goto fail;
204219820Sjeff		}
205219820Sjeff		bap = (ufs_daddr_t *)bp->b_data;
206219820Sjeff		nb = bap[indirs[i].in_off];
207219820Sjeff		if (i == num)
208219820Sjeff			break;
209219820Sjeff		i += 1;
210219820Sjeff		if (nb != 0) {
211219820Sjeff			bqrelse(bp);
212219820Sjeff			continue;
213219820Sjeff		}
214219820Sjeff		if (pref == 0)
215219820Sjeff			pref = ffs_blkpref(ip, lbn, 0, (ufs_daddr_t *)0);
216219820Sjeff		if (error =
217219820Sjeff		    ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize, cred, &newb)) {
218219820Sjeff			brelse(bp);
219219820Sjeff			goto fail;
220219820Sjeff		}
221219820Sjeff		nb = newb;
222219820Sjeff		*allocblk++ = nb;
223219820Sjeff		nbp = getblk(vp, indirs[i].in_lbn, fs->fs_bsize, 0, 0);
224219820Sjeff		nbp->b_blkno = fsbtodb(fs, nb);
225219820Sjeff		vfs_bio_clrbuf(nbp);
226219820Sjeff		/*
227219820Sjeff		 * Write synchronously so that indirect blocks
228219820Sjeff		 * never point at garbage.
229219820Sjeff		 */
230219820Sjeff		if (error = bwrite(nbp)) {
231			brelse(bp);
232			goto fail;
233		}
234		bap[indirs[i - 1].in_off] = nb;
235		/*
236		 * If required, write synchronously, otherwise use
237		 * delayed write.
238		 */
239		if (flags & B_SYNC) {
240			bwrite(bp);
241		} else {
242			if (bp->b_bufsize == fs->fs_bsize)
243				bp->b_flags |= B_CLUSTEROK;
244			bdwrite(bp);
245		}
246	}
247	/*
248	 * Get the data block, allocating if necessary.
249	 */
250	if (nb == 0) {
251		pref = ffs_blkpref(ip, lbn, indirs[i].in_off, &bap[0]);
252		error = ffs_alloc(ip,
253		    lbn, pref, (int)fs->fs_bsize, cred, &newb);
254		if (error) {
255			brelse(bp);
256			goto fail;
257		}
258		nb = newb;
259		*allocblk++ = nb;
260		nbp = getblk(vp, lbn, fs->fs_bsize, 0, 0);
261		nbp->b_blkno = fsbtodb(fs, nb);
262		if (flags & B_CLRBUF)
263			vfs_bio_clrbuf(nbp);
264		bap[indirs[i].in_off] = nb;
265		/*
266		 * If required, write synchronously, otherwise use
267		 * delayed write.
268		 */
269		if (flags & B_SYNC) {
270			bwrite(bp);
271		} else {
272			if (bp->b_bufsize == fs->fs_bsize)
273				bp->b_flags |= B_CLUSTEROK;
274			bdwrite(bp);
275		}
276		*bpp = nbp;
277		return (0);
278	}
279	brelse(bp);
280	if (flags & B_CLRBUF) {
281		error = bread(vp, lbn, (int)fs->fs_bsize, NOCRED, &nbp);
282		if (error) {
283			brelse(nbp);
284			goto fail;
285		}
286	} else {
287		nbp = getblk(vp, lbn, fs->fs_bsize, 0, 0);
288		nbp->b_blkno = fsbtodb(fs, nb);
289	}
290	*bpp = nbp;
291	return (0);
292fail:
293	/*
294	 * If we have failed part way through block allocation, we
295	 * have to deallocate any indirect blocks that we have allocated.
296	 */
297	for (deallocated = 0, blkp = allociblk; blkp < allocblk; blkp++) {
298		ffs_blkfree(ip, *blkp, fs->fs_bsize);
299		deallocated += fs->fs_bsize;
300	}
301	if (allocib != NULL)
302		*allocib = 0;
303	if (deallocated) {
304#ifdef QUOTA
305		/*
306		 * Restore user's disk quota because allocation failed.
307		 */
308		(void) chkdq(ip, (long)-btodb(deallocated), cred, FORCE);
309#endif
310		ip->i_blocks -= btodb(deallocated);
311		ip->i_flag |= IN_CHANGE | IN_UPDATE;
312	}
313	return (error);
314}
315