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 /*
221544Seschrock  * Copyright 2006 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  *
63789Sahrens  * When removing datasets, we want to destroy the snapshots in chronological
64789Sahrens  * order (because this is the most efficient method).  In order to accomplish
65789Sahrens  * this, we store the creation transaction group with each vertex and keep each
66789Sahrens  * vertex's edges sorted according to this value.  The topological sort will
67789Sahrens  * automatically walk the snapshots in the correct order.
68789Sahrens  */
69789Sahrens 
70789Sahrens #include <assert.h>
71789Sahrens #include <stdio.h>
72789Sahrens #include <stdlib.h>
73789Sahrens #include <string.h>
74789Sahrens #include <strings.h>
75789Sahrens #include <unistd.h>
76789Sahrens 
77789Sahrens #include <libzfs.h>
78789Sahrens 
79789Sahrens #include "libzfs_impl.h"
80789Sahrens #include "zfs_namecheck.h"
81789Sahrens 
82789Sahrens #define	MIN_EDGECOUNT	4
83789Sahrens 
84789Sahrens /*
85789Sahrens  * Vertex structure.  Indexed by dataset name, this structure maintains a list
86789Sahrens  * of edges to other vertices.
87789Sahrens  */
88789Sahrens struct zfs_edge;
89789Sahrens typedef struct zfs_vertex {
90789Sahrens 	char			zv_dataset[ZFS_MAXNAMELEN];
91789Sahrens 	struct zfs_vertex	*zv_next;
92789Sahrens 	int			zv_visited;
93789Sahrens 	uint64_t		zv_txg;
94789Sahrens 	struct zfs_edge		**zv_edges;
95789Sahrens 	int			zv_edgecount;
96789Sahrens 	int			zv_edgealloc;
97789Sahrens } zfs_vertex_t;
98789Sahrens 
99789Sahrens /*
100789Sahrens  * Edge structure.  Simply maintains a pointer to the destination vertex.  There
101789Sahrens  * is no need to store the source vertex, since we only use edges in the context
102789Sahrens  * of the source vertex.
103789Sahrens  */
104789Sahrens typedef struct zfs_edge {
105789Sahrens 	zfs_vertex_t		*ze_dest;
106789Sahrens 	struct zfs_edge		*ze_next;
107789Sahrens } zfs_edge_t;
108789Sahrens 
109789Sahrens #define	ZFS_GRAPH_SIZE		1027	/* this could be dynamic some day */
110789Sahrens 
111789Sahrens /*
112789Sahrens  * Graph structure.  Vertices are maintained in a hash indexed by dataset name.
113789Sahrens  */
114789Sahrens typedef struct zfs_graph {
115789Sahrens 	zfs_vertex_t		**zg_hash;
116789Sahrens 	size_t			zg_size;
117789Sahrens 	size_t			zg_nvertex;
118789Sahrens } zfs_graph_t;
119789Sahrens 
120789Sahrens /*
121789Sahrens  * Allocate a new edge pointing to the target vertex.
122789Sahrens  */
123789Sahrens static zfs_edge_t *
124*2082Seschrock zfs_edge_create(libzfs_handle_t *hdl, zfs_vertex_t *dest)
125789Sahrens {
126*2082Seschrock 	zfs_edge_t *zep = zfs_alloc(hdl, sizeof (zfs_edge_t));
127*2082Seschrock 
128*2082Seschrock 	if (zep == NULL)
129*2082Seschrock 		return (NULL);
130789Sahrens 
131789Sahrens 	zep->ze_dest = dest;
132789Sahrens 
133789Sahrens 	return (zep);
134789Sahrens }
135789Sahrens 
136789Sahrens /*
137789Sahrens  * Destroy an edge.
138789Sahrens  */
139789Sahrens static void
140789Sahrens zfs_edge_destroy(zfs_edge_t *zep)
141789Sahrens {
142789Sahrens 	free(zep);
143789Sahrens }
144789Sahrens 
145789Sahrens /*
146789Sahrens  * Allocate a new vertex with the given name.
147789Sahrens  */
148789Sahrens static zfs_vertex_t *
149*2082Seschrock zfs_vertex_create(libzfs_handle_t *hdl, const char *dataset)
150789Sahrens {
151*2082Seschrock 	zfs_vertex_t *zvp = zfs_alloc(hdl, sizeof (zfs_vertex_t));
152*2082Seschrock 
153*2082Seschrock 	if (zvp == NULL)
154*2082Seschrock 		return (NULL);
155789Sahrens 
156789Sahrens 	assert(strlen(dataset) < ZFS_MAXNAMELEN);
157789Sahrens 
158789Sahrens 	(void) strlcpy(zvp->zv_dataset, dataset, sizeof (zvp->zv_dataset));
159789Sahrens 
160*2082Seschrock 	if ((zvp->zv_edges = zfs_alloc(hdl,
161*2082Seschrock 	    MIN_EDGECOUNT * sizeof (void *))) == NULL) {
162*2082Seschrock 		free(zvp);
163*2082Seschrock 		return (NULL);
164*2082Seschrock 	}
165*2082Seschrock 
166789Sahrens 	zvp->zv_edgealloc = MIN_EDGECOUNT;
167789Sahrens 
168789Sahrens 	return (zvp);
169789Sahrens }
170789Sahrens 
171789Sahrens /*
172789Sahrens  * Destroy a vertex.  Frees up any associated edges.
173789Sahrens  */
174789Sahrens static void
175789Sahrens zfs_vertex_destroy(zfs_vertex_t *zvp)
176789Sahrens {
177789Sahrens 	int i;
178789Sahrens 
179789Sahrens 	for (i = 0; i < zvp->zv_edgecount; i++)
180789Sahrens 		zfs_edge_destroy(zvp->zv_edges[i]);
181789Sahrens 
182789Sahrens 	free(zvp->zv_edges);
183789Sahrens 	free(zvp);
184789Sahrens }
185789Sahrens 
186789Sahrens /*
187789Sahrens  * Given a vertex, add an edge to the destination vertex.
188789Sahrens  */
189*2082Seschrock static int
190*2082Seschrock zfs_vertex_add_edge(libzfs_handle_t *hdl, zfs_vertex_t *zvp,
191*2082Seschrock     zfs_vertex_t *dest)
192789Sahrens {
193*2082Seschrock 	zfs_edge_t *zep = zfs_edge_create(hdl, dest);
194*2082Seschrock 
195*2082Seschrock 	if (zep == NULL)
196*2082Seschrock 		return (-1);
197789Sahrens 
198789Sahrens 	if (zvp->zv_edgecount == zvp->zv_edgealloc) {
199*2082Seschrock 		zfs_edge_t **newedges = zfs_alloc(hdl, zvp->zv_edgealloc * 2 *
200789Sahrens 		    sizeof (void *));
201789Sahrens 
202*2082Seschrock 		if (newedges == NULL)
203*2082Seschrock 			return (-1);
204*2082Seschrock 
205789Sahrens 		bcopy(zvp->zv_edges, newedges,
206789Sahrens 		    zvp->zv_edgealloc * sizeof (void *));
207789Sahrens 
208789Sahrens 		zvp->zv_edgealloc *= 2;
209789Sahrens 		free(zvp->zv_edges);
210789Sahrens 		zvp->zv_edges = newedges;
211789Sahrens 	}
212789Sahrens 
213789Sahrens 	zvp->zv_edges[zvp->zv_edgecount++] = zep;
214*2082Seschrock 
215*2082Seschrock 	return (0);
216789Sahrens }
217789Sahrens 
218789Sahrens static int
219789Sahrens zfs_edge_compare(const void *a, const void *b)
220789Sahrens {
221789Sahrens 	const zfs_edge_t *ea = *((zfs_edge_t **)a);
222789Sahrens 	const zfs_edge_t *eb = *((zfs_edge_t **)b);
223789Sahrens 
224789Sahrens 	if (ea->ze_dest->zv_txg < eb->ze_dest->zv_txg)
225789Sahrens 		return (-1);
226789Sahrens 	if (ea->ze_dest->zv_txg > eb->ze_dest->zv_txg)
227789Sahrens 		return (1);
228789Sahrens 	return (0);
229789Sahrens }
230789Sahrens 
231789Sahrens /*
232789Sahrens  * Sort the given vertex edges according to the creation txg of each vertex.
233789Sahrens  */
234789Sahrens static void
235789Sahrens zfs_vertex_sort_edges(zfs_vertex_t *zvp)
236789Sahrens {
237789Sahrens 	if (zvp->zv_edgecount == 0)
238789Sahrens 		return;
239789Sahrens 
240789Sahrens 	qsort(zvp->zv_edges, zvp->zv_edgecount, sizeof (void *),
241789Sahrens 	    zfs_edge_compare);
242789Sahrens }
243789Sahrens 
244789Sahrens /*
245789Sahrens  * Construct a new graph object.  We allow the size to be specified as a
246789Sahrens  * parameter so in the future we can size the hash according to the number of
247789Sahrens  * datasets in the pool.
248789Sahrens  */
249789Sahrens static zfs_graph_t *
250*2082Seschrock zfs_graph_create(libzfs_handle_t *hdl, size_t size)
251789Sahrens {
252*2082Seschrock 	zfs_graph_t *zgp = zfs_alloc(hdl, sizeof (zfs_graph_t));
253*2082Seschrock 
254*2082Seschrock 	if (zgp == NULL)
255*2082Seschrock 		return (NULL);
256789Sahrens 
257789Sahrens 	zgp->zg_size = size;
258*2082Seschrock 	if ((zgp->zg_hash = zfs_alloc(hdl,
259*2082Seschrock 	    size * sizeof (zfs_vertex_t *))) == NULL) {
260*2082Seschrock 		free(zgp);
261*2082Seschrock 		return (NULL);
262*2082Seschrock 	}
263789Sahrens 
264789Sahrens 	return (zgp);
265789Sahrens }
266789Sahrens 
267789Sahrens /*
268789Sahrens  * Destroy a graph object.  We have to iterate over all the hash chains,
269789Sahrens  * destroying each vertex in the process.
270789Sahrens  */
271789Sahrens static void
272789Sahrens zfs_graph_destroy(zfs_graph_t *zgp)
273789Sahrens {
274789Sahrens 	int i;
275789Sahrens 	zfs_vertex_t *current, *next;
276789Sahrens 
277789Sahrens 	for (i = 0; i < zgp->zg_size; i++) {
278789Sahrens 		current = zgp->zg_hash[i];
279789Sahrens 		while (current != NULL) {
280789Sahrens 			next = current->zv_next;
281789Sahrens 			zfs_vertex_destroy(current);
282789Sahrens 			current = next;
283789Sahrens 		}
284789Sahrens 	}
285789Sahrens 
286789Sahrens 	free(zgp->zg_hash);
287789Sahrens 	free(zgp);
288789Sahrens }
289789Sahrens 
290789Sahrens /*
291789Sahrens  * Graph hash function.  Classic bernstein k=33 hash function, taken from
292789Sahrens  * usr/src/cmd/sgs/tools/common/strhash.c
293789Sahrens  */
294789Sahrens static size_t
295789Sahrens zfs_graph_hash(zfs_graph_t *zgp, const char *str)
296789Sahrens {
297789Sahrens 	size_t hash = 5381;
298789Sahrens 	int c;
299789Sahrens 
300789Sahrens 	while ((c = *str++) != 0)
301789Sahrens 		hash = ((hash << 5) + hash) + c; /* hash * 33 + c */
302789Sahrens 
303789Sahrens 	return (hash % zgp->zg_size);
304789Sahrens }
305789Sahrens 
306789Sahrens /*
307789Sahrens  * Given a dataset name, finds the associated vertex, creating it if necessary.
308789Sahrens  */
309789Sahrens static zfs_vertex_t *
310*2082Seschrock zfs_graph_lookup(libzfs_handle_t *hdl, zfs_graph_t *zgp, const char *dataset,
311*2082Seschrock     uint64_t txg)
312789Sahrens {
313789Sahrens 	size_t idx = zfs_graph_hash(zgp, dataset);
314789Sahrens 	zfs_vertex_t *zvp;
315789Sahrens 
316789Sahrens 	for (zvp = zgp->zg_hash[idx]; zvp != NULL; zvp = zvp->zv_next) {
317789Sahrens 		if (strcmp(zvp->zv_dataset, dataset) == 0) {
318789Sahrens 			if (zvp->zv_txg == 0)
319789Sahrens 				zvp->zv_txg = txg;
320789Sahrens 			return (zvp);
321789Sahrens 		}
322789Sahrens 	}
323789Sahrens 
324*2082Seschrock 	if ((zvp = zfs_vertex_create(hdl, dataset)) == NULL)
325*2082Seschrock 		return (NULL);
326*2082Seschrock 
327789Sahrens 	zvp->zv_next = zgp->zg_hash[idx];
328789Sahrens 	zvp->zv_txg = txg;
329789Sahrens 	zgp->zg_hash[idx] = zvp;
330789Sahrens 	zgp->zg_nvertex++;
331789Sahrens 
332789Sahrens 	return (zvp);
333789Sahrens }
334789Sahrens 
335789Sahrens /*
336789Sahrens  * Given two dataset names, create an edge between them.  For the source vertex,
337789Sahrens  * mark 'zv_visited' to indicate that we have seen this vertex, and not simply
338789Sahrens  * created it as a destination of another edge.  If 'dest' is NULL, then this
339789Sahrens  * is an individual vertex (i.e. the starting vertex), so don't add an edge.
340789Sahrens  */
341*2082Seschrock static int
342*2082Seschrock zfs_graph_add(libzfs_handle_t *hdl, zfs_graph_t *zgp, const char *source,
343*2082Seschrock     const char *dest, uint64_t txg)
344789Sahrens {
345789Sahrens 	zfs_vertex_t *svp, *dvp;
346789Sahrens 
347*2082Seschrock 	if ((svp = zfs_graph_lookup(hdl, zgp, source, 0)) == NULL)
348*2082Seschrock 		return (-1);
349789Sahrens 	svp->zv_visited = 1;
350789Sahrens 	if (dest != NULL) {
351*2082Seschrock 		dvp = zfs_graph_lookup(hdl, zgp, dest, txg);
352*2082Seschrock 		if (dvp == NULL)
353*2082Seschrock 			return (-1);
354*2082Seschrock 		if (zfs_vertex_add_edge(hdl, svp, dvp) != 0)
355*2082Seschrock 			return (-1);
356789Sahrens 	}
357*2082Seschrock 
358*2082Seschrock 	return (0);
359789Sahrens }
360789Sahrens 
361789Sahrens /*
362789Sahrens  * Iterate over all children of the given dataset, adding any vertices as
363*2082Seschrock  * necessary.  Returns 0 if no cloned snapshots were seen, -1 if there was an
364*2082Seschrock  * error, or 1 otherwise.  This is
365789Sahrens  * a simple recursive algorithm - the ZFS namespace typically is very flat.  We
366789Sahrens  * manually invoke the necessary ioctl() calls to avoid the overhead and
367789Sahrens  * additional semantics of zfs_open().
368789Sahrens  */
369789Sahrens static int
370*2082Seschrock iterate_children(libzfs_handle_t *hdl, zfs_graph_t *zgp, const char *dataset)
371789Sahrens {
372789Sahrens 	zfs_cmd_t zc = { 0 };
373*2082Seschrock 	int ret = 0, err;
374789Sahrens 	zfs_vertex_t *zvp;
375789Sahrens 
376789Sahrens 	/*
377789Sahrens 	 * Look up the source vertex, and avoid it if we've seen it before.
378789Sahrens 	 */
379*2082Seschrock 	zvp = zfs_graph_lookup(hdl, zgp, dataset, 0);
380*2082Seschrock 	if (zvp == NULL)
381*2082Seschrock 		return (-1);
382789Sahrens 	if (zvp->zv_visited)
383789Sahrens 		return (0);
384789Sahrens 
385789Sahrens 	for ((void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name));
386*2082Seschrock 	    ioctl(hdl->libzfs_fd, ZFS_IOC_DATASET_LIST_NEXT, &zc) == 0;
387789Sahrens 	    (void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name))) {
388789Sahrens 
389789Sahrens 		/*
390789Sahrens 		 * Ignore private dataset names.
391789Sahrens 		 */
392789Sahrens 		if (dataset_name_hidden(zc.zc_name))
393789Sahrens 			continue;
394789Sahrens 
395789Sahrens 		/*
396789Sahrens 		 * Get statistics for this dataset, to determine the type of the
397789Sahrens 		 * dataset and clone statistics.  If this fails, the dataset has
398789Sahrens 		 * since been removed, and we're pretty much screwed anyway.
399789Sahrens 		 */
400*2082Seschrock 		if (ioctl(hdl->libzfs_fd, ZFS_IOC_OBJSET_STATS, &zc) != 0)
401789Sahrens 			continue;
402789Sahrens 
403789Sahrens 		/*
404789Sahrens 		 * Add an edge between the parent and the child.
405789Sahrens 		 */
406*2082Seschrock 		if (zfs_graph_add(hdl, zgp, dataset, zc.zc_name,
407*2082Seschrock 		    zc.zc_objset_stats.dds_creation_txg) != 0)
408*2082Seschrock 			return (-1);
409789Sahrens 
410789Sahrens 		/*
411789Sahrens 		 * If this dataset has a clone parent, add an appropriate edge.
412789Sahrens 		 */
413*2082Seschrock 		if (zc.zc_objset_stats.dds_clone_of[0] != '\0' &&
414*2082Seschrock 		    zfs_graph_add(hdl, zgp, zc.zc_objset_stats.dds_clone_of,
415*2082Seschrock 		    zc.zc_name, zc.zc_objset_stats.dds_creation_txg) != 0)
416*2082Seschrock 			return (-1);
417789Sahrens 
418789Sahrens 		/*
419789Sahrens 		 * Iterate over all children
420789Sahrens 		 */
421*2082Seschrock 		err = iterate_children(hdl, zgp, zc.zc_name);
422*2082Seschrock 		if (err == -1)
423*2082Seschrock 			return (-1);
424*2082Seschrock 		else if (err == 1)
425*2082Seschrock 			ret = 1;
426789Sahrens 
427789Sahrens 		/*
428789Sahrens 		 * Indicate if we found a dataset with a non-zero clone count.
429789Sahrens 		 */
430789Sahrens 		if (zc.zc_objset_stats.dds_num_clones != 0)
431*2082Seschrock 			ret = 1;
432789Sahrens 	}
433789Sahrens 
434789Sahrens 	/*
435789Sahrens 	 * Now iterate over all snapshots.
436789Sahrens 	 */
437789Sahrens 	bzero(&zc, sizeof (zc));
438789Sahrens 
439789Sahrens 	for ((void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name));
440*2082Seschrock 	    ioctl(hdl->libzfs_fd, ZFS_IOC_SNAPSHOT_LIST_NEXT, &zc) == 0;
441789Sahrens 	    (void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name))) {
442789Sahrens 
443789Sahrens 		/*
444789Sahrens 		 * Get statistics for this dataset, to determine the type of the
445789Sahrens 		 * dataset and clone statistics.  If this fails, the dataset has
446789Sahrens 		 * since been removed, and we're pretty much screwed anyway.
447789Sahrens 		 */
448*2082Seschrock 		if (ioctl(hdl->libzfs_fd, ZFS_IOC_OBJSET_STATS, &zc) != 0)
449789Sahrens 			continue;
450789Sahrens 
451789Sahrens 		/*
452789Sahrens 		 * Add an edge between the parent and the child.
453789Sahrens 		 */
454*2082Seschrock 		if (zfs_graph_add(hdl, zgp, dataset, zc.zc_name,
455*2082Seschrock 		    zc.zc_objset_stats.dds_creation_txg) != 0)
456*2082Seschrock 			return (-1);
457789Sahrens 
458789Sahrens 		/*
459789Sahrens 		 * Indicate if we found a dataset with a non-zero clone count.
460789Sahrens 		 */
461789Sahrens 		if (zc.zc_objset_stats.dds_num_clones != 0)
462*2082Seschrock 			ret = 1;
463789Sahrens 	}
464789Sahrens 
465789Sahrens 	zvp->zv_visited = 1;
466789Sahrens 
467789Sahrens 	return (ret);
468789Sahrens }
469789Sahrens 
470789Sahrens /*
471789Sahrens  * Construct a complete graph of all necessary vertices.  First, we iterate over
472789Sahrens  * only our object's children.  If we don't find any cloned snapshots, then we
473789Sahrens  * simple return that.  Otherwise, we have to start at the pool root and iterate
474789Sahrens  * over all datasets.
475789Sahrens  */
476789Sahrens static zfs_graph_t *
477*2082Seschrock construct_graph(libzfs_handle_t *hdl, const char *dataset)
478789Sahrens {
479*2082Seschrock 	zfs_graph_t *zgp = zfs_graph_create(hdl, ZFS_GRAPH_SIZE);
480789Sahrens 	zfs_cmd_t zc = { 0 };
481*2082Seschrock 	int ret = 0;
482*2082Seschrock 
483*2082Seschrock 	if (zgp == NULL)
484*2082Seschrock 		return (zgp);
485789Sahrens 
486789Sahrens 	/*
487789Sahrens 	 * We need to explicitly check whether this dataset has clones or not,
488789Sahrens 	 * since iterate_children() only checks the children.
489789Sahrens 	 */
490789Sahrens 	(void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name));
491*2082Seschrock 	(void) ioctl(hdl->libzfs_fd, ZFS_IOC_OBJSET_STATS, &zc);
492789Sahrens 
493789Sahrens 	if (zc.zc_objset_stats.dds_num_clones != 0 ||
494*2082Seschrock 	    (ret = iterate_children(hdl, zgp, dataset)) != 0) {
495789Sahrens 		/*
496789Sahrens 		 * Determine pool name and try again.
497789Sahrens 		 */
498789Sahrens 		char *pool, *slash;
499789Sahrens 
500789Sahrens 		if ((slash = strchr(dataset, '/')) != NULL ||
501789Sahrens 		    (slash = strchr(dataset, '@')) != NULL) {
502*2082Seschrock 			pool = zfs_alloc(hdl, slash - dataset + 1);
503*2082Seschrock 			if (pool == NULL) {
504*2082Seschrock 				zfs_graph_destroy(zgp);
505*2082Seschrock 				return (NULL);
506*2082Seschrock 			}
507789Sahrens 			(void) strncpy(pool, dataset, slash - dataset);
508789Sahrens 			pool[slash - dataset] = '\0';
509789Sahrens 
510*2082Seschrock 			if (iterate_children(hdl, zgp, pool) == -1 ||
511*2082Seschrock 			    zfs_graph_add(hdl, zgp, pool, NULL, 0) != 0) {
512*2082Seschrock 				free(pool);
513*2082Seschrock 				zfs_graph_destroy(zgp);
514*2082Seschrock 				return (NULL);
515*2082Seschrock 			}
516789Sahrens 
517789Sahrens 			free(pool);
518789Sahrens 		}
519789Sahrens 	}
520*2082Seschrock 
521*2082Seschrock 	if (ret == -1 || zfs_graph_add(hdl, zgp, dataset, NULL, 0) != 0) {
522*2082Seschrock 		zfs_graph_destroy(zgp);
523*2082Seschrock 		return (NULL);
524*2082Seschrock 	}
525789Sahrens 
526789Sahrens 	return (zgp);
527789Sahrens }
528789Sahrens 
529789Sahrens /*
530789Sahrens  * Given a graph, do a recursive topological sort into the given array.  This is
531789Sahrens  * really just a depth first search, so that the deepest nodes appear first.
532789Sahrens  * hijack the 'zv_visited' marker to avoid visiting the same vertex twice.
533789Sahrens  */
534*2082Seschrock static int
535*2082Seschrock topo_sort(libzfs_handle_t *hdl, char **result, size_t *idx, zfs_vertex_t *zgv)
536789Sahrens {
537789Sahrens 	int i;
538789Sahrens 
539789Sahrens 	/* avoid doing a search if we don't have to */
540789Sahrens 	if (zgv->zv_visited == 2)
541*2082Seschrock 		return (0);
542789Sahrens 
543789Sahrens 	zfs_vertex_sort_edges(zgv);
544*2082Seschrock 	for (i = 0; i < zgv->zv_edgecount; i++) {
545*2082Seschrock 		if (topo_sort(hdl, result, idx, zgv->zv_edges[i]->ze_dest) != 0)
546*2082Seschrock 			return (-1);
547*2082Seschrock 	}
548789Sahrens 
549789Sahrens 	/* we may have visited this in the course of the above */
550789Sahrens 	if (zgv->zv_visited == 2)
551*2082Seschrock 		return (0);
552789Sahrens 
553*2082Seschrock 	if ((result[*idx] = zfs_alloc(hdl,
554*2082Seschrock 	    strlen(zgv->zv_dataset) + 1)) == NULL)
555*2082Seschrock 		return (-1);
556*2082Seschrock 
557789Sahrens 	(void) strcpy(result[*idx], zgv->zv_dataset);
558789Sahrens 	*idx += 1;
559789Sahrens 	zgv->zv_visited = 2;
560*2082Seschrock 	return (0);
561789Sahrens }
562789Sahrens 
563789Sahrens /*
564789Sahrens  * The only public interface for this file.  Do the dirty work of constructing a
565789Sahrens  * child list for the given object.  Construct the graph, do the toplogical
566789Sahrens  * sort, and then return the array of strings to the caller.
567789Sahrens  */
568789Sahrens char **
569*2082Seschrock get_dependents(libzfs_handle_t *hdl, const char *dataset, size_t *count)
570789Sahrens {
571789Sahrens 	char **result;
572789Sahrens 	zfs_graph_t *zgp;
573789Sahrens 	zfs_vertex_t *zvp;
574789Sahrens 
575*2082Seschrock 	if ((zgp = construct_graph(hdl, dataset)) == NULL)
576*2082Seschrock 		return (NULL);
577789Sahrens 
578*2082Seschrock 	if ((result = zfs_alloc(hdl,
579*2082Seschrock 	    zgp->zg_nvertex * sizeof (char *))) == NULL) {
580*2082Seschrock 		zfs_graph_destroy(zgp);
581*2082Seschrock 		return (NULL);
582*2082Seschrock 	}
583*2082Seschrock 
584*2082Seschrock 	if ((zvp = zfs_graph_lookup(hdl, zgp, dataset, 0)) == NULL) {
585*2082Seschrock 		free(result);
586*2082Seschrock 		zfs_graph_destroy(zgp);
587*2082Seschrock 		return (NULL);
588*2082Seschrock 	}
589789Sahrens 
590789Sahrens 	*count = 0;
591*2082Seschrock 	if (topo_sort(hdl, result, count, zvp) != 0) {
592*2082Seschrock 		free(result);
593*2082Seschrock 		zfs_graph_destroy(zgp);
594*2082Seschrock 		return (NULL);
595*2082Seschrock 	}
596789Sahrens 
597789Sahrens 	/*
598789Sahrens 	 * Get rid of the last entry, which is our starting vertex and not
599789Sahrens 	 * strictly a dependent.
600789Sahrens 	 */
601789Sahrens 	assert(*count > 0);
602789Sahrens 	free(result[*count - 1]);
603789Sahrens 	(*count)--;
604789Sahrens 
605789Sahrens 	zfs_graph_destroy(zgp);
606789Sahrens 
607789Sahrens 	return (result);
608789Sahrens }
609