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