]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.sbin/makefs/ffs/ffs_balloc.c
ident(1): Normalizing date format
[FreeBSD/FreeBSD.git] / usr.sbin / makefs / ffs / ffs_balloc.c
1 /*      $NetBSD: ffs_balloc.c,v 1.13 2004/06/20 22:20:18 jmc Exp $      */
2 /* From NetBSD: ffs_balloc.c,v 1.25 2001/08/08 08:36:36 lukem Exp */
3
4 /*-
5  * SPDX-License-Identifier: BSD-3-Clause
6  *
7  * Copyright (c) 1982, 1986, 1989, 1993
8  *      The Regents of the University of California.  All rights reserved.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  * 3. Neither the name of the University nor the names of its contributors
19  *    may be used to endorse or promote products derived from this software
20  *    without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32  * SUCH DAMAGE.
33  *
34  *      @(#)ffs_balloc.c        8.8 (Berkeley) 6/16/95
35  */
36
37 #include <sys/cdefs.h>
38 __FBSDID("$FreeBSD$");
39
40 #include <sys/param.h>
41 #include <sys/time.h>
42
43 #include <assert.h>
44 #include <errno.h>
45 #include <stdio.h>
46 #include <stdlib.h>
47 #include <string.h>
48
49 #include "makefs.h"
50
51 #include <ufs/ufs/dinode.h>
52 #include <ufs/ffs/fs.h>
53
54 #include "ffs/ufs_bswap.h"
55 #include "ffs/buf.h"
56 #include "ffs/ufs_inode.h"
57 #include "ffs/ffs_extern.h"
58
59 static int ffs_balloc_ufs1(struct inode *, off_t, int, struct buf **);
60 static int ffs_balloc_ufs2(struct inode *, off_t, int, struct buf **);
61
62 /*
63  * Balloc defines the structure of file system storage
64  * by allocating the physical blocks on a device given
65  * the inode and the logical block number in a file.
66  *
67  * Assume: flags == B_SYNC | B_CLRBUF
68  */
69
70 int
71 ffs_balloc(struct inode *ip, off_t offset, int bufsize, struct buf **bpp)
72 {
73         if (ip->i_fs->fs_magic == FS_UFS2_MAGIC)
74                 return ffs_balloc_ufs2(ip, offset, bufsize, bpp);
75         else
76                 return ffs_balloc_ufs1(ip, offset, bufsize, bpp);
77 }
78
79 static int
80 ffs_balloc_ufs1(struct inode *ip, off_t offset, int bufsize, struct buf **bpp)
81 {
82         daddr_t lbn, lastlbn;
83         int size;
84         int32_t nb;
85         struct buf *bp, *nbp;
86         struct fs *fs = ip->i_fs;
87         struct indir indirs[UFS_NIADDR + 2];
88         daddr_t newb, pref;
89         int32_t *bap;
90         int osize, nsize, num, i, error;
91         int32_t *allocblk, allociblk[UFS_NIADDR + 1];
92         int32_t *allocib;
93         const int needswap = UFS_FSNEEDSWAP(fs);
94
95         lbn = lblkno(fs, offset);
96         size = blkoff(fs, offset) + bufsize;
97         if (bpp != NULL) {
98                 *bpp = NULL;
99         }
100
101         assert(size <= fs->fs_bsize);
102         if (lbn < 0)
103                 return (EFBIG);
104
105         /*
106          * If the next write will extend the file into a new block,
107          * and the file is currently composed of a fragment
108          * this fragment has to be extended to be a full block.
109          */
110
111         lastlbn = lblkno(fs, ip->i_ffs1_size);
112         if (lastlbn < UFS_NDADDR && lastlbn < lbn) {
113                 nb = lastlbn;
114                 osize = blksize(fs, ip, nb);
115                 if (osize < fs->fs_bsize && osize > 0) {
116                         warnx("need to ffs_realloccg; not supported!");
117                         abort();
118                 }
119         }
120
121         /*
122          * The first UFS_NDADDR blocks are direct blocks
123          */
124
125         if (lbn < UFS_NDADDR) {
126                 nb = ufs_rw32(ip->i_ffs1_db[lbn], needswap);
127                 if (nb != 0 && ip->i_ffs1_size >=
128                     (uint64_t)lblktosize(fs, lbn + 1)) {
129
130                         /*
131                          * The block is an already-allocated direct block
132                          * and the file already extends past this block,
133                          * thus this must be a whole block.
134                          * Just read the block (if requested).
135                          */
136
137                         if (bpp != NULL) {
138                                 error = bread(ip->i_devvp, lbn, fs->fs_bsize,
139                                     NULL, bpp);
140                                 if (error) {
141                                         brelse(*bpp);
142                                         return (error);
143                                 }
144                         }
145                         return (0);
146                 }
147                 if (nb != 0) {
148
149                         /*
150                          * Consider need to reallocate a fragment.
151                          */
152
153                         osize = fragroundup(fs, blkoff(fs, ip->i_ffs1_size));
154                         nsize = fragroundup(fs, size);
155                         if (nsize <= osize) {
156
157                                 /*
158                                  * The existing block is already
159                                  * at least as big as we want.
160                                  * Just read the block (if requested).
161                                  */
162
163                                 if (bpp != NULL) {
164                                         error = bread(ip->i_devvp, lbn, osize,
165                                             NULL, bpp);
166                                         if (error) {
167                                                 brelse(*bpp);
168                                                 return (error);
169                                         }
170                                 }
171                                 return 0;
172                         } else {
173                                 warnx("need to ffs_realloccg; not supported!");
174                                 abort();
175                         }
176                 } else {
177
178                         /*
179                          * the block was not previously allocated,
180                          * allocate a new block or fragment.
181                          */
182
183                         if (ip->i_ffs1_size < (uint64_t)lblktosize(fs, lbn + 1))
184                                 nsize = fragroundup(fs, size);
185                         else
186                                 nsize = fs->fs_bsize;
187                         error = ffs_alloc(ip, lbn,
188                             ffs_blkpref_ufs1(ip, lbn, (int)lbn,
189                                 &ip->i_ffs1_db[0]),
190                                 nsize, &newb);
191                         if (error)
192                                 return (error);
193                         if (bpp != NULL) {
194                                 bp = getblk(ip->i_devvp, lbn, nsize, 0, 0, 0);
195                                 bp->b_blkno = fsbtodb(fs, newb);
196                                 clrbuf(bp);
197                                 *bpp = bp;
198                         }
199                 }
200                 ip->i_ffs1_db[lbn] = ufs_rw32((int32_t)newb, needswap);
201                 return (0);
202         }
203
204         /*
205          * Determine the number of levels of indirection.
206          */
207
208         pref = 0;
209         if ((error = ufs_getlbns(ip, lbn, indirs, &num)) != 0)
210                 return (error);
211
212         if (num < 1) {
213                 warnx("ffs_balloc: ufs_getlbns returned indirect block");
214                 abort();
215         }
216
217         /*
218          * Fetch the first indirect block allocating if necessary.
219          */
220
221         --num;
222         nb = ufs_rw32(ip->i_ffs1_ib[indirs[0].in_off], needswap);
223         allocib = NULL;
224         allocblk = allociblk;
225         if (nb == 0) {
226                 pref = ffs_blkpref_ufs1(ip, lbn, 0, (int32_t *)0);
227                 error = ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize, &newb);
228                 if (error)
229                         return error;
230                 nb = newb;
231                 *allocblk++ = nb;
232                 bp = getblk(ip->i_devvp, indirs[1].in_lbn, fs->fs_bsize, 0, 0, 0);
233                 bp->b_blkno = fsbtodb(fs, nb);
234                 clrbuf(bp);
235                 /*
236                  * Write synchronously so that indirect blocks
237                  * never point at garbage.
238                  */
239                 if ((error = bwrite(bp)) != 0)
240                         return error;
241                 allocib = &ip->i_ffs1_ib[indirs[0].in_off];
242                 *allocib = ufs_rw32((int32_t)nb, needswap);
243         }
244
245         /*
246          * Fetch through the indirect blocks, allocating as necessary.
247          */
248
249         for (i = 1;;) {
250                 error = bread(ip->i_devvp, indirs[i].in_lbn, fs->fs_bsize,
251                     NULL, &bp);
252                 if (error) {
253                         brelse(bp);
254                         return error;
255                 }
256                 bap = (int32_t *)bp->b_data;
257                 nb = ufs_rw32(bap[indirs[i].in_off], needswap);
258                 if (i == num)
259                         break;
260                 i++;
261                 if (nb != 0) {
262                         brelse(bp);
263                         continue;
264                 }
265                 if (pref == 0)
266                         pref = ffs_blkpref_ufs1(ip, lbn, 0, (int32_t *)0);
267                 error = ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize, &newb);
268                 if (error) {
269                         brelse(bp);
270                         return error;
271                 }
272                 nb = newb;
273                 *allocblk++ = nb;
274                 nbp = getblk(ip->i_devvp, indirs[i].in_lbn, fs->fs_bsize, 0, 0, 0);
275                 nbp->b_blkno = fsbtodb(fs, nb);
276                 clrbuf(nbp);
277                 /*
278                  * Write synchronously so that indirect blocks
279                  * never point at garbage.
280                  */
281
282                 if ((error = bwrite(nbp)) != 0) {
283                         brelse(bp);
284                         return error;
285                 }
286                 bap[indirs[i - 1].in_off] = ufs_rw32(nb, needswap);
287
288                 bwrite(bp);
289         }
290
291         /*
292          * Get the data block, allocating if necessary.
293          */
294
295         if (nb == 0) {
296                 pref = ffs_blkpref_ufs1(ip, lbn, indirs[num].in_off, &bap[0]);
297                 error = ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize, &newb);
298                 if (error) {
299                         brelse(bp);
300                         return error;
301                 }
302                 nb = newb;
303                 *allocblk++ = nb;
304                 if (bpp != NULL) {
305                         nbp = getblk(ip->i_devvp, lbn, fs->fs_bsize, 0, 0, 0);
306                         nbp->b_blkno = fsbtodb(fs, nb);
307                         clrbuf(nbp);
308                         *bpp = nbp;
309                 }
310                 bap[indirs[num].in_off] = ufs_rw32(nb, needswap);
311
312                 /*
313                  * If required, write synchronously, otherwise use
314                  * delayed write.
315                  */
316                 bwrite(bp);
317                 return (0);
318         }
319         brelse(bp);
320         if (bpp != NULL) {
321                 error = bread(ip->i_devvp, lbn, (int)fs->fs_bsize, NULL, &nbp);
322                 if (error) {
323                         brelse(nbp);
324                         return error;
325                 }
326                 *bpp = nbp;
327         }
328         return (0);
329 }
330
331 static int
332 ffs_balloc_ufs2(struct inode *ip, off_t offset, int bufsize, struct buf **bpp)
333 {
334         daddr_t lbn, lastlbn;
335         int size;
336         struct buf *bp, *nbp;
337         struct fs *fs = ip->i_fs;
338         struct indir indirs[UFS_NIADDR + 2];
339         daddr_t newb, pref, nb;
340         int64_t *bap;
341         int osize, nsize, num, i, error;
342         int64_t *allocblk, allociblk[UFS_NIADDR + 1];
343         int64_t *allocib;
344         const int needswap = UFS_FSNEEDSWAP(fs);
345
346         lbn = lblkno(fs, offset);
347         size = blkoff(fs, offset) + bufsize;
348         if (bpp != NULL) {
349                 *bpp = NULL;
350         }
351
352         assert(size <= fs->fs_bsize);
353         if (lbn < 0)
354                 return (EFBIG);
355
356         /*
357          * If the next write will extend the file into a new block,
358          * and the file is currently composed of a fragment
359          * this fragment has to be extended to be a full block.
360          */
361
362         lastlbn = lblkno(fs, ip->i_ffs2_size);
363         if (lastlbn < UFS_NDADDR && lastlbn < lbn) {
364                 nb = lastlbn;
365                 osize = blksize(fs, ip, nb);
366                 if (osize < fs->fs_bsize && osize > 0) {
367                         warnx("need to ffs_realloccg; not supported!");
368                         abort();
369                 }
370         }
371
372         /*
373          * The first UFS_NDADDR blocks are direct blocks
374          */
375
376         if (lbn < UFS_NDADDR) {
377                 nb = ufs_rw64(ip->i_ffs2_db[lbn], needswap);
378                 if (nb != 0 && ip->i_ffs2_size >=
379                     (uint64_t)lblktosize(fs, lbn + 1)) {
380
381                         /*
382                          * The block is an already-allocated direct block
383                          * and the file already extends past this block,
384                          * thus this must be a whole block.
385                          * Just read the block (if requested).
386                          */
387
388                         if (bpp != NULL) {
389                                 error = bread(ip->i_devvp, lbn, fs->fs_bsize,
390                                     NULL, bpp);
391                                 if (error) {
392                                         brelse(*bpp);
393                                         return (error);
394                                 }
395                         }
396                         return (0);
397                 }
398                 if (nb != 0) {
399
400                         /*
401                          * Consider need to reallocate a fragment.
402                          */
403
404                         osize = fragroundup(fs, blkoff(fs, ip->i_ffs2_size));
405                         nsize = fragroundup(fs, size);
406                         if (nsize <= osize) {
407
408                                 /*
409                                  * The existing block is already
410                                  * at least as big as we want.
411                                  * Just read the block (if requested).
412                                  */
413
414                                 if (bpp != NULL) {
415                                         error = bread(ip->i_devvp, lbn, osize,
416                                             NULL, bpp);
417                                         if (error) {
418                                                 brelse(*bpp);
419                                                 return (error);
420                                         }
421                                 }
422                                 return 0;
423                         } else {
424                                 warnx("need to ffs_realloccg; not supported!");
425                                 abort();
426                         }
427                 } else {
428
429                         /*
430                          * the block was not previously allocated,
431                          * allocate a new block or fragment.
432                          */
433
434                         if (ip->i_ffs2_size < (uint64_t)lblktosize(fs, lbn + 1))
435                                 nsize = fragroundup(fs, size);
436                         else
437                                 nsize = fs->fs_bsize;
438                         error = ffs_alloc(ip, lbn,
439                             ffs_blkpref_ufs2(ip, lbn, (int)lbn,
440                                 &ip->i_ffs2_db[0]),
441                                 nsize, &newb);
442                         if (error)
443                                 return (error);
444                         if (bpp != NULL) {
445                                 bp = getblk(ip->i_devvp, lbn, nsize, 0, 0, 0);
446                                 bp->b_blkno = fsbtodb(fs, newb);
447                                 clrbuf(bp);
448                                 *bpp = bp;
449                         }
450                 }
451                 ip->i_ffs2_db[lbn] = ufs_rw64(newb, needswap);
452                 return (0);
453         }
454
455         /*
456          * Determine the number of levels of indirection.
457          */
458
459         pref = 0;
460         if ((error = ufs_getlbns(ip, lbn, indirs, &num)) != 0)
461                 return (error);
462
463         if (num < 1) {
464                 warnx("ffs_balloc: ufs_getlbns returned indirect block");
465                 abort();
466         }
467
468         /*
469          * Fetch the first indirect block allocating if necessary.
470          */
471
472         --num;
473         nb = ufs_rw64(ip->i_ffs2_ib[indirs[0].in_off], needswap);
474         allocib = NULL;
475         allocblk = allociblk;
476         if (nb == 0) {
477                 pref = ffs_blkpref_ufs2(ip, lbn, 0, (int64_t *)0);
478                 error = ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize, &newb);
479                 if (error)
480                         return error;
481                 nb = newb;
482                 *allocblk++ = nb;
483                 bp = getblk(ip->i_devvp, indirs[1].in_lbn, fs->fs_bsize, 0, 0, 0);
484                 bp->b_blkno = fsbtodb(fs, nb);
485                 clrbuf(bp);
486                 /*
487                  * Write synchronously so that indirect blocks
488                  * never point at garbage.
489                  */
490                 if ((error = bwrite(bp)) != 0)
491                         return error;
492                 allocib = &ip->i_ffs2_ib[indirs[0].in_off];
493                 *allocib = ufs_rw64(nb, needswap);
494         }
495
496         /*
497          * Fetch through the indirect blocks, allocating as necessary.
498          */
499
500         for (i = 1;;) {
501                 error = bread(ip->i_devvp, indirs[i].in_lbn, fs->fs_bsize,
502                     NULL, &bp);
503                 if (error) {
504                         brelse(bp);
505                         return error;
506                 }
507                 bap = (int64_t *)bp->b_data;
508                 nb = ufs_rw64(bap[indirs[i].in_off], needswap);
509                 if (i == num)
510                         break;
511                 i++;
512                 if (nb != 0) {
513                         brelse(bp);
514                         continue;
515                 }
516                 if (pref == 0)
517                         pref = ffs_blkpref_ufs2(ip, lbn, 0, (int64_t *)0);
518                 error = ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize, &newb);
519                 if (error) {
520                         brelse(bp);
521                         return error;
522                 }
523                 nb = newb;
524                 *allocblk++ = nb;
525                 nbp = getblk(ip->i_devvp, indirs[i].in_lbn, fs->fs_bsize, 0, 0, 0);
526                 nbp->b_blkno = fsbtodb(fs, nb);
527                 clrbuf(nbp);
528                 /*
529                  * Write synchronously so that indirect blocks
530                  * never point at garbage.
531                  */
532
533                 if ((error = bwrite(nbp)) != 0) {
534                         brelse(bp);
535                         return error;
536                 }
537                 bap[indirs[i - 1].in_off] = ufs_rw64(nb, needswap);
538
539                 bwrite(bp);
540         }
541
542         /*
543          * Get the data block, allocating if necessary.
544          */
545
546         if (nb == 0) {
547                 pref = ffs_blkpref_ufs2(ip, lbn, indirs[num].in_off, &bap[0]);
548                 error = ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize, &newb);
549                 if (error) {
550                         brelse(bp);
551                         return error;
552                 }
553                 nb = newb;
554                 *allocblk++ = nb;
555                 if (bpp != NULL) {
556                         nbp = getblk(ip->i_devvp, lbn, fs->fs_bsize, 0, 0, 0);
557                         nbp->b_blkno = fsbtodb(fs, nb);
558                         clrbuf(nbp);
559                         *bpp = nbp;
560                 }
561                 bap[indirs[num].in_off] = ufs_rw64(nb, needswap);
562
563                 /*
564                  * If required, write synchronously, otherwise use
565                  * delayed write.
566                  */
567                 bwrite(bp);
568                 return (0);
569         }
570         brelse(bp);
571         if (bpp != NULL) {
572                 error = bread(ip->i_devvp, lbn, (int)fs->fs_bsize, NULL, &nbp);
573                 if (error) {
574                         brelse(nbp);
575                         return error;
576                 }
577                 *bpp = nbp;
578         }
579         return (0);
580 }