few ideas for zfsloader ( bootfs -> vfs.root.mountfrom)

Andriy Gapon avg at icyb.net.ua
Thu Apr 29 16:52:34 UTC 2010


on 16/03/2010 21:07 Andriy Gapon said the following:
> I have three crazy-ish ideas for zfsloader.
> Unfortunately, right now I am short on time and I am very short on ZFS knowledge
> to go for implementing them myself.
> 
> 1. If vfs.root.mountfrom is not already set and there is no root mount entry in
> fstab then set vfs.root.mountfrom to "zfs:<current-dataset>".
> This obviously requires being able to get properties of the current dataset
> (filesystem) and get the name from them.

I've made some progress on this, see the attached patch.
The patch is not complete.

What it can do right now:
1. set vfs.zfs.bootfs to something like "zfs:tank:1111" where 'tank' is a pool
name and '1111' is object id of dataset selected as boot filesystem (e.g. via bootfs).
2. set vfs.root.mountfrom to value of vfs.zfs.bootfs iff it was not set
explicietly and '/' entry was not found in fstab.

But right now ZFS can not be mounted using a filesystem specification in the above
format.

I see two ways forward:
1. Enhance ZFS mount kernel code, so that it accepts dataset id instead of its
name.  This doesn't seem to be very hard.
2. Enhance zfs boot code (zfsloader) to map boot dataset id to its name.  I have
prototype code (unfinished, non-working) for this that navigates from a dataset up
the hierarchy (via dir_obj, parent_dir_obj) and does a reverse lookup in directory
child map to find a name component.

While #2 seems nicer it also seems to be a waste, since the name will ultimately
be mapped to object id by ZFS kernel code anyways.

Also, I am not sure if we should care about multiple pools under the same name.
Maybe I should use pool guid instead of pool name in vfs.zfs.bootfs?


Thanks a lot for any comments and help with this.
-- 
Andriy Gapon
-------------- next part --------------
diff --git a/sys/boot/common/boot.c b/sys/boot/common/boot.c
index c6ab681..02ecb63 100644
--- a/sys/boot/common/boot.c
+++ b/sys/boot/common/boot.c
@@ -311,12 +311,12 @@ getrootmount(char *rootdev)
     if (getenv("vfs.root.mountfrom") != NULL)
 	return(0);
 
+    error = 1;
     sprintf(lbuf, "%s/etc/fstab", rootdev);
     if ((fd = open(lbuf, O_RDONLY)) < 0)
-	return(1);
+	goto end;
 
     /* loop reading lines from /etc/fstab    What was that about sscanf again? */
-    error = 1;
     while (fgetstr(lbuf, sizeof(lbuf), fd) >= 0) {
 	if ((lbuf[0] == 0) || (lbuf[0] == '#'))
 	    continue;
@@ -377,6 +377,18 @@ getrootmount(char *rootdev)
 	break;
     }
     close(fd);
+
+end:
+    if (error != 0) {
+	const char *zfs_bootfs;
+
+	zfs_bootfs = getenv("vfs.zfs.bootfs");
+	if (zfs_bootfs != NULL) {
+	    setenv("vfs.root.mountfrom", zfs_bootfs, 0);
+	    error = 0;
+	}
+    }
+
     return(error);
 }
 
diff --git a/sys/boot/i386/loader/main.c b/sys/boot/i386/loader/main.c
index 0738882..4768e64 100644
--- a/sys/boot/i386/loader/main.c
+++ b/sys/boot/i386/loader/main.c
@@ -79,6 +79,14 @@ extern	char bootprog_name[], bootprog_rev[], bootprog_date[], bootprog_maker[];
 /* XXX debugging */
 extern char end[];
 
+#ifdef LOADER_ZFS_SUPPORT
+extern struct devsw zfs_dev;
+
+extern uint64_t		zfs_guid_to_bootobj(uint64_t);
+extern const char *	zfs_guid_to_name(uint64_t);
+extern int		zfs_guid_to_unit(uint64_t);
+#endif
+
 static void *heap_top;
 static void *heap_bottom;
 
