1789Sahrens /*
2789Sahrens  * CDDL HEADER START
3789Sahrens  *
4789Sahrens  * The contents of this file are subject to the terms of the
51544Seschrock  * Common Development and Distribution License (the "License").
61544Seschrock  * You may not use this file except in compliance with the License.
7789Sahrens  *
8789Sahrens  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9789Sahrens  * or http://www.opensolaris.org/os/licensing.
10789Sahrens  * See the License for the specific language governing permissions
11789Sahrens  * and limitations under the License.
12789Sahrens  *
13789Sahrens  * When distributing Covered Code, include this CDDL HEADER in each
14789Sahrens  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15789Sahrens  * If applicable, add the following below this CDDL HEADER, with the
16789Sahrens  * fields enclosed by brackets "[]" replaced with your own identifying
17789Sahrens  * information: Portions Copyright [yyyy] [name of copyright owner]
18789Sahrens  *
19789Sahrens  * CDDL HEADER END
20789Sahrens  */
21789Sahrens /*
226027Srm160521  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
23789Sahrens  * Use is subject to license terms.
24789Sahrens  */
25789Sahrens 
26789Sahrens #pragma ident	"%Z%%M%	%I%	%E% SMI"
27789Sahrens 
28789Sahrens /*
29789Sahrens  * Iterate over all children of the current object.  This includes the normal
30789Sahrens  * dataset hierarchy, but also arbitrary hierarchies due to clones.  We want to
31789Sahrens  * walk all datasets in the pool, and construct a directed graph of the form:
32789Sahrens  *
33789Sahrens  * 			home
34789Sahrens  *                        |
35789Sahrens  *                   +----+----+
36789Sahrens  *                   |         |
37789Sahrens  *                   v         v             ws
38789Sahrens  *                  bar       baz             |
39789Sahrens  *                             |              |
40789Sahrens  *                             v              v
41789Sahrens  *                          @yesterday ----> foo
42789Sahrens  *
43789Sahrens  * In order to construct this graph, we have to walk every dataset in the pool,
44789Sahrens  * because the clone parent is stored as a property of the child, not the
45789Sahrens  * parent.  The parent only keeps track of the number of clones.
46789Sahrens  *
47789Sahrens  * In the normal case (without clones) this would be rather expensive.  To avoid
48789Sahrens  * unnecessary computation, we first try a walk of the subtree hierarchy
49789Sahrens  * starting from the initial node.  At each dataset, we construct a node in the
50789Sahrens  * graph and an edge leading from its parent.  If we don't see any snapshots
51789Sahrens  * with a non-zero clone count, then we are finished.
52789Sahrens  *
53789Sahrens  * If we do find a cloned snapshot, then we finish the walk of the current
54789Sahrens  * subtree, but indicate that we need to do a complete walk.  We then perform a
55789Sahrens  * global walk of all datasets, avoiding the subtree we already processed.
56789Sahrens  *
57789Sahrens  * At the end of this, we'll end up with a directed graph of all relevant (and
58789Sahrens  * possible some irrelevant) datasets in the system.  We need to both find our
59789Sahrens  * limiting subgraph and determine a safe ordering in which to destroy the
60789Sahrens  * datasets.  We do a topological ordering of our graph starting at our target
61789Sahrens  * dataset, and then walk the results in reverse.
62789Sahrens  *
632474Seschrock  * It's possible for the graph to have cycles if, for example, the user renames
642474Seschrock  * a clone to be the parent of its origin snapshot.  The user can request to
652474Seschrock  * generate an error in this case, or ignore the cycle and continue.
662474Seschrock  *
67789Sahrens  * When removing datasets, we want to destroy the snapshots in chronological
68789Sahrens  * order (because this is the most efficient method).  In order to accomplish
69789Sahrens  * this, we store the creation transaction group with each vertex and keep each
70789Sahrens  * vertex's edges sorted according to this value.  The topological sort will
71789Sahrens  * automatically walk the snapshots in the correct order.
72789Sahrens  */
73789Sahrens 
74789Sahrens #include <assert.h>
752474Seschrock #include <libintl.h>
76789Sahrens #include <stdio.h>
77789Sahrens #include <stdlib.h>
78789Sahrens #include <string.h>
79789Sahrens #include <strings.h>
80789Sahrens #include <unistd.h>
81789Sahrens 
82789Sahrens #include <libzfs.h>
83789Sahrens 
84789Sahrens #include "libzfs_impl.h"
85789Sahrens #include "zfs_namecheck.h"
86789Sahrens 
87789Sahrens #define	MIN_EDGECOUNT	4
88789Sahrens 
89789Sahrens /*
90789Sahrens  * Vertex structure.  Indexed by dataset name, this structure maintains a list
91789Sahrens  * of edges to other vertices.
92789Sahrens  */
93789Sahrens struct zfs_edge;
94789Sahrens typedef struct zfs_vertex {
95789Sahrens 	char			zv_dataset[ZFS_MAXNAMELEN];
96789Sahrens 	struct zfs_vertex	*zv_next;
97789Sahrens 	int			zv_visited;
98789Sahrens 	uint64_t		zv_txg;
99789Sahrens 	struct zfs_edge		**zv_edges;
100789Sahrens 	int			zv_edgecount;
101789Sahrens 	int			zv_edgealloc;
102789Sahrens } zfs_vertex_t;
103789Sahrens 
1042474Seschrock enum {
1052474Seschrock 	VISIT_SEEN = 1,
1062474Seschrock 	VISIT_SORT_PRE,
1072474Seschrock 	VISIT_SORT_POST
1082474Seschrock };
1092474Seschrock 
110789Sahrens /*
111789Sahrens  * Edge structure.  Simply maintains a pointer to the destination vertex.  There
112789Sahrens  * is no need to store the source vertex, since we only use edges in the context
113789Sahrens  * of the source vertex.
114789Sahrens  */
115789Sahrens typedef struct zfs_edge {
116789Sahrens 	zfs_vertex_t		*ze_dest;
117789Sahrens 	struct zfs_edge		*ze_next;
118789Sahrens } zfs_edge_t;
119789Sahrens 
120789Sahrens #define	ZFS_GRAPH_SIZE		1027	/* this could be dynamic some day */
121789Sahrens 
122789Sahrens /*
123789Sahrens  * Graph structure.  Vertices are maintained in a hash indexed by dataset name.
124789Sahrens  */
125789Sahrens typedef struct zfs_graph {
126789Sahrens 	zfs_vertex_t		**zg_hash;
127789Sahrens 	size_t			zg_size;
128789Sahrens 	size_t			zg_nvertex;
1296027Srm160521 	const char		*zg_root;
1306027Srm160521 	int			zg_clone_count;
131789Sahrens } zfs_graph_t;
132789Sahrens 
133789Sahrens /*
134789Sahrens  * Allocate a new edge pointing to the target vertex.
135789Sahrens  */
136789Sahrens static zfs_edge_t *
1372082Seschrock zfs_edge_create(libzfs_handle_t *hdl, zfs_vertex_t *dest)
138789Sahrens {
1392082Seschrock 	zfs_edge_t *zep = zfs_alloc(hdl, sizeof (zfs_edge_t));
1402082Seschrock 
1412082Seschrock 	if (zep == NULL)
1422082Seschrock 		return (NULL);
143789Sahrens 
144789Sahrens 	zep->ze_dest = dest;
145789Sahrens 
146789Sahrens 	return (zep);
147789Sahrens }
148789Sahrens 
149789Sahrens /*
150789Sahrens  * Destroy an edge.
151789Sahrens  */
152789Sahrens static void
153789Sahrens zfs_edge_destroy(zfs_edge_t *zep)
154789Sahrens {
155789Sahrens 	free(zep);
156789Sahrens }
157789Sahrens 
158789Sahrens /*
159789Sahrens  * Allocate a new vertex with the given name.
160789Sahrens  */
161789Sahrens static zfs_vertex_t *
1622082Seschrock zfs_vertex_create(libzfs_handle_t *hdl, const char *dataset)
163789Sahrens {
1642082Seschrock 	zfs_vertex_t *zvp = zfs_alloc(hdl, sizeof (zfs_vertex_t));
1652082Seschrock 
1662082Seschrock 	if (zvp == NULL)
1672082Seschrock 		return (NULL);
168789Sahrens 
169789Sahrens 	assert(strlen(dataset) < ZFS_MAXNAMELEN);
170789Sahrens 
171789Sahrens 	(void) strlcpy(zvp->zv_dataset, dataset, sizeof (zvp->zv_dataset));
172789Sahrens 
1732082Seschrock 	if ((zvp->zv_edges = zfs_alloc(hdl,
1742082Seschrock 	    MIN_EDGECOUNT * sizeof (void *))) == NULL) {
1752082Seschrock 		free(zvp);
1762082Seschrock 		return (NULL);
1772082Seschrock 	}
1782082Seschrock 
179789Sahrens 	zvp->zv_edgealloc = MIN_EDGECOUNT;
180789Sahrens 
181789Sahrens 	return (zvp);
182789Sahrens }
183789Sahrens 
184789Sahrens /*
185789Sahrens  * Destroy a vertex.  Frees up any associated edges.
186789Sahrens  */
187789Sahrens static void
188789Sahrens zfs_vertex_destroy(zfs_vertex_t *zvp)
189789Sahrens {
190789Sahrens 	int i;
191789Sahrens 
192789Sahrens 	for (i = 0; i < zvp->zv_edgecount; i++)
193789Sahrens 		zfs_edge_destroy(zvp->zv_edges[i]);
194789Sahrens 
195789Sahrens 	free(zvp->zv_edges);
196789Sahrens 	free(zvp);
197789Sahrens }
198789Sahrens 
199789Sahrens /*
200789Sahrens  * Given a vertex, add an edge to the destination vertex.
201789Sahrens  */
2022082Seschrock static int
2032082Seschrock zfs_vertex_add_edge(libzfs_handle_t *hdl, zfs_vertex_t *zvp,
2042082Seschrock     zfs_vertex_t *dest)
205789Sahrens {
2062082Seschrock 	zfs_edge_t *zep = zfs_edge_create(hdl, dest);
2072082Seschrock 
2082082Seschrock 	if (zep == NULL)
2092082Seschrock 		return (-1);
210789Sahrens 
211789Sahrens 	if (zvp->zv_edgecount == zvp->zv_edgealloc) {
2122676Seschrock 		void *ptr;
213789Sahrens 
2142676Seschrock 		if ((ptr = zfs_realloc(hdl, zvp->zv_edges,
2152676Seschrock 		    zvp->zv_edgealloc * sizeof (void *),
2162676Seschrock 		    zvp->zv_edgealloc * 2 * sizeof (void *))) == NULL)
2172082Seschrock 			return (-1);
2182082Seschrock 
2192676Seschrock 		zvp->zv_edges = ptr;
220789Sahrens 		zvp->zv_edgealloc *= 2;
221789Sahrens 	}
222789Sahrens 
223789Sahrens 	zvp->zv_edges[zvp->zv_edgecount++] = zep;
2242082Seschrock 
2252082Seschrock 	return (0);
226789Sahrens }
227789Sahrens 
228789Sahrens static int
229789Sahrens zfs_edge_compare(const void *a, const void *b)
230789Sahrens {
231789Sahrens 	const zfs_edge_t *ea = *((zfs_edge_t **)a);
232789Sahrens 	const zfs_edge_t *eb = *((zfs_edge_t **)b);
233789Sahrens 
234789Sahrens 	if (ea->ze_dest->zv_txg < eb->ze_dest->zv_txg)
235789Sahrens 		return (-1);
236789Sahrens 	if (ea->ze_dest->zv_txg > eb->ze_dest->zv_txg)
237789Sahrens 		return (1);
238789Sahrens 	return (0);
239789Sahrens }
240789Sahrens 
241789Sahrens /*
242789Sahrens  * Sort the given vertex edges according to the creation txg of each vertex.
243789Sahrens  */
244789Sahrens static void
245789Sahrens zfs_vertex_sort_edges(zfs_vertex_t *zvp)
246789Sahrens {
247789Sahrens 	if (zvp->zv_edgecount == 0)
248789Sahrens 		return;
249789Sahrens 
250789Sahrens 	qsort(zvp->zv_edges, zvp->zv_edgecount, sizeof (void *),
251789Sahrens 	    zfs_edge_compare);
252789Sahrens }
253789Sahrens 
254789Sahrens /*
255789Sahrens  * Construct a new graph object.  We allow the size to be specified as a
256789Sahrens  * parameter so in the future we can size the hash according to the number of
257789Sahrens  * datasets in the pool.
258789Sahrens  */
259789Sahrens static zfs_graph_t *
2606027Srm160521 zfs_graph_create(libzfs_handle_t *hdl, const char *dataset, size_t size)
261789Sahrens {
2622082Seschrock 	zfs_graph_t *zgp = zfs_alloc(hdl, sizeof (zfs_graph_t));
2632082Seschrock 
2642082Seschrock 	if (zgp == NULL)
2652082Seschrock 		return (NULL);
266789Sahrens 
267789Sahrens 	zgp->zg_size = size;
2682082Seschrock 	if ((zgp->zg_hash = zfs_alloc(hdl,
2692082Seschrock 	    size * sizeof (zfs_vertex_t *))) == NULL) {
2702082Seschrock 		free(zgp);
2712082Seschrock 		return (NULL);
2722082Seschrock 	}
273789Sahrens 
2746027Srm160521 	zgp->zg_root = dataset;
2756027Srm160521 	zgp->zg_clone_count = 0;
2766027Srm160521 
277789Sahrens 	return (zgp);
278789Sahrens }
279789Sahrens 
280789Sahrens /*
281789Sahrens  * Destroy a graph object.  We have to iterate over all the hash chains,
282789Sahrens  * destroying each vertex in the process.
283789Sahrens  */
284789Sahrens static void
285789Sahrens zfs_graph_destroy(zfs_graph_t *zgp)
286789Sahrens {
287789Sahrens 	int i;
288789Sahrens 	zfs_vertex_t *current, *next;
289789Sahrens 
290789Sahrens 	for (i = 0; i < zgp->zg_size; i++) {
291789Sahrens 		current = zgp->zg_hash[i];
292789Sahrens 		while (current != NULL) {
293789Sahrens 			next = current->zv_next;
294789Sahrens 			zfs_vertex_destroy(current);
295789Sahrens 			current = next;
296789Sahrens 		}
297789Sahrens 	}
298789Sahrens 
299789Sahrens 	free(zgp->zg_hash);
300789Sahrens 	free(zgp);
301789Sahrens }
302789Sahrens 
303789Sahrens /*
304789Sahrens  * Graph hash function.  Classic bernstein k=33 hash function, taken from
305789Sahrens  * usr/src/cmd/sgs/tools/common/strhash.c
306789Sahrens  */
307789Sahrens static size_t
308789Sahrens zfs_graph_hash(zfs_graph_t *zgp, const char *str)
309789Sahrens {
310789Sahrens 	size_t hash = 5381;
311789Sahrens 	int c;
312789Sahrens 
313789Sahrens 	while ((c = *str++) != 0)
314789Sahrens 		hash = ((hash << 5) + hash) + c; /* hash * 33 + c */
315789Sahrens 
316789Sahrens 	return (hash % zgp->zg_size);
317789Sahrens }
318789Sahrens 
319789Sahrens /*
320789Sahrens  * Given a dataset name, finds the associated vertex, creating it if necessary.
321789Sahrens  */
322789Sahrens static zfs_vertex_t *
3232082Seschrock zfs_graph_lookup(libzfs_handle_t *hdl, zfs_graph_t *zgp, const char *dataset,
3242082Seschrock     uint64_t txg)
325789Sahrens {
326789Sahrens 	size_t idx = zfs_graph_hash(zgp, dataset);
327789Sahrens 	zfs_vertex_t *zvp;
328789Sahrens 
329789Sahrens 	for (zvp = zgp->zg_hash[idx]; zvp != NULL; zvp = zvp->zv_next) {
330789Sahrens 		if (strcmp(zvp->zv_dataset, dataset) == 0) {
331789Sahrens 			if (zvp->zv_txg == 0)
332789Sahrens 				zvp->zv_txg = txg;
333789Sahrens 			return (zvp);
334789Sahrens 		}
335789Sahrens 	}
336789Sahrens 
3372082Seschrock 	if ((zvp = zfs_vertex_create(hdl, dataset)) == NULL)
3382082Seschrock 		return (NULL);
3392082Seschrock 
340789Sahrens 	zvp->zv_next = zgp->zg_hash[idx];
341789Sahrens 	zvp->zv_txg = txg;
342789Sahrens 	zgp->zg_hash[idx] = zvp;
343789Sahrens 	zgp->zg_nvertex++;
344789Sahrens 
345789Sahrens 	return (zvp);
346789Sahrens }
347789Sahrens 
348789Sahrens /*
349789Sahrens  * Given two dataset names, create an edge between them.  For the source vertex,
350789Sahrens  * mark 'zv_visited' to indicate that we have seen this vertex, and not simply
351789Sahrens  * created it as a destination of another edge.  If 'dest' is NULL, then this
352789Sahrens  * is an individual vertex (i.e. the starting vertex), so don't add an edge.
353789Sahrens  */
3542082Seschrock static int
3552082Seschrock zfs_graph_add(libzfs_handle_t *hdl, zfs_graph_t *zgp, const char *source,
3562082Seschrock     const char *dest, uint64_t txg)
357789Sahrens {
358789Sahrens 	zfs_vertex_t *svp, *dvp;
359789Sahrens 
3602082Seschrock 	if ((svp = zfs_graph_lookup(hdl, zgp, source, 0)) == NULL)
3612082Seschrock 		return (-1);
3622474Seschrock 	svp->zv_visited = VISIT_SEEN;
363789Sahrens 	if (dest != NULL) {
3642082Seschrock 		dvp = zfs_graph_lookup(hdl, zgp, dest, txg);
3652082Seschrock 		if (dvp == NULL)
3662082Seschrock 			return (-1);
3672082Seschrock 		if (zfs_vertex_add_edge(hdl, svp, dvp) != 0)
3682082Seschrock 			return (-1);
369789Sahrens 	}
3702082Seschrock 
3712082Seschrock 	return (0);
372789Sahrens }
373789Sahrens 
374789Sahrens /*
3756027Srm160521  * Iterate over all children of the given dataset, adding any vertices
3766027Srm160521  * as necessary.  Returns -1 if there was an error, or 0 otherwise.
3776027Srm160521  * This is a simple recursive algorithm - the ZFS namespace typically
3786027Srm160521  * is very flat.  We manually invoke the necessary ioctl() calls to
3796027Srm160521  * avoid the overhead and additional semantics of zfs_open().
380789Sahrens  */
381789Sahrens static int
3822082Seschrock iterate_children(libzfs_handle_t *hdl, zfs_graph_t *zgp, const char *dataset)
383789Sahrens {
384789Sahrens 	zfs_cmd_t zc = { 0 };
385789Sahrens 	zfs_vertex_t *zvp;
386789Sahrens 
387789Sahrens 	/*
388789Sahrens 	 * Look up the source vertex, and avoid it if we've seen it before.
389789Sahrens 	 */
3902082Seschrock 	zvp = zfs_graph_lookup(hdl, zgp, dataset, 0);
3912082Seschrock 	if (zvp == NULL)
3922082Seschrock 		return (-1);
3932474Seschrock 	if (zvp->zv_visited == VISIT_SEEN)
394789Sahrens 		return (0);
395789Sahrens 
3962474Seschrock 	/*
3976027Srm160521 	 * Iterate over all children
3982474Seschrock 	 */
399789Sahrens 	for ((void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name));
4002082Seschrock 	    ioctl(hdl->libzfs_fd, ZFS_IOC_DATASET_LIST_NEXT, &zc) == 0;
401789Sahrens 	    (void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name))) {
402789Sahrens 
403789Sahrens 		/*
404789Sahrens 		 * Ignore private dataset names.
405789Sahrens 		 */
406789Sahrens 		if (dataset_name_hidden(zc.zc_name))
407789Sahrens 			continue;
408789Sahrens 
409789Sahrens 		/*
410789Sahrens 		 * Get statistics for this dataset, to determine the type of the
411789Sahrens 		 * dataset and clone statistics.  If this fails, the dataset has
412789Sahrens 		 * since been removed, and we're pretty much screwed anyway.
413789Sahrens 		 */
4146027Srm160521 		zc.zc_objset_stats.dds_origin[0] = '\0';
4152082Seschrock 		if (ioctl(hdl->libzfs_fd, ZFS_IOC_OBJSET_STATS, &zc) != 0)
416789Sahrens 			continue;
417789Sahrens 
4186027Srm160521 		if (zc.zc_objset_stats.dds_origin[0] != '\0') {
4196027Srm160521 			if (zfs_graph_add(hdl, zgp,
4206027Srm160521 			    zc.zc_objset_stats.dds_origin, zc.zc_name,
4216027Srm160521 			    zc.zc_objset_stats.dds_creation_txg) != 0)
4226027Srm160521 				return (-1);
4236027Srm160521 			/*
4246027Srm160521 			 * Count origins only if they are contained in the graph
4256027Srm160521 			 */
4266027Srm160521 			if (isa_child_of(zc.zc_objset_stats.dds_origin,
4276027Srm160521 			    zgp->zg_root))
4286027Srm160521 				zgp->zg_clone_count--;
4296027Srm160521 		}
4306027Srm160521 
431789Sahrens 		/*
432789Sahrens 		 * Add an edge between the parent and the child.
433789Sahrens 		 */
4342082Seschrock 		if (zfs_graph_add(hdl, zgp, dataset, zc.zc_name,
4352082Seschrock 		    zc.zc_objset_stats.dds_creation_txg) != 0)
4362082Seschrock 			return (-1);
437789Sahrens 
438789Sahrens 		/*
4396027Srm160521 		 * Recursively visit child
440789Sahrens 		 */
4416027Srm160521 		if (iterate_children(hdl, zgp, zc.zc_name))
4422082Seschrock 			return (-1);
443789Sahrens 	}
444789Sahrens 
445789Sahrens 	/*
446789Sahrens 	 * Now iterate over all snapshots.
447789Sahrens 	 */
448789Sahrens 	bzero(&zc, sizeof (zc));
449789Sahrens 
450789Sahrens 	for ((void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name));
4512082Seschrock 	    ioctl(hdl->libzfs_fd, ZFS_IOC_SNAPSHOT_LIST_NEXT, &zc) == 0;
452789Sahrens 	    (void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name))) {
453789Sahrens 
454789Sahrens 		/*
455789Sahrens 		 * Get statistics for this dataset, to determine the type of the
456789Sahrens 		 * dataset and clone statistics.  If this fails, the dataset has
457789Sahrens 		 * since been removed, and we're pretty much screwed anyway.
458789Sahrens 		 */
4592082Seschrock 		if (ioctl(hdl->libzfs_fd, ZFS_IOC_OBJSET_STATS, &zc) != 0)
460789Sahrens 			continue;
461789Sahrens 
462789Sahrens 		/*
463789Sahrens 		 * Add an edge between the parent and the child.
464789Sahrens 		 */
4652082Seschrock 		if (zfs_graph_add(hdl, zgp, dataset, zc.zc_name,
4662082Seschrock 		    zc.zc_objset_stats.dds_creation_txg) != 0)
4672082Seschrock 			return (-1);
468789Sahrens 
4696027Srm160521 		zgp->zg_clone_count += zc.zc_objset_stats.dds_num_clones;
470789Sahrens 	}
471789Sahrens 
4722474Seschrock 	zvp->zv_visited = VISIT_SEEN;
473789Sahrens 
4746027Srm160521 	return (0);
475789Sahrens }
476789Sahrens 
477789Sahrens /*
4786027Srm160521  * Returns false if there are no snapshots with dependent clones in this
4796027Srm160521  * subtree or if all of those clones are also in this subtree.  Returns
4806027Srm160521  * true if there is an error or there are external dependents.
4816027Srm160521  */
4826027Srm160521 static boolean_t
4836027Srm160521 external_dependents(libzfs_handle_t *hdl, zfs_graph_t *zgp, const char *dataset)
4846027Srm160521 {
4856027Srm160521 	zfs_cmd_t zc = { 0 };
4866027Srm160521 
4876027Srm160521 	/*
4886027Srm160521 	 * Check whether this dataset is a clone or has clones since
4896027Srm160521 	 * iterate_children() only checks the children.
4906027Srm160521 	 */
4916027Srm160521 	(void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name));
4926027Srm160521 	if (ioctl(hdl->libzfs_fd, ZFS_IOC_OBJSET_STATS, &zc) != 0)
4936027Srm160521 		return (B_TRUE);
4946027Srm160521 
4956027Srm160521 	if (zc.zc_objset_stats.dds_origin[0] != '\0') {
4966027Srm160521 		if (zfs_graph_add(hdl, zgp,
4976027Srm160521 		    zc.zc_objset_stats.dds_origin, zc.zc_name,
4986027Srm160521 		    zc.zc_objset_stats.dds_creation_txg) != 0)
4996027Srm160521 			return (B_TRUE);
5006027Srm160521 		if (isa_child_of(zc.zc_objset_stats.dds_origin, dataset))
5016027Srm160521 			zgp->zg_clone_count--;
5026027Srm160521 	}
5036027Srm160521 
5046027Srm160521 	if ((zc.zc_objset_stats.dds_num_clones) ||
5056027Srm160521 	    iterate_children(hdl, zgp, dataset))
5066027Srm160521 		return (B_TRUE);
5076027Srm160521 
5086027Srm160521 	return (zgp->zg_clone_count != 0);
5096027Srm160521 }
5106027Srm160521 
5116027Srm160521 /*
5126027Srm160521  * Construct a complete graph of all necessary vertices.  First, iterate over
5136027Srm160521  * only our object's children.  If no cloned snapshots are found, or all of
5146027Srm160521  * the cloned snapshots are in this subtree then return a graph of the subtree.
5156027Srm160521  * Otherwise, start at the root of the pool and iterate over all datasets.
516789Sahrens  */
517789Sahrens static zfs_graph_t *
5182082Seschrock construct_graph(libzfs_handle_t *hdl, const char *dataset)
519789Sahrens {
5206027Srm160521 	zfs_graph_t *zgp = zfs_graph_create(hdl, dataset, ZFS_GRAPH_SIZE);
5212082Seschrock 	int ret = 0;
5222082Seschrock 
5232082Seschrock 	if (zgp == NULL)
5242082Seschrock 		return (zgp);
525789Sahrens 
5266027Srm160521 	if ((strchr(dataset, '/') == NULL) ||
5276027Srm160521 	    (external_dependents(hdl, zgp, dataset))) {
528789Sahrens 		/*
529789Sahrens 		 * Determine pool name and try again.
530789Sahrens 		 */
531*6148Srm160521 		int len = strcspn(dataset, "/@") + 1;
532*6148Srm160521 		char *pool = zfs_alloc(hdl, len);
533789Sahrens 
534*6148Srm160521 		if (pool == NULL) {
535*6148Srm160521 			zfs_graph_destroy(zgp);
536*6148Srm160521 			return (NULL);
537*6148Srm160521 		}
538*6148Srm160521 		(void) strlcpy(pool, dataset, len);
539789Sahrens 
540*6148Srm160521 		if (iterate_children(hdl, zgp, pool) == -1 ||
541*6148Srm160521 		    zfs_graph_add(hdl, zgp, pool, NULL, 0) != 0) {
542789Sahrens 			free(pool);
543*6148Srm160521 			zfs_graph_destroy(zgp);
544*6148Srm160521 			return (NULL);
545789Sahrens 		}
546*6148Srm160521 		free(pool);
547789Sahrens 	}
5482082Seschrock 
5492082Seschrock 	if (ret == -1 || zfs_graph_add(hdl, zgp, dataset, NULL, 0) != 0) {
5502082Seschrock 		zfs_graph_destroy(zgp);
5512082Seschrock 		return (NULL);
5522082Seschrock 	}
553789Sahrens 
554789Sahrens 	return (zgp);
555789Sahrens }
556789Sahrens 
557789Sahrens /*
558789Sahrens  * Given a graph, do a recursive topological sort into the given array.  This is
559789Sahrens  * really just a depth first search, so that the deepest nodes appear first.
560789Sahrens  * hijack the 'zv_visited' marker to avoid visiting the same vertex twice.
561789Sahrens  */
5622082Seschrock static int
5632474Seschrock topo_sort(libzfs_handle_t *hdl, boolean_t allowrecursion, char **result,
5642474Seschrock     size_t *idx, zfs_vertex_t *zgv)
565789Sahrens {
566789Sahrens 	int i;
567789Sahrens 
5682474Seschrock 	if (zgv->zv_visited == VISIT_SORT_PRE && !allowrecursion) {
5692474Seschrock 		/*
5702474Seschrock 		 * If we've already seen this vertex as part of our depth-first
5712474Seschrock 		 * search, then we have a cyclic dependency, and we must return
5722474Seschrock 		 * an error.
5732474Seschrock 		 */
5742474Seschrock 		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
5752474Seschrock 		    "recursive dependency at '%s'"),
5762474Seschrock 		    zgv->zv_dataset);
5772474Seschrock 		return (zfs_error(hdl, EZFS_RECURSIVE,
5782474Seschrock 		    dgettext(TEXT_DOMAIN,
5792474Seschrock 		    "cannot determine dependent datasets")));
5802474Seschrock 	} else if (zgv->zv_visited >= VISIT_SORT_PRE) {
5812474Seschrock 		/*
5822474Seschrock 		 * If we've already processed this as part of the topological
5832474Seschrock 		 * sort, then don't bother doing so again.
5842474Seschrock 		 */
5852474Seschrock 		return (0);
5862474Seschrock 	}
5872474Seschrock 
5882474Seschrock 	zgv->zv_visited = VISIT_SORT_PRE;
5892474Seschrock 
590789Sahrens 	/* avoid doing a search if we don't have to */
591789Sahrens 	zfs_vertex_sort_edges(zgv);
5922082Seschrock 	for (i = 0; i < zgv->zv_edgecount; i++) {
5932474Seschrock 		if (topo_sort(hdl, allowrecursion, result, idx,
5942474Seschrock 		    zgv->zv_edges[i]->ze_dest) != 0)
5952082Seschrock 			return (-1);
5962082Seschrock 	}
597789Sahrens 
598789Sahrens 	/* we may have visited this in the course of the above */
5992474Seschrock 	if (zgv->zv_visited == VISIT_SORT_POST)
6002082Seschrock 		return (0);
601789Sahrens 
6022082Seschrock 	if ((result[*idx] = zfs_alloc(hdl,
6032082Seschrock 	    strlen(zgv->zv_dataset) + 1)) == NULL)
6042082Seschrock 		return (-1);
6052082Seschrock 
606789Sahrens 	(void) strcpy(result[*idx], zgv->zv_dataset);
607789Sahrens 	*idx += 1;
6082474Seschrock 	zgv->zv_visited = VISIT_SORT_POST;
6092082Seschrock 	return (0);
610789Sahrens }
611789Sahrens 
612789Sahrens /*
613789Sahrens  * The only public interface for this file.  Do the dirty work of constructing a
614789Sahrens  * child list for the given object.  Construct the graph, do the toplogical
615789Sahrens  * sort, and then return the array of strings to the caller.
6162474Seschrock  *
6172474Seschrock  * The 'allowrecursion' parameter controls behavior when cycles are found.  If
6182474Seschrock  * it is set, the the cycle is ignored and the results returned as if the cycle
6192474Seschrock  * did not exist.  If it is not set, then the routine will generate an error if
6202474Seschrock  * a cycle is found.
621789Sahrens  */
6222474Seschrock int
6232474Seschrock get_dependents(libzfs_handle_t *hdl, boolean_t allowrecursion,
6242474Seschrock     const char *dataset, char ***result, size_t *count)
625789Sahrens {
626789Sahrens 	zfs_graph_t *zgp;
627789Sahrens 	zfs_vertex_t *zvp;
628789Sahrens 
6292082Seschrock 	if ((zgp = construct_graph(hdl, dataset)) == NULL)
6302474Seschrock 		return (-1);
631789Sahrens 
6322474Seschrock 	if ((*result = zfs_alloc(hdl,
6332082Seschrock 	    zgp->zg_nvertex * sizeof (char *))) == NULL) {
6342082Seschrock 		zfs_graph_destroy(zgp);
6352474Seschrock 		return (-1);
6362082Seschrock 	}
6372082Seschrock 
6382082Seschrock 	if ((zvp = zfs_graph_lookup(hdl, zgp, dataset, 0)) == NULL) {
6392474Seschrock 		free(*result);
6402082Seschrock 		zfs_graph_destroy(zgp);
6412474Seschrock 		return (-1);
6422082Seschrock 	}
643789Sahrens 
644789Sahrens 	*count = 0;
6452474Seschrock 	if (topo_sort(hdl, allowrecursion, *result, count, zvp) != 0) {
6462474Seschrock 		free(*result);
6472082Seschrock 		zfs_graph_destroy(zgp);
6482474Seschrock 		return (-1);
6492082Seschrock 	}
650789Sahrens 
651789Sahrens 	/*
652789Sahrens 	 * Get rid of the last entry, which is our starting vertex and not
653789Sahrens 	 * strictly a dependent.
654789Sahrens 	 */
655789Sahrens 	assert(*count > 0);
6562474Seschrock 	free((*result)[*count - 1]);
657789Sahrens 	(*count)--;
658789Sahrens 
659789Sahrens 	zfs_graph_destroy(zgp);
660789Sahrens 
6612474Seschrock 	return (0);
662789Sahrens }
663