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 /*
22*9396SMatthew.Ahrens@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23789Sahrens * Use is subject to license terms.
24789Sahrens */
25789Sahrens
26789Sahrens /*
27789Sahrens * Iterate over all children of the current object. This includes the normal
28789Sahrens * dataset hierarchy, but also arbitrary hierarchies due to clones. We want to
29789Sahrens * walk all datasets in the pool, and construct a directed graph of the form:
30789Sahrens *
31789Sahrens * home
32789Sahrens * |
33789Sahrens * +----+----+
34789Sahrens * | |
35789Sahrens * v v ws
36789Sahrens * bar baz |
37789Sahrens * | |
38789Sahrens * v v
39789Sahrens * @yesterday ----> foo
40789Sahrens *
41789Sahrens * In order to construct this graph, we have to walk every dataset in the pool,
42789Sahrens * because the clone parent is stored as a property of the child, not the
43789Sahrens * parent. The parent only keeps track of the number of clones.
44789Sahrens *
45789Sahrens * In the normal case (without clones) this would be rather expensive. To avoid
46789Sahrens * unnecessary computation, we first try a walk of the subtree hierarchy
47789Sahrens * starting from the initial node. At each dataset, we construct a node in the
48789Sahrens * graph and an edge leading from its parent. If we don't see any snapshots
49789Sahrens * with a non-zero clone count, then we are finished.
50789Sahrens *
51789Sahrens * If we do find a cloned snapshot, then we finish the walk of the current
52789Sahrens * subtree, but indicate that we need to do a complete walk. We then perform a
53789Sahrens * global walk of all datasets, avoiding the subtree we already processed.
54789Sahrens *
55789Sahrens * At the end of this, we'll end up with a directed graph of all relevant (and
56789Sahrens * possible some irrelevant) datasets in the system. We need to both find our
57789Sahrens * limiting subgraph and determine a safe ordering in which to destroy the
58789Sahrens * datasets. We do a topological ordering of our graph starting at our target
59789Sahrens * dataset, and then walk the results in reverse.
60789Sahrens *
612474Seschrock * It's possible for the graph to have cycles if, for example, the user renames
622474Seschrock * a clone to be the parent of its origin snapshot. The user can request to
632474Seschrock * generate an error in this case, or ignore the cycle and continue.
642474Seschrock *
65789Sahrens * When removing datasets, we want to destroy the snapshots in chronological
66789Sahrens * order (because this is the most efficient method). In order to accomplish
67789Sahrens * this, we store the creation transaction group with each vertex and keep each
68789Sahrens * vertex's edges sorted according to this value. The topological sort will
69789Sahrens * automatically walk the snapshots in the correct order.
70789Sahrens */
71789Sahrens
72789Sahrens #include <assert.h>
732474Seschrock #include <libintl.h>
74789Sahrens #include <stdio.h>
75789Sahrens #include <stdlib.h>
76789Sahrens #include <string.h>
77789Sahrens #include <strings.h>
78789Sahrens #include <unistd.h>
79789Sahrens
80789Sahrens #include <libzfs.h>
81789Sahrens
82789Sahrens #include "libzfs_impl.h"
83789Sahrens #include "zfs_namecheck.h"
84789Sahrens
85789Sahrens #define MIN_EDGECOUNT 4
86789Sahrens
87789Sahrens /*
88789Sahrens * Vertex structure. Indexed by dataset name, this structure maintains a list
89789Sahrens * of edges to other vertices.
90789Sahrens */
91789Sahrens struct zfs_edge;
92789Sahrens typedef struct zfs_vertex {
93789Sahrens char zv_dataset[ZFS_MAXNAMELEN];
94789Sahrens struct zfs_vertex *zv_next;
95789Sahrens int zv_visited;
96789Sahrens uint64_t zv_txg;
97789Sahrens struct zfs_edge **zv_edges;
98789Sahrens int zv_edgecount;
99789Sahrens int zv_edgealloc;
100789Sahrens } zfs_vertex_t;
101789Sahrens
1022474Seschrock enum {
1032474Seschrock VISIT_SEEN = 1,
1042474Seschrock VISIT_SORT_PRE,
1052474Seschrock VISIT_SORT_POST
1062474Seschrock };
1072474Seschrock
108789Sahrens /*
109789Sahrens * Edge structure. Simply maintains a pointer to the destination vertex. There
110789Sahrens * is no need to store the source vertex, since we only use edges in the context
111789Sahrens * of the source vertex.
112789Sahrens */
113789Sahrens typedef struct zfs_edge {
114789Sahrens zfs_vertex_t *ze_dest;
115789Sahrens struct zfs_edge *ze_next;
116789Sahrens } zfs_edge_t;
117789Sahrens
118789Sahrens #define ZFS_GRAPH_SIZE 1027 /* this could be dynamic some day */
119789Sahrens
120789Sahrens /*
121789Sahrens * Graph structure. Vertices are maintained in a hash indexed by dataset name.
122789Sahrens */
123789Sahrens typedef struct zfs_graph {
124789Sahrens zfs_vertex_t **zg_hash;
125789Sahrens size_t zg_size;
126789Sahrens size_t zg_nvertex;
1276027Srm160521 const char *zg_root;
1286027Srm160521 int zg_clone_count;
129789Sahrens } zfs_graph_t;
130789Sahrens
131789Sahrens /*
132789Sahrens * Allocate a new edge pointing to the target vertex.
133789Sahrens */
134789Sahrens static zfs_edge_t *
zfs_edge_create(libzfs_handle_t * hdl,zfs_vertex_t * dest)1352082Seschrock zfs_edge_create(libzfs_handle_t *hdl, zfs_vertex_t *dest)
136789Sahrens {
1372082Seschrock zfs_edge_t *zep = zfs_alloc(hdl, sizeof (zfs_edge_t));
1382082Seschrock
1392082Seschrock if (zep == NULL)
1402082Seschrock return (NULL);
141789Sahrens
142789Sahrens zep->ze_dest = dest;
143789Sahrens
144789Sahrens return (zep);
145789Sahrens }
146789Sahrens
147789Sahrens /*
148789Sahrens * Destroy an edge.
149789Sahrens */
150789Sahrens static void
zfs_edge_destroy(zfs_edge_t * zep)151789Sahrens zfs_edge_destroy(zfs_edge_t *zep)
152789Sahrens {
153789Sahrens free(zep);
154789Sahrens }
155789Sahrens
156789Sahrens /*
157789Sahrens * Allocate a new vertex with the given name.
158789Sahrens */
159789Sahrens static zfs_vertex_t *
zfs_vertex_create(libzfs_handle_t * hdl,const char * dataset)1602082Seschrock zfs_vertex_create(libzfs_handle_t *hdl, const char *dataset)
161789Sahrens {
1622082Seschrock zfs_vertex_t *zvp = zfs_alloc(hdl, sizeof (zfs_vertex_t));
1632082Seschrock
1642082Seschrock if (zvp == NULL)
1652082Seschrock return (NULL);
166789Sahrens
167789Sahrens assert(strlen(dataset) < ZFS_MAXNAMELEN);
168789Sahrens
169789Sahrens (void) strlcpy(zvp->zv_dataset, dataset, sizeof (zvp->zv_dataset));
170789Sahrens
1712082Seschrock if ((zvp->zv_edges = zfs_alloc(hdl,
1722082Seschrock MIN_EDGECOUNT * sizeof (void *))) == NULL) {
1732082Seschrock free(zvp);
1742082Seschrock return (NULL);
1752082Seschrock }
1762082Seschrock
177789Sahrens zvp->zv_edgealloc = MIN_EDGECOUNT;
178789Sahrens
179789Sahrens return (zvp);
180789Sahrens }
181789Sahrens
182789Sahrens /*
183789Sahrens * Destroy a vertex. Frees up any associated edges.
184789Sahrens */
185789Sahrens static void
zfs_vertex_destroy(zfs_vertex_t * zvp)186789Sahrens zfs_vertex_destroy(zfs_vertex_t *zvp)
187789Sahrens {
188789Sahrens int i;
189789Sahrens
190789Sahrens for (i = 0; i < zvp->zv_edgecount; i++)
191789Sahrens zfs_edge_destroy(zvp->zv_edges[i]);
192789Sahrens
193789Sahrens free(zvp->zv_edges);
194789Sahrens free(zvp);
195789Sahrens }
196789Sahrens
197789Sahrens /*
198789Sahrens * Given a vertex, add an edge to the destination vertex.
199789Sahrens */
2002082Seschrock static int
zfs_vertex_add_edge(libzfs_handle_t * hdl,zfs_vertex_t * zvp,zfs_vertex_t * dest)2012082Seschrock zfs_vertex_add_edge(libzfs_handle_t *hdl, zfs_vertex_t *zvp,
2022082Seschrock zfs_vertex_t *dest)
203789Sahrens {
2042082Seschrock zfs_edge_t *zep = zfs_edge_create(hdl, dest);
2052082Seschrock
2062082Seschrock if (zep == NULL)
2072082Seschrock return (-1);
208789Sahrens
209789Sahrens if (zvp->zv_edgecount == zvp->zv_edgealloc) {
2102676Seschrock void *ptr;
211789Sahrens
2122676Seschrock if ((ptr = zfs_realloc(hdl, zvp->zv_edges,
2132676Seschrock zvp->zv_edgealloc * sizeof (void *),
2142676Seschrock zvp->zv_edgealloc * 2 * sizeof (void *))) == NULL)
2152082Seschrock return (-1);
2162082Seschrock
2172676Seschrock zvp->zv_edges = ptr;
218789Sahrens zvp->zv_edgealloc *= 2;
219789Sahrens }
220789Sahrens
221789Sahrens zvp->zv_edges[zvp->zv_edgecount++] = zep;
2222082Seschrock
2232082Seschrock return (0);
224789Sahrens }
225789Sahrens
226789Sahrens static int
zfs_edge_compare(const void * a,const void * b)227789Sahrens zfs_edge_compare(const void *a, const void *b)
228789Sahrens {
229789Sahrens const zfs_edge_t *ea = *((zfs_edge_t **)a);
230789Sahrens const zfs_edge_t *eb = *((zfs_edge_t **)b);
231789Sahrens
232789Sahrens if (ea->ze_dest->zv_txg < eb->ze_dest->zv_txg)
233789Sahrens return (-1);
234789Sahrens if (ea->ze_dest->zv_txg > eb->ze_dest->zv_txg)
235789Sahrens return (1);
236789Sahrens return (0);
237789Sahrens }
238789Sahrens
239789Sahrens /*
240789Sahrens * Sort the given vertex edges according to the creation txg of each vertex.
241789Sahrens */
242789Sahrens static void
zfs_vertex_sort_edges(zfs_vertex_t * zvp)243789Sahrens zfs_vertex_sort_edges(zfs_vertex_t *zvp)
244789Sahrens {
245789Sahrens if (zvp->zv_edgecount == 0)
246789Sahrens return;
247789Sahrens
248789Sahrens qsort(zvp->zv_edges, zvp->zv_edgecount, sizeof (void *),
249789Sahrens zfs_edge_compare);
250789Sahrens }
251789Sahrens
252789Sahrens /*
253789Sahrens * Construct a new graph object. We allow the size to be specified as a
254789Sahrens * parameter so in the future we can size the hash according to the number of
255789Sahrens * datasets in the pool.
256789Sahrens */
257789Sahrens static zfs_graph_t *
zfs_graph_create(libzfs_handle_t * hdl,const char * dataset,size_t size)2586027Srm160521 zfs_graph_create(libzfs_handle_t *hdl, const char *dataset, size_t size)
259789Sahrens {
2602082Seschrock zfs_graph_t *zgp = zfs_alloc(hdl, sizeof (zfs_graph_t));
2612082Seschrock
2622082Seschrock if (zgp == NULL)
2632082Seschrock return (NULL);
264789Sahrens
265789Sahrens zgp->zg_size = size;
2662082Seschrock if ((zgp->zg_hash = zfs_alloc(hdl,
2672082Seschrock size * sizeof (zfs_vertex_t *))) == NULL) {
2682082Seschrock free(zgp);
2692082Seschrock return (NULL);
2702082Seschrock }
271789Sahrens
2726027Srm160521 zgp->zg_root = dataset;
2736027Srm160521 zgp->zg_clone_count = 0;
2746027Srm160521
275789Sahrens return (zgp);
276789Sahrens }
277789Sahrens
278789Sahrens /*
279789Sahrens * Destroy a graph object. We have to iterate over all the hash chains,
280789Sahrens * destroying each vertex in the process.
281789Sahrens */
282789Sahrens static void
zfs_graph_destroy(zfs_graph_t * zgp)283789Sahrens zfs_graph_destroy(zfs_graph_t *zgp)
284789Sahrens {
285789Sahrens int i;
286789Sahrens zfs_vertex_t *current, *next;
287789Sahrens
288789Sahrens for (i = 0; i < zgp->zg_size; i++) {
289789Sahrens current = zgp->zg_hash[i];
290789Sahrens while (current != NULL) {
291789Sahrens next = current->zv_next;
292789Sahrens zfs_vertex_destroy(current);
293789Sahrens current = next;
294789Sahrens }
295789Sahrens }
296789Sahrens
297789Sahrens free(zgp->zg_hash);
298789Sahrens free(zgp);
299789Sahrens }
300789Sahrens
301789Sahrens /*
302789Sahrens * Graph hash function. Classic bernstein k=33 hash function, taken from
303789Sahrens * usr/src/cmd/sgs/tools/common/strhash.c
304789Sahrens */
305789Sahrens static size_t
zfs_graph_hash(zfs_graph_t * zgp,const char * str)306789Sahrens zfs_graph_hash(zfs_graph_t *zgp, const char *str)
307789Sahrens {
308789Sahrens size_t hash = 5381;
309789Sahrens int c;
310789Sahrens
311789Sahrens while ((c = *str++) != 0)
312789Sahrens hash = ((hash << 5) + hash) + c; /* hash * 33 + c */
313789Sahrens
314789Sahrens return (hash % zgp->zg_size);
315789Sahrens }
316789Sahrens
317789Sahrens /*
318789Sahrens * Given a dataset name, finds the associated vertex, creating it if necessary.
319789Sahrens */
320789Sahrens static zfs_vertex_t *
zfs_graph_lookup(libzfs_handle_t * hdl,zfs_graph_t * zgp,const char * dataset,uint64_t txg)3212082Seschrock zfs_graph_lookup(libzfs_handle_t *hdl, zfs_graph_t *zgp, const char *dataset,
3222082Seschrock uint64_t txg)
323789Sahrens {
324789Sahrens size_t idx = zfs_graph_hash(zgp, dataset);
325789Sahrens zfs_vertex_t *zvp;
326789Sahrens
327789Sahrens for (zvp = zgp->zg_hash[idx]; zvp != NULL; zvp = zvp->zv_next) {
328789Sahrens if (strcmp(zvp->zv_dataset, dataset) == 0) {
329789Sahrens if (zvp->zv_txg == 0)
330789Sahrens zvp->zv_txg = txg;
331789Sahrens return (zvp);
332789Sahrens }
333789Sahrens }
334789Sahrens
3352082Seschrock if ((zvp = zfs_vertex_create(hdl, dataset)) == NULL)
3362082Seschrock return (NULL);
3372082Seschrock
338789Sahrens zvp->zv_next = zgp->zg_hash[idx];
339789Sahrens zvp->zv_txg = txg;
340789Sahrens zgp->zg_hash[idx] = zvp;
341789Sahrens zgp->zg_nvertex++;
342789Sahrens
343789Sahrens return (zvp);
344789Sahrens }
345789Sahrens
346789Sahrens /*
347789Sahrens * Given two dataset names, create an edge between them. For the source vertex,
348789Sahrens * mark 'zv_visited' to indicate that we have seen this vertex, and not simply
349789Sahrens * created it as a destination of another edge. If 'dest' is NULL, then this
350789Sahrens * is an individual vertex (i.e. the starting vertex), so don't add an edge.
351789Sahrens */
3522082Seschrock static int
zfs_graph_add(libzfs_handle_t * hdl,zfs_graph_t * zgp,const char * source,const char * dest,uint64_t txg)3532082Seschrock zfs_graph_add(libzfs_handle_t *hdl, zfs_graph_t *zgp, const char *source,
3542082Seschrock const char *dest, uint64_t txg)
355789Sahrens {
356789Sahrens zfs_vertex_t *svp, *dvp;
357789Sahrens
3582082Seschrock if ((svp = zfs_graph_lookup(hdl, zgp, source, 0)) == NULL)
3592082Seschrock return (-1);
3602474Seschrock svp->zv_visited = VISIT_SEEN;
361789Sahrens if (dest != NULL) {
3622082Seschrock dvp = zfs_graph_lookup(hdl, zgp, dest, txg);
3632082Seschrock if (dvp == NULL)
3642082Seschrock return (-1);
3652082Seschrock if (zfs_vertex_add_edge(hdl, svp, dvp) != 0)
3662082Seschrock return (-1);
367789Sahrens }
3682082Seschrock
3692082Seschrock return (0);
370789Sahrens }
371789Sahrens
372789Sahrens /*
3736027Srm160521 * Iterate over all children of the given dataset, adding any vertices
3746027Srm160521 * as necessary. Returns -1 if there was an error, or 0 otherwise.
3756027Srm160521 * This is a simple recursive algorithm - the ZFS namespace typically
3766027Srm160521 * is very flat. We manually invoke the necessary ioctl() calls to
3776027Srm160521 * avoid the overhead and additional semantics of zfs_open().
378789Sahrens */
379789Sahrens static int
iterate_children(libzfs_handle_t * hdl,zfs_graph_t * zgp,const char * dataset)3802082Seschrock iterate_children(libzfs_handle_t *hdl, zfs_graph_t *zgp, const char *dataset)
381789Sahrens {
382789Sahrens zfs_cmd_t zc = { 0 };
383789Sahrens zfs_vertex_t *zvp;
384789Sahrens
385789Sahrens /*
386789Sahrens * Look up the source vertex, and avoid it if we've seen it before.
387789Sahrens */
3882082Seschrock zvp = zfs_graph_lookup(hdl, zgp, dataset, 0);
3892082Seschrock if (zvp == NULL)
3902082Seschrock return (-1);
3912474Seschrock if (zvp->zv_visited == VISIT_SEEN)
392789Sahrens return (0);
393789Sahrens
3942474Seschrock /*
3956027Srm160521 * Iterate over all children
3962474Seschrock */
397789Sahrens for ((void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name));
3982082Seschrock ioctl(hdl->libzfs_fd, ZFS_IOC_DATASET_LIST_NEXT, &zc) == 0;
399789Sahrens (void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name))) {
400789Sahrens /*
401789Sahrens * Get statistics for this dataset, to determine the type of the
402789Sahrens * dataset and clone statistics. If this fails, the dataset has
403789Sahrens * since been removed, and we're pretty much screwed anyway.
404789Sahrens */
4056027Srm160521 zc.zc_objset_stats.dds_origin[0] = '\0';
4062082Seschrock if (ioctl(hdl->libzfs_fd, ZFS_IOC_OBJSET_STATS, &zc) != 0)
407789Sahrens continue;
408789Sahrens
4096027Srm160521 if (zc.zc_objset_stats.dds_origin[0] != '\0') {
4106027Srm160521 if (zfs_graph_add(hdl, zgp,
4116027Srm160521 zc.zc_objset_stats.dds_origin, zc.zc_name,
4126027Srm160521 zc.zc_objset_stats.dds_creation_txg) != 0)
4136027Srm160521 return (-1);
4146027Srm160521 /*
4156027Srm160521 * Count origins only if they are contained in the graph
4166027Srm160521 */
4176027Srm160521 if (isa_child_of(zc.zc_objset_stats.dds_origin,
4186027Srm160521 zgp->zg_root))
4196027Srm160521 zgp->zg_clone_count--;
4206027Srm160521 }
4216027Srm160521
422789Sahrens /*
423789Sahrens * Add an edge between the parent and the child.
424789Sahrens */
4252082Seschrock if (zfs_graph_add(hdl, zgp, dataset, zc.zc_name,
4262082Seschrock zc.zc_objset_stats.dds_creation_txg) != 0)
4272082Seschrock return (-1);
428789Sahrens
429789Sahrens /*
4306027Srm160521 * Recursively visit child
431789Sahrens */
4326027Srm160521 if (iterate_children(hdl, zgp, zc.zc_name))
4332082Seschrock return (-1);
434789Sahrens }
435789Sahrens
436789Sahrens /*
437789Sahrens * Now iterate over all snapshots.
438789Sahrens */
439789Sahrens bzero(&zc, sizeof (zc));
440789Sahrens
441789Sahrens for ((void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name));
4422082Seschrock ioctl(hdl->libzfs_fd, ZFS_IOC_SNAPSHOT_LIST_NEXT, &zc) == 0;
443789Sahrens (void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name))) {
444789Sahrens
445789Sahrens /*
446789Sahrens * Get statistics for this dataset, to determine the type of the
447789Sahrens * dataset and clone statistics. If this fails, the dataset has
448789Sahrens * since been removed, and we're pretty much screwed anyway.
449789Sahrens */
4502082Seschrock if (ioctl(hdl->libzfs_fd, ZFS_IOC_OBJSET_STATS, &zc) != 0)
451789Sahrens continue;
452789Sahrens
453789Sahrens /*
454789Sahrens * Add an edge between the parent and the child.
455789Sahrens */
4562082Seschrock if (zfs_graph_add(hdl, zgp, dataset, zc.zc_name,
4572082Seschrock zc.zc_objset_stats.dds_creation_txg) != 0)
4582082Seschrock return (-1);
459789Sahrens
4606027Srm160521 zgp->zg_clone_count += zc.zc_objset_stats.dds_num_clones;
461789Sahrens }
462789Sahrens
4632474Seschrock zvp->zv_visited = VISIT_SEEN;
464789Sahrens
4656027Srm160521 return (0);
466789Sahrens }
467789Sahrens
468789Sahrens /*
4696027Srm160521 * Returns false if there are no snapshots with dependent clones in this
4706027Srm160521 * subtree or if all of those clones are also in this subtree. Returns
4716027Srm160521 * true if there is an error or there are external dependents.
4726027Srm160521 */
4736027Srm160521 static boolean_t
external_dependents(libzfs_handle_t * hdl,zfs_graph_t * zgp,const char * dataset)4746027Srm160521 external_dependents(libzfs_handle_t *hdl, zfs_graph_t *zgp, const char *dataset)
4756027Srm160521 {
4766027Srm160521 zfs_cmd_t zc = { 0 };
4776027Srm160521
4786027Srm160521 /*
4796027Srm160521 * Check whether this dataset is a clone or has clones since
4806027Srm160521 * iterate_children() only checks the children.
4816027Srm160521 */
4826027Srm160521 (void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name));
4836027Srm160521 if (ioctl(hdl->libzfs_fd, ZFS_IOC_OBJSET_STATS, &zc) != 0)
4846027Srm160521 return (B_TRUE);
4856027Srm160521
4866027Srm160521 if (zc.zc_objset_stats.dds_origin[0] != '\0') {
4876027Srm160521 if (zfs_graph_add(hdl, zgp,
4886027Srm160521 zc.zc_objset_stats.dds_origin, zc.zc_name,
4896027Srm160521 zc.zc_objset_stats.dds_creation_txg) != 0)
4906027Srm160521 return (B_TRUE);
4916027Srm160521 if (isa_child_of(zc.zc_objset_stats.dds_origin, dataset))
4926027Srm160521 zgp->zg_clone_count--;
4936027Srm160521 }
4946027Srm160521
4956027Srm160521 if ((zc.zc_objset_stats.dds_num_clones) ||
4966027Srm160521 iterate_children(hdl, zgp, dataset))
4976027Srm160521 return (B_TRUE);
4986027Srm160521
4996027Srm160521 return (zgp->zg_clone_count != 0);
5006027Srm160521 }
5016027Srm160521
5026027Srm160521 /*
5036027Srm160521 * Construct a complete graph of all necessary vertices. First, iterate over
5046027Srm160521 * only our object's children. If no cloned snapshots are found, or all of
5056027Srm160521 * the cloned snapshots are in this subtree then return a graph of the subtree.
5066027Srm160521 * Otherwise, start at the root of the pool and iterate over all datasets.
507789Sahrens */
508789Sahrens static zfs_graph_t *
construct_graph(libzfs_handle_t * hdl,const char * dataset)5092082Seschrock construct_graph(libzfs_handle_t *hdl, const char *dataset)
510789Sahrens {
5116027Srm160521 zfs_graph_t *zgp = zfs_graph_create(hdl, dataset, ZFS_GRAPH_SIZE);
5122082Seschrock int ret = 0;
5132082Seschrock
5142082Seschrock if (zgp == NULL)
5152082Seschrock return (zgp);
516789Sahrens
5176027Srm160521 if ((strchr(dataset, '/') == NULL) ||
5186027Srm160521 (external_dependents(hdl, zgp, dataset))) {
519789Sahrens /*
520789Sahrens * Determine pool name and try again.
521789Sahrens */
5226148Srm160521 int len = strcspn(dataset, "/@") + 1;
5236148Srm160521 char *pool = zfs_alloc(hdl, len);
524789Sahrens
5256148Srm160521 if (pool == NULL) {
5266148Srm160521 zfs_graph_destroy(zgp);
5276148Srm160521 return (NULL);
5286148Srm160521 }
5296148Srm160521 (void) strlcpy(pool, dataset, len);
530789Sahrens
5316148Srm160521 if (iterate_children(hdl, zgp, pool) == -1 ||
5326148Srm160521 zfs_graph_add(hdl, zgp, pool, NULL, 0) != 0) {
533789Sahrens free(pool);
5346148Srm160521 zfs_graph_destroy(zgp);
5356148Srm160521 return (NULL);
536789Sahrens }
5376148Srm160521 free(pool);
538789Sahrens }
5392082Seschrock
5402082Seschrock if (ret == -1 || zfs_graph_add(hdl, zgp, dataset, NULL, 0) != 0) {
5412082Seschrock zfs_graph_destroy(zgp);
5422082Seschrock return (NULL);
5432082Seschrock }
544789Sahrens
545789Sahrens return (zgp);
546789Sahrens }
547789Sahrens
548789Sahrens /*
549789Sahrens * Given a graph, do a recursive topological sort into the given array. This is
550789Sahrens * really just a depth first search, so that the deepest nodes appear first.
551789Sahrens * hijack the 'zv_visited' marker to avoid visiting the same vertex twice.
552789Sahrens */
5532082Seschrock static int
topo_sort(libzfs_handle_t * hdl,boolean_t allowrecursion,char ** result,size_t * idx,zfs_vertex_t * zgv)5542474Seschrock topo_sort(libzfs_handle_t *hdl, boolean_t allowrecursion, char **result,
5552474Seschrock size_t *idx, zfs_vertex_t *zgv)
556789Sahrens {
557789Sahrens int i;
558789Sahrens
5592474Seschrock if (zgv->zv_visited == VISIT_SORT_PRE && !allowrecursion) {
5602474Seschrock /*
5612474Seschrock * If we've already seen this vertex as part of our depth-first
5622474Seschrock * search, then we have a cyclic dependency, and we must return
5632474Seschrock * an error.
5642474Seschrock */
5652474Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
5662474Seschrock "recursive dependency at '%s'"),
5672474Seschrock zgv->zv_dataset);
5682474Seschrock return (zfs_error(hdl, EZFS_RECURSIVE,
5692474Seschrock dgettext(TEXT_DOMAIN,
5702474Seschrock "cannot determine dependent datasets")));
5712474Seschrock } else if (zgv->zv_visited >= VISIT_SORT_PRE) {
5722474Seschrock /*
5732474Seschrock * If we've already processed this as part of the topological
5742474Seschrock * sort, then don't bother doing so again.
5752474Seschrock */
5762474Seschrock return (0);
5772474Seschrock }
5782474Seschrock
5792474Seschrock zgv->zv_visited = VISIT_SORT_PRE;
5802474Seschrock
581789Sahrens /* avoid doing a search if we don't have to */
582789Sahrens zfs_vertex_sort_edges(zgv);
5832082Seschrock for (i = 0; i < zgv->zv_edgecount; i++) {
5842474Seschrock if (topo_sort(hdl, allowrecursion, result, idx,
5852474Seschrock zgv->zv_edges[i]->ze_dest) != 0)
5862082Seschrock return (-1);
5872082Seschrock }
588789Sahrens
589789Sahrens /* we may have visited this in the course of the above */
5902474Seschrock if (zgv->zv_visited == VISIT_SORT_POST)
5912082Seschrock return (0);
592789Sahrens
5932082Seschrock if ((result[*idx] = zfs_alloc(hdl,
5942082Seschrock strlen(zgv->zv_dataset) + 1)) == NULL)
5952082Seschrock return (-1);
5962082Seschrock
597789Sahrens (void) strcpy(result[*idx], zgv->zv_dataset);
598789Sahrens *idx += 1;
5992474Seschrock zgv->zv_visited = VISIT_SORT_POST;
6002082Seschrock return (0);
601789Sahrens }
602789Sahrens
603789Sahrens /*
604789Sahrens * The only public interface for this file. Do the dirty work of constructing a
605789Sahrens * child list for the given object. Construct the graph, do the toplogical
606789Sahrens * sort, and then return the array of strings to the caller.
6072474Seschrock *
6082474Seschrock * The 'allowrecursion' parameter controls behavior when cycles are found. If
6092474Seschrock * it is set, the the cycle is ignored and the results returned as if the cycle
6102474Seschrock * did not exist. If it is not set, then the routine will generate an error if
6112474Seschrock * a cycle is found.
612789Sahrens */
6132474Seschrock int
get_dependents(libzfs_handle_t * hdl,boolean_t allowrecursion,const char * dataset,char *** result,size_t * count)6142474Seschrock get_dependents(libzfs_handle_t *hdl, boolean_t allowrecursion,
6152474Seschrock const char *dataset, char ***result, size_t *count)
616789Sahrens {
617789Sahrens zfs_graph_t *zgp;
618789Sahrens zfs_vertex_t *zvp;
619789Sahrens
6202082Seschrock if ((zgp = construct_graph(hdl, dataset)) == NULL)
6212474Seschrock return (-1);
622789Sahrens
6232474Seschrock if ((*result = zfs_alloc(hdl,
6242082Seschrock zgp->zg_nvertex * sizeof (char *))) == NULL) {
6252082Seschrock zfs_graph_destroy(zgp);
6262474Seschrock return (-1);
6272082Seschrock }
6282082Seschrock
6292082Seschrock if ((zvp = zfs_graph_lookup(hdl, zgp, dataset, 0)) == NULL) {
6302474Seschrock free(*result);
6312082Seschrock zfs_graph_destroy(zgp);
6322474Seschrock return (-1);
6332082Seschrock }
634789Sahrens
635789Sahrens *count = 0;
6362474Seschrock if (topo_sort(hdl, allowrecursion, *result, count, zvp) != 0) {
6372474Seschrock free(*result);
6382082Seschrock zfs_graph_destroy(zgp);
6392474Seschrock return (-1);
6402082Seschrock }
641789Sahrens
642789Sahrens /*
643789Sahrens * Get rid of the last entry, which is our starting vertex and not
644789Sahrens * strictly a dependent.
645789Sahrens */
646789Sahrens assert(*count > 0);
6472474Seschrock free((*result)[*count - 1]);
648789Sahrens (*count)--;
649789Sahrens
650789Sahrens zfs_graph_destroy(zgp);
651789Sahrens
6522474Seschrock return (0);
653789Sahrens }
654