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