]> git.saurik.com Git - apple/xnu.git/blob - bsd/ufs/ffs/ffs_balloc.c
8a1908418e8a95ed684e309fe2fe31338e989bca
[apple/xnu.git] / bsd / ufs / ffs / ffs_balloc.c
1 /*
2 * Copyright (c) 2006 Apple Computer, Inc. All Rights Reserved.
3 *
4 * @APPLE_LICENSE_OSREFERENCE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the
10 * License may not be used to create, or enable the creation or
11 * redistribution of, unlawful or unlicensed copies of an Apple operating
12 * system, or to circumvent, violate, or enable the circumvention or
13 * violation of, any terms of an Apple operating system software license
14 * agreement.
15 *
16 * Please obtain a copy of the License at
17 * http://www.opensource.apple.com/apsl/ and read it before using this
18 * file.
19 *
20 * The Original Code and all software distributed under the License are
21 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
22 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
23 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
24 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
25 * Please see the License for the specific language governing rights and
26 * limitations under the License.
27 *
28 * @APPLE_LICENSE_OSREFERENCE_HEADER_END@
29 */
30 /* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */
31 /*
32 * Copyright (c) 1982, 1986, 1989, 1993
33 * The Regents of the University of California. All rights reserved.
34 *
35 * Redistribution and use in source and binary forms, with or without
36 * modification, are permitted provided that the following conditions
37 * are met:
38 * 1. Redistributions of source code must retain the above copyright
39 * notice, this list of conditions and the following disclaimer.
40 * 2. Redistributions in binary form must reproduce the above copyright
41 * notice, this list of conditions and the following disclaimer in the
42 * documentation and/or other materials provided with the distribution.
43 * 3. All advertising materials mentioning features or use of this software
44 * must display the following acknowledgement:
45 * This product includes software developed by the University of
46 * California, Berkeley and its contributors.
47 * 4. Neither the name of the University nor the names of its contributors
48 * may be used to endorse or promote products derived from this software
49 * without specific prior written permission.
50 *
51 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
52 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
53 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
54 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
55 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
56 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
57 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
58 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
59 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
60 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
61 * SUCH DAMAGE.
62 *
63 * @(#)ffs_balloc.c 8.8 (Berkeley) 6/16/95
64 */
65
66 #include <rev_endian_fs.h>
67 #include <sys/param.h>
68 #include <sys/systm.h>
69 #include <sys/buf_internal.h>
70 #include <sys/proc.h>
71 #include <sys/kauth.h>
72 #include <sys/file.h>
73 #include <sys/vnode_internal.h>
74 #include <sys/ubc.h>
75 #include <sys/quota.h>
76
77 #if REV_ENDIAN_FS
78 #include <sys/mount_internal.h>
79 #endif /* REV_ENDIAN_FS */
80
81 #include <sys/vm.h>
82
83 #include <ufs/ufs/quota.h>
84 #include <ufs/ufs/inode.h>
85 #include <ufs/ufs/ufs_extern.h>
86
87 #include <ufs/ffs/fs.h>
88 #include <ufs/ffs/ffs_extern.h>
89
90 #if REV_ENDIAN_FS
91 #include <ufs/ufs/ufs_byte_order.h>
92 #include <architecture/byte_order.h>
93 #endif /* REV_ENDIAN_FS */
94
95 /*
96 * Balloc defines the structure of file system storage
97 * by allocating the physical blocks on a device given
98 * the inode and the logical block number in a file.
99 */
100 ffs_balloc(
101 register struct inode *ip,
102 register ufs_daddr_t lbn,
103 int size,
104 kauth_cred_t cred,
105 struct buf **bpp,
106 int flags,
107 int * blk_alloc)
108 {
109 register struct fs *fs;
110 register ufs_daddr_t nb;
111 struct buf *bp, *nbp;
112 struct vnode *vp = ITOV(ip);
113 struct indir indirs[NIADDR + 2];
114 ufs_daddr_t newb, *bap, pref;
115 int deallocated, osize, nsize, num, i, error;
116 ufs_daddr_t *allocib, *blkp, *allocblk, allociblk[NIADDR + 1];
117 int devBlockSize=0;
118 int alloc_buffer = 1;
119 struct mount *mp=vp->v_mount;
120 #if REV_ENDIAN_FS
121 int rev_endian=(mp->mnt_flag & MNT_REVEND);
122 #endif /* REV_ENDIAN_FS */
123
124 *bpp = NULL;
125 if (lbn < 0)
126 return (EFBIG);
127 fs = ip->i_fs;
128 if (flags & B_NOBUFF)
129 alloc_buffer = 0;
130
131 if (blk_alloc)
132 *blk_alloc = 0;
133
134 /*
135 * If the next write will extend the file into a new block,
136 * and the file is currently composed of a fragment
137 * this fragment has to be extended to be a full block.
138 */
139 nb = lblkno(fs, ip->i_size);
140 if (nb < NDADDR && nb < lbn) {
141 /* the filesize prior to this write can fit in direct
142 * blocks (ie. fragmentaion is possibly done)
143 * we are now extending the file write beyond
144 * the block which has end of file prior to this write
145 */
146 osize = blksize(fs, ip, nb);
147 /* osize gives disk allocated size in the last block. It is
148 * either in fragments or a file system block size */
149 if (osize < fs->fs_bsize && osize > 0) {
150 /* few fragments are already allocated,since the
151 * current extends beyond this block
152 * allocate the complete block as fragments are only
153 * in last block
154 */
155 error = ffs_realloccg(ip, nb,
156 ffs_blkpref(ip, nb, (int)nb, &ip->i_db[0]),
157 osize, (int)fs->fs_bsize, cred, &bp);
158 if (error)
159 return (error);
160 /* adjust the inode size we just grew */
161 /* it is in nb+1 as nb starts from 0 */
162 ip->i_size = (nb + 1) * fs->fs_bsize;
163 ubc_setsize(vp, (off_t)ip->i_size);
164
165 ip->i_db[nb] = dbtofsb(fs, (ufs_daddr_t)buf_blkno(bp));
166 ip->i_flag |= IN_CHANGE | IN_UPDATE;
167
168 if ((flags & B_SYNC) || (!alloc_buffer)) {
169 if (!alloc_buffer)
170 buf_setflags(bp, B_NOCACHE);
171 buf_bwrite(bp);
172 } else
173 buf_bdwrite(bp);
174 /* note that bp is already released here */
175 }
176 }
177 /*
178 * The first NDADDR blocks are direct blocks
179 */
180 if (lbn < NDADDR) {
181 nb = ip->i_db[lbn];
182 if (nb != 0 && ip->i_size >= (lbn + 1) * fs->fs_bsize) {
183 if (alloc_buffer) {
184 error = (int)buf_bread(vp, (daddr64_t)((unsigned)lbn), fs->fs_bsize, NOCRED, &bp);
185 if (error) {
186 buf_brelse(bp);
187 return (error);
188 }
189 *bpp = bp;
190 }
191 return (0);
192 }
193 if (nb != 0) {
194 /*
195 * Consider need to reallocate a fragment.
196 */
197 osize = fragroundup(fs, blkoff(fs, ip->i_size));
198 nsize = fragroundup(fs, size);
199 if (nsize <= osize) {
200 if (alloc_buffer) {
201 error = (int)buf_bread(vp, (daddr64_t)((unsigned)lbn), osize, NOCRED, &bp);
202 if (error) {
203 buf_brelse(bp);
204 return (error);
205 }
206 ip->i_flag |= IN_CHANGE | IN_UPDATE;
207 *bpp = bp;
208 return (0);
209 }
210 else {
211 ip->i_flag |= IN_CHANGE | IN_UPDATE;
212 return (0);
213 }
214 } else {
215 error = ffs_realloccg(ip, lbn,
216 ffs_blkpref(ip, lbn, (int)lbn,
217 &ip->i_db[0]), osize, nsize, cred, &bp);
218 if (error)
219 return (error);
220 ip->i_db[lbn] = dbtofsb(fs, (ufs_daddr_t)buf_blkno(bp));
221 ip->i_flag |= IN_CHANGE | IN_UPDATE;
222
223 /* adjust the inode size we just grew */
224 ip->i_size = (lbn * fs->fs_bsize) + size;
225 ubc_setsize(vp, (off_t)ip->i_size);
226
227 if (!alloc_buffer) {
228 buf_setflags(bp, B_NOCACHE);
229 if (flags & B_SYNC)
230 buf_bwrite(bp);
231 else
232 buf_bdwrite(bp);
233 } else
234 *bpp = bp;
235 return (0);
236
237 }
238 } else {
239 if (ip->i_size < (lbn + 1) * fs->fs_bsize)
240 nsize = fragroundup(fs, size);
241 else
242 nsize = fs->fs_bsize;
243 error = ffs_alloc(ip, lbn,
244 ffs_blkpref(ip, lbn, (int)lbn, &ip->i_db[0]),
245 nsize, cred, &newb);
246 if (error)
247 return (error);
248 if (alloc_buffer) {
249 bp = buf_getblk(vp, (daddr64_t)((unsigned)lbn), nsize, 0, 0, BLK_WRITE);
250 buf_setblkno(bp, (daddr64_t)((unsigned)fsbtodb(fs, newb)));
251
252 if (flags & B_CLRBUF)
253 buf_clear(bp);
254 }
255 ip->i_db[lbn] = newb;
256 ip->i_flag |= IN_CHANGE | IN_UPDATE;
257 if (blk_alloc) {
258 *blk_alloc = nsize;
259 }
260 if (alloc_buffer)
261 *bpp = bp;
262 return (0);
263 }
264 }
265 /*
266 * Determine the number of levels of indirection.
267 */
268 pref = 0;
269 if (error = ufs_getlbns(vp, lbn, indirs, &num))
270 return(error);
271 #if DIAGNOSTIC
272 if (num < 1)
273 panic ("ffs_balloc: ufs_bmaparray returned indirect block");
274 #endif
275 /*
276 * Fetch the first indirect block allocating if necessary.
277 */
278 --num;
279 nb = ip->i_ib[indirs[0].in_off];
280 allocib = NULL;
281 allocblk = allociblk;
282 if (nb == 0) {
283 pref = ffs_blkpref(ip, lbn, 0, (ufs_daddr_t *)0);
284 if (error = ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize,
285 cred, &newb))
286 return (error);
287 nb = newb;
288 *allocblk++ = nb;
289 bp = buf_getblk(vp, (daddr64_t)((unsigned)(indirs[1].in_lbn)), fs->fs_bsize, 0, 0, BLK_META);
290 buf_setblkno(bp, (daddr64_t)((unsigned)fsbtodb(fs, nb)));
291 buf_clear(bp);
292 /*
293 * Write synchronously conditional on mount flags.
294 */
295 if ((vp)->v_mount->mnt_flag & MNT_ASYNC) {
296 error = 0;
297 buf_bdwrite(bp);
298 } else if ((error = buf_bwrite(bp)) != 0) {
299 goto fail;
300 }
301 allocib = &ip->i_ib[indirs[0].in_off];
302 *allocib = nb;
303 ip->i_flag |= IN_CHANGE | IN_UPDATE;
304 }
305 /*
306 * Fetch through the indirect blocks, allocating as necessary.
307 */
308 for (i = 1;;) {
309 error = (int)buf_meta_bread(vp, (daddr64_t)((unsigned)(indirs[i].in_lbn)), (int)fs->fs_bsize, NOCRED, &bp);
310 if (error) {
311 buf_brelse(bp);
312 goto fail;
313 }
314 bap = (ufs_daddr_t *)buf_dataptr(bp);
315 #if REV_ENDIAN_FS
316 if (rev_endian)
317 nb = NXSwapLong(bap[indirs[i].in_off]);
318 else {
319 #endif /* REV_ENDIAN_FS */
320 nb = bap[indirs[i].in_off];
321 #if REV_ENDIAN_FS
322 }
323 #endif /* REV_ENDIAN_FS */
324 if (i == num)
325 break;
326 i += 1;
327 if (nb != 0) {
328 buf_brelse(bp);
329 continue;
330 }
331 if (pref == 0)
332 pref = ffs_blkpref(ip, lbn, 0, (ufs_daddr_t *)0);
333 if (error =
334 ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize, cred, &newb)) {
335 buf_brelse(bp);
336 goto fail;
337 }
338 nb = newb;
339 *allocblk++ = nb;
340 nbp = buf_getblk(vp, (daddr64_t)((unsigned)(indirs[i].in_lbn)), fs->fs_bsize, 0, 0, BLK_META);
341 buf_setblkno(nbp, (daddr64_t)((unsigned)fsbtodb(fs, nb)));
342 buf_clear(nbp);
343 /*
344 * Write synchronously conditional on mount flags.
345 */
346 if ((vp)->v_mount->mnt_flag & MNT_ASYNC) {
347 error = 0;
348 buf_bdwrite(nbp);
349 } else if (error = buf_bwrite(nbp)) {
350 buf_brelse(bp);
351 goto fail;
352 }
353 #if REV_ENDIAN_FS
354 if (rev_endian)
355 bap[indirs[i - 1].in_off] = NXSwapLong(nb);
356 else {
357 #endif /* REV_ENDIAN_FS */
358 bap[indirs[i - 1].in_off] = nb;
359 #if REV_ENDIAN_FS
360 }
361 #endif /* REV_ENDIAN_FS */
362 /*
363 * If required, write synchronously, otherwise use
364 * delayed write.
365 */
366 if (flags & B_SYNC) {
367 buf_bwrite(bp);
368 } else {
369 buf_bdwrite(bp);
370 }
371 }
372 /*
373 * Get the data block, allocating if necessary.
374 */
375 if (nb == 0) {
376 pref = ffs_blkpref(ip, lbn, indirs[i].in_off, &bap[0]);
377 if (error = ffs_alloc(ip,
378 lbn, pref, (int)fs->fs_bsize, cred, &newb)) {
379 buf_brelse(bp);
380 goto fail;
381 }
382 nb = newb;
383 *allocblk++ = nb;
384 #if REV_ENDIAN_FS
385 if (rev_endian)
386 bap[indirs[i].in_off] = NXSwapLong(nb);
387 else {
388 #endif /* REV_ENDIAN_FS */
389 bap[indirs[i].in_off] = nb;
390 #if REV_ENDIAN_FS
391 }
392 #endif /* REV_ENDIAN_FS */
393 /*
394 * If required, write synchronously, otherwise use
395 * delayed write.
396 */
397 if ((flags & B_SYNC)) {
398 buf_bwrite(bp);
399 } else {
400 buf_bdwrite(bp);
401 }
402 if(alloc_buffer ) {
403 nbp = buf_getblk(vp, (daddr64_t)((unsigned)lbn), fs->fs_bsize, 0, 0, BLK_WRITE);
404 buf_setblkno(nbp, (daddr64_t)((unsigned)fsbtodb(fs, nb)));
405
406 if (flags & B_CLRBUF)
407 buf_clear(nbp);
408 }
409 if (blk_alloc) {
410 *blk_alloc = fs->fs_bsize;
411 }
412 if(alloc_buffer)
413 *bpp = nbp;
414
415 return (0);
416 }
417 buf_brelse(bp);
418 if (alloc_buffer) {
419 if (flags & B_CLRBUF) {
420 error = (int)buf_bread(vp, (daddr64_t)((unsigned)lbn), (int)fs->fs_bsize, NOCRED, &nbp);
421 if (error) {
422 buf_brelse(nbp);
423 goto fail;
424 }
425 } else {
426 nbp = buf_getblk(vp, (daddr64_t)((unsigned)lbn), fs->fs_bsize, 0, 0, BLK_WRITE);
427 buf_setblkno(nbp, (daddr64_t)((unsigned)fsbtodb(fs, nb)));
428 }
429 *bpp = nbp;
430 }
431 return (0);
432 fail:
433 /*
434 * If we have failed part way through block allocation, we
435 * have to deallocate any indirect blocks that we have allocated.
436 */
437 for (deallocated = 0, blkp = allociblk; blkp < allocblk; blkp++) {
438 ffs_blkfree(ip, *blkp, fs->fs_bsize);
439 deallocated += fs->fs_bsize;
440 }
441 if (allocib != NULL)
442 *allocib = 0;
443 if (deallocated) {
444 devBlockSize = vfs_devblocksize(mp);
445 #if QUOTA
446 /*
447 * Restore user's disk quota because allocation failed.
448 */
449 (void) chkdq(ip, (int64_t)-deallocated, cred, FORCE);
450 #endif /* QUOTA */
451 ip->i_blocks -= btodb(deallocated, devBlockSize);
452 ip->i_flag |= IN_CHANGE | IN_UPDATE;
453 }
454 return (error);
455 }
456
457 /*
458 * ffs_blkalloc allocates a disk block for ffs_pageout(), as a consequence
459 * it does no buf_breads (that could lead to deadblock as the page may be already
460 * marked busy as it is being paged out. Also important to note that we are not
461 * growing the file in pageouts. So ip->i_size cannot increase by this call
462 * due to the way UBC works.
463 * This code is derived from ffs_balloc and many cases of that are dealt
464 * in ffs_balloc are not applicable here
465 * Do not call with B_CLRBUF flags as this should only be called only
466 * from pageouts
467 */
468 ffs_blkalloc(
469 struct inode *ip,
470 ufs_daddr_t lbn,
471 int size,
472 kauth_cred_t cred,
473 int flags)
474 {
475 register struct fs *fs;
476 register ufs_daddr_t nb;
477 struct buf *bp, *nbp;
478 struct vnode *vp = ITOV(ip);
479 struct indir indirs[NIADDR + 2];
480 ufs_daddr_t newb, *bap, pref;
481 int deallocated, osize, nsize, num, i, error;
482 ufs_daddr_t *allocib, *blkp, *allocblk, allociblk[NIADDR + 1];
483 int devBlockSize=0;
484 struct mount *mp=vp->v_mount;
485 #if REV_ENDIAN_FS
486 int rev_endian=(mp->mnt_flag & MNT_REVEND);
487 #endif /* REV_ENDIAN_FS */
488
489 fs = ip->i_fs;
490
491 if(size > fs->fs_bsize)
492 panic("ffs_blkalloc: too large for allocation");
493
494 /*
495 * If the next write will extend the file into a new block,
496 * and the file is currently composed of a fragment
497 * this fragment has to be extended to be a full block.
498 */
499 nb = lblkno(fs, ip->i_size);
500 if (nb < NDADDR && nb < lbn) {
501 panic("ffs_blkalloc():cannot extend file: i_size %d, lbn %d", ip->i_size, lbn);
502 }
503 /*
504 * The first NDADDR blocks are direct blocks
505 */
506 if (lbn < NDADDR) {
507 nb = ip->i_db[lbn];
508 if (nb != 0 && ip->i_size >= (lbn + 1) * fs->fs_bsize) {
509 /* TBD: trivial case; the block is already allocated */
510 return (0);
511 }
512 if (nb != 0) {
513 /*
514 * Consider need to reallocate a fragment.
515 */
516 osize = fragroundup(fs, blkoff(fs, ip->i_size));
517 nsize = fragroundup(fs, size);
518 if (nsize > osize) {
519 panic("ffs_allocblk: trying to extend a fragment");
520 }
521 return(0);
522 } else {
523 if (ip->i_size < (lbn + 1) * fs->fs_bsize)
524 nsize = fragroundup(fs, size);
525 else
526 nsize = fs->fs_bsize;
527 error = ffs_alloc(ip, lbn,
528 ffs_blkpref(ip, lbn, (int)lbn, &ip->i_db[0]),
529 nsize, cred, &newb);
530 if (error)
531 return (error);
532 ip->i_db[lbn] = newb;
533 ip->i_flag |= IN_CHANGE | IN_UPDATE;
534 return (0);
535 }
536 }
537 /*
538 * Determine the number of levels of indirection.
539 */
540 pref = 0;
541 if (error = ufs_getlbns(vp, lbn, indirs, &num))
542 return(error);
543
544 if(num == 0) {
545 panic("ffs_blkalloc: file with direct blocks only");
546 }
547
548 /*
549 * Fetch the first indirect block allocating if necessary.
550 */
551 --num;
552 nb = ip->i_ib[indirs[0].in_off];
553 allocib = NULL;
554 allocblk = allociblk;
555 if (nb == 0) {
556 pref = ffs_blkpref(ip, lbn, 0, (ufs_daddr_t *)0);
557 if (error = ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize,
558 cred, &newb))
559 return (error);
560 nb = newb;
561 *allocblk++ = nb;
562 bp = buf_getblk(vp, (daddr64_t)((unsigned)(indirs[1].in_lbn)), fs->fs_bsize, 0, 0, BLK_META);
563 buf_setblkno(bp, (daddr64_t)((unsigned)fsbtodb(fs, nb)));
564 buf_clear(bp);
565 /*
566 * Write synchronously conditional on mount flags.
567 */
568 if ((vp)->v_mount->mnt_flag & MNT_ASYNC) {
569 error = 0;
570 buf_bdwrite(bp);
571 } else if (error = buf_bwrite(bp)) {
572 goto fail;
573 }
574 allocib = &ip->i_ib[indirs[0].in_off];
575 *allocib = nb;
576 ip->i_flag |= IN_CHANGE | IN_UPDATE;
577 }
578 /*
579 * Fetch through the indirect blocks, allocating as necessary.
580 */
581 for (i = 1;;) {
582 error = (int)buf_meta_bread(vp, (daddr64_t)((unsigned)(indirs[i].in_lbn)), (int)fs->fs_bsize, NOCRED, &bp);
583 if (error) {
584 buf_brelse(bp);
585 goto fail;
586 }
587 bap = (ufs_daddr_t *)buf_dataptr(bp);
588 #if REV_ENDIAN_FS
589 if (rev_endian)
590 nb = NXSwapLong(bap[indirs[i].in_off]);
591 else {
592 #endif /* REV_ENDIAN_FS */
593 nb = bap[indirs[i].in_off];
594 #if REV_ENDIAN_FS
595 }
596 #endif /* REV_ENDIAN_FS */
597 if (i == num)
598 break;
599 i += 1;
600 if (nb != 0) {
601 buf_brelse(bp);
602 continue;
603 }
604 if (pref == 0)
605 pref = ffs_blkpref(ip, lbn, 0, (ufs_daddr_t *)0);
606 if (error =
607 ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize, cred, &newb)) {
608 buf_brelse(bp);
609 goto fail;
610 }
611 nb = newb;
612 *allocblk++ = nb;
613 nbp = buf_getblk(vp, (daddr64_t)((unsigned)(indirs[i].in_lbn)), fs->fs_bsize, 0, 0, BLK_META);
614 buf_setblkno(nbp, (daddr64_t)((unsigned)fsbtodb(fs, nb)));
615 buf_clear(nbp);
616 /*
617 * Write synchronously conditional on mount flags.
618 */
619 if ((vp)->v_mount->mnt_flag & MNT_ASYNC) {
620 error = 0;
621 buf_bdwrite(nbp);
622 } else if (error = buf_bwrite(nbp)) {
623 buf_brelse(bp);
624 goto fail;
625 }
626 #if REV_ENDIAN_FS
627 if (rev_endian)
628 bap[indirs[i - 1].in_off] = NXSwapLong(nb);
629 else {
630 #endif /* REV_ENDIAN_FS */
631 bap[indirs[i - 1].in_off] = nb;
632 #if REV_ENDIAN_FS
633 }
634 #endif /* REV_ENDIAN_FS */
635 /*
636 * If required, write synchronously, otherwise use
637 * delayed write.
638 */
639 if (flags & B_SYNC) {
640 buf_bwrite(bp);
641 } else {
642 buf_bdwrite(bp);
643 }
644 }
645 /*
646 * Get the data block, allocating if necessary.
647 */
648 if (nb == 0) {
649 pref = ffs_blkpref(ip, lbn, indirs[i].in_off, &bap[0]);
650 if (error = ffs_alloc(ip,
651 lbn, pref, (int)fs->fs_bsize, cred, &newb)) {
652 buf_brelse(bp);
653 goto fail;
654 }
655 nb = newb;
656 *allocblk++ = nb;
657 #if REV_ENDIAN_FS
658 if (rev_endian)
659 bap[indirs[i].in_off] = NXSwapLong(nb);
660 else {
661 #endif /* REV_ENDIAN_FS */
662 bap[indirs[i].in_off] = nb;
663 #if REV_ENDIAN_FS
664 }
665 #endif /* REV_ENDIAN_FS */
666 /*
667 * If required, write synchronously, otherwise use
668 * delayed write.
669 */
670 if (flags & B_SYNC) {
671 buf_bwrite(bp);
672 } else {
673 buf_bdwrite(bp);
674 }
675 return (0);
676 }
677 buf_brelse(bp);
678 return (0);
679 fail:
680 /*
681 * If we have failed part way through block allocation, we
682 * have to deallocate any indirect blocks that we have allocated.
683 */
684 for (deallocated = 0, blkp = allociblk; blkp < allocblk; blkp++) {
685 ffs_blkfree(ip, *blkp, fs->fs_bsize);
686 deallocated += fs->fs_bsize;
687 }
688 if (allocib != NULL)
689 *allocib = 0;
690 if (deallocated) {
691 devBlockSize = vfs_devblocksize(mp);
692 #if QUOTA
693 /*
694 * Restore user's disk quota because allocation failed.
695 */
696 (void) chkdq(ip, (int64_t)-deallocated, cred, FORCE);
697 #endif /* QUOTA */
698 ip->i_blocks -= btodb(deallocated, devBlockSize);
699 ip->i_flag |= IN_CHANGE | IN_UPDATE;
700 }
701 return (error);
702 }