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 /* 221544Seschrock * Copyright 2006 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; 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) { 210*2676Seschrock void *ptr; 211789Sahrens 212*2676Seschrock if ((ptr = zfs_realloc(hdl, zvp->zv_edges, 213*2676Seschrock zvp->zv_edgealloc * sizeof (void *), 214*2676Seschrock zvp->zv_edgealloc * 2 * sizeof (void *))) == NULL) 2152082Seschrock return (-1); 2162082Seschrock 217*2676Seschrock 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 * 2582082Seschrock zfs_graph_create(libzfs_handle_t *hdl, 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 272789Sahrens return (zgp); 273789Sahrens } 274789Sahrens 275789Sahrens /* 276789Sahrens * Destroy a graph object. We have to iterate over all the hash chains, 277789Sahrens * destroying each vertex in the process. 278789Sahrens */ 279789Sahrens static void 280789Sahrens zfs_graph_destroy(zfs_graph_t *zgp) 281789Sahrens { 282789Sahrens int i; 283789Sahrens zfs_vertex_t *current, *next; 284789Sahrens 285789Sahrens for (i = 0; i < zgp->zg_size; i++) { 286789Sahrens current = zgp->zg_hash[i]; 287789Sahrens while (current != NULL) { 288789Sahrens next = current->zv_next; 289789Sahrens zfs_vertex_destroy(current); 290789Sahrens current = next; 291789Sahrens } 292789Sahrens } 293789Sahrens 294789Sahrens free(zgp->zg_hash); 295789Sahrens free(zgp); 296789Sahrens } 297789Sahrens 298789Sahrens /* 299789Sahrens * Graph hash function. Classic bernstein k=33 hash function, taken from 300789Sahrens * usr/src/cmd/sgs/tools/common/strhash.c 301789Sahrens */ 302789Sahrens static size_t 303789Sahrens zfs_graph_hash(zfs_graph_t *zgp, const char *str) 304789Sahrens { 305789Sahrens size_t hash = 5381; 306789Sahrens int c; 307789Sahrens 308789Sahrens while ((c = *str++) != 0) 309789Sahrens hash = ((hash << 5) + hash) + c; /* hash * 33 + c */ 310789Sahrens 311789Sahrens return (hash % zgp->zg_size); 312789Sahrens } 313789Sahrens 314789Sahrens /* 315789Sahrens * Given a dataset name, finds the associated vertex, creating it if necessary. 316789Sahrens */ 317789Sahrens static zfs_vertex_t * 3182082Seschrock zfs_graph_lookup(libzfs_handle_t *hdl, zfs_graph_t *zgp, const char *dataset, 3192082Seschrock uint64_t txg) 320789Sahrens { 321789Sahrens size_t idx = zfs_graph_hash(zgp, dataset); 322789Sahrens zfs_vertex_t *zvp; 323789Sahrens 324789Sahrens for (zvp = zgp->zg_hash[idx]; zvp != NULL; zvp = zvp->zv_next) { 325789Sahrens if (strcmp(zvp->zv_dataset, dataset) == 0) { 326789Sahrens if (zvp->zv_txg == 0) 327789Sahrens zvp->zv_txg = txg; 328789Sahrens return (zvp); 329789Sahrens } 330789Sahrens } 331789Sahrens 3322082Seschrock if ((zvp = zfs_vertex_create(hdl, dataset)) == NULL) 3332082Seschrock return (NULL); 3342082Seschrock 335789Sahrens zvp->zv_next = zgp->zg_hash[idx]; 336789Sahrens zvp->zv_txg = txg; 337789Sahrens zgp->zg_hash[idx] = zvp; 338789Sahrens zgp->zg_nvertex++; 339789Sahrens 340789Sahrens return (zvp); 341789Sahrens } 342789Sahrens 343789Sahrens /* 344789Sahrens * Given two dataset names, create an edge between them. For the source vertex, 345789Sahrens * mark 'zv_visited' to indicate that we have seen this vertex, and not simply 346789Sahrens * created it as a destination of another edge. If 'dest' is NULL, then this 347789Sahrens * is an individual vertex (i.e. the starting vertex), so don't add an edge. 348789Sahrens */ 3492082Seschrock static int 3502082Seschrock zfs_graph_add(libzfs_handle_t *hdl, zfs_graph_t *zgp, const char *source, 3512082Seschrock const char *dest, uint64_t txg) 352789Sahrens { 353789Sahrens zfs_vertex_t *svp, *dvp; 354789Sahrens 3552082Seschrock if ((svp = zfs_graph_lookup(hdl, zgp, source, 0)) == NULL) 3562082Seschrock return (-1); 3572474Seschrock svp->zv_visited = VISIT_SEEN; 358789Sahrens if (dest != NULL) { 3592082Seschrock dvp = zfs_graph_lookup(hdl, zgp, dest, txg); 3602082Seschrock if (dvp == NULL) 3612082Seschrock return (-1); 3622082Seschrock if (zfs_vertex_add_edge(hdl, svp, dvp) != 0) 3632082Seschrock return (-1); 364789Sahrens } 3652082Seschrock 3662082Seschrock return (0); 367789Sahrens } 368789Sahrens 369789Sahrens /* 370789Sahrens * Iterate over all children of the given dataset, adding any vertices as 3712082Seschrock * necessary. Returns 0 if no cloned snapshots were seen, -1 if there was an 3722474Seschrock * error, or 1 otherwise. This is a simple recursive algorithm - the ZFS 3732474Seschrock * namespace typically is very flat. We manually invoke the necessary ioctl() 3742474Seschrock * calls to avoid the overhead and additional semantics of zfs_open(). 375789Sahrens */ 376789Sahrens static int 3772082Seschrock iterate_children(libzfs_handle_t *hdl, zfs_graph_t *zgp, const char *dataset) 378789Sahrens { 379789Sahrens zfs_cmd_t zc = { 0 }; 3802082Seschrock int ret = 0, err; 381789Sahrens zfs_vertex_t *zvp; 382789Sahrens 383789Sahrens /* 384789Sahrens * Look up the source vertex, and avoid it if we've seen it before. 385789Sahrens */ 3862082Seschrock zvp = zfs_graph_lookup(hdl, zgp, dataset, 0); 3872082Seschrock if (zvp == NULL) 3882082Seschrock return (-1); 3892474Seschrock if (zvp->zv_visited == VISIT_SEEN) 390789Sahrens return (0); 391789Sahrens 3922474Seschrock /* 3932474Seschrock * We check the clone parent here instead of within the loop, so that if 3942474Seschrock * the root dataset has been promoted from a clone, we find its parent 3952474Seschrock * appropriately. 3962474Seschrock */ 3972474Seschrock (void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name)); 3982474Seschrock if (ioctl(hdl->libzfs_fd, ZFS_IOC_OBJSET_STATS, &zc) == 0 && 3992474Seschrock zc.zc_objset_stats.dds_clone_of[0] != '\0') { 4002474Seschrock if (zfs_graph_add(hdl, zgp, zc.zc_objset_stats.dds_clone_of, 4012474Seschrock zc.zc_name, zc.zc_objset_stats.dds_creation_txg) != 0) 4022474Seschrock return (-1); 4032474Seschrock } 4042474Seschrock 405789Sahrens for ((void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name)); 4062082Seschrock ioctl(hdl->libzfs_fd, ZFS_IOC_DATASET_LIST_NEXT, &zc) == 0; 407789Sahrens (void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name))) { 408789Sahrens 409789Sahrens /* 410789Sahrens * Ignore private dataset names. 411789Sahrens */ 412789Sahrens if (dataset_name_hidden(zc.zc_name)) 413789Sahrens continue; 414789Sahrens 415789Sahrens /* 416789Sahrens * Get statistics for this dataset, to determine the type of the 417789Sahrens * dataset and clone statistics. If this fails, the dataset has 418789Sahrens * since been removed, and we're pretty much screwed anyway. 419789Sahrens */ 4202082Seschrock if (ioctl(hdl->libzfs_fd, ZFS_IOC_OBJSET_STATS, &zc) != 0) 421789Sahrens continue; 422789Sahrens 423789Sahrens /* 424789Sahrens * Add an edge between the parent and the child. 425789Sahrens */ 4262082Seschrock if (zfs_graph_add(hdl, zgp, dataset, zc.zc_name, 4272082Seschrock zc.zc_objset_stats.dds_creation_txg) != 0) 4282082Seschrock return (-1); 429789Sahrens 430789Sahrens /* 431789Sahrens * Iterate over all children 432789Sahrens */ 4332082Seschrock err = iterate_children(hdl, zgp, zc.zc_name); 4342082Seschrock if (err == -1) 4352082Seschrock return (-1); 4362082Seschrock else if (err == 1) 4372082Seschrock ret = 1; 438789Sahrens 439789Sahrens /* 440789Sahrens * Indicate if we found a dataset with a non-zero clone count. 441789Sahrens */ 442789Sahrens if (zc.zc_objset_stats.dds_num_clones != 0) 4432082Seschrock ret = 1; 444789Sahrens } 445789Sahrens 446789Sahrens /* 447789Sahrens * Now iterate over all snapshots. 448789Sahrens */ 449789Sahrens bzero(&zc, sizeof (zc)); 450789Sahrens 451789Sahrens for ((void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name)); 4522082Seschrock ioctl(hdl->libzfs_fd, ZFS_IOC_SNAPSHOT_LIST_NEXT, &zc) == 0; 453789Sahrens (void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name))) { 454789Sahrens 455789Sahrens /* 456789Sahrens * Get statistics for this dataset, to determine the type of the 457789Sahrens * dataset and clone statistics. If this fails, the dataset has 458789Sahrens * since been removed, and we're pretty much screwed anyway. 459789Sahrens */ 4602082Seschrock if (ioctl(hdl->libzfs_fd, ZFS_IOC_OBJSET_STATS, &zc) != 0) 461789Sahrens continue; 462789Sahrens 463789Sahrens /* 464789Sahrens * Add an edge between the parent and the child. 465789Sahrens */ 4662082Seschrock if (zfs_graph_add(hdl, zgp, dataset, zc.zc_name, 4672082Seschrock zc.zc_objset_stats.dds_creation_txg) != 0) 4682082Seschrock return (-1); 469789Sahrens 470789Sahrens /* 471789Sahrens * Indicate if we found a dataset with a non-zero clone count. 472789Sahrens */ 473789Sahrens if (zc.zc_objset_stats.dds_num_clones != 0) 4742082Seschrock ret = 1; 475789Sahrens } 476789Sahrens 4772474Seschrock zvp->zv_visited = VISIT_SEEN; 478789Sahrens 479789Sahrens return (ret); 480789Sahrens } 481789Sahrens 482789Sahrens /* 483789Sahrens * Construct a complete graph of all necessary vertices. First, we iterate over 484789Sahrens * only our object's children. If we don't find any cloned snapshots, then we 485789Sahrens * simple return that. Otherwise, we have to start at the pool root and iterate 486789Sahrens * over all datasets. 487789Sahrens */ 488789Sahrens static zfs_graph_t * 4892082Seschrock construct_graph(libzfs_handle_t *hdl, const char *dataset) 490789Sahrens { 4912082Seschrock zfs_graph_t *zgp = zfs_graph_create(hdl, ZFS_GRAPH_SIZE); 492789Sahrens zfs_cmd_t zc = { 0 }; 4932082Seschrock int ret = 0; 4942082Seschrock 4952082Seschrock if (zgp == NULL) 4962082Seschrock return (zgp); 497789Sahrens 498789Sahrens /* 499789Sahrens * We need to explicitly check whether this dataset has clones or not, 500789Sahrens * since iterate_children() only checks the children. 501789Sahrens */ 502789Sahrens (void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name)); 5032082Seschrock (void) ioctl(hdl->libzfs_fd, ZFS_IOC_OBJSET_STATS, &zc); 504789Sahrens 505789Sahrens if (zc.zc_objset_stats.dds_num_clones != 0 || 5062082Seschrock (ret = iterate_children(hdl, zgp, dataset)) != 0) { 507789Sahrens /* 508789Sahrens * Determine pool name and try again. 509789Sahrens */ 510789Sahrens char *pool, *slash; 511789Sahrens 512789Sahrens if ((slash = strchr(dataset, '/')) != NULL || 513789Sahrens (slash = strchr(dataset, '@')) != NULL) { 5142082Seschrock pool = zfs_alloc(hdl, slash - dataset + 1); 5152082Seschrock if (pool == NULL) { 5162082Seschrock zfs_graph_destroy(zgp); 5172082Seschrock return (NULL); 5182082Seschrock } 519789Sahrens (void) strncpy(pool, dataset, slash - dataset); 520789Sahrens pool[slash - dataset] = '\0'; 521789Sahrens 5222082Seschrock if (iterate_children(hdl, zgp, pool) == -1 || 5232082Seschrock zfs_graph_add(hdl, zgp, pool, NULL, 0) != 0) { 5242082Seschrock free(pool); 5252082Seschrock zfs_graph_destroy(zgp); 5262082Seschrock return (NULL); 5272082Seschrock } 528789Sahrens 529789Sahrens free(pool); 530789Sahrens } 531789Sahrens } 5322082Seschrock 5332082Seschrock if (ret == -1 || zfs_graph_add(hdl, zgp, dataset, NULL, 0) != 0) { 5342082Seschrock zfs_graph_destroy(zgp); 5352082Seschrock return (NULL); 5362082Seschrock } 537789Sahrens 538789Sahrens return (zgp); 539789Sahrens } 540789Sahrens 541789Sahrens /* 542789Sahrens * Given a graph, do a recursive topological sort into the given array. This is 543789Sahrens * really just a depth first search, so that the deepest nodes appear first. 544789Sahrens * hijack the 'zv_visited' marker to avoid visiting the same vertex twice. 545789Sahrens */ 5462082Seschrock static int 5472474Seschrock topo_sort(libzfs_handle_t *hdl, boolean_t allowrecursion, char **result, 5482474Seschrock size_t *idx, zfs_vertex_t *zgv) 549789Sahrens { 550789Sahrens int i; 551789Sahrens 5522474Seschrock if (zgv->zv_visited == VISIT_SORT_PRE && !allowrecursion) { 5532474Seschrock /* 5542474Seschrock * If we've already seen this vertex as part of our depth-first 5552474Seschrock * search, then we have a cyclic dependency, and we must return 5562474Seschrock * an error. 5572474Seschrock */ 5582474Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 5592474Seschrock "recursive dependency at '%s'"), 5602474Seschrock zgv->zv_dataset); 5612474Seschrock return (zfs_error(hdl, EZFS_RECURSIVE, 5622474Seschrock dgettext(TEXT_DOMAIN, 5632474Seschrock "cannot determine dependent datasets"))); 5642474Seschrock } else if (zgv->zv_visited >= VISIT_SORT_PRE) { 5652474Seschrock /* 5662474Seschrock * If we've already processed this as part of the topological 5672474Seschrock * sort, then don't bother doing so again. 5682474Seschrock */ 5692474Seschrock return (0); 5702474Seschrock } 5712474Seschrock 5722474Seschrock zgv->zv_visited = VISIT_SORT_PRE; 5732474Seschrock 574789Sahrens /* avoid doing a search if we don't have to */ 575789Sahrens zfs_vertex_sort_edges(zgv); 5762082Seschrock for (i = 0; i < zgv->zv_edgecount; i++) { 5772474Seschrock if (topo_sort(hdl, allowrecursion, result, idx, 5782474Seschrock zgv->zv_edges[i]->ze_dest) != 0) 5792082Seschrock return (-1); 5802082Seschrock } 581789Sahrens 582789Sahrens /* we may have visited this in the course of the above */ 5832474Seschrock if (zgv->zv_visited == VISIT_SORT_POST) 5842082Seschrock return (0); 585789Sahrens 5862082Seschrock if ((result[*idx] = zfs_alloc(hdl, 5872082Seschrock strlen(zgv->zv_dataset) + 1)) == NULL) 5882082Seschrock return (-1); 5892082Seschrock 590789Sahrens (void) strcpy(result[*idx], zgv->zv_dataset); 591789Sahrens *idx += 1; 5922474Seschrock zgv->zv_visited = VISIT_SORT_POST; 5932082Seschrock return (0); 594789Sahrens } 595789Sahrens 596789Sahrens /* 597789Sahrens * The only public interface for this file. Do the dirty work of constructing a 598789Sahrens * child list for the given object. Construct the graph, do the toplogical 599789Sahrens * sort, and then return the array of strings to the caller. 6002474Seschrock * 6012474Seschrock * The 'allowrecursion' parameter controls behavior when cycles are found. If 6022474Seschrock * it is set, the the cycle is ignored and the results returned as if the cycle 6032474Seschrock * did not exist. If it is not set, then the routine will generate an error if 6042474Seschrock * a cycle is found. 605789Sahrens */ 6062474Seschrock int 6072474Seschrock get_dependents(libzfs_handle_t *hdl, boolean_t allowrecursion, 6082474Seschrock const char *dataset, char ***result, size_t *count) 609789Sahrens { 610789Sahrens zfs_graph_t *zgp; 611789Sahrens zfs_vertex_t *zvp; 612789Sahrens 6132082Seschrock if ((zgp = construct_graph(hdl, dataset)) == NULL) 6142474Seschrock return (-1); 615789Sahrens 6162474Seschrock if ((*result = zfs_alloc(hdl, 6172082Seschrock zgp->zg_nvertex * sizeof (char *))) == NULL) { 6182082Seschrock zfs_graph_destroy(zgp); 6192474Seschrock return (-1); 6202082Seschrock } 6212082Seschrock 6222082Seschrock if ((zvp = zfs_graph_lookup(hdl, zgp, dataset, 0)) == NULL) { 6232474Seschrock free(*result); 6242082Seschrock zfs_graph_destroy(zgp); 6252474Seschrock return (-1); 6262082Seschrock } 627789Sahrens 628789Sahrens *count = 0; 6292474Seschrock if (topo_sort(hdl, allowrecursion, *result, count, zvp) != 0) { 6302474Seschrock free(*result); 6312082Seschrock zfs_graph_destroy(zgp); 6322474Seschrock return (-1); 6332082Seschrock } 634789Sahrens 635789Sahrens /* 636789Sahrens * Get rid of the last entry, which is our starting vertex and not 637789Sahrens * strictly a dependent. 638789Sahrens */ 639789Sahrens assert(*count > 0); 6402474Seschrock free((*result)[*count - 1]); 641789Sahrens (*count)--; 642789Sahrens 643789Sahrens zfs_graph_destroy(zgp); 644789Sahrens 6452474Seschrock return (0); 646789Sahrens } 647