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