--- 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_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;
/*