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>