git: 1a2920e96aac - stable/13 - makefs: fix calculation of file sizes

From: Alan Somers <asomers_at_FreeBSD.org>
Date: Sat, 18 Jun 2022 14:17:50 UTC
The branch stable/13 has been updated by asomers:

URL: https://cgit.FreeBSD.org/src/commit/?id=1a2920e96aacc253b4f65405640074bf595c431d

commit 1a2920e96aacc253b4f65405640074bf595c431d
Author:     Alan Somers <asomers@FreeBSD.org>
AuthorDate: 2022-05-16 22:32:10 +0000
Commit:     Alan Somers <asomers@FreeBSD.org>
CommitDate: 2022-06-18 14:17:23 +0000

    makefs: fix calculation of file sizes
    
    When a new FS image is created we need to calculate how much space each
    file is going to consume.
    Fix two bugs in that logic:
    
    1) Count the space needed for indirect blocks for large files.
    1) Normally the trailing data of a file is written to a block of frag
       size, 4 kB by default.
    
    However for files that use indirect blocks a full block is allocated,
    32kB by default.  Take that into account.
    
    Adjust size calculations to match what is done in ffs_mkfs routine:
    
    * Depending on the UFS version the superblock is stored at a different
      offset. Take that into account.
    * Add the cylinder group block size.
    * All of the above has to be aligned to the block size.
    
    Finally, Remove "ncg" variable. It's always 1 and it was used to
    multiply stuff.
    
    PR:             229929
    Reviewed by:    mckusick
    Sponsored by:   Semihalf
    Submitted by:   Kornel Dulęba <mindal@semihalf.com>
    Differential Revision:  https://reviews.freebsd.org/D35131
    Differential Revision:  https://reviews.freebsd.org/D35132
    
    (cherry picked from commit ecdc04d006de93eb343ce3b77208abd937d4f8ac)
---
 usr.sbin/makefs/ffs.c                     | 50 ++++++++++++++++++-------------
 usr.sbin/makefs/tests/makefs_ffs_tests.sh |  1 -
 2 files changed, 30 insertions(+), 21 deletions(-)

diff --git a/usr.sbin/makefs/ffs.c b/usr.sbin/makefs/ffs.c
index 6429c54e8a9f..29972317c80b 100644
--- a/usr.sbin/makefs/ffs.c
+++ b/usr.sbin/makefs/ffs.c
@@ -324,7 +324,6 @@ ffs_makefs(const char *image, const char *dir, fsnode *root, fsinfo_t *fsopts)
 static void
 ffs_validate(const char *dir, fsnode *root, fsinfo_t *fsopts)
 {
-	int32_t	ncg = 1;
 #ifdef notyet
 	int32_t	spc, nspf, ncyl, fssize;
 #endif
@@ -395,22 +394,26 @@ ffs_validate(const char *dir, fsnode *root, fsinfo_t *fsopts)
 		fsopts->size =
 		    fsopts->size * (100 + fsopts->freeblockpc) / 100;
 
-		/* add space needed for superblocks */
 	/*
-	 * The old SBOFF (SBLOCK_UFS1) is used here because makefs is
-	 * typically used for small filesystems where space matters.
-	 * XXX make this an option.
+	 * Add space needed for superblock, cylblock and to store inodes.
+	 * All of those segments are aligned to the block size.
+	 * XXX: This has to match calculations done in ffs_mkfs.
 	 */
-	fsopts->size += (SBLOCK_UFS1 + SBLOCKSIZE) * ncg;
-		/* add space needed to store inodes, x3 for blockmaps, etc */
-	if (ffs_opts->version == 1)
-		fsopts->size += ncg * DINODE1_SIZE *
-		    roundup(fsopts->inodes / ncg, 
-			ffs_opts->bsize / DINODE1_SIZE);
-	else
-		fsopts->size += ncg * DINODE2_SIZE *
-		    roundup(fsopts->inodes / ncg, 
-			ffs_opts->bsize / DINODE2_SIZE);
+	if (ffs_opts->version == 1) {
+		fsopts->size +=
+		    roundup(SBLOCK_UFS1 + SBLOCKSIZE, ffs_opts->bsize);
+		fsopts->size += roundup(SBLOCKSIZE, ffs_opts->bsize);
+		fsopts->size += ffs_opts->bsize;
+		fsopts->size +=  DINODE1_SIZE *
+		    roundup(fsopts->inodes, ffs_opts->bsize / DINODE1_SIZE);
+	} else {
+		fsopts->size +=
+		    roundup(SBLOCK_UFS2 + SBLOCKSIZE, ffs_opts->bsize);
+		fsopts->size += roundup(SBLOCKSIZE, ffs_opts->bsize);
+		fsopts->size += ffs_opts->bsize;
+		fsopts->size += DINODE2_SIZE *
+		    roundup(fsopts->inodes, ffs_opts->bsize / DINODE2_SIZE);
+	}
 
 		/* add minfree */
 	if (ffs_opts->minfree > 0)
@@ -620,12 +623,19 @@ ffs_size_dir(fsnode *root, fsinfo_t *fsopts)
 		    e, tmpdir.d_namlen, this, curdirsize);		\
 } while (0);
 
-	/*
-	 * XXX	this needs to take into account extra space consumed
-	 *	by indirect blocks, etc.
-	 */
 #define	ADDSIZE(x) do {							\
-	fsopts->size += roundup((x), ffs_opts->fsize);			\
+	if ((size_t)(x) < UFS_NDADDR * (size_t)ffs_opts->bsize) {	\
+		fsopts->size += roundup((x), ffs_opts->fsize);		\
+	} else {							\
+		/* Count space consumed by indirecttion blocks. */	\
+		fsopts->size +=	ffs_opts->bsize *			\
+		    (howmany((x), UFS_NDADDR * ffs_opts->bsize) - 1);	\
+		/*							\
+		 * If the file is big enough to use indirect blocks,	\
+		 * we allocate bsize block for trailing data.		\
+		 */							\
+		fsopts->size += roundup((x), ffs_opts->bsize);		\
+	}								\
 } while (0);
 
 	curdirsize = 0;
diff --git a/usr.sbin/makefs/tests/makefs_ffs_tests.sh b/usr.sbin/makefs/tests/makefs_ffs_tests.sh
index 55be19f099eb..1a415cb5f518 100644
--- a/usr.sbin/makefs/tests/makefs_ffs_tests.sh
+++ b/usr.sbin/makefs/tests/makefs_ffs_tests.sh
@@ -57,7 +57,6 @@ check_ffs_image_contents()
 atf_test_case autocalculate_image_size cleanup
 autocalculate_image_size_body()
 {
-	atf_expect_fail "PR 229929 makefs(8) can underestimate image size"
 	create_test_inputs
 
 	atf_check -e empty -o save:$TEST_SPEC_FILE -s exit:0 \