Mercurial > illumos > illumos-gate
changeset 6027:68b03551f113
6609196 'zfs destroy -r' can needlessly iterate over all filesystems in pool
6612830 zpool import shouldn't slowly iterate over all filesystems
author | rm160521 |
---|---|
date | Fri, 15 Feb 2008 19:55:15 -0800 |
parents | 4898f2ba5e8b |
children | 72bc433f666e |
files | usr/src/lib/libzfs/common/libzfs_changelist.c usr/src/lib/libzfs/common/libzfs_graph.c usr/src/lib/libzfs/common/libzfs_impl.h usr/src/lib/libzfs/common/libzfs_mount.c |
diffstat | 4 files changed, 78 insertions(+), 56 deletions(-) [+] |
line wrap: on
line diff
--- a/usr/src/lib/libzfs/common/libzfs_changelist.c Fri Feb 15 17:04:27 2008 -0800 +++ b/usr/src/lib/libzfs/common/libzfs_changelist.c Fri Feb 15 19:55:15 2008 -0800 @@ -20,7 +20,7 @@ */ /* - * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. * * Portions Copyright 2007 Ramprakash Jelari @@ -284,7 +284,7 @@ /* * Is this "dataset" a child of "parent"? */ -static boolean_t +boolean_t isa_child_of(const char *dataset, const char *parent) { int len;
--- a/usr/src/lib/libzfs/common/libzfs_graph.c Fri Feb 15 17:04:27 2008 -0800 +++ b/usr/src/lib/libzfs/common/libzfs_graph.c Fri Feb 15 19:55:15 2008 -0800 @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -126,6 +126,8 @@ zfs_vertex_t **zg_hash; size_t zg_size; size_t zg_nvertex; + const char *zg_root; + int zg_clone_count; } zfs_graph_t; /* @@ -255,7 +257,7 @@ * datasets in the pool. */ static zfs_graph_t * -zfs_graph_create(libzfs_handle_t *hdl, size_t size) +zfs_graph_create(libzfs_handle_t *hdl, const char *dataset, size_t size) { zfs_graph_t *zgp = zfs_alloc(hdl, sizeof (zfs_graph_t)); @@ -269,6 +271,9 @@ return (NULL); } + zgp->zg_root = dataset; + zgp->zg_clone_count = 0; + return (zgp); } @@ -367,17 +372,16 @@ } /* - * Iterate over all children of the given dataset, adding any vertices as - * necessary. Returns 0 if no cloned snapshots were seen, -1 if there was an - * error, or 1 otherwise. This is a simple recursive algorithm - the ZFS - * namespace typically is very flat. We manually invoke the necessary ioctl() - * calls to avoid the overhead and additional semantics of zfs_open(). + * Iterate over all children of the given dataset, adding any vertices + * as necessary. Returns -1 if there was an error, or 0 otherwise. + * This is a simple recursive algorithm - the ZFS namespace typically + * is very flat. We manually invoke the necessary ioctl() calls to + * avoid the overhead and additional semantics of zfs_open(). */ static int iterate_children(libzfs_handle_t *hdl, zfs_graph_t *zgp, const char *dataset) { zfs_cmd_t zc = { 0 }; - int ret = 0, err; zfs_vertex_t *zvp; /* @@ -390,18 +394,8 @@ return (0); /* - * We check the clone parent here instead of within the loop, so that if - * the root dataset has been promoted from a clone, we find its parent - * appropriately. + * Iterate over all children */ - (void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name)); - if (ioctl(hdl->libzfs_fd, ZFS_IOC_OBJSET_STATS, &zc) == 0 && - zc.zc_objset_stats.dds_origin[0] != '\0') { - if (zfs_graph_add(hdl, zgp, zc.zc_objset_stats.dds_origin, - zc.zc_name, zc.zc_objset_stats.dds_creation_txg) != 0) - return (-1); - } - for ((void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name)); ioctl(hdl->libzfs_fd, ZFS_IOC_DATASET_LIST_NEXT, &zc) == 0; (void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name))) { @@ -417,9 +411,23 @@ * dataset and clone statistics. If this fails, the dataset has * since been removed, and we're pretty much screwed anyway. */ + zc.zc_objset_stats.dds_origin[0] = '\0'; if (ioctl(hdl->libzfs_fd, ZFS_IOC_OBJSET_STATS, &zc) != 0) continue; + if (zc.zc_objset_stats.dds_origin[0] != '\0') { + if (zfs_graph_add(hdl, zgp, + zc.zc_objset_stats.dds_origin, zc.zc_name, + zc.zc_objset_stats.dds_creation_txg) != 0) + return (-1); + /* + * Count origins only if they are contained in the graph + */ + if (isa_child_of(zc.zc_objset_stats.dds_origin, + zgp->zg_root)) + zgp->zg_clone_count--; + } + /* * Add an edge between the parent and the child. */ @@ -428,19 +436,10 @@ return (-1); /* - * Iterate over all children + * Recursively visit child */ - err = iterate_children(hdl, zgp, zc.zc_name); - if (err == -1) + if (iterate_children(hdl, zgp, zc.zc_name)) return (-1); - else if (err == 1) - ret = 1; - - /* - * Indicate if we found a dataset with a non-zero clone count. - */ - if (zc.zc_objset_stats.dds_num_clones != 0) - ret = 1; } /* @@ -467,43 +466,65 @@ zc.zc_objset_stats.dds_creation_txg) != 0) return (-1); - /* - * Indicate if we found a dataset with a non-zero clone count. - */ - if (zc.zc_objset_stats.dds_num_clones != 0) - ret = 1; + zgp->zg_clone_count += zc.zc_objset_stats.dds_num_clones; } zvp->zv_visited = VISIT_SEEN; - return (ret); + return (0); } /* - * Construct a complete graph of all necessary vertices. First, we iterate over - * only our object's children. If we don't find any cloned snapshots, then we - * simple return that. Otherwise, we have to start at the pool root and iterate - * over all datasets. + * Returns false if there are no snapshots with dependent clones in this + * subtree or if all of those clones are also in this subtree. Returns + * true if there is an error or there are external dependents. + */ +static boolean_t +external_dependents(libzfs_handle_t *hdl, zfs_graph_t *zgp, const char *dataset) +{ + zfs_cmd_t zc = { 0 }; + + /* + * Check whether this dataset is a clone or has clones since + * iterate_children() only checks the children. + */ + (void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name)); + if (ioctl(hdl->libzfs_fd, ZFS_IOC_OBJSET_STATS, &zc) != 0) + return (B_TRUE); + + if (zc.zc_objset_stats.dds_origin[0] != '\0') { + if (zfs_graph_add(hdl, zgp, + zc.zc_objset_stats.dds_origin, zc.zc_name, + zc.zc_objset_stats.dds_creation_txg) != 0) + return (B_TRUE); + if (isa_child_of(zc.zc_objset_stats.dds_origin, dataset)) + zgp->zg_clone_count--; + } + + if ((zc.zc_objset_stats.dds_num_clones) || + iterate_children(hdl, zgp, dataset)) + return (B_TRUE); + + return (zgp->zg_clone_count != 0); +} + +/* + * Construct a complete graph of all necessary vertices. First, iterate over + * only our object's children. If no cloned snapshots are found, or all of + * the cloned snapshots are in this subtree then return a graph of the subtree. + * Otherwise, start at the root of the pool and iterate over all datasets. */ static zfs_graph_t * construct_graph(libzfs_handle_t *hdl, const char *dataset) { - zfs_graph_t *zgp = zfs_graph_create(hdl, ZFS_GRAPH_SIZE); - zfs_cmd_t zc = { 0 }; + zfs_graph_t *zgp = zfs_graph_create(hdl, dataset, ZFS_GRAPH_SIZE); int ret = 0; if (zgp == NULL) return (zgp); - /* - * We need to explicitly check whether this dataset has clones or not, - * since iterate_children() only checks the children. - */ - (void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name)); - (void) ioctl(hdl->libzfs_fd, ZFS_IOC_OBJSET_STATS, &zc); - - if (zc.zc_objset_stats.dds_num_clones != 0 || - (ret = iterate_children(hdl, zgp, dataset)) != 0) { + if ((strchr(dataset, '/') == NULL) || + (external_dependents(hdl, zgp, dataset))) { /* * Determine pool name and try again. */
--- a/usr/src/lib/libzfs/common/libzfs_impl.h Fri Feb 15 17:04:27 2008 -0800 +++ b/usr/src/lib/libzfs/common/libzfs_impl.h Fri Feb 15 19:55:15 2008 -0800 @@ -151,6 +151,7 @@ void remove_mountpoint(zfs_handle_t *); int create_parents(libzfs_handle_t *, char *, int); +boolean_t isa_child_of(const char *dataset, const char *parent); zfs_handle_t *make_dataset_handle(libzfs_handle_t *, const char *);
--- a/usr/src/lib/libzfs/common/libzfs_mount.c Fri Feb 15 17:04:27 2008 -0800 +++ b/usr/src/lib/libzfs/common/libzfs_mount.c Fri Feb 15 19:55:15 2008 -0800 @@ -1117,7 +1117,7 @@ cbp->cb_datasets[cbp->cb_used++] = zhp; - return (zfs_iter_children(zhp, mount_cb, cbp)); + return (zfs_iter_filesystems(zhp, mount_cb, cbp)); } static int @@ -1166,7 +1166,7 @@ int *good; /* - * Gather all datasets within the pool. + * Gather all non-snap datasets within the pool. */ if ((cb.cb_datasets = zfs_alloc(hdl, 4 * sizeof (void *))) == NULL) return (-1); @@ -1178,7 +1178,7 @@ cb.cb_datasets[0] = zfsp; cb.cb_used = 1; - if (zfs_iter_children(zfsp, mount_cb, &cb) != 0) + if (zfs_iter_filesystems(zfsp, mount_cb, &cb) != 0) goto out; /*