@@ -266,20 +274,22 @@ extract_currdev(void)
      * which ZFS pool we are booting from.
      */
     if (kargs->bootflags & KARGS_FLAGS_ZFS) {
-	/*
-	 * Dig out the pool guid and convert it to a 'unit number'
-	 */
-	uint64_t guid;
-	int unit;
-	char devname[32];
-	extern int zfs_guid_to_unit(uint64_t);
+    	char buf[256];
+        uint64_t boot_obj;
+    	const char *poolname;
+    	int unit;
 
-	guid = kargs->zfspool;
-	unit = zfs_guid_to_unit(guid);
+	unit = zfs_guid_to_unit(kargs->zfspool);
 	if (unit >= 0) {
 	    new_currdev.d_dev = &zfs_dev;
 	    new_currdev.d_type = new_currdev.d_dev->dv_type;
 	    new_currdev.d_unit = unit;
+	    new_currdev.d_kind.zfs.pool_guid = kargs->zfspool; /* XXX unused */
+
+	    poolname = zfs_guid_to_name(kargs->zfspool);
+	    boot_obj = zfs_guid_to_bootobj(kargs->zfspool);
+	    sprintf(buf, "zfs:%s:%llu", poolname, boot_obj); /* XXX snprintf? */
+	    setenv("vfs.zfs.bootfs", buf, 1);
 	}
     }
 #endif
diff --git a/sys/boot/zfs/zfs.c b/sys/boot/zfs/zfs.c
index 99bb60a..8ea8ad0 100644
--- a/sys/boot/zfs/zfs.c
+++ b/sys/boot/zfs/zfs.c
@@ -387,6 +387,32 @@ zfs_guid_to_unit(uint64_t guid)
 	return (-1);
 }
 
+const char *
+zfs_guid_to_name(uint64_t guid)
+{
+	spa_t *spa;
+
+	STAILQ_FOREACH(spa, &zfs_pools, spa_link)
+		if (spa->spa_guid == guid)
+			return (spa->spa_name);
+
+	return (NULL);
+}
+
+uint64_t
+zfs_guid_to_bootobj(uint64_t guid)
+{
+	spa_t *spa;
+
+	STAILQ_FOREACH(spa, &zfs_pools, spa_link)
+		if (spa->spa_guid == guid) {
+			zfs_mount_pool(spa);
+			return (spa->spa_root_obj);
+		}
+
+	return (0);
+}
+
 static int
 zfs_dev_init(void) 
 {
diff --git a/sys/boot/zfs/zfsimpl.c b/sys/boot/zfs/zfsimpl.c
index 1407eb5..67d3a23 100644
--- a/sys/boot/zfs/zfsimpl.c
+++ b/sys/boot/zfs/zfsimpl.c
@@ -1421,6 +1421,7 @@ zfs_mount_dataset(spa_t *spa, uint64_t objnum, objset_phys_t *objset)
 		return (EIO);
 	}
 
+	spa->spa_root_obj = objnum;
 	return (0);
 }
 
diff --git a/sys/cddl/boot/zfs/zfsimpl.h b/sys/cddl/boot/zfs/zfsimpl.h
index ef13487..4647016 100644
--- a/sys/cddl/boot/zfs/zfsimpl.h
+++ b/sys/cddl/boot/zfs/zfsimpl.h
@@ -1205,4 +1205,5 @@ typedef struct spa {
 	vdev_list_t	spa_vdevs;	/* list of all toplevel vdevs */
 	objset_phys_t	spa_mos;	/* MOS for this pool */
 	objset_phys_t	spa_root_objset; /* current mounted ZPL objset */
+	uint64_t	spa_root_obj;	/* current mounted ZPL object id */
 } spa_t;


More information about the freebsd-fs mailing list