git: 5fece2484324 - main - makefs: zfs: Allow the path vdev property to be set

From: Jose Luis Duran <jlduran_at_FreeBSD.org>
Date: Fri, 21 Aug 2026 19:04:22 UTC
The branch main has been updated by jlduran:

URL: https://cgit.FreeBSD.org/src/commit/?id=5fece2484324be52737e4cea86658a4b8d3107fc

commit 5fece2484324be52737e4cea86658a4b8d3107fc
Author:     Jose Luis Duran <jlduran@FreeBSD.org>
AuthorDate: 2026-08-21 19:02:04 +0000
Commit:     Jose Luis Duran <jlduran@FreeBSD.org>
CommitDate: 2026-08-21 19:02:04 +0000

    makefs: zfs: Allow the path vdev property to be set
    
    This allows specifying custom vdev paths (such as GPT labels like
    /dev/gpt/...) when creating ZFS filesystem images via makefs(8), rather
    than defaulting to /dev/null.
    
    Reviewed by:    markj
    MFC after:      1 week
    Differential Revision:  https://reviews.freebsd.org/D59031
---
 usr.sbin/makefs/makefs.8                  | 38 ++++++++++++++------------
 usr.sbin/makefs/tests/makefs_zfs_tests.sh | 45 +++++++++++++++++++++++++++++++
 usr.sbin/makefs/zfs.c                     | 10 ++++++-
 usr.sbin/makefs/zfs/zfs.h                 |  1 +
 4 files changed, 76 insertions(+), 18 deletions(-)

diff --git a/usr.sbin/makefs/makefs.8 b/usr.sbin/makefs/makefs.8
index f77e07902ad2..56e2ffda956f 100644
--- a/usr.sbin/makefs/makefs.8
+++ b/usr.sbin/makefs/makefs.8
@@ -33,7 +33,7 @@
 .\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 .\" POSSIBILITY OF SUCH DAMAGE.
 .\"
-.Dd January 5, 2026
+.Dd August 12, 2026
 .Dt MAKEFS 8
 .Os
 .Sh NAME
@@ -452,7 +452,7 @@ The following keywords are supported (see
 .Xr newfs_msdos 8
 for more details):
 .Pp
-.Bl -tag -width omit-trailing-period -offset indent -compact
+.Bl -tag -width sectors_per_cluster -offset indent -compact
 .It Cm backup_sector
 Location of the backup boot sector.
 .It Cm block_size
@@ -531,36 +531,40 @@ The arguments consist of a keyword, an equal sign
 and a value.
 The following keywords are supported:
 .Pp
-.Bl -tag -width omit-trailing-period -offset indent -compact
-.It ashift
+.Bl -tag -width verify-txgs -offset indent -compact
+.It Cm ashift
 The base-2 logarithm of the minimum block size.
 Typical values are 9 (512B blocks) and 12 (4KB blocks).
 The default value is 12.
-.It bootfs
+.It Cm bootfs
 The name of the bootable dataset for the pool.
 Specifying this option causes the
 .Ql bootfs
 property to be set in the created pool.
-.It mssize
+.It Cm mssize
 The size of metaslabs in the created pool.
 By default,
 .Nm
 allocates large (up to 512MB) metaslabs with the expectation that
 the image will be auto-expanded upon first use.
 This option allows the default heuristic to be overridden.
-.It verify-txgs
+.It Cm path
+The path to the device for this vdev.
+The default is
+.Pa /dev/null .
+.It Cm verify-txgs
 Prompt OpenZFS to verify pool metadata during import.
 This is disabled by default as it may significantly increase import times.
-.It poolguid
+.It Cm 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
+.It Cm poolname
 The name of the ZFS pool.
 This option must be specified.
-.It rootpath
+.It Cm rootpath
 An implicit path prefix added to dataset mountpoints.
 By default it is
 .Pa /<poolname> .
@@ -570,7 +574,7 @@ should be set to
 .Pa / .
 At least one dataset must have a mountpoint equal to
 .Va rootpath .
-.It fs
+.It Cm fs
 Create an additional dataset.
 This option may be specified multiple times.
 The argument value must be of the form
@@ -600,12 +604,12 @@ may be specified following the dataset name.
 The following properties may be set for a dataset:
 .Pp
 .Bl -hang -compact -offset indent
-.It atime
-.It canmount
-.It compression
-.It exec
-.It mountpoint
-.It setuid
+.It Cm atime
+.It Cm canmount
+.It Cm compression
+.It Cm exec
+.It Cm mountpoint
+.It Cm setuid
 .El
 Note that
 .Nm
diff --git a/usr.sbin/makefs/tests/makefs_zfs_tests.sh b/usr.sbin/makefs/tests/makefs_zfs_tests.sh
index 5b6c701ca291..22adfda00d2b 100644
--- a/usr.sbin/makefs/tests/makefs_zfs_tests.sh
+++ b/usr.sbin/makefs/tests/makefs_zfs_tests.sh
@@ -947,6 +947,50 @@ used_space_props_cleanup()
 	common_cleanup
 }
 
