Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 22 Sep 2012 19:20:54 +0300
From:      Andriy Gapon <avg@FreeBSD.org>
To:        freebsd-fs@FreeBSD.org
Subject:   lszfs command for loader
Message-ID:  <505DE566.2080307@FreeBSD.org>

next in thread | raw e-mail | index | archive | help

Please find a patch that implements lszfs loader command.
The command can list child filesystems of a specified filesystem (including root
dataset).
The command is really simplistic, a list goes directly to console, so there is
no filtering of hidden filesystem names etc.

The command is intended to facilitate recovery on systems that use "Boot
Environments" approach for boot/root filesystem.

http://people.freebsd.org/~avg/lszfs.diff

diff --git a/sys/boot/i386/loader/main.c b/sys/boot/i386/loader/main.c
index 80c8178..84ae713 100644
--- a/sys/boot/i386/loader/main.c
+++ b/sys/boot/i386/loader/main.c
@@ -330,6 +330,29 @@ command_heap(int argc, char *argv[])
     return(CMD_OK);
 }

+#ifdef LOADER_ZFS_SUPPORT
+COMMAND_SET(lszfs, "lszfs", "list child datasets of a zfs dataset",
+    command_lszfs);
+
+static int
+command_lszfs(int argc, char *argv[])
+{
+    int err;
+
+    if (argc != 2) {
+	command_errmsg = "wrong number of arguments";
+	return (CMD_ERROR);
+    }
+
+    err = zfs_list(argv[1]);
+    if (err != 0) {
+	command_errmsg = strerror(err);
+	return (CMD_ERROR);
+    }
+    return (CMD_OK);
+}
+#endif
+
 /* ISA bus access functions for PnP. */
 static int
 isa_inb(int port)
diff --git a/sys/boot/zfs/libzfs.h b/sys/boot/zfs/libzfs.h
index 7ad3a72..6834f8b 100644
--- a/sys/boot/zfs/libzfs.h
+++ b/sys/boot/zfs/libzfs.h
@@ -61,6 +61,7 @@ int	zfs_parsedev(struct zfs_devdesc *dev, const char *devspec,
 		     const char **path);
 char	*zfs_fmtdev(void *vdev);
 int	zfs_probe_dev(const char *devname, uint64_t *pool_guid);
+int	zfs_list(const char *name);

 extern struct devsw zfs_dev;
 extern struct fs_ops zfs_fsops;
diff --git a/sys/boot/zfs/zfs.c b/sys/boot/zfs/zfs.c
index eb8833f..3fc5f50 100644
--- a/sys/boot/zfs/zfs.c
+++ b/sys/boot/zfs/zfs.c
@@ -658,3 +658,38 @@ zfs_fmtdev(void *vdev)
 		    rootname);
 	return (buf);
 }
+
+int
+zfs_list(const char *name)
+{
+	static char	poolname[ZFS_MAXNAMELEN];
+	uint64_t	objid;
+	spa_t		*spa;
+	const char	*dsname;
+	int		len;
+	int		rv;
+
+	len = strlen(name);
+	dsname = strchr(name, '/');
+	if (dsname != NULL) {
+		len = dsname - name;
+		dsname++;
+	}
+	memcpy(poolname, name, len);
+	poolname[len] = '\0';
+
+	spa = spa_find_by_name(poolname);
+	if (!spa)
+		return (ENXIO);
+	rv = zfs_spa_init(spa);
+	if (rv != 0)
+		return (rv);
+	if (dsname != NULL)
+		rv = zfs_lookup_dataset(spa, dsname, &objid);
+	else
+		rv = zfs_get_root(spa, &objid);
+	if (rv != 0)
+		return (rv);
+	rv = zfs_list_dataset(spa, objid);
+	return (0);
+}
diff --git a/sys/boot/zfs/zfsimpl.c b/sys/boot/zfs/zfsimpl.c
index 219d7af..18f5d9a 100644
--- a/sys/boot/zfs/zfsimpl.c
+++ b/sys/boot/zfs/zfsimpl.c
@@ -1415,8 +1415,6 @@ zap_lookup(const spa_t *spa, const dnode_phys_t *dnode,
const char *name, uint64
 	return (EIO);
 }

-#ifdef BOOT2
-
 /*
  * List a microzap directory. Assumes that the zap scratch buffer contains
  * the directory contents.
@@ -1541,8 +1539,6 @@ zap_list(const spa_t *spa, const dnode_phys_t *dnode)
 		return fzap_list(spa, dnode);
 }

-#endif
-
 static int
 objset_get_dnode(const spa_t *spa, const objset_phys_t *os, uint64_t objnum,
dnode_phys_t *dnode)
 {
@@ -1779,6 +1775,38 @@ zfs_lookup_dataset(const spa_t *spa, const char *name,
uint64_t *objnum)
 	return (0);
 }

+#ifndef BOOT2
+static int
+zfs_list_dataset(const spa_t *spa, uint64_t objnum/*, int pos, char *entry*/)
+{
+	uint64_t dir_obj, child_dir_zapobj;
+	dnode_phys_t child_dir_zap, dir, dataset;
+	dsl_dataset_phys_t *ds;
+	dsl_dir_phys_t *dd;
+
+	if (objset_get_dnode(spa, &spa->spa_mos, objnum, &dataset)) {
+		printf("ZFS: can't find dataset %ju\n", (uintmax_t)objnum);
+		return (EIO);
+	}
+	ds = (dsl_dataset_phys_t *) &dataset.dn_bonus;
+	dir_obj = ds->ds_dir_obj;
+
+	if (objset_get_dnode(spa, &spa->spa_mos, dir_obj, &dir)) {
+		printf("ZFS: can't find dirobj %ju\n", (uintmax_t)dir_obj);
+		return (EIO);
+	}
+	dd = (dsl_dir_phys_t *)&dir.dn_bonus;
+
+	child_dir_zapobj = dd->dd_child_dir_zapobj;
+	if (objset_get_dnode(spa, &spa->spa_mos, child_dir_zapobj, &child_dir_zap) != 0) {
+		printf("ZFS: can't find child zap %ju\n", (uintmax_t)dir_obj);
+		return (EIO);
+	}
+
+	return (zap_list(spa, &child_dir_zap) != 0);
+}
+#endif
+
 /*
  * Find the object set given the object number of its dataset object
  * and return its details in *objset

-- 
Andriy Gapon



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?505DE566.2080307>