xref: /openbsd/sys/ufs/ffs/ffs_balloc.c (revision 93f62a9e)
1*93f62a9eStedu /*	$OpenBSD: ffs_balloc.c,v 1.37 2011/07/04 04:30:41 tedu Exp $	*/
2d28910b8Sniklas /*	$NetBSD: ffs_balloc.c,v 1.3 1996/02/09 22:22:21 christos Exp $	*/
3df930be7Sderaadt 
4df930be7Sderaadt /*
5f4342418Spedro  * Copyright (c) 2002 Networks Associates Technology, Inc.
6f4342418Spedro  * All rights reserved.
7f4342418Spedro  *
8f4342418Spedro  * This software was developed for the FreeBSD Project by Marshall
9f4342418Spedro  * Kirk McKusick and Network Associates Laboratories, the Security
10f4342418Spedro  * Research Division of Network Associates, Inc. under DARPA/SPAWAR
11f4342418Spedro  * contract N66001-01-C-8035 ("CBOSS"), as part of the DARPA CHATS
12f4342418Spedro  * research program.
13f4342418Spedro  *
14df930be7Sderaadt  * Copyright (c) 1982, 1986, 1989, 1993
15df930be7Sderaadt  *	The Regents of the University of California.  All rights reserved.
16df930be7Sderaadt  *
17df930be7Sderaadt  * Redistribution and use in source and binary forms, with or without
18df930be7Sderaadt  * modification, are permitted provided that the following conditions
19df930be7Sderaadt  * are met:
20df930be7Sderaadt  * 1. Redistributions of source code must retain the above copyright
21df930be7Sderaadt  *    notice, this list of conditions and the following disclaimer.
22df930be7Sderaadt  * 2. Redistributions in binary form must reproduce the above copyright
23df930be7Sderaadt  *    notice, this list of conditions and the following disclaimer in the
24df930be7Sderaadt  *    documentation and/or other materials provided with the distribution.
2529295d1cSmillert  * 3. Neither the name of the University nor the names of its contributors
26df930be7Sderaadt  *    may be used to endorse or promote products derived from this software
27df930be7Sderaadt  *    without specific prior written permission.
28df930be7Sderaadt  *
29df930be7Sderaadt  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
30df930be7Sderaadt  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
31df930be7Sderaadt  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
32df930be7Sderaadt  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
33df930be7Sderaadt  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
34df930be7Sderaadt  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
35df930be7Sderaadt  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
36df930be7Sderaadt  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
37df930be7Sderaadt  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
38df930be7Sderaadt  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
39df930be7Sderaadt  * SUCH DAMAGE.
40df930be7Sderaadt  *
41df930be7Sderaadt  *	@(#)ffs_balloc.c	8.4 (Berkeley) 9/23/93
42df930be7Sderaadt  */
43df930be7Sderaadt 
44df930be7Sderaadt #include <sys/param.h>
45df930be7Sderaadt #include <sys/systm.h>
46df930be7Sderaadt #include <sys/buf.h>
47df930be7Sderaadt #include <sys/proc.h>
48df930be7Sderaadt #include <sys/file.h>
4907feb63cScsapuntz #include <sys/mount.h>
50df930be7Sderaadt #include <sys/vnode.h>
51df930be7Sderaadt 
526348b7ebSart #include <uvm/uvm_extern.h>
536348b7ebSart 
54df930be7Sderaadt #include <ufs/ufs/quota.h>
55df930be7Sderaadt #include <ufs/ufs/inode.h>
56fb844963Spedro #include <ufs/ufs/ufsmount.h>
57df930be7Sderaadt #include <ufs/ufs/ufs_extern.h>
58df930be7Sderaadt 
59df930be7Sderaadt #include <ufs/ffs/fs.h>
60df930be7Sderaadt #include <ufs/ffs/ffs_extern.h>
61df930be7Sderaadt 
62f4342418Spedro int ffs1_balloc(struct inode *, off_t, int, struct ucred *, int, struct buf **);
63f4342418Spedro #ifdef FFS2
64f4342418Spedro int ffs2_balloc(struct inode *, off_t, int, struct ucred *, int, struct buf **);
65f4342418Spedro #endif
66f4342418Spedro 
67df930be7Sderaadt /*
68df930be7Sderaadt  * Balloc defines the structure of file system storage
69df930be7Sderaadt  * by allocating the physical blocks on a device given
70df930be7Sderaadt  * the inode and the logical block number in a file.
71df930be7Sderaadt  */
72d28910b8Sniklas int
73f4342418Spedro ffs1_balloc(struct inode *ip, off_t startoffset, int size, struct ucred *cred,
74b080ad39Scsapuntz     int flags, struct buf **bpp)
7507feb63cScsapuntz {
768add4794Sotto 	daddr64_t lbn, nb, newb, pref;
7707feb63cScsapuntz 	struct fs *fs;
78df930be7Sderaadt 	struct buf *bp, *nbp;
7907feb63cScsapuntz 	struct vnode *vp;
80fcf048c1Spedro 	struct proc *p;
81df930be7Sderaadt 	struct indir indirs[NIADDR + 2];
828add4794Sotto 	int32_t *bap;
8307feb63cScsapuntz 	int deallocated, osize, nsize, num, i, error;
84a09be2a2Spedro 	int32_t *allocib, *blkp, *allocblk, allociblk[NIADDR+1];
856cd4677cSart 	int unwindidx = -1;
86df930be7Sderaadt 
87b080ad39Scsapuntz 	vp = ITOV(ip);
88f6d35f95Sderaadt 	fs = ip->i_fs;
89fcf048c1Spedro 	p = curproc;
90b080ad39Scsapuntz 	lbn = lblkno(fs, startoffset);
91b080ad39Scsapuntz 	size = blkoff(fs, startoffset) + size;
9207feb63cScsapuntz 	if (size > fs->fs_bsize)
93f4342418Spedro 		panic("ffs1_balloc: blk too big");
94947c4e29Sart 	if (bpp != NULL)
95b080ad39Scsapuntz 		*bpp = NULL;
9607feb63cScsapuntz 	if (lbn < 0)
9707feb63cScsapuntz 		return (EFBIG);
98df930be7Sderaadt 
99df930be7Sderaadt 	/*
100df930be7Sderaadt 	 * If the next write will extend the file into a new block,
101df930be7Sderaadt 	 * and the file is currently composed of a fragment
102df930be7Sderaadt 	 * this fragment has to be extended to be a full block.
103df930be7Sderaadt 	 */
104fb844963Spedro 	nb = lblkno(fs, ip->i_ffs1_size);
10507feb63cScsapuntz 	if (nb < NDADDR && nb < lbn) {
106df930be7Sderaadt 		osize = blksize(fs, ip, nb);
107df930be7Sderaadt 		if (osize < fs->fs_bsize && osize > 0) {
108df930be7Sderaadt 			error = ffs_realloccg(ip, nb,
109f4342418Spedro 			    ffs1_blkpref(ip, nb, (int)nb, &ip->i_ffs1_db[0]),
110947c4e29Sart 			    osize, (int)fs->fs_bsize, cred, bpp, &newb);
111df930be7Sderaadt 			if (error)
112df930be7Sderaadt 				return (error);
11307feb63cScsapuntz 			if (DOINGSOFTDEP(vp))
1146c194e8dSart 				softdep_setup_allocdirect(ip, nb, newb,
115fb844963Spedro 				    ip->i_ffs1_db[nb], fs->fs_bsize, osize,
116947c4e29Sart 				    bpp ? *bpp : NULL);
11707feb63cScsapuntz 
118fb844963Spedro 			ip->i_ffs1_size = lblktosize(fs, nb + 1);
119fb844963Spedro 			uvm_vnp_setsize(vp, ip->i_ffs1_size);
120fb844963Spedro 			ip->i_ffs1_db[nb] = newb;
121df930be7Sderaadt 			ip->i_flag |= IN_CHANGE | IN_UPDATE;
122947c4e29Sart 			if (bpp != NULL) {
123df930be7Sderaadt 				if (flags & B_SYNC)
124947c4e29Sart 					bwrite(*bpp);
125df930be7Sderaadt 				else
126947c4e29Sart 					bawrite(*bpp);
127947c4e29Sart 			}
128df930be7Sderaadt 		}
129df930be7Sderaadt 	}
130df930be7Sderaadt 	/*
131df930be7Sderaadt 	 * The first NDADDR blocks are direct blocks
132df930be7Sderaadt 	 */
13307feb63cScsapuntz 	if (lbn < NDADDR) {
134fb844963Spedro 		nb = ip->i_ffs1_db[lbn];
135fb844963Spedro 		if (nb != 0 && ip->i_ffs1_size >= lblktosize(fs, lbn + 1)) {
136947c4e29Sart 			/*
137947c4e29Sart 			 * The block is an already-allocated direct block
138947c4e29Sart 			 * and the file already extends past this block,
139947c4e29Sart 			 * thus this must be a whole block.
140947c4e29Sart 			 * Just read the block (if requested).
141947c4e29Sart 			 */
142947c4e29Sart 
143947c4e29Sart 			if (bpp != NULL) {
144*93f62a9eStedu 				error = bread(vp, lbn, fs->fs_bsize, bpp);
145df930be7Sderaadt 				if (error) {
146947c4e29Sart 					brelse(*bpp);
147df930be7Sderaadt 					return (error);
148df930be7Sderaadt 				}
149947c4e29Sart 			}
150df930be7Sderaadt 			return (0);
151df930be7Sderaadt 		}
152df930be7Sderaadt 		if (nb != 0) {
153df930be7Sderaadt 			/*
154df930be7Sderaadt 			 * Consider need to reallocate a fragment.
155df930be7Sderaadt 			 */
156fb844963Spedro 			osize = fragroundup(fs, blkoff(fs, ip->i_ffs1_size));
157df930be7Sderaadt 			nsize = fragroundup(fs, size);
158df930be7Sderaadt 			if (nsize <= osize) {
159947c4e29Sart 				/*
160947c4e29Sart 				 * The existing block is already
161947c4e29Sart 				 * at least as big as we want.
162947c4e29Sart 				 * Just read the block (if requested).
163947c4e29Sart 				 */
164947c4e29Sart 				if (bpp != NULL) {
165f43037e0Spedro 					error = bread(vp, lbn, fs->fs_bsize,
166*93f62a9eStedu 					    bpp);
167df930be7Sderaadt 					if (error) {
168947c4e29Sart 						brelse(*bpp);
169df930be7Sderaadt 						return (error);
170df930be7Sderaadt 					}
171f43037e0Spedro 					(*bpp)->b_bcount = osize;
172947c4e29Sart 				}
173947c4e29Sart 				return (0);
174df930be7Sderaadt 			} else {
175947c4e29Sart 				/*
176947c4e29Sart 				 * The existing block is smaller than we
177947c4e29Sart 				 * want, grow it.
178947c4e29Sart 				 */
17907feb63cScsapuntz 				error = ffs_realloccg(ip, lbn,
180f4342418Spedro 				    ffs1_blkpref(ip, lbn, (int)lbn,
181fb844963Spedro 					&ip->i_ffs1_db[0]),
182947c4e29Sart 				    osize, nsize, cred, bpp, &newb);
183df930be7Sderaadt 				if (error)
184df930be7Sderaadt 					return (error);
18507feb63cScsapuntz 				if (DOINGSOFTDEP(vp))
18607feb63cScsapuntz 					softdep_setup_allocdirect(ip, lbn,
187947c4e29Sart 					    newb, nb, nsize, osize,
188947c4e29Sart 					    bpp ? *bpp : NULL);
189df930be7Sderaadt 			}
190df930be7Sderaadt 		} else {
191947c4e29Sart 			/*
192947c4e29Sart 			 * The block was not previously allocated,
193947c4e29Sart 			 * allocate a new block or fragment.
194947c4e29Sart 			 */
195947c4e29Sart 
196fb844963Spedro 			if (ip->i_ffs1_size < lblktosize(fs, lbn + 1))
197df930be7Sderaadt 				nsize = fragroundup(fs, size);
198df930be7Sderaadt 			else
199df930be7Sderaadt 				nsize = fs->fs_bsize;
20007feb63cScsapuntz 			error = ffs_alloc(ip, lbn,
201f4342418Spedro 			    ffs1_blkpref(ip, lbn, (int)lbn, &ip->i_ffs1_db[0]),
202df930be7Sderaadt 			    nsize, cred, &newb);
203df930be7Sderaadt 			if (error)
204df930be7Sderaadt 				return (error);
205947c4e29Sart 			if (bpp != NULL) {
206f43037e0Spedro 				*bpp = getblk(vp, lbn, fs->fs_bsize, 0, 0);
207f43037e0Spedro 				if (nsize < fs->fs_bsize)
208f43037e0Spedro 					(*bpp)->b_bcount = nsize;
209947c4e29Sart 				(*bpp)->b_blkno = fsbtodb(fs, newb);
210df930be7Sderaadt 				if (flags & B_CLRBUF)
211947c4e29Sart 					clrbuf(*bpp);
212947c4e29Sart 			}
21307feb63cScsapuntz 			if (DOINGSOFTDEP(vp))
21407feb63cScsapuntz 				softdep_setup_allocdirect(ip, lbn, newb, 0,
215947c4e29Sart 				    nsize, 0, bpp ? *bpp : NULL);
216df930be7Sderaadt 		}
217fb844963Spedro 		ip->i_ffs1_db[lbn] = newb;
218df930be7Sderaadt 		ip->i_flag |= IN_CHANGE | IN_UPDATE;
219df930be7Sderaadt 		return (0);
220df930be7Sderaadt 	}
221947c4e29Sart 
222df930be7Sderaadt 	/*
223df930be7Sderaadt 	 * Determine the number of levels of indirection.
224df930be7Sderaadt 	 */
225df930be7Sderaadt 	pref = 0;
22607feb63cScsapuntz 	if ((error = ufs_getlbns(vp, lbn, indirs, &num)) != 0)
227df930be7Sderaadt 		return(error);
228df930be7Sderaadt #ifdef DIAGNOSTIC
229df930be7Sderaadt 	if (num < 1)
230f4342418Spedro 		panic ("ffs1_balloc: ufs_bmaparray returned indirect block");
231df930be7Sderaadt #endif
232df930be7Sderaadt 	/*
233df930be7Sderaadt 	 * Fetch the first indirect block allocating if necessary.
234df930be7Sderaadt 	 */
235df930be7Sderaadt 	--num;
236fb844963Spedro 	nb = ip->i_ffs1_ib[indirs[0].in_off];
23707feb63cScsapuntz 
23807feb63cScsapuntz 	allocib = NULL;
23907feb63cScsapuntz 	allocblk = allociblk;
240df930be7Sderaadt 	if (nb == 0) {
2418add4794Sotto 		pref = ffs1_blkpref(ip, lbn, 0, (int32_t *)0);
242d28910b8Sniklas 	        error = ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize,
243d28910b8Sniklas 				  cred, &newb);
244d28910b8Sniklas 		if (error)
245947c4e29Sart 			goto fail;
246df930be7Sderaadt 		nb = newb;
24707feb63cScsapuntz 
24807feb63cScsapuntz 		*allocblk++ = nb;
249df930be7Sderaadt 		bp = getblk(vp, indirs[1].in_lbn, fs->fs_bsize, 0, 0);
25007feb63cScsapuntz 		bp->b_blkno = fsbtodb(fs, nb);
251df930be7Sderaadt 		clrbuf(bp);
25207feb63cScsapuntz 
25307feb63cScsapuntz 		if (DOINGSOFTDEP(vp)) {
25407feb63cScsapuntz 			softdep_setup_allocdirect(ip, NDADDR + indirs[0].in_off,
25507feb63cScsapuntz 			    newb, 0, fs->fs_bsize, 0, bp);
25607feb63cScsapuntz 			bdwrite(bp);
25707feb63cScsapuntz 		} else {
258df930be7Sderaadt 			/*
259df930be7Sderaadt 			 * Write synchronously so that indirect blocks
260df930be7Sderaadt 			 * never point at garbage.
261df930be7Sderaadt 			 */
26207feb63cScsapuntz 			if ((error = bwrite(bp)) != 0)
26307feb63cScsapuntz 				goto fail;
264df930be7Sderaadt 		}
265fb844963Spedro 		allocib = &ip->i_ffs1_ib[indirs[0].in_off];
26607feb63cScsapuntz 		*allocib = nb;
267df930be7Sderaadt 		ip->i_flag |= IN_CHANGE | IN_UPDATE;
268df930be7Sderaadt 	}
269947c4e29Sart 
270df930be7Sderaadt 	/*
271df930be7Sderaadt 	 * Fetch through the indirect blocks, allocating as necessary.
272df930be7Sderaadt 	 */
273df930be7Sderaadt 	for (i = 1;;) {
274*93f62a9eStedu 		error = bread(vp, indirs[i].in_lbn, (int)fs->fs_bsize, &bp);
275df930be7Sderaadt 		if (error) {
276df930be7Sderaadt 			brelse(bp);
27707feb63cScsapuntz 			goto fail;
278df930be7Sderaadt 		}
2798add4794Sotto 		bap = (int32_t *)bp->b_data;
280df930be7Sderaadt 		nb = bap[indirs[i].in_off];
281df930be7Sderaadt 		if (i == num)
282df930be7Sderaadt 			break;
2833853cac8Sart 		i++;
284df930be7Sderaadt 		if (nb != 0) {
285df930be7Sderaadt 			brelse(bp);
286df930be7Sderaadt 			continue;
287df930be7Sderaadt 		}
288df930be7Sderaadt 		if (pref == 0)
2898add4794Sotto 			pref = ffs1_blkpref(ip, lbn, 0, (int32_t *)0);
290d28910b8Sniklas 		error = ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize, cred,
291d28910b8Sniklas 				  &newb);
292d28910b8Sniklas 		if (error) {
293df930be7Sderaadt 			brelse(bp);
29407feb63cScsapuntz 			goto fail;
295df930be7Sderaadt 		}
296df930be7Sderaadt 		nb = newb;
29707feb63cScsapuntz 		*allocblk++ = nb;
298df930be7Sderaadt 		nbp = getblk(vp, indirs[i].in_lbn, fs->fs_bsize, 0, 0);
299df930be7Sderaadt 		nbp->b_blkno = fsbtodb(fs, nb);
300df930be7Sderaadt 		clrbuf(nbp);
30107feb63cScsapuntz 
30207feb63cScsapuntz 		if (DOINGSOFTDEP(vp)) {
30307feb63cScsapuntz 			softdep_setup_allocindir_meta(nbp, ip, bp,
30407feb63cScsapuntz 			    indirs[i - 1].in_off, nb);
30507feb63cScsapuntz 			bdwrite(nbp);
30607feb63cScsapuntz 		} else {
307df930be7Sderaadt 			/*
308df930be7Sderaadt 			 * Write synchronously so that indirect blocks
309df930be7Sderaadt 			 * never point at garbage.
310df930be7Sderaadt 			 */
311d28910b8Sniklas 			if ((error = bwrite(nbp)) != 0) {
312df930be7Sderaadt 				brelse(bp);
31307feb63cScsapuntz 				goto fail;
31407feb63cScsapuntz 			}
315df930be7Sderaadt 		}
316df930be7Sderaadt 		bap[indirs[i - 1].in_off] = nb;
3176cd4677cSart 		if (allocib == NULL && unwindidx < 0)
3186cd4677cSart 			unwindidx = i - 1;
319df930be7Sderaadt 		/*
320df930be7Sderaadt 		 * If required, write synchronously, otherwise use
321df930be7Sderaadt 		 * delayed write.
322df930be7Sderaadt 		 */
323df930be7Sderaadt 		if (flags & B_SYNC) {
324df930be7Sderaadt 			bwrite(bp);
325df930be7Sderaadt 		} else {
326df930be7Sderaadt 			bdwrite(bp);
327df930be7Sderaadt 		}
328df930be7Sderaadt 	}
329df930be7Sderaadt 	/*
330df930be7Sderaadt 	 * Get the data block, allocating if necessary.
331df930be7Sderaadt 	 */
332df930be7Sderaadt 	if (nb == 0) {
333f4342418Spedro 		pref = ffs1_blkpref(ip, lbn, indirs[i].in_off, &bap[0]);
334d28910b8Sniklas 		error = ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize, cred,
335d28910b8Sniklas 				  &newb);
336d28910b8Sniklas 		if (error) {
337df930be7Sderaadt 			brelse(bp);
33807feb63cScsapuntz 			goto fail;
339df930be7Sderaadt 		}
340df930be7Sderaadt 		nb = newb;
34107feb63cScsapuntz 		*allocblk++ = nb;
342947c4e29Sart 		if (bpp != NULL) {
343df930be7Sderaadt 			nbp = getblk(vp, lbn, fs->fs_bsize, 0, 0);
344df930be7Sderaadt 			nbp->b_blkno = fsbtodb(fs, nb);
345df930be7Sderaadt 			if (flags & B_CLRBUF)
346df930be7Sderaadt 				clrbuf(nbp);
347947c4e29Sart 			*bpp = nbp;
348947c4e29Sart 		}
34907feb63cScsapuntz 		if (DOINGSOFTDEP(vp))
35007feb63cScsapuntz 			softdep_setup_allocindir_page(ip, lbn, bp,
351947c4e29Sart 			    indirs[i].in_off, nb, 0, bpp ? *bpp : NULL);
352df930be7Sderaadt 		bap[indirs[i].in_off] = nb;
353df930be7Sderaadt 		/*
354df930be7Sderaadt 		 * If required, write synchronously, otherwise use
355df930be7Sderaadt 		 * delayed write.
356df930be7Sderaadt 		 */
357df930be7Sderaadt 		if (flags & B_SYNC) {
358df930be7Sderaadt 			bwrite(bp);
359df930be7Sderaadt 		} else {
360df930be7Sderaadt 			bdwrite(bp);
361df930be7Sderaadt 		}
362df930be7Sderaadt 		return (0);
363df930be7Sderaadt 	}
364df930be7Sderaadt 	brelse(bp);
365947c4e29Sart 	if (bpp != NULL) {
366df930be7Sderaadt 		if (flags & B_CLRBUF) {
367*93f62a9eStedu 			error = bread(vp, lbn, (int)fs->fs_bsize, &nbp);
368df930be7Sderaadt 			if (error) {
369df930be7Sderaadt 				brelse(nbp);
37007feb63cScsapuntz 				goto fail;
371df930be7Sderaadt 			}
372df930be7Sderaadt 		} else {
373df930be7Sderaadt 			nbp = getblk(vp, lbn, fs->fs_bsize, 0, 0);
374df930be7Sderaadt 			nbp->b_blkno = fsbtodb(fs, nb);
375df930be7Sderaadt 		}
376b080ad39Scsapuntz 		*bpp = nbp;
377947c4e29Sart 	}
378df930be7Sderaadt 	return (0);
37907feb63cScsapuntz 
38007feb63cScsapuntz fail:
38107feb63cScsapuntz 	/*
382fcf048c1Spedro 	 * If we have failed to allocate any blocks, simply return the error.
383fcf048c1Spedro 	 * This is the usual case and avoids the need to fsync the file.
38407feb63cScsapuntz 	 */
385fcf048c1Spedro 	if (allocblk == allociblk && allocib == NULL && unwindidx == -1)
386fcf048c1Spedro 		return (error);
387fcf048c1Spedro 	/*
388fcf048c1Spedro 	 * If we have failed part way through block allocation, we have to
389fcf048c1Spedro 	 * deallocate any indirect blocks that we have allocated. We have to
390fcf048c1Spedro 	 * fsync the file before we start to get rid of all of its
391fcf048c1Spedro 	 * dependencies so that we do not leave them dangling. We have to sync
392fcf048c1Spedro 	 * it at the end so that the softdep code does not find any untracked
393fcf048c1Spedro 	 * changes. Although this is really slow, running out of disk space is
39480adcad8Smartynas 	 * not expected to be a common occurrence. The error return from fsync
395fcf048c1Spedro 	 * is ignored as we already have an error to return to the user.
396fcf048c1Spedro 	 */
397fcf048c1Spedro 	VOP_FSYNC(vp, p->p_ucred, MNT_WAIT, p);
39807feb63cScsapuntz 	for (deallocated = 0, blkp = allociblk; blkp < allocblk; blkp++) {
39907feb63cScsapuntz 		ffs_blkfree(ip, *blkp, fs->fs_bsize);
40007feb63cScsapuntz 		deallocated += fs->fs_bsize;
40107feb63cScsapuntz 	}
4026cd4677cSart 	if (allocib != NULL) {
40307feb63cScsapuntz 		*allocib = 0;
4046cd4677cSart 	} else if (unwindidx >= 0) {
4056cd4677cSart 		int r;
4066cd4677cSart 
407*93f62a9eStedu 		r = bread(vp, indirs[unwindidx].in_lbn, (int)fs->fs_bsize, &bp);
4086cd4677cSart 		if (r)
4096cd4677cSart 			panic("Could not unwind indirect block, error %d", r);
4108add4794Sotto 		bap = (int32_t *)bp->b_data;
4116cd4677cSart 		bap[indirs[unwindidx].in_off] = 0;
4126cd4677cSart 		if (flags & B_SYNC) {
4136cd4677cSart 			bwrite(bp);
4146cd4677cSart 		} else {
4156cd4677cSart 			bdwrite(bp);
4166cd4677cSart 		}
4176cd4677cSart 	}
41807feb63cScsapuntz 	if (deallocated) {
41907feb63cScsapuntz 		/*
42007feb63cScsapuntz 		 * Restore user's disk quota because allocation failed.
42107feb63cScsapuntz 		 */
4225f7d6642Scsapuntz 		(void)ufs_quota_free_blocks(ip, btodb(deallocated), cred);
4235f7d6642Scsapuntz 
424fb844963Spedro 		ip->i_ffs1_blocks -= btodb(deallocated);
42507feb63cScsapuntz 		ip->i_flag |= IN_CHANGE | IN_UPDATE;
42607feb63cScsapuntz 	}
427fcf048c1Spedro 	VOP_FSYNC(vp, p->p_ucred, MNT_WAIT, p);
4286cd4677cSart 	return (error);
429df930be7Sderaadt }
430f4342418Spedro 
431f4342418Spedro #ifdef FFS2
432f4342418Spedro int
433f4342418Spedro ffs2_balloc(struct inode *ip, off_t off, int size, struct ucred *cred,
434f4342418Spedro     int flags, struct buf **bpp)
435f4342418Spedro {
4368add4794Sotto 	daddr64_t lbn, lastlbn, nb, newb, *blkp;
4378add4794Sotto 	daddr64_t pref, *allocblk, allociblk[NIADDR + 1];
4381ac585afSderaadt 	daddr64_t *bap, *allocib;
439f4342418Spedro 	int deallocated, osize, nsize, num, i, error, unwindidx, r;
440f4342418Spedro 	struct buf *bp, *nbp;
441f4342418Spedro 	struct indir indirs[NIADDR + 2];
442f4342418Spedro 	struct fs *fs;
443f4342418Spedro 	struct vnode *vp;
444c1df8807Ssturm 	struct proc *p;
445f4342418Spedro 
446f4342418Spedro 	vp = ITOV(ip);
447f4342418Spedro 	fs = ip->i_fs;
448c1df8807Ssturm 	p = curproc;
44916a60b30Ssturm 	unwindidx = -1;
450f4342418Spedro 
451f4342418Spedro 	lbn = lblkno(fs, off);
452f4342418Spedro 	size = blkoff(fs, off) + size;
453f4342418Spedro 
454f4342418Spedro 	if (size > fs->fs_bsize)
455f4342418Spedro 		panic("ffs2_balloc: block too big");
456f4342418Spedro 
457f4342418Spedro 	if (bpp != NULL)
458f4342418Spedro 		*bpp = NULL;
459f4342418Spedro 
460f4342418Spedro 	if (lbn < 0)
461f4342418Spedro 		return (EFBIG);
462f4342418Spedro 
463f4342418Spedro 	/*
464f4342418Spedro 	 * If the next write will extend the file into a new block, and the
465f4342418Spedro 	 * file is currently composed of a fragment, this fragment has to be
466f4342418Spedro 	 * extended to be a full block.
467f4342418Spedro 	 */
468f4342418Spedro 	lastlbn = lblkno(fs, ip->i_ffs2_size);
469f4342418Spedro 	if (lastlbn < NDADDR && lastlbn < lbn) {
470f4342418Spedro 		nb = lastlbn;
471f4342418Spedro 		osize = blksize(fs, ip, nb);
472f4342418Spedro 		if (osize < fs->fs_bsize && osize > 0) {
473f4342418Spedro 			error = ffs_realloccg(ip, nb, ffs2_blkpref(ip,
474f4342418Spedro 			    lastlbn, nb, &ip->i_ffs2_db[0]), osize,
475f4342418Spedro 			    (int) fs->fs_bsize, cred, bpp, &newb);
476f4342418Spedro 			if (error)
477f4342418Spedro 				return (error);
478f4342418Spedro 
479f4342418Spedro 			if (DOINGSOFTDEP(vp))
480f4342418Spedro 				softdep_setup_allocdirect(ip, nb, newb,
481f4342418Spedro 				    ip->i_ffs2_db[nb], fs->fs_bsize, osize,
482f4342418Spedro 				    bpp ? *bpp : NULL);
483f4342418Spedro 
484f4342418Spedro 			ip->i_ffs2_size = lblktosize(fs, nb + 1);
485f4342418Spedro 			uvm_vnp_setsize(vp, ip->i_ffs2_size);
486f4342418Spedro 			ip->i_ffs2_db[nb] = newb;
487f4342418Spedro 			ip->i_flag |= IN_CHANGE | IN_UPDATE;
488f4342418Spedro 
489f4342418Spedro 			if (bpp) {
490f4342418Spedro 				if (flags & B_SYNC)
491f4342418Spedro 					bwrite(*bpp);
492f4342418Spedro 				else
493f4342418Spedro 					bawrite(*bpp);
494f4342418Spedro 			}
495f4342418Spedro 		}
496f4342418Spedro 	}
497f4342418Spedro 
498f4342418Spedro 	/*
499f4342418Spedro 	 * The first NDADDR blocks are direct.
500f4342418Spedro 	 */
501f4342418Spedro 	if (lbn < NDADDR) {
502f4342418Spedro 
503f4342418Spedro 		nb = ip->i_ffs2_db[lbn];
504f4342418Spedro 
505f4342418Spedro 		if (nb != 0 && ip->i_ffs2_size >= lblktosize(fs, lbn + 1)) {
506f4342418Spedro 			/*
507f4342418Spedro 			 * The direct block is already allocated and the file
508f4342418Spedro 			 * extends past this block, thus this must be a whole
509f4342418Spedro 			 * block. Just read it, if requested.
510f4342418Spedro 			 */
511f4342418Spedro 			if (bpp != NULL) {
512*93f62a9eStedu 				error = bread(vp, lbn, fs->fs_bsize, bpp);
513f4342418Spedro 				if (error) {
514f4342418Spedro 					brelse(*bpp);
515f4342418Spedro 					return (error);
516f4342418Spedro 				}
517f4342418Spedro 			}
518f4342418Spedro 
519f4342418Spedro 			return (0);
520f4342418Spedro 		}
521f4342418Spedro 
522f4342418Spedro 		if (nb != 0) {
523f4342418Spedro 			/*
524f4342418Spedro 			 * Consider the need to allocate a fragment.
525f4342418Spedro 			 */
526f4342418Spedro 			osize = fragroundup(fs, blkoff(fs, ip->i_ffs2_size));
527f4342418Spedro 			nsize = fragroundup(fs, size);
528f4342418Spedro 
529f4342418Spedro 			if (nsize <= osize) {
530f4342418Spedro 				/*
531f4342418Spedro 				 * The existing block is already at least as
532f4342418Spedro 				 * big as we want. Just read it, if requested.
533f4342418Spedro 				 */
534f4342418Spedro 				if (bpp != NULL) {
535f43037e0Spedro 					error = bread(vp, lbn, fs->fs_bsize,
536*93f62a9eStedu 					    bpp);
537f4342418Spedro 					if (error) {
538f4342418Spedro 						brelse(*bpp);
539f4342418Spedro 						return (error);
540f4342418Spedro 					}
541f43037e0Spedro 					(*bpp)->b_bcount = osize;
542f4342418Spedro 				}
543f4342418Spedro 
544f4342418Spedro 				return (0);
545f4342418Spedro 			} else {
546f4342418Spedro 				/*
547f4342418Spedro 				 * The existing block is smaller than we want,
548f4342418Spedro 				 * grow it.
549f4342418Spedro 				 */
550f4342418Spedro 				error = ffs_realloccg(ip, lbn,
551f4342418Spedro 				    ffs2_blkpref(ip, lbn, (int) lbn,
552f4342418Spedro 				    &ip->i_ffs2_db[0]), osize, nsize, cred,
553f4342418Spedro 				    bpp, &newb);
554f4342418Spedro 				if (error)
555f4342418Spedro 					return (error);
556f4342418Spedro 
557f4342418Spedro 				if (DOINGSOFTDEP(vp))
558f4342418Spedro 					softdep_setup_allocdirect(ip, lbn,
559f4342418Spedro 					    newb, nb, nsize, osize,
560f4342418Spedro 					    bpp ? *bpp : NULL);
561f4342418Spedro 			}
562f4342418Spedro 		} else {
563f4342418Spedro 			/*
564f4342418Spedro 			 * The block was not previously allocated, allocate a
565f4342418Spedro 			 * new block or fragment.
566f4342418Spedro 			 */
567f4342418Spedro 			if (ip->i_ffs2_size < lblktosize(fs, lbn + 1))
568f4342418Spedro 				nsize = fragroundup(fs, size);
569f4342418Spedro 			else
570f4342418Spedro 				nsize = fs->fs_bsize;
571f4342418Spedro 
572f4342418Spedro 			error = ffs_alloc(ip, lbn, ffs2_blkpref(ip, lbn,
573f4342418Spedro 			    (int) lbn, &ip->i_ffs2_db[0]), nsize, cred, &newb);
574f4342418Spedro 			if (error)
575f4342418Spedro 				return (error);
576f4342418Spedro 
577f4342418Spedro 			if (bpp != NULL) {
578f43037e0Spedro 				bp = getblk(vp, lbn, fs->fs_bsize, 0, 0);
579f43037e0Spedro 				if (nsize < fs->fs_bsize)
580f43037e0Spedro 					bp->b_bcount = nsize;
581f4342418Spedro 				bp->b_blkno = fsbtodb(fs, newb);
582f4342418Spedro 				if (flags & B_CLRBUF)
583f4342418Spedro 					clrbuf(bp);
584f4342418Spedro 				*bpp = bp;
585f4342418Spedro 			}
586f4342418Spedro 
587f4342418Spedro 			if (DOINGSOFTDEP(vp))
588f4342418Spedro 				softdep_setup_allocdirect(ip, lbn, newb, 0,
589f4342418Spedro 				    nsize, 0, bpp ? *bpp : NULL);
5905d1e8defSpedro 		}
591f4342418Spedro 
592f4342418Spedro 		ip->i_ffs2_db[lbn] = newb;
593f4342418Spedro 		ip->i_flag |= IN_CHANGE | IN_UPDATE;
594f4342418Spedro 
595f4342418Spedro 		return (0);
596f4342418Spedro 	}
597f4342418Spedro 
598f4342418Spedro 	/*
599f4342418Spedro 	 * Determine the number of levels of indirection.
600f4342418Spedro 	 */
601f4342418Spedro 	pref = 0;
602f4342418Spedro 	error = ufs_getlbns(vp, lbn, indirs, &num);
603f4342418Spedro 	if (error)
604f4342418Spedro 		return (error);
605f4342418Spedro 
606244cffc3Spedro #ifdef DIAGNOSTIC
607244cffc3Spedro 	if (num < 1)
608244cffc3Spedro 		panic("ffs2_balloc: ufs_bmaparray returned indirect block");
609244cffc3Spedro #endif
610244cffc3Spedro 
611f4342418Spedro 	/*
612f4342418Spedro 	 * Fetch the first indirect block allocating it necessary.
613f4342418Spedro 	 */
614f4342418Spedro 	--num;
615f4342418Spedro 	nb = ip->i_ffs2_ib[indirs[0].in_off];
616f4342418Spedro 	allocib = NULL;
617f4342418Spedro 	allocblk = allociblk;
618f4342418Spedro 
619f4342418Spedro 	if (nb == 0) {
620f4342418Spedro 		pref = ffs2_blkpref(ip, lbn, 0, NULL);
621f4342418Spedro 		error = ffs_alloc(ip, lbn, pref, (int) fs->fs_bsize, cred,
622f4342418Spedro 		    &newb);
623f4342418Spedro 		if (error)
624f4342418Spedro 			goto fail;
625f4342418Spedro 
626f4342418Spedro 		nb = newb;
627f4342418Spedro 		*allocblk++ = nb;
628f4342418Spedro 		bp = getblk(vp, indirs[1].in_lbn, fs->fs_bsize, 0, 0);
629f4342418Spedro 		bp->b_blkno = fsbtodb(fs, nb);
630f4342418Spedro 		clrbuf(bp);
631f4342418Spedro 
632f4342418Spedro 		if (DOINGSOFTDEP(vp)) {
633f4342418Spedro 			softdep_setup_allocdirect(ip, NDADDR + indirs[0].in_off,
634f4342418Spedro 			    newb, 0, fs->fs_bsize, 0, bp);
635f4342418Spedro 			bdwrite(bp);
636f4342418Spedro 		} else {
637f4342418Spedro 			/*
638f4342418Spedro 			 * Write synchronously so that indirect blocks never
639f4342418Spedro 			 * point at garbage.
640f4342418Spedro 			 */
641f4342418Spedro 			error = bwrite(bp);
642f4342418Spedro 			if (error)
643f4342418Spedro 				goto fail;
644f4342418Spedro 		}
645f4342418Spedro 
646f4342418Spedro 		unwindidx = 0;
647f4342418Spedro 		allocib = &ip->i_ffs2_ib[indirs[0].in_off];
648f4342418Spedro 		*allocib = nb;
649f4342418Spedro 		ip->i_flag |= IN_CHANGE | IN_UPDATE;
650f4342418Spedro 	}
651f4342418Spedro 
652f4342418Spedro 	/*
653f4342418Spedro 	 * Fetch through the indirect blocks, allocating as necessary.
654f4342418Spedro 	 */
655f4342418Spedro 	for (i = 1;;) {
656*93f62a9eStedu 		error = bread(vp, indirs[i].in_lbn, (int)fs->fs_bsize, &bp);
657f4342418Spedro 		if (error) {
658f4342418Spedro 			brelse(bp);
659f4342418Spedro 			goto fail;
660f4342418Spedro 		}
661f4342418Spedro 
662f4342418Spedro 		bap = (int64_t *) bp->b_data;
663f4342418Spedro 		nb = bap[indirs[i].in_off];
664f4342418Spedro 
665f4342418Spedro 		if (i == num)
666f4342418Spedro 			break;
667f4342418Spedro 
668f4342418Spedro 		i++;
669f4342418Spedro 
670f4342418Spedro 		if (nb != 0) {
671f4342418Spedro 			brelse(bp);
672f4342418Spedro 			continue;
673f4342418Spedro 		}
674f4342418Spedro 
675f4342418Spedro 		if (pref == 0)
676f4342418Spedro 			pref = ffs2_blkpref(ip, lbn, 0, NULL);
677f4342418Spedro 
678f4342418Spedro 		error = ffs_alloc(ip, lbn, pref, (int) fs->fs_bsize, cred,
679f4342418Spedro 		    &newb);
680f4342418Spedro 		if (error) {
681f4342418Spedro 			brelse(bp);
682f4342418Spedro 			goto fail;
683f4342418Spedro 		}
684f4342418Spedro 
685f4342418Spedro 		nb = newb;
686f4342418Spedro 		*allocblk++ = nb;
687f4342418Spedro 		nbp = getblk(vp, indirs[i].in_lbn, fs->fs_bsize, 0, 0);
688f4342418Spedro 		nbp->b_blkno = fsbtodb(fs, nb);
689f4342418Spedro 		clrbuf(nbp);
690f4342418Spedro 
691f4342418Spedro 		if (DOINGSOFTDEP(vp)) {
692f4342418Spedro 			softdep_setup_allocindir_meta(nbp, ip, bp,
693f4342418Spedro 			    indirs[i - 1].in_off, nb);
694f4342418Spedro 			bdwrite(nbp);
695f4342418Spedro 		} else {
696f4342418Spedro 			/*
697f4342418Spedro 			 * Write synchronously so that indirect blocks never
698f4342418Spedro 			 * point at garbage.
699f4342418Spedro 			 */
700f4342418Spedro 			error = bwrite(nbp);
701f4342418Spedro 			if (error) {
702f4342418Spedro 				brelse(bp);
703f4342418Spedro 				goto fail;
704f4342418Spedro 			}
705f4342418Spedro 		}
706f4342418Spedro 
707f4342418Spedro 		if (unwindidx < 0)
708f4342418Spedro 			unwindidx = i - 1;
709f4342418Spedro 
710f4342418Spedro 		bap[indirs[i - 1].in_off] = nb;
711f4342418Spedro 
712f4342418Spedro 		/*
713f4342418Spedro 		 * If required, write synchronously, otherwise use delayed
714f4342418Spedro 		 * write.
715f4342418Spedro 		 */
716f4342418Spedro 		if (flags & B_SYNC)
717f4342418Spedro 			bwrite(bp);
718f4342418Spedro 		else
719f4342418Spedro 			bdwrite(bp);
720f4342418Spedro 	}
721f4342418Spedro 
722f4342418Spedro 	/*
723f4342418Spedro 	 * Get the data block, allocating if necessary.
724f4342418Spedro 	 */
725f4342418Spedro 	if (nb == 0) {
726f4342418Spedro 		pref = ffs2_blkpref(ip, lbn, indirs[num].in_off, &bap[0]);
727f4342418Spedro 
728f4342418Spedro 		error = ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize, cred,
729f4342418Spedro 		    &newb);
730f4342418Spedro 		if (error) {
731f4342418Spedro 			brelse(bp);
732f4342418Spedro 			goto fail;
733f4342418Spedro 		}
734f4342418Spedro 
735f4342418Spedro 		nb = newb;
736f4342418Spedro 		*allocblk++ = nb;
737f4342418Spedro 
738f4342418Spedro 		if (bpp != NULL) {
739f4342418Spedro 			nbp = getblk(vp, lbn, fs->fs_bsize, 0, 0);
740f4342418Spedro 			nbp->b_blkno = fsbtodb(fs, nb);
741f4342418Spedro 			if (flags & B_CLRBUF)
742f4342418Spedro 				clrbuf(nbp);
743f4342418Spedro 			*bpp = nbp;
744f4342418Spedro 		}
745f4342418Spedro 
746f4342418Spedro 		if (DOINGSOFTDEP(vp))
747f4342418Spedro 			softdep_setup_allocindir_page(ip, lbn, bp,
748f4342418Spedro 			    indirs[num].in_off, nb, 0, bpp ? *bpp : NULL);
749f4342418Spedro 
750f4342418Spedro 		bap[indirs[num].in_off] = nb;
751f4342418Spedro 
752f4342418Spedro 		if (allocib == NULL && unwindidx < 0)
753f4342418Spedro 			unwindidx = i - 1;
754f4342418Spedro 
755f4342418Spedro 		/*
756f4342418Spedro 		 * If required, write synchronously, otherwise use delayed
757f4342418Spedro 		 * write.
758f4342418Spedro 		 */
759f4342418Spedro 		if (flags & B_SYNC)
760f4342418Spedro 			bwrite(bp);
761f4342418Spedro 		else
762f4342418Spedro 			bdwrite(bp);
763f4342418Spedro 
764f4342418Spedro 		return (0);
765f4342418Spedro 	}
766f4342418Spedro 
767f4342418Spedro 	brelse(bp);
768f4342418Spedro 
769f4342418Spedro 	if (bpp != NULL) {
770f4342418Spedro 		if (flags & B_CLRBUF) {
771*93f62a9eStedu 			error = bread(vp, lbn, (int)fs->fs_bsize, &nbp);
772f4342418Spedro 			if (error) {
773f4342418Spedro 				brelse(nbp);
774f4342418Spedro 				goto fail;
775f4342418Spedro 			}
776f4342418Spedro 		} else {
777f4342418Spedro 			nbp = getblk(vp, lbn, fs->fs_bsize, 0, 0);
778f4342418Spedro 			nbp->b_blkno = fsbtodb(fs, nb);
779f4342418Spedro 			clrbuf(nbp);
780f4342418Spedro 		}
781f4342418Spedro 
782f4342418Spedro 		*bpp = nbp;
783f4342418Spedro 	}
784f4342418Spedro 
785f4342418Spedro 	return (0);
786f4342418Spedro 
787f4342418Spedro fail:
788c1df8807Ssturm 	/*
789c1df8807Ssturm 	 * If we have failed to allocate any blocks, simply return the error.
790c1df8807Ssturm 	 * This is the usual case and avoids the need to fsync the file.
791c1df8807Ssturm 	 */
792c1df8807Ssturm 	if (allocblk == allociblk && allocib == NULL && unwindidx == -1)
793c1df8807Ssturm 		return (error);
794f4342418Spedro 	/*
795f4342418Spedro 	 * If we have failed part way through block allocation, we have to
796c1df8807Ssturm 	 * deallocate any indirect blocks that we have allocated. We have to
797c1df8807Ssturm 	 * fsync the file before we start to get rid of all of its
798c1df8807Ssturm 	 * dependencies so that we do not leave them dangling. We have to sync
799c1df8807Ssturm 	 * it at the end so that the softdep code does not find any untracked
800c1df8807Ssturm 	 * changes. Although this is really slow, running out of disk space is
80180adcad8Smartynas 	 * not expected to be a common occurrence. The error return from fsync
802c1df8807Ssturm 	 * is ignored as we already have an error to return to the user.
803f4342418Spedro 	 */
804c1df8807Ssturm 	VOP_FSYNC(vp, p->p_ucred, MNT_WAIT, p);
805f4342418Spedro 	if (unwindidx >= 0) {
806f4342418Spedro 		/*
807f4342418Spedro 		 * First write out any buffers we've created to resolve their
808f4342418Spedro 		 * softdeps. This must be done in reverse order of creation so
809f4342418Spedro 		 * that we resolve the dependencies in one pass.
810f4342418Spedro 		 * Write the cylinder group buffers for these buffers too.
811f4342418Spedro 		 */
812f4342418Spedro 		 for (i = num; i >= unwindidx; i--) {
813f4342418Spedro 		 	if (i == 0)
814f4342418Spedro 				break;
815f4342418Spedro 
816f4342418Spedro 			bp = getblk(vp, indirs[i].in_lbn, (int) fs->fs_bsize,
817f4342418Spedro 			    0, 0);
818f4342418Spedro 			if (bp->b_flags & B_DELWRI) {
819f4342418Spedro 				nb = fsbtodb(fs, cgtod(fs, dtog(fs,
820f4342418Spedro 				    dbtofsb(fs, bp->b_blkno))));
821f4342418Spedro 				bwrite(bp);
822f4342418Spedro 				bp = getblk(ip->i_devvp, nb,
823f4342418Spedro 				    (int) fs->fs_cgsize, 0, 0);
824f4342418Spedro 				if (bp->b_flags & B_DELWRI)
825f4342418Spedro 					bwrite(bp);
826f4342418Spedro 				else {
827f4342418Spedro 					bp->b_flags |= B_INVAL;
828f4342418Spedro 					brelse(bp);
829f4342418Spedro 				}
830f4342418Spedro 			} else {
831f4342418Spedro 				bp->b_flags |= B_INVAL;
832f4342418Spedro 				brelse(bp);
833f4342418Spedro 			}
834f4342418Spedro 		}
835f4342418Spedro 
836f4342418Spedro 		if (DOINGSOFTDEP(vp) && unwindidx == 0) {
837f4342418Spedro 			ip->i_flag |= IN_CHANGE | IN_UPDATE;
838f4342418Spedro 			ffs_update(ip, NULL, NULL, MNT_WAIT);
839f4342418Spedro 		}
840f4342418Spedro 
841f4342418Spedro 		/*
842f4342418Spedro 		 * Now that any dependencies that we created have been
843f4342418Spedro 		 * resolved, we can undo the partial allocation.
844f4342418Spedro 		 */
845f4342418Spedro 		if (unwindidx == 0) {
846f4342418Spedro 			*allocib = 0;
847f4342418Spedro 			ip->i_flag |= IN_CHANGE | IN_UPDATE;
848f4342418Spedro 			if (DOINGSOFTDEP(vp))
849f4342418Spedro 				ffs_update(ip, NULL, NULL, MNT_WAIT);
850f4342418Spedro 		} else {
851f4342418Spedro 			r = bread(vp, indirs[unwindidx].in_lbn,
852*93f62a9eStedu 			    (int)fs->fs_bsize, &bp);
853f4342418Spedro 			if (r)
854f4342418Spedro 				panic("ffs2_balloc: unwind failed");
855f4342418Spedro 
856f4342418Spedro 			bap = (int64_t *) bp->b_data;
857f4342418Spedro 			bap[indirs[unwindidx].in_off] = 0;
858f4342418Spedro 			bwrite(bp);
859f4342418Spedro 		}
860f4342418Spedro 
861f4342418Spedro 		for (i = unwindidx + 1; i <= num; i++) {
862f4342418Spedro 			bp = getblk(vp, indirs[i].in_lbn, (int)fs->fs_bsize, 0,
863f4342418Spedro 			    0);
864f4342418Spedro 			bp->b_flags |= B_INVAL;
865f4342418Spedro 			brelse(bp);
866f4342418Spedro 		}
867f4342418Spedro 	}
868f4342418Spedro 
869f4342418Spedro 	for (deallocated = 0, blkp = allociblk; blkp < allocblk; blkp++) {
870f4342418Spedro 		ffs_blkfree(ip, *blkp, fs->fs_bsize);
871f4342418Spedro 		deallocated += fs->fs_bsize;
872f4342418Spedro 	}
873f4342418Spedro 
874f4342418Spedro 	if (deallocated) {
875f4342418Spedro 		/*
876f4342418Spedro 	 	 * Restore user's disk quota because allocation failed.
877f4342418Spedro 	 	 */
878f4342418Spedro 		(void) ufs_quota_free_blocks(ip, btodb(deallocated), cred);
879f4342418Spedro 
880f4342418Spedro 		ip->i_ffs2_blocks -= btodb(deallocated);
881f4342418Spedro 		ip->i_flag |= IN_CHANGE | IN_UPDATE;
882f4342418Spedro 	}
883c1df8807Ssturm 	VOP_FSYNC(vp, p->p_ucred, MNT_WAIT, p);
884f4342418Spedro 	return (error);
885f4342418Spedro }
886f4342418Spedro #endif /* FFS2 */
887f4342418Spedro 
888f4342418Spedro /*
889f4342418Spedro  * Balloc defines the structure of file system storage by allocating the
890f4342418Spedro  * physical blocks given the inode and the logical block number in a file.
891f4342418Spedro  */
892f4342418Spedro int
893f4342418Spedro ffs_balloc(struct inode *ip, off_t off, int size, struct ucred *cred,
894f4342418Spedro     int flags, struct buf **bpp)
895f4342418Spedro {
896f4342418Spedro #ifdef FFS2
897f4342418Spedro 	if (ip->i_fs->fs_magic == FS_UFS2_MAGIC)
898f4342418Spedro 		return (ffs2_balloc(ip, off, size, cred, flags, bpp));
899f4342418Spedro 	else
900f4342418Spedro #endif
901f4342418Spedro 		return (ffs1_balloc(ip, off, size, cred, flags, bpp));
902f4342418Spedro }
903