1*789Sahrens /*
2*789Sahrens  * CDDL HEADER START
3*789Sahrens  *
4*789Sahrens  * The contents of this file are subject to the terms of the
5*789Sahrens  * Common Development and Distribution License, Version 1.0 only
6*789Sahrens  * (the "License").  You may not use this file except in compliance
7*789Sahrens  * with the License.
8*789Sahrens  *
9*789Sahrens  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*789Sahrens  * or http://www.opensolaris.org/os/licensing.
11*789Sahrens  * See the License for the specific language governing permissions
12*789Sahrens  * and limitations under the License.
13*789Sahrens  *
14*789Sahrens  * When distributing Covered Code, include this CDDL HEADER in each
15*789Sahrens  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*789Sahrens  * If applicable, add the following below this CDDL HEADER, with the
17*789Sahrens  * fields enclosed by brackets "[]" replaced with your own identifying
18*789Sahrens  * information: Portions Copyright [yyyy] [name of copyright owner]
19*789Sahrens  *
20*789Sahrens  * CDDL HEADER END
21*789Sahrens  */
22*789Sahrens /*
23*789Sahrens  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24*789Sahrens  * Use is subject to license terms.
25*789Sahrens  */
26*789Sahrens 
27*789Sahrens #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*789Sahrens 
29*789Sahrens /*
30*789Sahrens  * Iterate over all children of the current object.  This includes the normal
31*789Sahrens  * dataset hierarchy, but also arbitrary hierarchies due to clones.  We want to
32*789Sahrens  * walk all datasets in the pool, and construct a directed graph of the form:
33*789Sahrens  *
34*789Sahrens  * 			home
35*789Sahrens  *                        |
36*789Sahrens  *                   +----+----+
37*789Sahrens  *                   |         |
38*789Sahrens  *                   v         v             ws
39*789Sahrens  *                  bar       baz             |
40*789Sahrens  *                             |              |
41*789Sahrens  *                             v              v
42*789Sahrens  *                          @yesterday ----> foo
43*789Sahrens  *
44*789Sahrens  * In order to construct this graph, we have to walk every dataset in the pool,
45*789Sahrens  * because the clone parent is stored as a property of the child, not the
46*789Sahrens  * parent.  The parent only keeps track of the number of clones.
47*789Sahrens  *
48*789Sahrens  * In the normal case (without clones) this would be rather expensive.  To avoid
49*789Sahrens  * unnecessary computation, we first try a walk of the subtree hierarchy
50*789Sahrens  * starting from the initial node.  At each dataset, we construct a node in the
51*789Sahrens  * graph and an edge leading from its parent.  If we don't see any snapshots
52*789Sahrens  * with a non-zero clone count, then we are finished.
53*789Sahrens  *
54*789Sahrens  * If we do find a cloned snapshot, then we finish the walk of the current
55*789Sahrens  * subtree, but indicate that we need to do a complete walk.  We then perform a
56*789Sahrens  * global walk of all datasets, avoiding the subtree we already processed.
57*789Sahrens  *
58*789Sahrens  * At the end of this, we'll end up with a directed graph of all relevant (and
59*789Sahrens  * possible some irrelevant) datasets in the system.  We need to both find our
60*789Sahrens  * limiting subgraph and determine a safe ordering in which to destroy the
61*789Sahrens  * datasets.  We do a topological ordering of our graph starting at our target
62*789Sahrens  * dataset, and then walk the results in reverse.
63*789Sahrens  *
64*789Sahrens  * When removing datasets, we want to destroy the snapshots in chronological
65*789Sahrens  * order (because this is the most efficient method).  In order to accomplish
66*789Sahrens  * this, we store the creation transaction group with each vertex and keep each
67*789Sahrens  * vertex's edges sorted according to this value.  The topological sort will
68*789Sahrens  * automatically walk the snapshots in the correct order.
69*789Sahrens  */
70*789Sahrens 
71*789Sahrens #include <assert.h>
72*789Sahrens #include <stdio.h>
73*789Sahrens #include <stdlib.h>
74*789Sahrens #include <string.h>
75*789Sahrens #include <strings.h>
76*789Sahrens #include <unistd.h>
77*789Sahrens 
78*789Sahrens #include <libzfs.h>
79*789Sahrens 
80*789Sahrens #include "libzfs_impl.h"
81*789Sahrens #include "zfs_namecheck.h"
82*789Sahrens 
83*789Sahrens #define	MIN_EDGECOUNT	4
84*789Sahrens 
85*789Sahrens /*
86*789Sahrens  * Vertex structure.  Indexed by dataset name, this structure maintains a list
87*789Sahrens  * of edges to other vertices.
88*789Sahrens  */
89*789Sahrens struct zfs_edge;
90*789Sahrens typedef struct zfs_vertex {
91*789Sahrens 	char			zv_dataset[ZFS_MAXNAMELEN];
92*789Sahrens 	struct zfs_vertex	*zv_next;
93*789Sahrens 	int			zv_visited;
94*789Sahrens 	uint64_t		zv_txg;
95*789Sahrens 	struct zfs_edge		**zv_edges;
96*789Sahrens 	int			zv_edgecount;
97*789Sahrens 	int			zv_edgealloc;
98*789Sahrens } zfs_vertex_t;
99*789Sahrens 
100*789Sahrens /*
101*789Sahrens  * Edge structure.  Simply maintains a pointer to the destination vertex.  There
102*789Sahrens  * is no need to store the source vertex, since we only use edges in the context
103*789Sahrens  * of the source vertex.
104*789Sahrens  */
105*789Sahrens typedef struct zfs_edge {
106*789Sahrens 	zfs_vertex_t		*ze_dest;
107*789Sahrens 	struct zfs_edge		*ze_next;
108*789Sahrens } zfs_edge_t;
109*789Sahrens 
110*789Sahrens #define	ZFS_GRAPH_SIZE		1027	/* this could be dynamic some day */
111*789Sahrens 
112*789Sahrens /*
113*789Sahrens  * Graph structure.  Vertices are maintained in a hash indexed by dataset name.
114*789Sahrens  */
115*789Sahrens typedef struct zfs_graph {
116*789Sahrens 	zfs_vertex_t		**zg_hash;
117*789Sahrens 	size_t			zg_size;
118*789Sahrens 	size_t			zg_nvertex;
119*789Sahrens } zfs_graph_t;
120*789Sahrens 
121*789Sahrens /*
122*789Sahrens  * Allocate a new edge pointing to the target vertex.
123*789Sahrens  */
124*789Sahrens static zfs_edge_t *
125*789Sahrens zfs_edge_create(zfs_vertex_t *dest)
126*789Sahrens {
127*789Sahrens 	zfs_edge_t *zep = zfs_malloc(sizeof (zfs_edge_t));
128*789Sahrens 
129*789Sahrens 	zep->ze_dest = dest;
130*789Sahrens 
131*789Sahrens 	return (zep);
132*789Sahrens }
133*789Sahrens 
134*789Sahrens /*
135*789Sahrens  * Destroy an edge.
136*789Sahrens  */
137*789Sahrens static void
138*789Sahrens zfs_edge_destroy(zfs_edge_t *zep)
139*789Sahrens {
140*789Sahrens 	free(zep);
141*789Sahrens }
142*789Sahrens 
143*789Sahrens /*
144*789Sahrens  * Allocate a new vertex with the given name.
145*789Sahrens  */
146*789Sahrens static zfs_vertex_t *
147*789Sahrens zfs_vertex_create(const char *dataset)
148*789Sahrens {
149*789Sahrens 	zfs_vertex_t *zvp = zfs_malloc(sizeof (zfs_vertex_t));
150*789Sahrens 
151*789Sahrens 	assert(strlen(dataset) < ZFS_MAXNAMELEN);
152*789Sahrens 
153*789Sahrens 	(void) strlcpy(zvp->zv_dataset, dataset, sizeof (zvp->zv_dataset));
154*789Sahrens 
155*789Sahrens 	zvp->zv_edges = zfs_malloc(MIN_EDGECOUNT * sizeof (void *));
156*789Sahrens 	zvp->zv_edgealloc = MIN_EDGECOUNT;
157*789Sahrens 
158*789Sahrens 	return (zvp);
159*789Sahrens }
160*789Sahrens 
161*789Sahrens /*
162*789Sahrens  * Destroy a vertex.  Frees up any associated edges.
163*789Sahrens  */
164*789Sahrens static void
165*789Sahrens zfs_vertex_destroy(zfs_vertex_t *zvp)
166*789Sahrens {
167*789Sahrens 	int i;
168*789Sahrens 
169*789Sahrens 	for (i = 0; i < zvp->zv_edgecount; i++)
170*789Sahrens 		zfs_edge_destroy(zvp->zv_edges[i]);
171*789Sahrens 
172*789Sahrens 	free(zvp->zv_edges);
173*789Sahrens 	free(zvp);
174*789Sahrens }
175*789Sahrens 
176*789Sahrens /*
177*789Sahrens  * Given a vertex, add an edge to the destination vertex.
178*789Sahrens  */
179*789Sahrens static void
180*789Sahrens zfs_vertex_add_edge(zfs_vertex_t *zvp, zfs_vertex_t *dest)
181*789Sahrens {
182*789Sahrens 	zfs_edge_t *zep = zfs_edge_create(dest);
183*789Sahrens 
184*789Sahrens 	if (zvp->zv_edgecount == zvp->zv_edgealloc) {
185*789Sahrens 		zfs_edge_t **newedges = zfs_malloc(zvp->zv_edgealloc * 2 *
186*789Sahrens 		    sizeof (void *));
187*789Sahrens 
188*789Sahrens 		bcopy(zvp->zv_edges, newedges,
189*789Sahrens 		    zvp->zv_edgealloc * sizeof (void *));
190*789Sahrens 
191*789Sahrens 		zvp->zv_edgealloc *= 2;
192*789Sahrens 		free(zvp->zv_edges);
193*789Sahrens 		zvp->zv_edges = newedges;
194*789Sahrens 	}
195*789Sahrens 
196*789Sahrens 	zvp->zv_edges[zvp->zv_edgecount++] = zep;
197*789Sahrens }
198*789Sahrens 
199*789Sahrens static int
200*789Sahrens zfs_edge_compare(const void *a, const void *b)
201*789Sahrens {
202*789Sahrens 	const zfs_edge_t *ea = *((zfs_edge_t **)a);
203*789Sahrens 	const zfs_edge_t *eb = *((zfs_edge_t **)b);
204*789Sahrens 
205*789Sahrens 	if (ea->ze_dest->zv_txg < eb->ze_dest->zv_txg)
206*789Sahrens 		return (-1);
207*789Sahrens 	if (ea->ze_dest->zv_txg > eb->ze_dest->zv_txg)
208*789Sahrens 		return (1);
209*789Sahrens 	return (0);
210*789Sahrens }
211*789Sahrens 
212*789Sahrens /*
213*789Sahrens  * Sort the given vertex edges according to the creation txg of each vertex.
214*789Sahrens  */
215*789Sahrens static void
216*789Sahrens zfs_vertex_sort_edges(zfs_vertex_t *zvp)
217*789Sahrens {
218*789Sahrens 	if (zvp->zv_edgecount == 0)
219*789Sahrens 		return;
220*789Sahrens 
221*789Sahrens 	qsort(zvp->zv_edges, zvp->zv_edgecount, sizeof (void *),
222*789Sahrens 	    zfs_edge_compare);
223*789Sahrens }
224*789Sahrens 
225*789Sahrens /*
226*789Sahrens  * Construct a new graph object.  We allow the size to be specified as a
227*789Sahrens  * parameter so in the future we can size the hash according to the number of
228*789Sahrens  * datasets in the pool.
229*789Sahrens  */
230*789Sahrens static zfs_graph_t *
231*789Sahrens zfs_graph_create(size_t size)
232*789Sahrens {
233*789Sahrens 	zfs_graph_t *zgp = zfs_malloc(sizeof (zfs_graph_t));
234*789Sahrens 
235*789Sahrens 	zgp->zg_size = size;
236*789Sahrens 	zgp->zg_hash = zfs_malloc(size * sizeof (zfs_vertex_t *));
237*789Sahrens 
238*789Sahrens 	return (zgp);
239*789Sahrens }
240*789Sahrens 
241*789Sahrens /*
242*789Sahrens  * Destroy a graph object.  We have to iterate over all the hash chains,
243*789Sahrens  * destroying each vertex in the process.
244*789Sahrens  */
245*789Sahrens static void
246*789Sahrens zfs_graph_destroy(zfs_graph_t *zgp)
247*789Sahrens {
248*789Sahrens 	int i;
249*789Sahrens 	zfs_vertex_t *current, *next;
250*789Sahrens 
251*789Sahrens 	for (i = 0; i < zgp->zg_size; i++) {
252*789Sahrens 		current = zgp->zg_hash[i];
253*789Sahrens 		while (current != NULL) {
254*789Sahrens 			next = current->zv_next;
255*789Sahrens 			zfs_vertex_destroy(current);
256*789Sahrens 			current = next;
257*789Sahrens 		}
258*789Sahrens 	}
259*789Sahrens 
260*789Sahrens 	free(zgp->zg_hash);
261*789Sahrens 	free(zgp);
262*789Sahrens }
263*789Sahrens 
264*789Sahrens /*
265*789Sahrens  * Graph hash function.  Classic bernstein k=33 hash function, taken from
266*789Sahrens  * usr/src/cmd/sgs/tools/common/strhash.c
267*789Sahrens  */
268*789Sahrens static size_t
269*789Sahrens zfs_graph_hash(zfs_graph_t *zgp, const char *str)
270*789Sahrens {
271*789Sahrens 	size_t hash = 5381;
272*789Sahrens 	int c;
273*789Sahrens 
274*789Sahrens 	while ((c = *str++) != 0)
275*789Sahrens 		hash = ((hash << 5) + hash) + c; /* hash * 33 + c */
276*789Sahrens 
277*789Sahrens 	return (hash % zgp->zg_size);
278*789Sahrens }
279*789Sahrens 
280*789Sahrens /*
281*789Sahrens  * Given a dataset name, finds the associated vertex, creating it if necessary.
282*789Sahrens  */
283*789Sahrens static zfs_vertex_t *
284*789Sahrens zfs_graph_lookup(zfs_graph_t *zgp, const char *dataset, uint64_t txg)
285*789Sahrens {
286*789Sahrens 	size_t idx = zfs_graph_hash(zgp, dataset);
287*789Sahrens 	zfs_vertex_t *zvp;
288*789Sahrens 
289*789Sahrens 	for (zvp = zgp->zg_hash[idx]; zvp != NULL; zvp = zvp->zv_next) {
290*789Sahrens 		if (strcmp(zvp->zv_dataset, dataset) == 0) {
291*789Sahrens 			if (zvp->zv_txg == 0)
292*789Sahrens 				zvp->zv_txg = txg;
293*789Sahrens 			return (zvp);
294*789Sahrens 		}
295*789Sahrens 	}
296*789Sahrens 
297*789Sahrens 	zvp = zfs_vertex_create(dataset);
298*789Sahrens 	zvp->zv_next = zgp->zg_hash[idx];
299*789Sahrens 	zvp->zv_txg = txg;
300*789Sahrens 	zgp->zg_hash[idx] = zvp;
301*789Sahrens 	zgp->zg_nvertex++;
302*789Sahrens 
303*789Sahrens 	return (zvp);
304*789Sahrens }
305*789Sahrens 
306*789Sahrens /*
307*789Sahrens  * Given two dataset names, create an edge between them.  For the source vertex,
308*789Sahrens  * mark 'zv_visited' to indicate that we have seen this vertex, and not simply
309*789Sahrens  * created it as a destination of another edge.  If 'dest' is NULL, then this
310*789Sahrens  * is an individual vertex (i.e. the starting vertex), so don't add an edge.
311*789Sahrens  */
312*789Sahrens static void
313*789Sahrens zfs_graph_add(zfs_graph_t *zgp, const char *source, const char *dest,
314*789Sahrens     uint64_t txg)
315*789Sahrens {
316*789Sahrens 	zfs_vertex_t *svp, *dvp;
317*789Sahrens 
318*789Sahrens 	svp = zfs_graph_lookup(zgp, source, 0);
319*789Sahrens 	svp->zv_visited = 1;
320*789Sahrens 	if (dest != NULL) {
321*789Sahrens 		dvp = zfs_graph_lookup(zgp, dest, txg);
322*789Sahrens 		zfs_vertex_add_edge(svp, dvp);
323*789Sahrens 	}
324*789Sahrens }
325*789Sahrens 
326*789Sahrens /*
327*789Sahrens  * Iterate over all children of the given dataset, adding any vertices as
328*789Sahrens  * necessary.  Returns 0 if no cloned snapshots were seen, 1 otherwise.  This is
329*789Sahrens  * a simple recursive algorithm - the ZFS namespace typically is very flat.  We
330*789Sahrens  * manually invoke the necessary ioctl() calls to avoid the overhead and
331*789Sahrens  * additional semantics of zfs_open().
332*789Sahrens  */
333*789Sahrens static int
334*789Sahrens iterate_children(zfs_graph_t *zgp, const char *dataset)
335*789Sahrens {
336*789Sahrens 	zfs_cmd_t zc = { 0 };
337*789Sahrens 	int ret = 0;
338*789Sahrens 	zfs_vertex_t *zvp;
339*789Sahrens 
340*789Sahrens 	/*
341*789Sahrens 	 * Look up the source vertex, and avoid it if we've seen it before.
342*789Sahrens 	 */
343*789Sahrens 	zvp = zfs_graph_lookup(zgp, dataset, 0);
344*789Sahrens 	if (zvp->zv_visited)
345*789Sahrens 		return (0);
346*789Sahrens 
347*789Sahrens 	for ((void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name));
348*789Sahrens 	    ioctl(zfs_fd, ZFS_IOC_DATASET_LIST_NEXT, &zc) == 0;
349*789Sahrens 	    (void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name))) {
350*789Sahrens 
351*789Sahrens 		/*
352*789Sahrens 		 * Ignore private dataset names.
353*789Sahrens 		 */
354*789Sahrens 		if (dataset_name_hidden(zc.zc_name))
355*789Sahrens 			continue;
356*789Sahrens 
357*789Sahrens 		/*
358*789Sahrens 		 * Get statistics for this dataset, to determine the type of the
359*789Sahrens 		 * dataset and clone statistics.  If this fails, the dataset has
360*789Sahrens 		 * since been removed, and we're pretty much screwed anyway.
361*789Sahrens 		 */
362*789Sahrens 		if (ioctl(zfs_fd, ZFS_IOC_OBJSET_STATS, &zc) != 0)
363*789Sahrens 			continue;
364*789Sahrens 
365*789Sahrens 		/*
366*789Sahrens 		 * Add an edge between the parent and the child.
367*789Sahrens 		 */
368*789Sahrens 		zfs_graph_add(zgp, dataset, zc.zc_name,
369*789Sahrens 		    zc.zc_objset_stats.dds_creation_txg);
370*789Sahrens 
371*789Sahrens 		/*
372*789Sahrens 		 * If this dataset has a clone parent, add an appropriate edge.
373*789Sahrens 		 */
374*789Sahrens 		if (zc.zc_objset_stats.dds_clone_of[0] != '\0')
375*789Sahrens 			zfs_graph_add(zgp, zc.zc_objset_stats.dds_clone_of,
376*789Sahrens 			    zc.zc_name, zc.zc_objset_stats.dds_creation_txg);
377*789Sahrens 
378*789Sahrens 		/*
379*789Sahrens 		 * Iterate over all children
380*789Sahrens 		 */
381*789Sahrens 		ret |= iterate_children(zgp, zc.zc_name);
382*789Sahrens 
383*789Sahrens 		/*
384*789Sahrens 		 * Indicate if we found a dataset with a non-zero clone count.
385*789Sahrens 		 */
386*789Sahrens 		if (zc.zc_objset_stats.dds_num_clones != 0)
387*789Sahrens 			ret |= 1;
388*789Sahrens 	}
389*789Sahrens 
390*789Sahrens 	/*
391*789Sahrens 	 * Now iterate over all snapshots.
392*789Sahrens 	 */
393*789Sahrens 	bzero(&zc, sizeof (zc));
394*789Sahrens 
395*789Sahrens 	for ((void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name));
396*789Sahrens 	    ioctl(zfs_fd, ZFS_IOC_SNAPSHOT_LIST_NEXT, &zc) == 0;
397*789Sahrens 	    (void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name))) {
398*789Sahrens 
399*789Sahrens 		/*
400*789Sahrens 		 * Get statistics for this dataset, to determine the type of the
401*789Sahrens 		 * dataset and clone statistics.  If this fails, the dataset has
402*789Sahrens 		 * since been removed, and we're pretty much screwed anyway.
403*789Sahrens 		 */
404*789Sahrens 		if (ioctl(zfs_fd, ZFS_IOC_OBJSET_STATS, &zc) != 0)
405*789Sahrens 			continue;
406*789Sahrens 
407*789Sahrens 		/*
408*789Sahrens 		 * Add an edge between the parent and the child.
409*789Sahrens 		 */
410*789Sahrens 		zfs_graph_add(zgp, dataset, zc.zc_name,
411*789Sahrens 		    zc.zc_objset_stats.dds_creation_txg);
412*789Sahrens 
413*789Sahrens 		/*
414*789Sahrens 		 * Indicate if we found a dataset with a non-zero clone count.
415*789Sahrens 		 */
416*789Sahrens 		if (zc.zc_objset_stats.dds_num_clones != 0)
417*789Sahrens 			ret |= 1;
418*789Sahrens 	}
419*789Sahrens 
420*789Sahrens 	zvp->zv_visited = 1;
421*789Sahrens 
422*789Sahrens 	return (ret);
423*789Sahrens }
424*789Sahrens 
425*789Sahrens /*
426*789Sahrens  * Construct a complete graph of all necessary vertices.  First, we iterate over
427*789Sahrens  * only our object's children.  If we don't find any cloned snapshots, then we
428*789Sahrens  * simple return that.  Otherwise, we have to start at the pool root and iterate
429*789Sahrens  * over all datasets.
430*789Sahrens  */
431*789Sahrens static zfs_graph_t *
432*789Sahrens construct_graph(const char *dataset)
433*789Sahrens {
434*789Sahrens 	zfs_graph_t *zgp = zfs_graph_create(ZFS_GRAPH_SIZE);
435*789Sahrens 	zfs_cmd_t zc = { 0 };
436*789Sahrens 
437*789Sahrens 	/*
438*789Sahrens 	 * We need to explicitly check whether this dataset has clones or not,
439*789Sahrens 	 * since iterate_children() only checks the children.
440*789Sahrens 	 */
441*789Sahrens 	(void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name));
442*789Sahrens 	(void) ioctl(zfs_fd, ZFS_IOC_OBJSET_STATS, &zc);
443*789Sahrens 
444*789Sahrens 	if (zc.zc_objset_stats.dds_num_clones != 0 ||
445*789Sahrens 	    iterate_children(zgp, dataset) != 0) {
446*789Sahrens 		/*
447*789Sahrens 		 * Determine pool name and try again.
448*789Sahrens 		 */
449*789Sahrens 		char *pool, *slash;
450*789Sahrens 
451*789Sahrens 		if ((slash = strchr(dataset, '/')) != NULL ||
452*789Sahrens 		    (slash = strchr(dataset, '@')) != NULL) {
453*789Sahrens 			pool = zfs_malloc(slash - dataset + 1);
454*789Sahrens 			(void) strncpy(pool, dataset, slash - dataset);
455*789Sahrens 			pool[slash - dataset] = '\0';
456*789Sahrens 
457*789Sahrens 			(void) iterate_children(zgp, pool);
458*789Sahrens 			zfs_graph_add(zgp, pool, NULL, 0);
459*789Sahrens 
460*789Sahrens 			free(pool);
461*789Sahrens 		}
462*789Sahrens 	}
463*789Sahrens 	zfs_graph_add(zgp, dataset, NULL, 0);
464*789Sahrens 
465*789Sahrens 	return (zgp);
466*789Sahrens }
467*789Sahrens 
468*789Sahrens /*
469*789Sahrens  * Given a graph, do a recursive topological sort into the given array.  This is
470*789Sahrens  * really just a depth first search, so that the deepest nodes appear first.
471*789Sahrens  * hijack the 'zv_visited' marker to avoid visiting the same vertex twice.
472*789Sahrens  */
473*789Sahrens static void
474*789Sahrens topo_sort(char **result, size_t *idx, zfs_vertex_t *zgv)
475*789Sahrens {
476*789Sahrens 	int i;
477*789Sahrens 
478*789Sahrens 	/* avoid doing a search if we don't have to */
479*789Sahrens 	if (zgv->zv_visited == 2)
480*789Sahrens 		return;
481*789Sahrens 
482*789Sahrens 	zfs_vertex_sort_edges(zgv);
483*789Sahrens 	for (i = 0; i < zgv->zv_edgecount; i++)
484*789Sahrens 		topo_sort(result, idx, zgv->zv_edges[i]->ze_dest);
485*789Sahrens 
486*789Sahrens 	/* we may have visited this in the course of the above */
487*789Sahrens 	if (zgv->zv_visited == 2)
488*789Sahrens 		return;
489*789Sahrens 
490*789Sahrens 	result[*idx] = zfs_malloc(strlen(zgv->zv_dataset) + 1);
491*789Sahrens 	(void) strcpy(result[*idx], zgv->zv_dataset);
492*789Sahrens 	*idx += 1;
493*789Sahrens 	zgv->zv_visited = 2;
494*789Sahrens }
495*789Sahrens 
496*789Sahrens /*
497*789Sahrens  * The only public interface for this file.  Do the dirty work of constructing a
498*789Sahrens  * child list for the given object.  Construct the graph, do the toplogical
499*789Sahrens  * sort, and then return the array of strings to the caller.
500*789Sahrens  */
501*789Sahrens char **
502*789Sahrens get_dependents(const char *dataset, size_t *count)
503*789Sahrens {
504*789Sahrens 	char **result;
505*789Sahrens 	zfs_graph_t *zgp;
506*789Sahrens 	zfs_vertex_t *zvp;
507*789Sahrens 
508*789Sahrens 	zgp = construct_graph(dataset);
509*789Sahrens 	result = zfs_malloc(zgp->zg_nvertex * sizeof (char *));
510*789Sahrens 
511*789Sahrens 	zvp = zfs_graph_lookup(zgp, dataset, 0);
512*789Sahrens 
513*789Sahrens 	*count = 0;
514*789Sahrens 	topo_sort(result, count, zvp);
515*789Sahrens 
516*789Sahrens 	/*
517*789Sahrens 	 * Get rid of the last entry, which is our starting vertex and not
518*789Sahrens 	 * strictly a dependent.
519*789Sahrens 	 */
520*789Sahrens 	assert(*count > 0);
521*789Sahrens 	free(result[*count - 1]);
522*789Sahrens 	(*count)--;
523*789Sahrens 
524*789Sahrens 	zfs_graph_destroy(zgp);
525*789Sahrens 
526*789Sahrens 	return (result);
527*789Sahrens }
528