1185222Ssam/*	$NetBSD: ffs_balloc.c,v 1.13 2004/06/20 22:20:18 jmc Exp $	*/
2185222Ssam/* From NetBSD: ffs_balloc.c,v 1.25 2001/08/08 08:36:36 lukem Exp */
3185222Ssam
4185222Ssam/*
5185222Ssam * Copyright (c) 1982, 1986, 1989, 1993
6185222Ssam *	The Regents of the University of California.  All rights reserved.
7185222Ssam *
8185222Ssam * Redistribution and use in source and binary forms, with or without
9185222Ssam * modification, are permitted provided that the following conditions
10185222Ssam * are met:
11185222Ssam * 1. Redistributions of source code must retain the above copyright
12185222Ssam *    notice, this list of conditions and the following disclaimer.
13185222Ssam * 2. Redistributions in binary form must reproduce the above copyright
14185222Ssam *    notice, this list of conditions and the following disclaimer in the
15185222Ssam *    documentation and/or other materials provided with the distribution.
16185222Ssam * 3. Neither the name of the University nor the names of its contributors
17185222Ssam *    may be used to endorse or promote products derived from this software
18185222Ssam *    without specific prior written permission.
19185222Ssam *
20185222Ssam * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21185222Ssam * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22185222Ssam * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23185222Ssam * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24185222Ssam * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25185222Ssam * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26185222Ssam * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27185222Ssam * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28185222Ssam * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29185222Ssam * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30185222Ssam * SUCH DAMAGE.
31185222Ssam *
32185222Ssam *	@(#)ffs_balloc.c	8.8 (Berkeley) 6/16/95
33185222Ssam */
34185222Ssam
35185222Ssam#include <sys/cdefs.h>
36186334Ssam__FBSDID("$FreeBSD$");
37185222Ssam
38185222Ssam#include <sys/param.h>
39185222Ssam#include <sys/time.h>
40185222Ssam
41185222Ssam#include <assert.h>
42185222Ssam#include <errno.h>
43185222Ssam#include <stdio.h>
44185222Ssam#include <stdlib.h>
45185222Ssam#include <string.h>
46185222Ssam
47185222Ssam#include "makefs.h"
48185222Ssam
49185222Ssam#include <ufs/ufs/dinode.h>
50185222Ssam#include <ufs/ffs/fs.h>
51185222Ssam
52186261Ssam#include "ffs/ufs_bswap.h"
53185222Ssam#include "ffs/buf.h"
54185222Ssam#include "ffs/ufs_inode.h"
55185222Ssam#include "ffs/ffs_extern.h"
56185222Ssam
57185222Ssamstatic int ffs_balloc_ufs1(struct inode *, off_t, int, struct buf **);
58185222Ssamstatic int ffs_balloc_ufs2(struct inode *, off_t, int, struct buf **);
59185222Ssam
60185222Ssam/*
61185222Ssam * Balloc defines the structure of file system storage
62185222Ssam * by allocating the physical blocks on a device given
63185222Ssam * the inode and the logical block number in a file.
64185222Ssam *
65185222Ssam * Assume: flags == B_SYNC | B_CLRBUF
66185222Ssam */
67185222Ssam
68185222Ssamint
69185222Ssamffs_balloc(struct inode *ip, off_t offset, int bufsize, struct buf **bpp)
70185222Ssam{
71185222Ssam	if (ip->i_fs->fs_magic == FS_UFS2_MAGIC)
72185222Ssam		return ffs_balloc_ufs2(ip, offset, bufsize, bpp);
73185222Ssam	else
74185222Ssam		return ffs_balloc_ufs1(ip, offset, bufsize, bpp);
75185222Ssam}
76185222Ssam
77185222Ssamstatic int
78185222Ssamffs_balloc_ufs1(struct inode *ip, off_t offset, int bufsize, struct buf **bpp)
79185222Ssam{
80185222Ssam	daddr_t lbn, lastlbn;
81185222Ssam	int size;
82185222Ssam	int32_t nb;
83185222Ssam	struct buf *bp, *nbp;
84185222Ssam	struct fs *fs = ip->i_fs;
85185222Ssam	struct indir indirs[NIADDR + 2];
86185222Ssam	daddr_t newb, pref;
87185222Ssam	int32_t *bap;
88185222Ssam	int osize, nsize, num, i, error;
89185222Ssam	int32_t *allocblk, allociblk[NIADDR + 1];
90185222Ssam	int32_t *allocib;
91185222Ssam	const int needswap = UFS_FSNEEDSWAP(fs);
92185222Ssam
93185222Ssam	lbn = lblkno(fs, offset);
94185222Ssam	size = blkoff(fs, offset) + bufsize;
95185222Ssam	if (bpp != NULL) {
96185222Ssam		*bpp = NULL;
97185222Ssam	}
98185222Ssam
99185222Ssam	assert(size <= fs->fs_bsize);
100185222Ssam	if (lbn < 0)
101185222Ssam		return (EFBIG);
102185222Ssam
103185222Ssam	/*
104185222Ssam	 * If the next write will extend the file into a new block,
105185222Ssam	 * and the file is currently composed of a fragment
106185222Ssam	 * this fragment has to be extended to be a full block.
107185222Ssam	 */
108185222Ssam
109185222Ssam	lastlbn = lblkno(fs, ip->i_ffs1_size);
110185222Ssam	if (lastlbn < NDADDR && lastlbn < lbn) {
111185222Ssam		nb = lastlbn;
112185222Ssam		osize = blksize(fs, ip, nb);
113185222Ssam		if (osize < fs->fs_bsize && osize > 0) {
114185222Ssam			warnx("need to ffs_realloccg; not supported!");
115185222Ssam			abort();
116185222Ssam		}
117185222Ssam	}
118185222Ssam
119185222Ssam	/*
120185222Ssam	 * The first NDADDR blocks are direct blocks
121185222Ssam	 */
122185222Ssam
123185222Ssam	if (lbn < NDADDR) {
124185222Ssam		nb = ufs_rw32(ip->i_ffs1_db[lbn], needswap);
125185222Ssam		if (nb != 0 && ip->i_ffs1_size >= lblktosize(fs, lbn + 1)) {
126185222Ssam
127185222Ssam			/*
128185222Ssam			 * The block is an already-allocated direct block
129185222Ssam			 * and the file already extends past this block,
130185222Ssam			 * thus this must be a whole block.
131185222Ssam			 * Just read the block (if requested).
132185222Ssam			 */
133185222Ssam
134185222Ssam			if (bpp != NULL) {
135185222Ssam				error = bread(ip->i_fd, ip->i_fs, lbn,
136185222Ssam				    fs->fs_bsize, bpp);
137185222Ssam				if (error) {
138185222Ssam					brelse(*bpp);
139185222Ssam					return (error);
140185222Ssam				}
141185222Ssam			}
142185222Ssam			return (0);
143185222Ssam		}
144185222Ssam		if (nb != 0) {
145185222Ssam
146185222Ssam			/*
147185222Ssam			 * Consider need to reallocate a fragment.
148185222Ssam			 */
149185222Ssam
150185222Ssam			osize = fragroundup(fs, blkoff(fs, ip->i_ffs1_size));
151185222Ssam			nsize = fragroundup(fs, size);
152185222Ssam			if (nsize <= osize) {
153185222Ssam
154185222Ssam				/*
155185222Ssam				 * The existing block is already
156185222Ssam				 * at least as big as we want.
157185222Ssam				 * Just read the block (if requested).
158185222Ssam				 */
159185222Ssam
160185222Ssam				if (bpp != NULL) {
161185222Ssam					error = bread(ip->i_fd, ip->i_fs, lbn,
162185222Ssam					    osize, bpp);
163185222Ssam					if (error) {
164185222Ssam						brelse(*bpp);
165185222Ssam						return (error);
166185222Ssam					}
167185222Ssam				}
168185222Ssam				return 0;
169185222Ssam			} else {
170185222Ssam				warnx("need to ffs_realloccg; not supported!");
171185222Ssam				abort();
172185222Ssam			}
173185222Ssam		} else {
174185222Ssam
175185222Ssam			/*
176185222Ssam			 * the block was not previously allocated,
177185222Ssam			 * allocate a new block or fragment.
178185222Ssam			 */
179185222Ssam
180185222Ssam			if (ip->i_ffs1_size < lblktosize(fs, lbn + 1))
181185222Ssam				nsize = fragroundup(fs, size);
182185222Ssam			else
183185222Ssam				nsize = fs->fs_bsize;
184185222Ssam			error = ffs_alloc(ip, lbn,
185185222Ssam			    ffs_blkpref_ufs1(ip, lbn, (int)lbn,
186185222Ssam				&ip->i_ffs1_db[0]),
187185222Ssam				nsize, &newb);
188185222Ssam			if (error)
189185222Ssam				return (error);
190185222Ssam			if (bpp != NULL) {
191185222Ssam				bp = getblk(ip->i_fd, ip->i_fs, lbn, nsize);
192185222Ssam				bp->b_blkno = fsbtodb(fs, newb);
193185222Ssam				clrbuf(bp);
194185222Ssam				*bpp = bp;
195185222Ssam			}
196185222Ssam		}
197185222Ssam		ip->i_ffs1_db[lbn] = ufs_rw32((int32_t)newb, needswap);
198185222Ssam		return (0);
199185222Ssam	}
200185222Ssam
201185222Ssam	/*
202185222Ssam	 * Determine the number of levels of indirection.
203185222Ssam	 */
204185222Ssam
205185222Ssam	pref = 0;
206185222Ssam	if ((error = ufs_getlbns(ip, lbn, indirs, &num)) != 0)
207185222Ssam		return (error);
208185222Ssam
209185222Ssam	if (num < 1) {
210185222Ssam		warnx("ffs_balloc: ufs_getlbns returned indirect block");
211185222Ssam		abort();
212185222Ssam	}
213185222Ssam
214185222Ssam	/*
215185222Ssam	 * Fetch the first indirect block allocating if necessary.
216185222Ssam	 */
217185222Ssam
218185222Ssam	--num;
219185222Ssam	nb = ufs_rw32(ip->i_ffs1_ib[indirs[0].in_off], needswap);
220185222Ssam	allocib = NULL;
221185222Ssam	allocblk = allociblk;
222185222Ssam	if (nb == 0) {
223185222Ssam		pref = ffs_blkpref_ufs1(ip, lbn, 0, (int32_t *)0);
224185222Ssam		error = ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize, &newb);
225185222Ssam		if (error)
226185222Ssam			return error;
227185222Ssam		nb = newb;
228185222Ssam		*allocblk++ = nb;
229185222Ssam		bp = getblk(ip->i_fd, ip->i_fs, indirs[1].in_lbn, fs->fs_bsize);
230185222Ssam		bp->b_blkno = fsbtodb(fs, nb);
231185222Ssam		clrbuf(bp);
232185222Ssam		/*
233185222Ssam		 * Write synchronously so that indirect blocks
234185222Ssam		 * never point at garbage.
235185222Ssam		 */
236185222Ssam		if ((error = bwrite(bp)) != 0)
237185222Ssam			return error;
238185222Ssam		allocib = &ip->i_ffs1_ib[indirs[0].in_off];
239185222Ssam		*allocib = ufs_rw32((int32_t)nb, needswap);
240185222Ssam	}
241185222Ssam
242185222Ssam	/*
243185222Ssam	 * Fetch through the indirect blocks, allocating as necessary.
244185222Ssam	 */
245185222Ssam
246185222Ssam	for (i = 1;;) {
247185222Ssam		error = bread(ip->i_fd, ip->i_fs, indirs[i].in_lbn,
248185222Ssam		    fs->fs_bsize, &bp);
249185222Ssam		if (error) {
250185222Ssam			brelse(bp);
251185222Ssam			return error;
252185222Ssam		}
253185222Ssam		bap = (int32_t *)bp->b_data;
254185222Ssam		nb = ufs_rw32(bap[indirs[i].in_off], needswap);
255185222Ssam		if (i == num)
256185222Ssam			break;
257185222Ssam		i++;
258185222Ssam		if (nb != 0) {
259185222Ssam			brelse(bp);
260185222Ssam			continue;
261185222Ssam		}
262185222Ssam		if (pref == 0)
263185222Ssam			pref = ffs_blkpref_ufs1(ip, lbn, 0, (int32_t *)0);
264185222Ssam		error = ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize, &newb);
265185222Ssam		if (error) {
266185222Ssam			brelse(bp);
267185222Ssam			return error;
268185222Ssam		}
269185222Ssam		nb = newb;
270185222Ssam		*allocblk++ = nb;
271185222Ssam		nbp = getblk(ip->i_fd, ip->i_fs, indirs[i].in_lbn,
272185222Ssam		    fs->fs_bsize);
273185222Ssam		nbp->b_blkno = fsbtodb(fs, nb);
274185222Ssam		clrbuf(nbp);
275185222Ssam		/*
276185222Ssam		 * Write synchronously so that indirect blocks
277185222Ssam		 * never point at garbage.
278185222Ssam		 */
279185222Ssam
280185222Ssam		if ((error = bwrite(nbp)) != 0) {
281185222Ssam			brelse(bp);
282185222Ssam			return error;
283185222Ssam		}
284185222Ssam		bap[indirs[i - 1].in_off] = ufs_rw32(nb, needswap);
285185222Ssam
286185222Ssam		bwrite(bp);
287185222Ssam	}
288185222Ssam
289185222Ssam	/*
290185222Ssam	 * Get the data block, allocating if necessary.
291185222Ssam	 */
292185222Ssam
293185222Ssam	if (nb == 0) {
294185222Ssam		pref = ffs_blkpref_ufs1(ip, lbn, indirs[num].in_off, &bap[0]);
295185222Ssam		error = ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize, &newb);
296185222Ssam		if (error) {
297185222Ssam			brelse(bp);
298185222Ssam			return error;
299185222Ssam		}
300185222Ssam		nb = newb;
301185222Ssam		*allocblk++ = nb;
302185222Ssam		if (bpp != NULL) {
303185222Ssam			nbp = getblk(ip->i_fd, ip->i_fs, lbn, fs->fs_bsize);
304185222Ssam			nbp->b_blkno = fsbtodb(fs, nb);
305185222Ssam			clrbuf(nbp);
306185222Ssam			*bpp = nbp;
307185222Ssam		}
308185222Ssam		bap[indirs[num].in_off] = ufs_rw32(nb, needswap);
309185222Ssam
310185222Ssam		/*
311185222Ssam		 * If required, write synchronously, otherwise use
312185222Ssam		 * delayed write.
313185222Ssam		 */
314185222Ssam		bwrite(bp);
315185222Ssam		return (0);
316185222Ssam	}
317185222Ssam	brelse(bp);
318185222Ssam	if (bpp != NULL) {
319185222Ssam		error = bread(ip->i_fd, ip->i_fs, lbn, (int)fs->fs_bsize, &nbp);
320185222Ssam		if (error) {
321185222Ssam			brelse(nbp);
322185222Ssam			return error;
323185222Ssam		}
324185222Ssam		*bpp = nbp;
325185222Ssam	}
326185222Ssam	return (0);
327185222Ssam}
328185222Ssam
329185222Ssamstatic int
330185222Ssamffs_balloc_ufs2(struct inode *ip, off_t offset, int bufsize, struct buf **bpp)
331185222Ssam{
332185222Ssam	daddr_t lbn, lastlbn;
333185222Ssam	int size;
334185222Ssam	struct buf *bp, *nbp;
335185222Ssam	struct fs *fs = ip->i_fs;
336185222Ssam	struct indir indirs[NIADDR + 2];
337185222Ssam	daddr_t newb, pref, nb;
338185222Ssam	int64_t *bap;
339185222Ssam	int osize, nsize, num, i, error;
340185222Ssam	int64_t *allocblk, allociblk[NIADDR + 1];
341185222Ssam	int64_t *allocib;
342185222Ssam	const int needswap = UFS_FSNEEDSWAP(fs);
343185222Ssam
344185222Ssam	lbn = lblkno(fs, offset);
345185222Ssam	size = blkoff(fs, offset) + bufsize;
346185222Ssam	if (bpp != NULL) {
347185222Ssam		*bpp = NULL;
348185222Ssam	}
349185222Ssam
350185222Ssam	assert(size <= fs->fs_bsize);
351185222Ssam	if (lbn < 0)
352185222Ssam		return (EFBIG);
353185222Ssam
354185222Ssam	/*
355185222Ssam	 * If the next write will extend the file into a new block,
356185222Ssam	 * and the file is currently composed of a fragment
357185222Ssam	 * this fragment has to be extended to be a full block.
358185222Ssam	 */
359185222Ssam
360185222Ssam	lastlbn = lblkno(fs, ip->i_ffs2_size);
361185222Ssam	if (lastlbn < NDADDR && lastlbn < lbn) {
362185222Ssam		nb = lastlbn;
363185222Ssam		osize = blksize(fs, ip, nb);
364185222Ssam		if (osize < fs->fs_bsize && osize > 0) {
365185222Ssam			warnx("need to ffs_realloccg; not supported!");
366185222Ssam			abort();
367185222Ssam		}
368185222Ssam	}
369185222Ssam
370185222Ssam	/*
371185222Ssam	 * The first NDADDR blocks are direct blocks
372185222Ssam	 */
373185222Ssam
374185222Ssam	if (lbn < NDADDR) {
375185222Ssam		nb = ufs_rw64(ip->i_ffs2_db[lbn], needswap);
376185222Ssam		if (nb != 0 && ip->i_ffs2_size >= lblktosize(fs, lbn + 1)) {
377185222Ssam
378185222Ssam			/*
379185222Ssam			 * The block is an already-allocated direct block
380185222Ssam			 * and the file already extends past this block,
381185222Ssam			 * thus this must be a whole block.
382185222Ssam			 * Just read the block (if requested).
383185222Ssam			 */
384185222Ssam
385185222Ssam			if (bpp != NULL) {
386185222Ssam				error = bread(ip->i_fd, ip->i_fs, lbn,
387185222Ssam				    fs->fs_bsize, bpp);
388185222Ssam				if (error) {
389185222Ssam					brelse(*bpp);
390185222Ssam					return (error);
391185222Ssam				}
392185222Ssam			}
393185222Ssam			return (0);
394185222Ssam		}
395185222Ssam		if (nb != 0) {
396185222Ssam
397185222Ssam			/*
398185222Ssam			 * Consider need to reallocate a fragment.
399185222Ssam			 */
400185222Ssam
401185222Ssam			osize = fragroundup(fs, blkoff(fs, ip->i_ffs2_size));
402185222Ssam			nsize = fragroundup(fs, size);
403185222Ssam			if (nsize <= osize) {
404185222Ssam
405185222Ssam				/*
406185222Ssam				 * The existing block is already
407185222Ssam				 * at least as big as we want.
408185222Ssam				 * Just read the block (if requested).
409185222Ssam				 */
410185222Ssam
411185222Ssam				if (bpp != NULL) {
412185222Ssam					error = bread(ip->i_fd, ip->i_fs, lbn,
413185222Ssam					    osize, bpp);
414185222Ssam					if (error) {
415185222Ssam						brelse(*bpp);
416185222Ssam						return (error);
417185222Ssam					}
418185222Ssam				}
419185222Ssam				return 0;
420185222Ssam			} else {
421185222Ssam				warnx("need to ffs_realloccg; not supported!");
422185222Ssam				abort();
423185222Ssam			}
424185222Ssam		} else {
425185222Ssam
426185222Ssam			/*
427185222Ssam			 * the block was not previously allocated,
428185222Ssam			 * allocate a new block or fragment.
429185222Ssam			 */
430185222Ssam
431185222Ssam			if (ip->i_ffs2_size < lblktosize(fs, lbn + 1))
432185222Ssam				nsize = fragroundup(fs, size);
433185222Ssam			else
434185222Ssam				nsize = fs->fs_bsize;
435185222Ssam			error = ffs_alloc(ip, lbn,
436185222Ssam			    ffs_blkpref_ufs2(ip, lbn, (int)lbn,
437185222Ssam				&ip->i_ffs2_db[0]),
438185222Ssam				nsize, &newb);
439185222Ssam			if (error)
440185222Ssam				return (error);
441185222Ssam			if (bpp != NULL) {
442185222Ssam				bp = getblk(ip->i_fd, ip->i_fs, lbn, nsize);
443185222Ssam				bp->b_blkno = fsbtodb(fs, newb);
444185222Ssam				clrbuf(bp);
445185222Ssam				*bpp = bp;
446185222Ssam			}
447185222Ssam		}
448185222Ssam		ip->i_ffs2_db[lbn] = ufs_rw64(newb, needswap);
449185222Ssam		return (0);
450185222Ssam	}
451185222Ssam
452185222Ssam	/*
453185222Ssam	 * Determine the number of levels of indirection.
454185222Ssam	 */
455185222Ssam
456185222Ssam	pref = 0;
457185222Ssam	if ((error = ufs_getlbns(ip, lbn, indirs, &num)) != 0)
458185222Ssam		return (error);
459185222Ssam
460185222Ssam	if (num < 1) {
461185222Ssam		warnx("ffs_balloc: ufs_getlbns returned indirect block");
462185222Ssam		abort();
463185222Ssam	}
464185222Ssam
465185222Ssam	/*
466185222Ssam	 * Fetch the first indirect block allocating if necessary.
467185222Ssam	 */
468185222Ssam
469185222Ssam	--num;
470185222Ssam	nb = ufs_rw64(ip->i_ffs2_ib[indirs[0].in_off], needswap);
471185222Ssam	allocib = NULL;
472185222Ssam	allocblk = allociblk;
473185222Ssam	if (nb == 0) {
474185222Ssam		pref = ffs_blkpref_ufs2(ip, lbn, 0, (int64_t *)0);
475185222Ssam		error = ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize, &newb);
476185222Ssam		if (error)
477185222Ssam			return error;
478185222Ssam		nb = newb;
479185222Ssam		*allocblk++ = nb;
480185222Ssam		bp = getblk(ip->i_fd, ip->i_fs, indirs[1].in_lbn, fs->fs_bsize);
481185222Ssam		bp->b_blkno = fsbtodb(fs, nb);
482185222Ssam		clrbuf(bp);
483185222Ssam		/*
484185222Ssam		 * Write synchronously so that indirect blocks
485185222Ssam		 * never point at garbage.
486185222Ssam		 */
487185222Ssam		if ((error = bwrite(bp)) != 0)
488185222Ssam			return error;
489185222Ssam		allocib = &ip->i_ffs2_ib[indirs[0].in_off];
490185222Ssam		*allocib = ufs_rw64(nb, needswap);
491185222Ssam	}
492185222Ssam
493185222Ssam	/*
494185222Ssam	 * Fetch through the indirect blocks, allocating as necessary.
495185222Ssam	 */
496185222Ssam
497185222Ssam	for (i = 1;;) {
498185222Ssam		error = bread(ip->i_fd, ip->i_fs, indirs[i].in_lbn,
499185222Ssam		    fs->fs_bsize, &bp);
500185222Ssam		if (error) {
501185222Ssam			brelse(bp);
502185222Ssam			return error;
503185222Ssam		}
504185222Ssam		bap = (int64_t *)bp->b_data;
505185222Ssam		nb = ufs_rw64(bap[indirs[i].in_off], needswap);
506185222Ssam		if (i == num)
507185222Ssam			break;
508185222Ssam		i++;
509185222Ssam		if (nb != 0) {
510185222Ssam			brelse(bp);
511185222Ssam			continue;
512185222Ssam		}
513185222Ssam		if (pref == 0)
514185222Ssam			pref = ffs_blkpref_ufs2(ip, lbn, 0, (int64_t *)0);
515185222Ssam		error = ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize, &newb);
516185222Ssam		if (error) {
517185222Ssam			brelse(bp);
518185222Ssam			return error;
519185222Ssam		}
520185222Ssam		nb = newb;
521185222Ssam		*allocblk++ = nb;
522185222Ssam		nbp = getblk(ip->i_fd, ip->i_fs, indirs[i].in_lbn,
523185222Ssam		    fs->fs_bsize);
524185222Ssam		nbp->b_blkno = fsbtodb(fs, nb);
525185222Ssam		clrbuf(nbp);
526185222Ssam		/*
527185222Ssam		 * Write synchronously so that indirect blocks
528185222Ssam		 * never point at garbage.
529185222Ssam		 */
530185222Ssam
531185222Ssam		if ((error = bwrite(nbp)) != 0) {
532185222Ssam			brelse(bp);
533185222Ssam			return error;
534185222Ssam		}
535185222Ssam		bap[indirs[i - 1].in_off] = ufs_rw64(nb, needswap);
536185222Ssam
537185222Ssam		bwrite(bp);
538185222Ssam	}
539185222Ssam
540185222Ssam	/*
541185222Ssam	 * Get the data block, allocating if necessary.
542185222Ssam	 */
543185222Ssam
544185222Ssam	if (nb == 0) {
545185222Ssam		pref = ffs_blkpref_ufs2(ip, lbn, indirs[num].in_off, &bap[0]);
546185222Ssam		error = ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize, &newb);
547185222Ssam		if (error) {
548185222Ssam			brelse(bp);
549185222Ssam			return error;
550185222Ssam		}
551185222Ssam		nb = newb;
552185222Ssam		*allocblk++ = nb;
553185222Ssam		if (bpp != NULL) {
554185222Ssam			nbp = getblk(ip->i_fd, ip->i_fs, lbn, fs->fs_bsize);
555185222Ssam			nbp->b_blkno = fsbtodb(fs, nb);
556185222Ssam			clrbuf(nbp);
557185222Ssam			*bpp = nbp;
558185222Ssam		}
559185222Ssam		bap[indirs[num].in_off] = ufs_rw64(nb, needswap);
560185222Ssam
561185222Ssam		/*
562185222Ssam		 * If required, write synchronously, otherwise use
563185222Ssam		 * delayed write.
564185222Ssam		 */
565185222Ssam		bwrite(bp);
566185222Ssam		return (0);
567185222Ssam	}
568185222Ssam	brelse(bp);
569185222Ssam	if (bpp != NULL) {
570185222Ssam		error = bread(ip->i_fd, ip->i_fs, lbn, (int)fs->fs_bsize, &nbp);
571185222Ssam		if (error) {
572185222Ssam			brelse(nbp);
573185222Ssam			return error;
574185222Ssam		}
575185222Ssam		*bpp = nbp;
576185222Ssam	}
577185222Ssam	return (0);
578185222Ssam}
579