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