+#
+# Test setting the path of the vdev.
+#
+# The pool is associated to /dev/md0 by default, i.e., when no path is specified.
+# When the path vdevprops(7) is specified, verify it gets set.
+#
+atf_test_case path_vdev_props cleanup
+path_vdev_props_body()
+{
+	local md zdb_path
+	local vdev_path="/dev/gpt/testdisk"
+
+	create_test_inputs
+
+	atf_check $MAKEFS -s 1g -o rootpath=/ \
+	    -o poolname=$ZFS_POOL_NAME \
+	    -o path=${vdev_path} \
+	    $TEST_IMAGE $TEST_INPUTS_DIR
+
+	# Check the raw path property before import_image.
+	atf_check -o save:$TEST_MD_DEVICE_FILE mdconfig -a -f $TEST_IMAGE
+	zdb_path=$(zdb -C -e -p /dev/$(cat $TEST_MD_DEVICE_FILE) \
+	    $ZFS_POOL_NAME 2>/dev/null | awk -F"'" '/path:/ {print $2; exit}')
+	atf_check -o inline:"${vdev_path}\n" echo "$zdb_path"
+
+	# Cleanup before import_image.
+	if [ -f "$TEST_MD_DEVICE_FILE" ]; then
+		md=$(cat $TEST_MD_DEVICE_FILE)
+		if [ -c /dev/"$md" ]; then
+			mdconfig -o force -d -u "$md"
+		fi
+	fi
+
+	# Once imported, the path will be /dev/$(cat $TEST_MD_DEVICE_FILE),
+	# as /dev/gpt/testdisk does not really exist.
+	import_image
+
+	check_image_contents
+}
+path_vdev_props_cleanup()
+{
+	common_cleanup
+}
+
 # Verify that file permissions are set properly.  Make sure that non-executable
 # files can't be executed.
 atf_test_case perms cleanup
@@ -1089,6 +1133,7 @@ atf_init_test_cases()
 	atf_add_test_case soft_links
 	atf_add_test_case root_props
 	atf_add_test_case used_space_props
+	atf_add_test_case path_vdev_props
 	atf_add_test_case perms
 	atf_add_test_case T_flag_dir
 	atf_add_test_case T_flag_F_flag
diff --git a/usr.sbin/makefs/zfs.c b/usr.sbin/makefs/zfs.c
index e33a182e5c8f..1288c52141ab 100644
--- a/usr.sbin/makefs/zfs.c
+++ b/usr.sbin/makefs/zfs.c
@@ -86,6 +86,8 @@ zfs_prep_opts(fsinfo_t *fsopts)
 		  0, 0, "Bootable dataset" },
 		{ '\0', "mssize", &zfs->mssize, OPT_INT64,
 		  MINMSSIZE, MAXMSSIZE, "Metaslab size" },
+		{ '\0', "path", &zfs->vdevpath, OPT_STRPTR,
+		  0, 0, "The path to the device for this vdev" },
 		{ '\0', "poolguid", &zfs->poolguid, OPT_INT64,
 		  0, INT64_MAX, "ZFS pool GUID" },
 		{ '\0', "poolname", &zfs->poolname, OPT_STRPTR,
@@ -240,6 +242,11 @@ zfs_check_opts(fsinfo_t *fsopts)
 	if (zfs->rootpath[0] != '/')
 		errx(1, "mountpoint `%s' must be absolute", zfs->rootpath);
 
+	if (zfs->vdevpath == NULL)
+		easprintf(&zfs->vdevpath, "/dev/null");
+	if (zfs->vdevpath[0] != '/')
+		errx(1, "path `%s' must be absolute", zfs->vdevpath);
+
 	if (zfs->ashift == 0)
 		zfs->ashift = 12;
 
@@ -254,6 +261,7 @@ zfs_cleanup_opts(fsinfo_t *fsopts)
 
 	zfs = fsopts->fs_specific;
 	free(zfs->rootpath);
+	free(zfs->vdevpath);
 	free(zfs->bootfs);
 	free(__DECONST(void *, zfs->poolname));
 	STAILQ_FOREACH_SAFE(d, &zfs->datasetdescs, next, tmp) {
@@ -330,7 +338,7 @@ pool_disk_vdev_config_nvcreate(zfs_opt_t *zfs)
 	nvlist_add_uint64(diskvdevnv, ZPOOL_CONFIG_ASIZE, zfs->asize);
 	nvlist_add_uint64(diskvdevnv, ZPOOL_CONFIG_GUID, zfs->vdevguid);
 	nvlist_add_uint64(diskvdevnv, ZPOOL_CONFIG_ID, 0);
-	nvlist_add_string(diskvdevnv, ZPOOL_CONFIG_PATH, "/dev/null");
+	nvlist_add_string(diskvdevnv, ZPOOL_CONFIG_PATH, zfs->vdevpath);
 	nvlist_add_uint64(diskvdevnv, ZPOOL_CONFIG_WHOLE_DISK, 1);
 	nvlist_add_uint64(diskvdevnv, ZPOOL_CONFIG_CREATE_TXG, TXG);
 	nvlist_add_uint64(diskvdevnv, ZPOOL_CONFIG_METASLAB_ARRAY,
diff --git a/usr.sbin/makefs/zfs/zfs.h b/usr.sbin/makefs/zfs/zfs.h
index 33694e2bdbee..13f2ece43c69 100644
--- a/usr.sbin/makefs/zfs/zfs.h
+++ b/usr.sbin/makefs/zfs/zfs.h
@@ -79,6 +79,7 @@ typedef struct {
 	/* Pool parameters. */
 	const char	*poolname;
 	char		*rootpath;	/* implicit mount point prefix */
+	char		*vdevpath;	/* vdev path, pool property */
 	char		*bootfs;	/* bootable dataset, pool property */
 	int		ashift;		/* vdev block size */
 	uint64_t	mssize;		/* metaslab size */