diff options
Diffstat (limited to 'usr.sbin/makefs')
-rw-r--r-- | usr.sbin/makefs/ffs.c | 2 | ||||
-rw-r--r-- | usr.sbin/makefs/makefs.8 | 16 | ||||
-rw-r--r-- | usr.sbin/makefs/tests/Makefile | 4 | ||||
-rw-r--r-- | usr.sbin/makefs/tests/makefs_msdos_tests.sh | 2 | ||||
-rw-r--r-- | usr.sbin/makefs/tests/makefs_zfs_tests.sh | 92 | ||||
-rw-r--r-- | usr.sbin/makefs/zfs.c | 6 | ||||
-rw-r--r-- | usr.sbin/makefs/zfs/dsl.c | 65 | ||||
-rw-r--r-- | usr.sbin/makefs/zfs/fs.c | 45 | ||||
-rw-r--r-- | usr.sbin/makefs/zfs/objset.c | 1 | ||||
-rw-r--r-- | usr.sbin/makefs/zfs/vdev.c | 1 | ||||
-rw-r--r-- | usr.sbin/makefs/zfs/zap.c | 13 |
11 files changed, 201 insertions, 46 deletions
diff --git a/usr.sbin/makefs/ffs.c b/usr.sbin/makefs/ffs.c index 4efcd20ad91a..c0fcadf11fba 100644 --- a/usr.sbin/makefs/ffs.c +++ b/usr.sbin/makefs/ffs.c @@ -1056,7 +1056,7 @@ ffs_make_dirbuf(dirbuf_t *dbuf, const char *name, fsnode *node, int needswap) reclen = DIRSIZ_SWAP(0, &de, needswap); de.d_reclen = ufs_rw16(reclen, needswap); - dp = (struct direct *)(dbuf->buf + dbuf->cur); + dp = dbuf->buf == NULL ? NULL : (struct direct *)(dbuf->buf + dbuf->cur); llen = 0; if (dp != NULL) llen = DIRSIZ_SWAP(0, dp, needswap); diff --git a/usr.sbin/makefs/makefs.8 b/usr.sbin/makefs/makefs.8 index a11eaf8206e9..d20f69d87559 100644 --- a/usr.sbin/makefs/makefs.8 +++ b/usr.sbin/makefs/makefs.8 @@ -33,8 +33,7 @@ .\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE .\" POSSIBILITY OF SUCH DAMAGE. .\" -.Dd January 19, 2024 - +.Dd July 19, 2025 .Dt MAKEFS 8 .Os .Sh NAME @@ -551,6 +550,12 @@ This option allows the default heuristic to be overridden. .It verify-txgs Prompt OpenZFS to verify pool metadata during import. This is disabled by default as it may significantly increase import times. +.It poolguid +Use the specified 64-bit integer as the pool GUID. +If this option is not specified, the pool GUID will be random but fixed +across multiple identical invocations of +.Nm . +This option is useful for testing but not required for reproducibility. .It poolname The name of the ZFS pool. This option must be specified. @@ -596,10 +601,17 @@ The following properties may be set for a dataset: .Bl -tag -compact -offset indent .It atime .It canmount +.It compression .It exec .It mountpoint .It setuid .El +Note that +.Nm +does not implement compression of files included in the image, +regardless of the value of the +.Dv compression +property. .El .Sh SEE ALSO .Xr mtree 5 , diff --git a/usr.sbin/makefs/tests/Makefile b/usr.sbin/makefs/tests/Makefile index 345b728651d6..748bafa06211 100644 --- a/usr.sbin/makefs/tests/Makefile +++ b/usr.sbin/makefs/tests/Makefile @@ -7,10 +7,6 @@ ATF_TESTS_SH+= makefs_msdos_tests TEST_METADATA.makefs_msdos_tests+= required_files="/sbin/mount_msdosfs" .if ${MK_ZFS} != "no" ATF_TESTS_SH+= makefs_zfs_tests -# ZFS pools created by makefs always have the same GUID, so OpenZFS -# refuses to import more than one at a time. Thus the ZFS tests cannot -# be run in parallel for now. -TEST_METADATA.makefs_zfs_tests+= is_exclusive="true" .endif BINDIR= ${TESTSDIR} diff --git a/usr.sbin/makefs/tests/makefs_msdos_tests.sh b/usr.sbin/makefs/tests/makefs_msdos_tests.sh index b36b43b3abf6..fb94429b477b 100644 --- a/usr.sbin/makefs/tests/makefs_msdos_tests.sh +++ b/usr.sbin/makefs/tests/makefs_msdos_tests.sh @@ -4,7 +4,7 @@ # Copyright (c) 2025 The FreeBSD Foundation # # This software was developed by Klara, Inc. -# under sponsorship from the FreeBSD Foundation and the Sovereign Tech Agency. +# under sponsorship from the FreeBSD Foundation. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are diff --git a/usr.sbin/makefs/tests/makefs_zfs_tests.sh b/usr.sbin/makefs/tests/makefs_zfs_tests.sh index 520d1f211ac3..2fafce85b347 100644 --- a/usr.sbin/makefs/tests/makefs_zfs_tests.sh +++ b/usr.sbin/makefs/tests/makefs_zfs_tests.sh @@ -28,7 +28,7 @@ # SUCH DAMAGE. # -MAKEFS="makefs -t zfs -o verify-txgs=true" +MAKEFS="makefs -t zfs -o verify-txgs=true -o poolguid=$$" ZFS_POOL_NAME="makefstest$$" TEST_ZFS_POOL_NAME="$TMPDIR/poolname" @@ -124,6 +124,95 @@ basic_cleanup() common_cleanup } +# +# Try configuring various compression algorithms. +# +atf_test_case compression cleanup +compression_body() +{ + create_test_inputs + + cd $TEST_INPUTS_DIR + mkdir dir + mkdir dir2 + cd - + + for alg in off on lzjb gzip gzip-1 gzip-2 gzip-3 gzip-4 \ + gzip-5 gzip-6 gzip-7 gzip-8 gzip-9 zle lz4 zstd; do + atf_check $MAKEFS -s 1g -o rootpath=/ \ + -o poolname=$ZFS_POOL_NAME \ + -o fs=${ZFS_POOL_NAME}\;compression=$alg \ + -o fs=${ZFS_POOL_NAME}/dir \ + -o fs=${ZFS_POOL_NAME}/dir2\;compression=off \ + $TEST_IMAGE $TEST_INPUTS_DIR + + import_image + + check_image_contents + + if [ $alg = gzip-6 ]; then + # ZFS reports gzip-6 as just gzip since it uses + # a default compression level of 6. + alg=gzip + fi + # The "dir" dataset's compression algorithm should be + # inherited from the root dataset. + atf_check -o inline:$alg\\n -e empty -s exit:0 \ + zfs get -H -o value compression ${ZFS_POOL_NAME} + atf_check -o inline:$alg\\n -e empty -s exit:0 \ + zfs get -H -o value compression ${ZFS_POOL_NAME}/dir + atf_check -o inline:off\\n -e empty -s exit:0 \ + zfs get -H -o value compression ${ZFS_POOL_NAME}/dir2 + + atf_check -e ignore dd if=/dev/random \ + of=${TEST_MOUNT_DIR}/dir/random bs=1M count=10 + atf_check -e ignore dd if=/dev/zero \ + of=${TEST_MOUNT_DIR}/dir/zero bs=1M count=10 + atf_check -e ignore dd if=/dev/zero \ + of=${TEST_MOUNT_DIR}/dir2/zero bs=1M count=10 + + # Export and reimport to ensure that everything is + # flushed to disk. + atf_check zpool export ${ZFS_POOL_NAME} + atf_check -o ignore -e empty -s exit:0 \ + zdb -e -p /dev/$(cat $TEST_MD_DEVICE_FILE) -mmm -ddddd \ + $ZFS_POOL_NAME + atf_check zpool import -R $TEST_MOUNT_DIR $ZFS_POOL_NAME + + if [ $alg = off ]; then + # If compression is off, the files should be the + # same size as the input. + atf_check -o match:"^11[[:space:]]+${TEST_MOUNT_DIR}/dir/random" \ + du -m ${TEST_MOUNT_DIR}/dir/random + atf_check -o match:"^11[[:space:]]+${TEST_MOUNT_DIR}/dir/zero" \ + du -m ${TEST_MOUNT_DIR}/dir/zero + atf_check -o match:"^11[[:space:]]+${TEST_MOUNT_DIR}/dir2/zero" \ + du -m ${TEST_MOUNT_DIR}/dir2/zero + else + # If compression is on, the dir/zero file ought + # to be smaller. + atf_check -o match:"^1[[:space:]]+${TEST_MOUNT_DIR}/dir/zero" \ + du -m ${TEST_MOUNT_DIR}/dir/zero + atf_check -o match:"^11[[:space:]]+${TEST_MOUNT_DIR}/dir/random" \ + du -m ${TEST_MOUNT_DIR}/dir/random + atf_check -o match:"^11[[:space:]]+${TEST_MOUNT_DIR}/dir2/zero" \ + du -m ${TEST_MOUNT_DIR}/dir2/zero + fi + + atf_check zpool destroy ${ZFS_POOL_NAME} + atf_check rm -f ${TEST_ZFS_POOL_NAME} + atf_check mdconfig -d -u $(cat ${TEST_MD_DEVICE_FILE}) + atf_check rm -f ${TEST_MD_DEVICE_FILE} + done +} +compression_cleanup() +{ + common_cleanup +} + +# +# Try destroying a dataset that was created by makefs. +# atf_test_case dataset_removal cleanup dataset_removal_body() { @@ -939,6 +1028,7 @@ atf_init_test_cases() { atf_add_test_case autoexpand atf_add_test_case basic + atf_add_test_case compression atf_add_test_case dataset_removal atf_add_test_case devfs atf_add_test_case empty_dir diff --git a/usr.sbin/makefs/zfs.c b/usr.sbin/makefs/zfs.c index 66e7f8dafc9c..8d50c450541b 100644 --- a/usr.sbin/makefs/zfs.c +++ b/usr.sbin/makefs/zfs.c @@ -38,6 +38,7 @@ #include <stdalign.h> #include <stdbool.h> #include <stddef.h> +#include <stdint.h> #include <stdlib.h> #include <string.h> #include <unistd.h> @@ -85,6 +86,8 @@ zfs_prep_opts(fsinfo_t *fsopts) 0, 0, "Bootable dataset" }, { '\0', "mssize", &zfs->mssize, OPT_INT64, MINMSSIZE, MAXMSSIZE, "Metaslab size" }, + { '\0', "poolguid", &zfs->poolguid, OPT_INT64, + 0, INT64_MAX, "ZFS pool GUID" }, { '\0', "poolname", &zfs->poolname, OPT_STRPTR, 0, 0, "ZFS pool name" }, { '\0', "rootpath", &zfs->rootpath, OPT_STRPTR, @@ -547,7 +550,8 @@ pool_init(zfs_opt_t *zfs) { uint64_t dnid; - zfs->poolguid = randomguid(); + if (zfs->poolguid == 0) + zfs->poolguid = randomguid(); zfs->vdevguid = randomguid(); zfs->mos = objset_alloc(zfs, DMU_OST_META); diff --git a/usr.sbin/makefs/zfs/dsl.c b/usr.sbin/makefs/zfs/dsl.c index f7264b9d2ca7..1977521d7f92 100644 --- a/usr.sbin/makefs/zfs/dsl.c +++ b/usr.sbin/makefs/zfs/dsl.c @@ -119,7 +119,7 @@ dsl_dir_get_mountpoint(zfs_opt_t *zfs, zfs_dsl_dir_t *dir) if (nvlist_find_string(pdir->propsnv, "mountpoint", &tmp) == 0) { - easprintf(&mountpoint, "%s%s%s", tmp, + (void)easprintf(&mountpoint, "%s%s%s", tmp, tmp[strlen(tmp) - 1] == '/' ? "" : "/", origmountpoint); free(tmp); @@ -127,7 +127,7 @@ dsl_dir_get_mountpoint(zfs_opt_t *zfs, zfs_dsl_dir_t *dir) break; } - easprintf(&mountpoint, "%s/%s", pdir->name, + (void)easprintf(&mountpoint, "%s/%s", pdir->name, origmountpoint); free(origmountpoint); } @@ -175,24 +175,57 @@ dsl_dir_set_prop(zfs_opt_t *zfs, zfs_dsl_dir_t *dir, const char *key, "the root path `%s'", val, zfs->rootpath); } } - nvlist_add_string(nvl, key, val); + (void)nvlist_add_string(nvl, key, val); } else if (strcmp(key, "atime") == 0 || strcmp(key, "exec") == 0 || strcmp(key, "setuid") == 0) { if (strcmp(val, "on") == 0) - nvlist_add_uint64(nvl, key, 1); + (void)nvlist_add_uint64(nvl, key, 1); else if (strcmp(val, "off") == 0) - nvlist_add_uint64(nvl, key, 0); + (void)nvlist_add_uint64(nvl, key, 0); else errx(1, "invalid value `%s' for %s", val, key); } else if (strcmp(key, "canmount") == 0) { if (strcmp(val, "noauto") == 0) - nvlist_add_uint64(nvl, key, 2); + (void)nvlist_add_uint64(nvl, key, 2); else if (strcmp(val, "on") == 0) - nvlist_add_uint64(nvl, key, 1); + (void)nvlist_add_uint64(nvl, key, 1); else if (strcmp(val, "off") == 0) - nvlist_add_uint64(nvl, key, 0); + (void)nvlist_add_uint64(nvl, key, 0); else errx(1, "invalid value `%s' for %s", val, key); + } else if (strcmp(key, "compression") == 0) { + size_t i; + + const struct zfs_compression_algorithm { + const char *name; + enum zio_compress alg; + } compression_algorithms[] = { + { "off", ZIO_COMPRESS_OFF }, + { "on", ZIO_COMPRESS_ON }, + { "lzjb", ZIO_COMPRESS_LZJB }, + { "gzip", ZIO_COMPRESS_GZIP_6 }, + { "gzip-1", ZIO_COMPRESS_GZIP_1 }, + { "gzip-2", ZIO_COMPRESS_GZIP_2 }, + { "gzip-3", ZIO_COMPRESS_GZIP_3 }, + { "gzip-4", ZIO_COMPRESS_GZIP_4 }, + { "gzip-5", ZIO_COMPRESS_GZIP_5 }, + { "gzip-6", ZIO_COMPRESS_GZIP_6 }, + { "gzip-7", ZIO_COMPRESS_GZIP_7 }, + { "gzip-8", ZIO_COMPRESS_GZIP_8 }, + { "gzip-9", ZIO_COMPRESS_GZIP_9 }, + { "zle", ZIO_COMPRESS_ZLE }, + { "lz4", ZIO_COMPRESS_LZ4 }, + { "zstd", ZIO_COMPRESS_ZSTD }, + }; + for (i = 0; i < nitems(compression_algorithms); i++) { + if (strcmp(val, compression_algorithms[i].name) == 0) { + nvlist_add_uint64(nvl, key, + compression_algorithms[i].alg); + break; + } + } + if (i == nitems(compression_algorithms)) + errx(1, "invalid compression algorithm `%s'", val); } else { errx(1, "unknown property `%s'", key); } @@ -204,7 +237,7 @@ dsl_metadir_alloc(zfs_opt_t *zfs, const char *name) zfs_dsl_dir_t *dir; char *path; - easprintf(&path, "%s/%s", zfs->poolname, name); + (void)easprintf(&path, "%s/%s", zfs->poolname, name); dir = dsl_dir_alloc(zfs, path); free(path); return (dir); @@ -236,9 +269,6 @@ dsl_init(zfs_opt_t *zfs) zfs->rootdsldir = dsl_dir_alloc(zfs, NULL); - nvlist_add_uint64(zfs->rootdsldir->propsnv, "compression", - ZIO_COMPRESS_OFF); - zfs->rootds = dsl_dataset_alloc(zfs, zfs->rootdsldir); zfs->rootdsldir->headds = zfs->rootds; @@ -288,11 +318,15 @@ dsl_init(zfs_opt_t *zfs) } /* - * Set the root dataset's mount point if the user didn't override the - * default. + * Set the root dataset's mount point and compression strategy if the + * user didn't override the defaults. */ + if (nvpair_find(zfs->rootdsldir->propsnv, "compression") == NULL) { + (void)nvlist_add_uint64(zfs->rootdsldir->propsnv, + "compression", ZIO_COMPRESS_OFF); + } if (nvpair_find(zfs->rootdsldir->propsnv, "mountpoint") == NULL) { - nvlist_add_string(zfs->rootdsldir->propsnv, "mountpoint", + (void)nvlist_add_string(zfs->rootdsldir->propsnv, "mountpoint", zfs->rootpath); } } @@ -397,6 +431,7 @@ dsl_dir_alloc(zfs_opt_t *zfs, const char *name) STAILQ_INIT(&l); STAILQ_INSERT_HEAD(&l, zfs->rootdsldir, next); origname = dirname = nextdir = estrdup(name); + parent = NULL; for (lp = &l;; lp = &parent->children) { dirname = strsep(&nextdir, "/"); if (nextdir == NULL) diff --git a/usr.sbin/makefs/zfs/fs.c b/usr.sbin/makefs/zfs/fs.c index 073dce3ce697..75f6e30e1500 100644 --- a/usr.sbin/makefs/zfs/fs.c +++ b/usr.sbin/makefs/zfs/fs.c @@ -28,6 +28,7 @@ * SUCH DAMAGE. */ +#include <sys/param.h> #include <sys/stat.h> #include <assert.h> @@ -383,22 +384,34 @@ fs_populate_sattrs(struct fs_populate_arg *arg, const fsnode *cur, links = 1; /* .. */ objsize = 1; /* .. */ - /* - * The size of a ZPL directory is the number of entries - * (including "." and ".."), and the link count is the number of - * entries which are directories (including "." and ".."). - */ - for (fsnode *c = fsnode_isroot(cur) ? cur->next : cur->child; - c != NULL; c = c->next) { - switch (c->type) { - case S_IFDIR: - links++; - /* FALLTHROUGH */ - case S_IFREG: - case S_IFLNK: - objsize++; - break; + if ((cur->inode->flags & FI_ROOT) == 0 ) { + /* + * The size of a ZPL directory is the number of entries + * (including "." and ".."), and the link count is the + * number of entries which are directories + * (including "." and ".."). + */ + for (fsnode *c = + fsnode_isroot(cur) ? cur->next : cur->child; + c != NULL; c = c->next) { + switch (c->type) { + case S_IFDIR: + links++; + /* FALLTHROUGH */ + case S_IFREG: + case S_IFLNK: + objsize++; + break; + } } + } else { + /* + * Root directory children do belong to + * different dataset and this directory is + * empty in the current objset. + */ + links++; /* . */ + objsize++; /* . */ } /* The root directory is its own parent. */ @@ -734,7 +747,7 @@ fs_add_zpl_attr_layout(zfs_zap_t *zap, unsigned int index, assert(sizeof(layout[0]) == 2); - snprintf(ti, sizeof(ti), "%u", index); + (void)snprintf(ti, sizeof(ti), "%u", index); zap_add(zap, ti, sizeof(sa_attr_type_t), sacnt, (const uint8_t *)layout); } diff --git a/usr.sbin/makefs/zfs/objset.c b/usr.sbin/makefs/zfs/objset.c index 6be732db477a..f47953ac4339 100644 --- a/usr.sbin/makefs/zfs/objset.c +++ b/usr.sbin/makefs/zfs/objset.c @@ -28,6 +28,7 @@ * SUCH DAMAGE. */ +#include <sys/param.h> #include <assert.h> #include <stdlib.h> #include <string.h> diff --git a/usr.sbin/makefs/zfs/vdev.c b/usr.sbin/makefs/zfs/vdev.c index ef9e681af2da..afcce402cb13 100644 --- a/usr.sbin/makefs/zfs/vdev.c +++ b/usr.sbin/makefs/zfs/vdev.c @@ -28,6 +28,7 @@ * SUCH DAMAGE. */ +#include <sys/param.h> #include <assert.h> #include <fcntl.h> #include <stdlib.h> diff --git a/usr.sbin/makefs/zfs/zap.c b/usr.sbin/makefs/zfs/zap.c index decf5fc6a473..316d1446cecf 100644 --- a/usr.sbin/makefs/zfs/zap.c +++ b/usr.sbin/makefs/zfs/zap.c @@ -28,7 +28,7 @@ * SUCH DAMAGE. */ -#include <sys/types.h> +#include <sys/param.h> #include <sys/endian.h> #include <assert.h> @@ -172,14 +172,14 @@ zap_add_uint64_self(zfs_zap_t *zap, uint64_t val) { char name[32]; - snprintf(name, sizeof(name), "%jx", (uintmax_t)val); + (void)snprintf(name, sizeof(name), "%jx", (uintmax_t)val); zap_add(zap, name, sizeof(uint64_t), 1, (uint8_t *)&val); } void zap_add_string(zfs_zap_t *zap, const char *name, const char *val) { - zap_add(zap, name, 1, strlen(val) + 1, val); + zap_add(zap, name, 1, strlen(val) + 1, (const uint8_t *)val); } bool @@ -221,7 +221,8 @@ zap_micro_write(zfs_opt_t *zfs, zfs_zap_t *zap) STAILQ_FOREACH(ent, &zap->kvps, next) { memcpy(&ment->mze_value, ent->valp, ent->intsz * ent->intcnt); ment->mze_cd = cd++; - strlcpy(ment->mze_name, ent->name, sizeof(ment->mze_name)); + (void)strlcpy(ment->mze_name, ent->name, + sizeof(ment->mze_name)); ment++; } @@ -247,6 +248,7 @@ zap_fat_write_array_chunk(zap_leaf_t *l, uint16_t li, size_t sz, struct zap_leaf_array *la; assert(sz <= ZAP_MAXVALUELEN); + assert(sz > 0); for (uint16_t n, resid = sz; resid > 0; resid -= n, val += n, li++) { n = MIN(resid, ZAP_LEAF_ARRAY_BYTES); @@ -503,7 +505,8 @@ zap_fat_write(zfs_opt_t *zfs, zfs_zap_t *zap) le->le_value_intlen = ent->intsz; le->le_value_numints = ent->intcnt; le->le_hash = ent->hash; - zap_fat_write_array_chunk(&l, *lptr + 1, namelen, ent->name); + zap_fat_write_array_chunk(&l, *lptr + 1, namelen, + (uint8_t *)ent->name); zap_fat_write_array_chunk(&l, *lptr + 1 + nnamechunks, ent->intcnt * ent->intsz, ent->valp); } |