xref: /openbsd/sys/ufs/ffs/ffs_balloc.c (revision 3b9d585e)
1*3b9d585eSjsg /*	$OpenBSD: ffs_balloc.c,v 1.47 2024/04/13 23:44:11 jsg 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>
4807feb63cScsapuntz #include <sys/mount.h>
49df930be7Sderaadt #include <sys/vnode.h>
50df930be7Sderaadt 
51df930be7Sderaadt #include <ufs/ufs/quota.h>
52df930be7Sderaadt #include <ufs/ufs/inode.h>
53fb844963Spedro #include <ufs/ufs/ufsmount.h>
54df930be7Sderaadt #include <ufs/ufs/ufs_extern.h>
55df930be7Sderaadt 
56df930be7Sderaadt #include <ufs/ffs/fs.h>
57df930be7Sderaadt #include <ufs/ffs/ffs_extern.h>
58df930be7Sderaadt 
59f4342418Spedro int ffs1_balloc(struct inode *, off_t, int, struct ucred *, int, struct buf **);
60f4342418Spedro #ifdef FFS2
61f4342418Spedro int ffs2_balloc(struct inode *, off_t, int, struct ucred *, int, struct buf **);
62f4342418Spedro #endif
63f4342418Spedro 
64df930be7Sderaadt /*
65df930be7Sderaadt  * Balloc defines the structure of file system storage
66df930be7Sderaadt  * by allocating the physical blocks on a device given
67df930be7Sderaadt  * the inode and the logical block number in a file.
68df930be7Sderaadt  */
69d28910b8Sniklas int
ffs1_balloc(struct inode * ip,off_t startoffset,int size,struct ucred * cred,int flags,struct buf ** bpp)70f4342418Spedro ffs1_balloc(struct inode *ip, off_t startoffset, int size, struct ucred *cred,
71b080ad39Scsapuntz     int flags, struct buf **bpp)
7207feb63cScsapuntz {
731abdbfdeSderaadt 	daddr_t lbn, nb, newb, pref;
7407feb63cScsapuntz 	struct fs *fs;
75df930be7Sderaadt 	struct buf *bp, *nbp;
7607feb63cScsapuntz 	struct vnode *vp;
77fcf048c1Spedro 	struct proc *p;
78df930be7Sderaadt 	struct indir indirs[NIADDR + 2];
798add4794Sotto 	int32_t *bap;
8007feb63cScsapuntz 	int deallocated, osize, nsize, num, i, error;
81a09be2a2Spedro 	int32_t *allocib, *blkp, *allocblk, allociblk[NIADDR+1];
826cd4677cSart 	int unwindidx = -1;
83df930be7Sderaadt 
84b080ad39Scsapuntz 	vp = ITOV(ip);
85f6d35f95Sderaadt 	fs = ip->i_fs;
86fcf048c1Spedro 	p = curproc;
87b080ad39Scsapuntz 	lbn = lblkno(fs, startoffset);
88b080ad39Scsapuntz 	size = blkoff(fs, startoffset) + size;
8907feb63cScsapuntz 	if (size > fs->fs_bsize)
90f4342418Spedro 		panic("ffs1_balloc: blk too big");
91947c4e29Sart 	if (bpp != NULL)
92b080ad39Scsapuntz 		*bpp = NULL;
9307feb63cScsapuntz 	if (lbn < 0)
9407feb63cScsapuntz 		return (EFBIG);
95df930be7Sderaadt 
96df930be7Sderaadt 	/*
97df930be7Sderaadt 	 * If the next write will extend the file into a new block,
98df930be7Sderaadt 	 * and the file is currently composed of a fragment
99df930be7Sderaadt 	 * this fragment has to be extended to be a full block.
100df930be7Sderaadt 	 */
101fb844963Spedro 	nb = lblkno(fs, ip->i_ffs1_size);
10207feb63cScsapuntz 	if (nb < NDADDR && nb < lbn) {
103df930be7Sderaadt 		osize = blksize(fs, ip, nb);
104df930be7Sderaadt 		if (osize < fs->fs_bsize && osize > 0) {
105df930be7Sderaadt 			error = ffs_realloccg(ip, nb,
106f4342418Spedro 			    ffs1_blkpref(ip, nb, (int)nb, &ip->i_ffs1_db[0]),
107947c4e29Sart 			    osize, (int)fs->fs_bsize, cred, bpp, &newb);
108df930be7Sderaadt 			if (error)
109df930be7Sderaadt 				return (error);
11007feb63cScsapuntz 
111fb844963Spedro 			ip->i_ffs1_size = lblktosize(fs, nb + 1);
112fb844963Spedro 			uvm_vnp_setsize(vp, ip->i_ffs1_size);
113fb844963Spedro 			ip->i_ffs1_db[nb] = newb;
114df930be7Sderaadt 			ip->i_flag |= IN_CHANGE | IN_UPDATE;
115947c4e29Sart 			if (bpp != NULL) {
116df930be7Sderaadt 				if (flags & B_SYNC)
117947c4e29Sart 					bwrite(*bpp);
118df930be7Sderaadt 				else
119947c4e29Sart 					bawrite(*bpp);
120947c4e29Sart 			}
121df930be7Sderaadt 		}
122df930be7Sderaadt 	}
123df930be7Sderaadt 	/*
124df930be7Sderaadt 	 * The first NDADDR blocks are direct blocks
125df930be7Sderaadt 	 */
12607feb63cScsapuntz 	if (lbn < NDADDR) {
127fb844963Spedro 		nb = ip->i_ffs1_db[lbn];
128fb844963Spedro 		if (nb != 0 && ip->i_ffs1_size >= lblktosize(fs, lbn + 1)) {
129947c4e29Sart 			/*
130947c4e29Sart 			 * The block is an already-allocated direct block
131947c4e29Sart 			 * and the file already extends past this block,
132947c4e29Sart 			 * thus this must be a whole block.
133947c4e29Sart 			 * Just read the block (if requested).
134947c4e29Sart 			 */
135947c4e29Sart 
136947c4e29Sart 			if (bpp != NULL) {
13793f62a9eStedu 				error = bread(vp, lbn, fs->fs_bsize, bpp);
138df930be7Sderaadt 				if (error) {
139947c4e29Sart 					brelse(*bpp);
140df930be7Sderaadt 					return (error);
141df930be7Sderaadt 				}
142947c4e29Sart 			}
143df930be7Sderaadt 			return (0);
144df930be7Sderaadt 		}
145df930be7Sderaadt 		if (nb != 0) {
146df930be7Sderaadt 			/*
147df930be7Sderaadt 			 * Consider need to reallocate a fragment.
148df930be7Sderaadt 			 */
149fb844963Spedro 			osize = fragroundup(fs, blkoff(fs, ip->i_ffs1_size));
150df930be7Sderaadt 			nsize = fragroundup(fs, size);
151df930be7Sderaadt 			if (nsize <= osize) {
152947c4e29Sart 				/*
153947c4e29Sart 				 * The existing block is already
154947c4e29Sart 				 * at least as big as we want.
155947c4e29Sart 				 * Just read the block (if requested).
156947c4e29Sart 				 */
157947c4e29Sart 				if (bpp != NULL) {
158f43037e0Spedro 					error = bread(vp, lbn, fs->fs_bsize,
15993f62a9eStedu 					    bpp);
160df930be7Sderaadt 					if (error) {
161947c4e29Sart 						brelse(*bpp);
162df930be7Sderaadt 						return (error);
163df930be7Sderaadt 					}
164b78384fcSbeck 					buf_adjcnt((*bpp), osize);
165947c4e29Sart 				}
166947c4e29Sart 				return (0);
167df930be7Sderaadt 			} else {
168947c4e29Sart 				/*
169947c4e29Sart 				 * The existing block is smaller than we
170947c4e29Sart 				 * want, grow it.
171947c4e29Sart 				 */
17207feb63cScsapuntz 				error = ffs_realloccg(ip, lbn,
173f4342418Spedro 				    ffs1_blkpref(ip, lbn, (int)lbn,
174fb844963Spedro 					&ip->i_ffs1_db[0]),
175947c4e29Sart 				    osize, nsize, cred, bpp, &newb);
176df930be7Sderaadt 				if (error)
177df930be7Sderaadt 					return (error);
178df930be7Sderaadt 			}
179df930be7Sderaadt 		} else {
180947c4e29Sart 			/*
181947c4e29Sart 			 * The block was not previously allocated,
182947c4e29Sart 			 * allocate a new block or fragment.
183947c4e29Sart 			 */
184947c4e29Sart 
185fb844963Spedro 			if (ip->i_ffs1_size < lblktosize(fs, lbn + 1))
186df930be7Sderaadt 				nsize = fragroundup(fs, size);
187df930be7Sderaadt 			else
188df930be7Sderaadt 				nsize = fs->fs_bsize;
18907feb63cScsapuntz 			error = ffs_alloc(ip, lbn,
190f4342418Spedro 			    ffs1_blkpref(ip, lbn, (int)lbn, &ip->i_ffs1_db[0]),
191df930be7Sderaadt 			    nsize, cred, &newb);
192df930be7Sderaadt 			if (error)
193df930be7Sderaadt 				return (error);
194947c4e29Sart 			if (bpp != NULL) {
195570df5c4Scheloha 				*bpp = getblk(vp, lbn, fs->fs_bsize, 0, INFSLP);
196f43037e0Spedro 				if (nsize < fs->fs_bsize)
197f43037e0Spedro 					(*bpp)->b_bcount = nsize;
198947c4e29Sart 				(*bpp)->b_blkno = fsbtodb(fs, newb);
199df930be7Sderaadt 				if (flags & B_CLRBUF)
200947c4e29Sart 					clrbuf(*bpp);
201947c4e29Sart 			}
202df930be7Sderaadt 		}
203fb844963Spedro 		ip->i_ffs1_db[lbn] = newb;
204df930be7Sderaadt 		ip->i_flag |= IN_CHANGE | IN_UPDATE;
205df930be7Sderaadt 		return (0);
206df930be7Sderaadt 	}
207947c4e29Sart 
208df930be7Sderaadt 	/*
209df930be7Sderaadt 	 * Determine the number of levels of indirection.
210df930be7Sderaadt 	 */
211df930be7Sderaadt 	pref = 0;
21207feb63cScsapuntz 	if ((error = ufs_getlbns(vp, lbn, indirs, &num)) != 0)
213df930be7Sderaadt 		return(error);
214df930be7Sderaadt #ifdef DIAGNOSTIC
215df930be7Sderaadt 	if (num < 1)
216f4342418Spedro 		panic ("ffs1_balloc: ufs_bmaparray returned indirect block");
217df930be7Sderaadt #endif
218df930be7Sderaadt 	/*
219df930be7Sderaadt 	 * Fetch the first indirect block allocating if necessary.
220df930be7Sderaadt 	 */
221df930be7Sderaadt 	--num;
222fb844963Spedro 	nb = ip->i_ffs1_ib[indirs[0].in_off];
22307feb63cScsapuntz 
22407feb63cScsapuntz 	allocib = NULL;
22507feb63cScsapuntz 	allocblk = allociblk;
226df930be7Sderaadt 	if (nb == 0) {
2279266689dStedu 		pref = ffs1_blkpref(ip, lbn, -indirs[0].in_off - 1, NULL);
228d28910b8Sniklas 	        error = ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize,
229d28910b8Sniklas 				  cred, &newb);
230d28910b8Sniklas 		if (error)
231947c4e29Sart 			goto fail;
232df930be7Sderaadt 		nb = newb;
23307feb63cScsapuntz 
23407feb63cScsapuntz 		*allocblk++ = nb;
235570df5c4Scheloha 		bp = getblk(vp, indirs[1].in_lbn, fs->fs_bsize, 0, INFSLP);
23607feb63cScsapuntz 		bp->b_blkno = fsbtodb(fs, nb);
237df930be7Sderaadt 		clrbuf(bp);
23807feb63cScsapuntz 
239df930be7Sderaadt 		/*
240df930be7Sderaadt 		 * Write synchronously so that indirect blocks
241df930be7Sderaadt 		 * never point at garbage.
242df930be7Sderaadt 		 */
24307feb63cScsapuntz 		if ((error = bwrite(bp)) != 0)
24407feb63cScsapuntz 			goto fail;
245fb844963Spedro 		allocib = &ip->i_ffs1_ib[indirs[0].in_off];
24607feb63cScsapuntz 		*allocib = nb;
247df930be7Sderaadt 		ip->i_flag |= IN_CHANGE | IN_UPDATE;
248df930be7Sderaadt 	}
249947c4e29Sart 
250df930be7Sderaadt 	/*
251df930be7Sderaadt 	 * Fetch through the indirect blocks, allocating as necessary.
252df930be7Sderaadt 	 */
253df930be7Sderaadt 	for (i = 1;;) {
25493f62a9eStedu 		error = bread(vp, indirs[i].in_lbn, (int)fs->fs_bsize, &bp);
255df930be7Sderaadt 		if (error) {
256df930be7Sderaadt 			brelse(bp);
25707feb63cScsapuntz 			goto fail;
258df930be7Sderaadt 		}
2598add4794Sotto 		bap = (int32_t *)bp->b_data;
260df930be7Sderaadt 		nb = bap[indirs[i].in_off];
261df930be7Sderaadt 		if (i == num)
262df930be7Sderaadt 			break;
2633853cac8Sart 		i++;
264df930be7Sderaadt 		if (nb != 0) {
265df930be7Sderaadt 			brelse(bp);
266df930be7Sderaadt 			continue;
267df930be7Sderaadt 		}
268df930be7Sderaadt 		if (pref == 0)
2699266689dStedu 			pref = ffs1_blkpref(ip, lbn, i - num - 1, NULL);
270d28910b8Sniklas 		error = ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize, cred,
271d28910b8Sniklas 				  &newb);
272d28910b8Sniklas 		if (error) {
273df930be7Sderaadt 			brelse(bp);
27407feb63cScsapuntz 			goto fail;
275df930be7Sderaadt 		}
276df930be7Sderaadt 		nb = newb;
27707feb63cScsapuntz 		*allocblk++ = nb;
278570df5c4Scheloha 		nbp = getblk(vp, indirs[i].in_lbn, fs->fs_bsize, 0, INFSLP);
279df930be7Sderaadt 		nbp->b_blkno = fsbtodb(fs, nb);
280df930be7Sderaadt 		clrbuf(nbp);
28107feb63cScsapuntz 
282df930be7Sderaadt 		/*
283df930be7Sderaadt 		 * Write synchronously so that indirect blocks
284df930be7Sderaadt 		 * never point at garbage.
285df930be7Sderaadt 		 */
286d28910b8Sniklas 		if ((error = bwrite(nbp)) != 0) {
287df930be7Sderaadt 			brelse(bp);
28807feb63cScsapuntz 			goto fail;
28907feb63cScsapuntz 		}
290df930be7Sderaadt 		bap[indirs[i - 1].in_off] = nb;
2916cd4677cSart 		if (allocib == NULL && unwindidx < 0)
2926cd4677cSart 			unwindidx = i - 1;
293df930be7Sderaadt 		/*
294df930be7Sderaadt 		 * If required, write synchronously, otherwise use
295df930be7Sderaadt 		 * delayed write.
296df930be7Sderaadt 		 */
297df930be7Sderaadt 		if (flags & B_SYNC) {
298df930be7Sderaadt 			bwrite(bp);
299df930be7Sderaadt 		} else {
300df930be7Sderaadt 			bdwrite(bp);
301df930be7Sderaadt 		}
302df930be7Sderaadt 	}
303df930be7Sderaadt 	/*
304df930be7Sderaadt 	 * Get the data block, allocating if necessary.
305df930be7Sderaadt 	 */
306df930be7Sderaadt 	if (nb == 0) {
307f4342418Spedro 		pref = ffs1_blkpref(ip, lbn, indirs[i].in_off, &bap[0]);
308d28910b8Sniklas 		error = ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize, cred,
309d28910b8Sniklas 				  &newb);
310d28910b8Sniklas 		if (error) {
311df930be7Sderaadt 			brelse(bp);
31207feb63cScsapuntz 			goto fail;
313df930be7Sderaadt 		}
314df930be7Sderaadt 		nb = newb;
31507feb63cScsapuntz 		*allocblk++ = nb;
316947c4e29Sart 		if (bpp != NULL) {
317570df5c4Scheloha 			nbp = getblk(vp, lbn, fs->fs_bsize, 0, INFSLP);
318df930be7Sderaadt 			nbp->b_blkno = fsbtodb(fs, nb);
319df930be7Sderaadt 			if (flags & B_CLRBUF)
320df930be7Sderaadt 				clrbuf(nbp);
321947c4e29Sart 			*bpp = nbp;
322947c4e29Sart 		}
323df930be7Sderaadt 		bap[indirs[i].in_off] = nb;
324df930be7Sderaadt 		/*
325df930be7Sderaadt 		 * If required, write synchronously, otherwise use
326df930be7Sderaadt 		 * delayed write.
327df930be7Sderaadt 		 */
328df930be7Sderaadt 		if (flags & B_SYNC) {
329df930be7Sderaadt 			bwrite(bp);
330df930be7Sderaadt 		} else {
331df930be7Sderaadt 			bdwrite(bp);
332df930be7Sderaadt 		}
333df930be7Sderaadt 		return (0);
334df930be7Sderaadt 	}
335df930be7Sderaadt 	brelse(bp);
336947c4e29Sart 	if (bpp != NULL) {
337df930be7Sderaadt 		if (flags & B_CLRBUF) {
33893f62a9eStedu 			error = bread(vp, lbn, (int)fs->fs_bsize, &nbp);
339df930be7Sderaadt 			if (error) {
340df930be7Sderaadt 				brelse(nbp);
34107feb63cScsapuntz 				goto fail;
342df930be7Sderaadt 			}
343df930be7Sderaadt 		} else {
344570df5c4Scheloha 			nbp = getblk(vp, lbn, fs->fs_bsize, 0, INFSLP);
345df930be7Sderaadt 			nbp->b_blkno = fsbtodb(fs, nb);
346df930be7Sderaadt 		}
347b080ad39Scsapuntz 		*bpp = nbp;
348947c4e29Sart 	}
349df930be7Sderaadt 	return (0);
35007feb63cScsapuntz 
35107feb63cScsapuntz fail:
35207feb63cScsapuntz 	/*
353fcf048c1Spedro 	 * If we have failed to allocate any blocks, simply return the error.
354fcf048c1Spedro 	 * This is the usual case and avoids the need to fsync the file.
35507feb63cScsapuntz 	 */
356fcf048c1Spedro 	if (allocblk == allociblk && allocib == NULL && unwindidx == -1)
357fcf048c1Spedro 		return (error);
358fcf048c1Spedro 	/*
359fcf048c1Spedro 	 * If we have failed part way through block allocation, we have to
360fcf048c1Spedro 	 * deallocate any indirect blocks that we have allocated. We have to
361fcf048c1Spedro 	 * fsync the file before we start to get rid of all of its
362fcf048c1Spedro 	 * dependencies so that we do not leave them dangling. We have to sync
363fcf048c1Spedro 	 * it at the end so that the softdep code does not find any untracked
364fcf048c1Spedro 	 * changes. Although this is really slow, running out of disk space is
36580adcad8Smartynas 	 * not expected to be a common occurrence. The error return from fsync
366fcf048c1Spedro 	 * is ignored as we already have an error to return to the user.
367fcf048c1Spedro 	 */
368fcf048c1Spedro 	VOP_FSYNC(vp, p->p_ucred, MNT_WAIT, p);
36907feb63cScsapuntz 	for (deallocated = 0, blkp = allociblk; blkp < allocblk; blkp++) {
37007feb63cScsapuntz 		ffs_blkfree(ip, *blkp, fs->fs_bsize);
37107feb63cScsapuntz 		deallocated += fs->fs_bsize;
37207feb63cScsapuntz 	}
3736cd4677cSart 	if (allocib != NULL) {
37407feb63cScsapuntz 		*allocib = 0;
3756cd4677cSart 	} else if (unwindidx >= 0) {
3766cd4677cSart 		int r;
3776cd4677cSart 
37893f62a9eStedu 		r = bread(vp, indirs[unwindidx].in_lbn, (int)fs->fs_bsize, &bp);
3796cd4677cSart 		if (r)
3806cd4677cSart 			panic("Could not unwind indirect block, error %d", r);
3818add4794Sotto 		bap = (int32_t *)bp->b_data;
3826cd4677cSart 		bap[indirs[unwindidx].in_off] = 0;
3836cd4677cSart 		if (flags & B_SYNC) {
3846cd4677cSart 			bwrite(bp);
3856cd4677cSart 		} else {
3866cd4677cSart 			bdwrite(bp);
3876cd4677cSart 		}
3886cd4677cSart 	}
38907feb63cScsapuntz 	if (deallocated) {
39007feb63cScsapuntz 		/*
39107feb63cScsapuntz 		 * Restore user's disk quota because allocation failed.
39207feb63cScsapuntz 		 */
3935f7d6642Scsapuntz 		(void)ufs_quota_free_blocks(ip, btodb(deallocated), cred);
3945f7d6642Scsapuntz 
395fb844963Spedro 		ip->i_ffs1_blocks -= btodb(deallocated);
39607feb63cScsapuntz 		ip->i_flag |= IN_CHANGE | IN_UPDATE;
39707feb63cScsapuntz 	}
398fcf048c1Spedro 	VOP_FSYNC(vp, p->p_ucred, MNT_WAIT, p);
3996cd4677cSart 	return (error);
400df930be7Sderaadt }
401f4342418Spedro 
402f4342418Spedro #ifdef FFS2
403f4342418Spedro int
ffs2_balloc(struct inode * ip,off_t off,int size,struct ucred * cred,int flags,struct buf ** bpp)404f4342418Spedro ffs2_balloc(struct inode *ip, off_t off, int size, struct ucred *cred,
405f4342418Spedro     int flags, struct buf **bpp)
406f4342418Spedro {
4071abdbfdeSderaadt 	daddr_t lbn, lastlbn, nb, newb, *blkp;
4081abdbfdeSderaadt 	daddr_t pref, *allocblk, allociblk[NIADDR + 1];
4091abdbfdeSderaadt 	daddr_t *bap, *allocib;
410f4342418Spedro 	int deallocated, osize, nsize, num, i, error, unwindidx, r;
411f4342418Spedro 	struct buf *bp, *nbp;
412f4342418Spedro 	struct indir indirs[NIADDR + 2];
413f4342418Spedro 	struct fs *fs;
414f4342418Spedro 	struct vnode *vp;
415c1df8807Ssturm 	struct proc *p;
416f4342418Spedro 
417f4342418Spedro 	vp = ITOV(ip);
418f4342418Spedro 	fs = ip->i_fs;
419c1df8807Ssturm 	p = curproc;
42016a60b30Ssturm 	unwindidx = -1;
421f4342418Spedro 
422f4342418Spedro 	lbn = lblkno(fs, off);
423f4342418Spedro 	size = blkoff(fs, off) + size;
424f4342418Spedro 
425f4342418Spedro 	if (size > fs->fs_bsize)
426f4342418Spedro 		panic("ffs2_balloc: block too big");
427f4342418Spedro 
428f4342418Spedro 	if (bpp != NULL)
429f4342418Spedro 		*bpp = NULL;
430f4342418Spedro 
431f4342418Spedro 	if (lbn < 0)
432f4342418Spedro 		return (EFBIG);
433f4342418Spedro 
434f4342418Spedro 	/*
435f4342418Spedro 	 * If the next write will extend the file into a new block, and the
436f4342418Spedro 	 * file is currently composed of a fragment, this fragment has to be
437f4342418Spedro 	 * extended to be a full block.
438f4342418Spedro 	 */
439f4342418Spedro 	lastlbn = lblkno(fs, ip->i_ffs2_size);
440f4342418Spedro 	if (lastlbn < NDADDR && lastlbn < lbn) {
441f4342418Spedro 		nb = lastlbn;
442f4342418Spedro 		osize = blksize(fs, ip, nb);
443f4342418Spedro 		if (osize < fs->fs_bsize && osize > 0) {
444f4342418Spedro 			error = ffs_realloccg(ip, nb, ffs2_blkpref(ip,
445f4342418Spedro 			    lastlbn, nb, &ip->i_ffs2_db[0]), osize,
446f4342418Spedro 			    (int) fs->fs_bsize, cred, bpp, &newb);
447f4342418Spedro 			if (error)
448f4342418Spedro 				return (error);
449f4342418Spedro 
450f4342418Spedro 			ip->i_ffs2_size = lblktosize(fs, nb + 1);
451f4342418Spedro 			uvm_vnp_setsize(vp, ip->i_ffs2_size);
452f4342418Spedro 			ip->i_ffs2_db[nb] = newb;
453f4342418Spedro 			ip->i_flag |= IN_CHANGE | IN_UPDATE;
454f4342418Spedro 
455f4342418Spedro 			if (bpp) {
456f4342418Spedro 				if (flags & B_SYNC)
457f4342418Spedro 					bwrite(*bpp);
458f4342418Spedro 				else
459f4342418Spedro 					bawrite(*bpp);
460f4342418Spedro 			}
461f4342418Spedro 		}
462f4342418Spedro 	}
463f4342418Spedro 
464f4342418Spedro 	/*
465f4342418Spedro 	 * The first NDADDR blocks are direct.
466f4342418Spedro 	 */
467f4342418Spedro 	if (lbn < NDADDR) {
468f4342418Spedro 
469f4342418Spedro 		nb = ip->i_ffs2_db[lbn];
470f4342418Spedro 
471f4342418Spedro 		if (nb != 0 && ip->i_ffs2_size >= lblktosize(fs, lbn + 1)) {
472f4342418Spedro 			/*
473f4342418Spedro 			 * The direct block is already allocated and the file
474f4342418Spedro 			 * extends past this block, thus this must be a whole
475f4342418Spedro 			 * block. Just read it, if requested.
476f4342418Spedro 			 */
477f4342418Spedro 			if (bpp != NULL) {
47893f62a9eStedu 				error = bread(vp, lbn, fs->fs_bsize, bpp);
479f4342418Spedro 				if (error) {
480f4342418Spedro 					brelse(*bpp);
481f4342418Spedro 					return (error);
482f4342418Spedro 				}
483f4342418Spedro 			}
484f4342418Spedro 
485f4342418Spedro 			return (0);
486f4342418Spedro 		}
487f4342418Spedro 
488f4342418Spedro 		if (nb != 0) {
489f4342418Spedro 			/*
490f4342418Spedro 			 * Consider the need to allocate a fragment.
491f4342418Spedro 			 */
492f4342418Spedro 			osize = fragroundup(fs, blkoff(fs, ip->i_ffs2_size));
493f4342418Spedro 			nsize = fragroundup(fs, size);
494f4342418Spedro 
495f4342418Spedro 			if (nsize <= osize) {
496f4342418Spedro 				/*
497f4342418Spedro 				 * The existing block is already at least as
498f4342418Spedro 				 * big as we want. Just read it, if requested.
499f4342418Spedro 				 */
500f4342418Spedro 				if (bpp != NULL) {
501f43037e0Spedro 					error = bread(vp, lbn, fs->fs_bsize,
50293f62a9eStedu 					    bpp);
503f4342418Spedro 					if (error) {
504f4342418Spedro 						brelse(*bpp);
505f4342418Spedro 						return (error);
506f4342418Spedro 					}
507b78384fcSbeck 					buf_adjcnt((*bpp), osize);
508f4342418Spedro 				}
509f4342418Spedro 
510f4342418Spedro 				return (0);
511f4342418Spedro 			} else {
512f4342418Spedro 				/*
513f4342418Spedro 				 * The existing block is smaller than we want,
514f4342418Spedro 				 * grow it.
515f4342418Spedro 				 */
516f4342418Spedro 				error = ffs_realloccg(ip, lbn,
517f4342418Spedro 				    ffs2_blkpref(ip, lbn, (int) lbn,
518f4342418Spedro 				    &ip->i_ffs2_db[0]), osize, nsize, cred,
519f4342418Spedro 				    bpp, &newb);
520f4342418Spedro 				if (error)
521f4342418Spedro 					return (error);
522f4342418Spedro 			}
523f4342418Spedro 		} else {
524f4342418Spedro 			/*
525f4342418Spedro 			 * The block was not previously allocated, allocate a
526f4342418Spedro 			 * new block or fragment.
527f4342418Spedro 			 */
528f4342418Spedro 			if (ip->i_ffs2_size < lblktosize(fs, lbn + 1))
529f4342418Spedro 				nsize = fragroundup(fs, size);
530f4342418Spedro 			else
531f4342418Spedro 				nsize = fs->fs_bsize;
532f4342418Spedro 
533f4342418Spedro 			error = ffs_alloc(ip, lbn, ffs2_blkpref(ip, lbn,
534f4342418Spedro 			    (int) lbn, &ip->i_ffs2_db[0]), nsize, cred, &newb);
535f4342418Spedro 			if (error)
536f4342418Spedro 				return (error);
537f4342418Spedro 
538f4342418Spedro 			if (bpp != NULL) {
539570df5c4Scheloha 				bp = getblk(vp, lbn, fs->fs_bsize, 0, INFSLP);
540f43037e0Spedro 				if (nsize < fs->fs_bsize)
541f43037e0Spedro 					bp->b_bcount = nsize;
542f4342418Spedro 				bp->b_blkno = fsbtodb(fs, newb);
543f4342418Spedro 				if (flags & B_CLRBUF)
544f4342418Spedro 					clrbuf(bp);
545f4342418Spedro 				*bpp = bp;
546f4342418Spedro 			}
5475d1e8defSpedro 		}
548f4342418Spedro 
549f4342418Spedro 		ip->i_ffs2_db[lbn] = newb;
550f4342418Spedro 		ip->i_flag |= IN_CHANGE | IN_UPDATE;
551f4342418Spedro 
552f4342418Spedro 		return (0);
553f4342418Spedro 	}
554f4342418Spedro 
555f4342418Spedro 	/*
556f4342418Spedro 	 * Determine the number of levels of indirection.
557f4342418Spedro 	 */
558f4342418Spedro 	pref = 0;
559f4342418Spedro 	error = ufs_getlbns(vp, lbn, indirs, &num);
560f4342418Spedro 	if (error)
561f4342418Spedro 		return (error);
562f4342418Spedro 
563244cffc3Spedro #ifdef DIAGNOSTIC
564244cffc3Spedro 	if (num < 1)
565244cffc3Spedro 		panic("ffs2_balloc: ufs_bmaparray returned indirect block");
566244cffc3Spedro #endif
567244cffc3Spedro 
568f4342418Spedro 	/*
569f4342418Spedro 	 * Fetch the first indirect block allocating it necessary.
570f4342418Spedro 	 */
571f4342418Spedro 	--num;
572f4342418Spedro 	nb = ip->i_ffs2_ib[indirs[0].in_off];
573f4342418Spedro 	allocib = NULL;
574f4342418Spedro 	allocblk = allociblk;
575f4342418Spedro 
576f4342418Spedro 	if (nb == 0) {
5779266689dStedu 		pref = ffs2_blkpref(ip, lbn, -indirs[0].in_off - 1, NULL);
578f4342418Spedro 		error = ffs_alloc(ip, lbn, pref, (int) fs->fs_bsize, cred,
579f4342418Spedro 		    &newb);
580f4342418Spedro 		if (error)
581f4342418Spedro 			goto fail;
582f4342418Spedro 
583f4342418Spedro 		nb = newb;
584f4342418Spedro 		*allocblk++ = nb;
585570df5c4Scheloha 		bp = getblk(vp, indirs[1].in_lbn, fs->fs_bsize, 0, INFSLP);
586f4342418Spedro 		bp->b_blkno = fsbtodb(fs, nb);
587f4342418Spedro 		clrbuf(bp);
588f4342418Spedro 
589f4342418Spedro 		/*
590f4342418Spedro 		 * Write synchronously so that indirect blocks never
591f4342418Spedro 		 * point at garbage.
592f4342418Spedro 		 */
593f4342418Spedro 		error = bwrite(bp);
594f4342418Spedro 		if (error)
595f4342418Spedro 			goto fail;
596f4342418Spedro 
597f4342418Spedro 		unwindidx = 0;
598f4342418Spedro 		allocib = &ip->i_ffs2_ib[indirs[0].in_off];
599f4342418Spedro 		*allocib = nb;
600f4342418Spedro 		ip->i_flag |= IN_CHANGE | IN_UPDATE;
601f4342418Spedro 	}
602f4342418Spedro 
603f4342418Spedro 	/*
604f4342418Spedro 	 * Fetch through the indirect blocks, allocating as necessary.
605f4342418Spedro 	 */
606f4342418Spedro 	for (i = 1;;) {
60793f62a9eStedu 		error = bread(vp, indirs[i].in_lbn, (int)fs->fs_bsize, &bp);
608f4342418Spedro 		if (error) {
609f4342418Spedro 			brelse(bp);
610f4342418Spedro 			goto fail;
611f4342418Spedro 		}
612f4342418Spedro 
613f4342418Spedro 		bap = (int64_t *) bp->b_data;
614f4342418Spedro 		nb = bap[indirs[i].in_off];
615f4342418Spedro 
616f4342418Spedro 		if (i == num)
617f4342418Spedro 			break;
618f4342418Spedro 
619f4342418Spedro 		i++;
620f4342418Spedro 
621f4342418Spedro 		if (nb != 0) {
622f4342418Spedro 			brelse(bp);
623f4342418Spedro 			continue;
624f4342418Spedro 		}
625f4342418Spedro 
626f4342418Spedro 		if (pref == 0)
6279266689dStedu 			pref = ffs2_blkpref(ip, lbn, i - num - 1, NULL);
628f4342418Spedro 
629f4342418Spedro 		error = ffs_alloc(ip, lbn, pref, (int) fs->fs_bsize, cred,
630f4342418Spedro 		    &newb);
631f4342418Spedro 		if (error) {
632f4342418Spedro 			brelse(bp);
633f4342418Spedro 			goto fail;
634f4342418Spedro 		}
635f4342418Spedro 
636f4342418Spedro 		nb = newb;
637f4342418Spedro 		*allocblk++ = nb;
638570df5c4Scheloha 		nbp = getblk(vp, indirs[i].in_lbn, fs->fs_bsize, 0, INFSLP);
639f4342418Spedro 		nbp->b_blkno = fsbtodb(fs, nb);
640f4342418Spedro 		clrbuf(nbp);
641f4342418Spedro 
642f4342418Spedro 		/*
643f4342418Spedro 		 * Write synchronously so that indirect blocks never
644f4342418Spedro 		 * point at garbage.
645f4342418Spedro 		 */
646f4342418Spedro 		error = bwrite(nbp);
647f4342418Spedro 		if (error) {
648f4342418Spedro 			brelse(bp);
649f4342418Spedro 			goto fail;
650f4342418Spedro 		}
651f4342418Spedro 
652f4342418Spedro 		if (unwindidx < 0)
653f4342418Spedro 			unwindidx = i - 1;
654f4342418Spedro 
655f4342418Spedro 		bap[indirs[i - 1].in_off] = nb;
656f4342418Spedro 
657f4342418Spedro 		/*
658f4342418Spedro 		 * If required, write synchronously, otherwise use delayed
659f4342418Spedro 		 * write.
660f4342418Spedro 		 */
661f4342418Spedro 		if (flags & B_SYNC)
662f4342418Spedro 			bwrite(bp);
663f4342418Spedro 		else
664f4342418Spedro 			bdwrite(bp);
665f4342418Spedro 	}
666f4342418Spedro 
667f4342418Spedro 	/*
668f4342418Spedro 	 * Get the data block, allocating if necessary.
669f4342418Spedro 	 */
670f4342418Spedro 	if (nb == 0) {
671f4342418Spedro 		pref = ffs2_blkpref(ip, lbn, indirs[num].in_off, &bap[0]);
672f4342418Spedro 
673f4342418Spedro 		error = ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize, cred,
674f4342418Spedro 		    &newb);
675f4342418Spedro 		if (error) {
676f4342418Spedro 			brelse(bp);
677f4342418Spedro 			goto fail;
678f4342418Spedro 		}
679f4342418Spedro 
680f4342418Spedro 		nb = newb;
681f4342418Spedro 		*allocblk++ = nb;
682f4342418Spedro 
683f4342418Spedro 		if (bpp != NULL) {
684570df5c4Scheloha 			nbp = getblk(vp, lbn, fs->fs_bsize, 0, INFSLP);
685f4342418Spedro 			nbp->b_blkno = fsbtodb(fs, nb);
686f4342418Spedro 			if (flags & B_CLRBUF)
687f4342418Spedro 				clrbuf(nbp);
688f4342418Spedro 			*bpp = nbp;
689f4342418Spedro 		}
690f4342418Spedro 
691f4342418Spedro 		bap[indirs[num].in_off] = nb;
692f4342418Spedro 
693f4342418Spedro 		if (allocib == NULL && unwindidx < 0)
694f4342418Spedro 			unwindidx = i - 1;
695f4342418Spedro 
696f4342418Spedro 		/*
697f4342418Spedro 		 * If required, write synchronously, otherwise use delayed
698f4342418Spedro 		 * write.
699f4342418Spedro 		 */
700f4342418Spedro 		if (flags & B_SYNC)
701f4342418Spedro 			bwrite(bp);
702f4342418Spedro 		else
703f4342418Spedro 			bdwrite(bp);
704f4342418Spedro 
705f4342418Spedro 		return (0);
706f4342418Spedro 	}
707f4342418Spedro 
708f4342418Spedro 	brelse(bp);
709f4342418Spedro 
710f4342418Spedro 	if (bpp != NULL) {
711f4342418Spedro 		if (flags & B_CLRBUF) {
71293f62a9eStedu 			error = bread(vp, lbn, (int)fs->fs_bsize, &nbp);
713f4342418Spedro 			if (error) {
714f4342418Spedro 				brelse(nbp);
715f4342418Spedro 				goto fail;
716f4342418Spedro 			}
717f4342418Spedro 		} else {
718570df5c4Scheloha 			nbp = getblk(vp, lbn, fs->fs_bsize, 0, INFSLP);
719f4342418Spedro 			nbp->b_blkno = fsbtodb(fs, nb);
720f4342418Spedro 			clrbuf(nbp);
721f4342418Spedro 		}
722f4342418Spedro 
723f4342418Spedro 		*bpp = nbp;
724f4342418Spedro 	}
725f4342418Spedro 
726f4342418Spedro 	return (0);
727f4342418Spedro 
728f4342418Spedro fail:
729c1df8807Ssturm 	/*
730c1df8807Ssturm 	 * If we have failed to allocate any blocks, simply return the error.
731c1df8807Ssturm 	 * This is the usual case and avoids the need to fsync the file.
732c1df8807Ssturm 	 */
733c1df8807Ssturm 	if (allocblk == allociblk && allocib == NULL && unwindidx == -1)
734c1df8807Ssturm 		return (error);
735f4342418Spedro 	/*
736f4342418Spedro 	 * If we have failed part way through block allocation, we have to
737c1df8807Ssturm 	 * deallocate any indirect blocks that we have allocated. We have to
738c1df8807Ssturm 	 * fsync the file before we start to get rid of all of its
739c1df8807Ssturm 	 * dependencies so that we do not leave them dangling. We have to sync
740c1df8807Ssturm 	 * it at the end so that the softdep code does not find any untracked
741c1df8807Ssturm 	 * changes. Although this is really slow, running out of disk space is
74280adcad8Smartynas 	 * not expected to be a common occurrence. The error return from fsync
743c1df8807Ssturm 	 * is ignored as we already have an error to return to the user.
744f4342418Spedro 	 */
745c1df8807Ssturm 	VOP_FSYNC(vp, p->p_ucred, MNT_WAIT, p);
746f4342418Spedro 	if (unwindidx >= 0) {
747f4342418Spedro 		/*
748f4342418Spedro 		 * First write out any buffers we've created to resolve their
749f4342418Spedro 		 * softdeps. This must be done in reverse order of creation so
750f4342418Spedro 		 * that we resolve the dependencies in one pass.
751f4342418Spedro 		 * Write the cylinder group buffers for these buffers too.
752f4342418Spedro 		 */
753f4342418Spedro 		for (i = num; i >= unwindidx; i--) {
754f4342418Spedro 		 	if (i == 0)
755f4342418Spedro 				break;
756f4342418Spedro 
757f4342418Spedro 			bp = getblk(vp, indirs[i].in_lbn, (int) fs->fs_bsize,
758570df5c4Scheloha 			    0, INFSLP);
759f4342418Spedro 			if (bp->b_flags & B_DELWRI) {
760f4342418Spedro 				nb = fsbtodb(fs, cgtod(fs, dtog(fs,
761f4342418Spedro 				    dbtofsb(fs, bp->b_blkno))));
762f4342418Spedro 				bwrite(bp);
763f4342418Spedro 				bp = getblk(ip->i_devvp, nb,
764570df5c4Scheloha 				    (int) fs->fs_cgsize, 0, INFSLP);
765f4342418Spedro 				if (bp->b_flags & B_DELWRI)
766f4342418Spedro 					bwrite(bp);
767f4342418Spedro 				else {
768f4342418Spedro 					bp->b_flags |= B_INVAL;
769f4342418Spedro 					brelse(bp);
770f4342418Spedro 				}
771f4342418Spedro 			} else {
772f4342418Spedro 				bp->b_flags |= B_INVAL;
773f4342418Spedro 				brelse(bp);
774f4342418Spedro 			}
775f4342418Spedro 		}
776f4342418Spedro 
777f4342418Spedro 		/*
778f4342418Spedro 		 * Now that any dependencies that we created have been
779f4342418Spedro 		 * resolved, we can undo the partial allocation.
780f4342418Spedro 		 */
781f4342418Spedro 		if (unwindidx == 0) {
782f4342418Spedro 			*allocib = 0;
783f4342418Spedro 			ip->i_flag |= IN_CHANGE | IN_UPDATE;
784f4342418Spedro 		} else {
785f4342418Spedro 			r = bread(vp, indirs[unwindidx].in_lbn,
78693f62a9eStedu 			    (int)fs->fs_bsize, &bp);
787f4342418Spedro 			if (r)
788f4342418Spedro 				panic("ffs2_balloc: unwind failed");
789f4342418Spedro 
790f4342418Spedro 			bap = (int64_t *) bp->b_data;
791f4342418Spedro 			bap[indirs[unwindidx].in_off] = 0;
792f4342418Spedro 			bwrite(bp);
793f4342418Spedro 		}
794f4342418Spedro 
795f4342418Spedro 		for (i = unwindidx + 1; i <= num; i++) {
796f4342418Spedro 			bp = getblk(vp, indirs[i].in_lbn, (int)fs->fs_bsize, 0,
797570df5c4Scheloha 			    INFSLP);
798f4342418Spedro 			bp->b_flags |= B_INVAL;
799f4342418Spedro 			brelse(bp);
800f4342418Spedro 		}
801f4342418Spedro 	}
802f4342418Spedro 
803f4342418Spedro 	for (deallocated = 0, blkp = allociblk; blkp < allocblk; blkp++) {
804f4342418Spedro 		ffs_blkfree(ip, *blkp, fs->fs_bsize);
805f4342418Spedro 		deallocated += fs->fs_bsize;
806f4342418Spedro 	}
807f4342418Spedro 
808f4342418Spedro 	if (deallocated) {
809f4342418Spedro 		/*
810f4342418Spedro 	 	 * Restore user's disk quota because allocation failed.
811f4342418Spedro 	 	 */
812f4342418Spedro 		(void) ufs_quota_free_blocks(ip, btodb(deallocated), cred);
813f4342418Spedro 
814f4342418Spedro 		ip->i_ffs2_blocks -= btodb(deallocated);
815f4342418Spedro 		ip->i_flag |= IN_CHANGE | IN_UPDATE;
816f4342418Spedro 	}
817c1df8807Ssturm 	VOP_FSYNC(vp, p->p_ucred, MNT_WAIT, p);
818f4342418Spedro 	return (error);
819f4342418Spedro }
820f4342418Spedro #endif /* FFS2 */
821f4342418Spedro 
822f4342418Spedro /*
823f4342418Spedro  * Balloc defines the structure of file system storage by allocating the
824f4342418Spedro  * physical blocks given the inode and the logical block number in a file.
825f4342418Spedro  */
826f4342418Spedro int
ffs_balloc(struct inode * ip,off_t off,int size,struct ucred * cred,int flags,struct buf ** bpp)827f4342418Spedro ffs_balloc(struct inode *ip, off_t off, int size, struct ucred *cred,
828f4342418Spedro     int flags, struct buf **bpp)
829f4342418Spedro {
830f4342418Spedro #ifdef FFS2
831f4342418Spedro 	if (ip->i_fs->fs_magic == FS_UFS2_MAGIC)
832f4342418Spedro 		return (ffs2_balloc(ip, off, size, cred, flags, bpp));
833f4342418Spedro 	else
834f4342418Spedro #endif
835f4342418Spedro 		return (ffs1_balloc(ip, off, size, cred, flags, bpp));
836f4342418Spedro }
837