]>
Commit | Line | Data |
---|---|---|
1c79356b | 1 | /* |
5d5c5d0d A |
2 | * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. |
3 | * | |
8f6c56a5 | 4 | * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ |
1c79356b | 5 | * |
8f6c56a5 A |
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 | |
8ad349bb | 24 | * limitations under the License. |
8f6c56a5 A |
25 | * |
26 | * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ | |
1c79356b A |
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> | |
91447636 | 67 | #include <sys/buf_internal.h> |
1c79356b | 68 | #include <sys/proc.h> |
91447636 | 69 | #include <sys/kauth.h> |
1c79356b | 70 | #include <sys/file.h> |
91447636 | 71 | #include <sys/vnode_internal.h> |
1c79356b | 72 | #include <sys/ubc.h> |
9bccf70c A |
73 | #include <sys/quota.h> |
74 | ||
1c79356b | 75 | #if REV_ENDIAN_FS |
91447636 | 76 | #include <sys/mount_internal.h> |
1c79356b A |
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> | |
8f6c56a5 | 90 | #include <architecture/byte_order.h> |
1c79356b A |
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 | */ | |
91447636 A |
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) | |
1c79356b A |
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; | |
1c79356b | 117 | struct mount *mp=vp->v_mount; |
91447636 | 118 | #if REV_ENDIAN_FS |
1c79356b A |
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); | |
91447636 | 158 | /* adjust the inode size we just grew */ |
1c79356b A |
159 | /* it is in nb+1 as nb starts from 0 */ |
160 | ip->i_size = (nb + 1) * fs->fs_bsize; | |
91447636 A |
161 | ubc_setsize(vp, (off_t)ip->i_size); |
162 | ||
163 | ip->i_db[nb] = dbtofsb(fs, (ufs_daddr_t)buf_blkno(bp)); | |
1c79356b | 164 | ip->i_flag |= IN_CHANGE | IN_UPDATE; |
91447636 | 165 | |
1c79356b A |
166 | if ((flags & B_SYNC) || (!alloc_buffer)) { |
167 | if (!alloc_buffer) | |
91447636 A |
168 | buf_setflags(bp, B_NOCACHE); |
169 | buf_bwrite(bp); | |
1c79356b | 170 | } else |
91447636 | 171 | buf_bdwrite(bp); |
1c79356b A |
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) { | |
91447636 | 182 | error = (int)buf_bread(vp, (daddr64_t)((unsigned)lbn), fs->fs_bsize, NOCRED, &bp); |
1c79356b | 183 | if (error) { |
91447636 | 184 | buf_brelse(bp); |
1c79356b A |
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) { | |
91447636 | 199 | error = (int)buf_bread(vp, (daddr64_t)((unsigned)lbn), osize, NOCRED, &bp); |
1c79356b | 200 | if (error) { |
91447636 | 201 | buf_brelse(bp); |
1c79356b A |
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); | |
91447636 | 218 | ip->i_db[lbn] = dbtofsb(fs, (ufs_daddr_t)buf_blkno(bp)); |
1c79356b | 219 | ip->i_flag |= IN_CHANGE | IN_UPDATE; |
91447636 A |
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); | |
55e303ae | 227 | if (flags & B_SYNC) |
91447636 | 228 | buf_bwrite(bp); |
55e303ae | 229 | else |
91447636 | 230 | buf_bdwrite(bp); |
1c79356b A |
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) { | |
91447636 A |
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); | |
1c79356b A |
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) | |
55e303ae | 271 | panic ("ffs_balloc: ufs_bmaparray returned indirect block"); |
1c79356b A |
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; | |
91447636 A |
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); | |
1c79356b | 290 | /* |
55e303ae | 291 | * Write synchronously conditional on mount flags. |
1c79356b | 292 | */ |
55e303ae A |
293 | if ((vp)->v_mount->mnt_flag & MNT_ASYNC) { |
294 | error = 0; | |
91447636 A |
295 | buf_bdwrite(bp); |
296 | } else if ((error = buf_bwrite(bp)) != 0) { | |
1c79356b | 297 | goto fail; |
55e303ae | 298 | } |
1c79356b A |
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;;) { | |
91447636 | 307 | error = (int)buf_meta_bread(vp, (daddr64_t)((unsigned)(indirs[i].in_lbn)), (int)fs->fs_bsize, NOCRED, &bp); |
1c79356b | 308 | if (error) { |
91447636 | 309 | buf_brelse(bp); |
1c79356b A |
310 | goto fail; |
311 | } | |
91447636 | 312 | bap = (ufs_daddr_t *)buf_dataptr(bp); |
1c79356b A |
313 | #if REV_ENDIAN_FS |
314 | if (rev_endian) | |
8f6c56a5 | 315 | nb = NXSwapLong(bap[indirs[i].in_off]); |
1c79356b A |
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) { | |
91447636 | 326 | buf_brelse(bp); |
1c79356b A |
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)) { | |
91447636 | 333 | buf_brelse(bp); |
1c79356b A |
334 | goto fail; |
335 | } | |
336 | nb = newb; | |
337 | *allocblk++ = nb; | |
91447636 A |
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); | |
1c79356b | 341 | /* |
55e303ae | 342 | * Write synchronously conditional on mount flags. |
1c79356b | 343 | */ |
55e303ae A |
344 | if ((vp)->v_mount->mnt_flag & MNT_ASYNC) { |
345 | error = 0; | |
91447636 A |
346 | buf_bdwrite(nbp); |
347 | } else if (error = buf_bwrite(nbp)) { | |
348 | buf_brelse(bp); | |
1c79356b A |
349 | goto fail; |
350 | } | |
351 | #if REV_ENDIAN_FS | |
352 | if (rev_endian) | |
8f6c56a5 | 353 | bap[indirs[i - 1].in_off] = NXSwapLong(nb); |
1c79356b A |
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) { | |
91447636 | 365 | buf_bwrite(bp); |
1c79356b | 366 | } else { |
91447636 | 367 | buf_bdwrite(bp); |
1c79356b A |
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)) { | |
91447636 | 377 | buf_brelse(bp); |
1c79356b A |
378 | goto fail; |
379 | } | |
380 | nb = newb; | |
381 | *allocblk++ = nb; | |
382 | #if REV_ENDIAN_FS | |
383 | if (rev_endian) | |
8f6c56a5 | 384 | bap[indirs[i].in_off] = NXSwapLong(nb); |
1c79356b A |
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)) { | |
91447636 | 396 | buf_bwrite(bp); |
1c79356b | 397 | } else { |
91447636 | 398 | buf_bdwrite(bp); |
1c79356b A |
399 | } |
400 | if(alloc_buffer ) { | |
91447636 A |
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 | ||
1c79356b | 404 | if (flags & B_CLRBUF) |
91447636 | 405 | buf_clear(nbp); |
1c79356b A |
406 | } |
407 | if (blk_alloc) { | |
408 | *blk_alloc = fs->fs_bsize; | |
409 | } | |
410 | if(alloc_buffer) | |
411 | *bpp = nbp; | |
412 | ||
413 | return (0); | |
414 | } | |
91447636 | 415 | buf_brelse(bp); |
1c79356b | 416 | if (alloc_buffer) { |
91447636 A |
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))); | |
1c79356b | 426 | } |
91447636 | 427 | *bpp = nbp; |
1c79356b A |
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) { | |
91447636 | 442 | devBlockSize = vfs_devblocksize(mp); |
1c79356b A |
443 | #if QUOTA |
444 | /* | |
445 | * Restore user's disk quota because allocation failed. | |
446 | */ | |
9bccf70c | 447 | (void) chkdq(ip, (int64_t)-deallocated, cred, FORCE); |
1c79356b A |
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 | |
91447636 | 457 | * it does no buf_breads (that could lead to deadblock as the page may be already |
1c79356b A |
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 | */ | |
91447636 A |
466 | ffs_blkalloc( |
467 | struct inode *ip, | |
468 | ufs_daddr_t lbn, | |
469 | int size, | |
470 | kauth_cred_t cred, | |
471 | int flags) | |
1c79356b A |
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; | |
1c79356b | 482 | struct mount *mp=vp->v_mount; |
91447636 | 483 | #if REV_ENDIAN_FS |
1c79356b A |
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) | |
55e303ae | 490 | panic("ffs_blkalloc: too large for allocation"); |
1c79356b A |
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) { | |
55e303ae | 499 | panic("ffs_blkalloc():cannot extend file: i_size %d, lbn %d", ip->i_size, lbn); |
1c79356b A |
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) { | |
55e303ae | 517 | panic("ffs_allocblk: trying to extend a fragment"); |
1c79356b A |
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) { | |
55e303ae | 543 | panic("ffs_blkalloc: file with direct blocks only"); |
1c79356b A |
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; | |
91447636 A |
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); | |
1c79356b | 563 | /* |
55e303ae | 564 | * Write synchronously conditional on mount flags. |
1c79356b | 565 | */ |
55e303ae A |
566 | if ((vp)->v_mount->mnt_flag & MNT_ASYNC) { |
567 | error = 0; | |
91447636 A |
568 | buf_bdwrite(bp); |
569 | } else if (error = buf_bwrite(bp)) { | |
1c79356b | 570 | goto fail; |
55e303ae | 571 | } |
1c79356b A |
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;;) { | |
91447636 | 580 | error = (int)buf_meta_bread(vp, (daddr64_t)((unsigned)(indirs[i].in_lbn)), (int)fs->fs_bsize, NOCRED, &bp); |
1c79356b | 581 | if (error) { |
91447636 | 582 | buf_brelse(bp); |
1c79356b A |
583 | goto fail; |
584 | } | |
91447636 | 585 | bap = (ufs_daddr_t *)buf_dataptr(bp); |
1c79356b A |
586 | #if REV_ENDIAN_FS |
587 | if (rev_endian) | |
8f6c56a5 | 588 | nb = NXSwapLong(bap[indirs[i].in_off]); |
1c79356b A |
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) { | |
91447636 | 599 | buf_brelse(bp); |
1c79356b A |
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)) { | |
91447636 | 606 | buf_brelse(bp); |
1c79356b A |
607 | goto fail; |
608 | } | |
609 | nb = newb; | |
610 | *allocblk++ = nb; | |
91447636 A |
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); | |
1c79356b | 614 | /* |
55e303ae | 615 | * Write synchronously conditional on mount flags. |
1c79356b | 616 | */ |
55e303ae A |
617 | if ((vp)->v_mount->mnt_flag & MNT_ASYNC) { |
618 | error = 0; | |
91447636 A |
619 | buf_bdwrite(nbp); |
620 | } else if (error = buf_bwrite(nbp)) { | |
621 | buf_brelse(bp); | |
1c79356b A |
622 | goto fail; |
623 | } | |
624 | #if REV_ENDIAN_FS | |
625 | if (rev_endian) | |
8f6c56a5 | 626 | bap[indirs[i - 1].in_off] = NXSwapLong(nb); |
1c79356b A |
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) { | |
91447636 | 638 | buf_bwrite(bp); |
1c79356b | 639 | } else { |
91447636 | 640 | buf_bdwrite(bp); |
1c79356b A |
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)) { | |
91447636 | 650 | buf_brelse(bp); |
1c79356b A |
651 | goto fail; |
652 | } | |
653 | nb = newb; | |
654 | *allocblk++ = nb; | |
655 | #if REV_ENDIAN_FS | |
656 | if (rev_endian) | |
8f6c56a5 | 657 | bap[indirs[i].in_off] = NXSwapLong(nb); |
1c79356b A |
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) { | |
91447636 | 669 | buf_bwrite(bp); |
1c79356b | 670 | } else { |
91447636 | 671 | buf_bdwrite(bp); |
1c79356b A |
672 | } |
673 | return (0); | |
674 | } | |
91447636 | 675 | buf_brelse(bp); |
1c79356b A |
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) { | |
91447636 | 689 | devBlockSize = vfs_devblocksize(mp); |
1c79356b A |
690 | #if QUOTA |
691 | /* | |
692 | * Restore user's disk quota because allocation failed. | |
693 | */ | |
9bccf70c | 694 | (void) chkdq(ip, (int64_t)-deallocated, cred, FORCE); |
1c79356b A |
695 | #endif /* QUOTA */ |
696 | ip->i_blocks -= btodb(deallocated, devBlockSize); | |
697 | ip->i_flag |= IN_CHANGE | IN_UPDATE; | |
698 | } | |
699 | return (error); | |
700 | } |