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 * 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 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 * 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 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 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 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 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 * 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 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 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 * 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 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 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 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 * 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 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 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