From owner-freebsd-fs@FreeBSD.ORG Sat Sep 22 16:20:58 2012 Return-Path: Delivered-To: freebsd-fs@FreeBSD.org Received: from mx1.freebsd.org (mx1.freebsd.org [69.147.83.52]) by hub.freebsd.org (Postfix) with ESMTP id 9E25C1065678; Sat, 22 Sep 2012 16:20:58 +0000 (UTC) (envelope-from avg@FreeBSD.org) Received: from citadel.icyb.net.ua (citadel.icyb.net.ua [212.40.38.140]) by mx1.freebsd.org (Postfix) with ESMTP id 35A438FC22; Sat, 22 Sep 2012 16:20:56 +0000 (UTC) Received: from porto.starpoint.kiev.ua (porto-e.starpoint.kiev.ua [212.40.38.100]) by citadel.icyb.net.ua (8.8.8p3/ICyb-2.3exp) with ESMTP id TAA07394; Sat, 22 Sep 2012 19:20:55 +0300 (EEST) (envelope-from avg@FreeBSD.org) Received: from localhost ([127.0.0.1]) by porto.starpoint.kiev.ua with esmtp (Exim 4.34 (FreeBSD)) id 1TFSRr-000NSw-H9; Sat, 22 Sep 2012 19:20:55 +0300 Message-ID: <505DE566.2080307@FreeBSD.org> Date: Sat, 22 Sep 2012 19:20:54 +0300 From: Andriy Gapon User-Agent: Mozilla/5.0 (X11; FreeBSD amd64; rv:15.0) Gecko/20120913 Thunderbird/15.0.1 MIME-Version: 1.0 To: freebsd-fs@FreeBSD.org X-Enigmail-Version: 1.4.3 Content-Type: text/plain; charset=X-VIET-VPS Content-Transfer-Encoding: 7bit Cc: Subject: lszfs command for loader X-BeenThere: freebsd-fs@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: Filesystems List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sat, 22 Sep 2012 16:20:58 -0000 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