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 * 63*2474Seschrock * It's possible for the graph to have cycles if, for example, the user renames 64*2474Seschrock * a clone to be the parent of its origin snapshot. The user can request to 65*2474Seschrock * generate an error in this case, or ignore the cycle and continue. 66*2474Seschrock * 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> 75*2474Seschrock #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 104*2474Seschrock enum { 105*2474Seschrock VISIT_SEEN = 1, 106*2474Seschrock VISIT_SORT_PRE, 107*2474Seschrock VISIT_SORT_POST 108*2474Seschrock }; 109*2474Seschrock 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) { 2102082Seschrock zfs_edge_t **newedges = zfs_alloc(hdl, zvp->zv_edgealloc * 2 * 211789Sahrens sizeof (void *)); 212789Sahrens 2132082Seschrock if (newedges == NULL) 2142082Seschrock return (-1); 2152082Seschrock 216789Sahrens bcopy(zvp->zv_edges, newedges, 217789Sahrens zvp->zv_edgealloc * sizeof (void *)); 218789Sahrens 219789Sahrens zvp->zv_edgealloc *= 2; 220789Sahrens free(zvp->zv_edges); 221789Sahrens zvp->zv_edges = newedges; 222789Sahrens } 223789Sahrens 224789Sahrens zvp->zv_edges[zvp->zv_edgecount++] = zep; 2252082Seschrock 2262082Seschrock return (0); 227789Sahrens } 228789Sahrens 229789Sahrens static int 230789Sahrens zfs_edge_compare(const void *a, const void *b) 231789Sahrens { 232789Sahrens const zfs_edge_t *ea = *((zfs_edge_t **)a); 233789Sahrens const zfs_edge_t *eb = *((zfs_edge_t **)b); 234789Sahrens 235789Sahrens if (ea->ze_dest->zv_txg < eb->ze_dest->zv_txg) 236789Sahrens return (-1); 237789Sahrens if (ea->ze_dest->zv_txg > eb->ze_dest->zv_txg) 238789Sahrens return (1); 239789Sahrens return (0); 240789Sahrens } 241789Sahrens 242789Sahrens /* 243789Sahrens * Sort the given vertex edges according to the creation txg of each vertex. 244789Sahrens */ 245789Sahrens static void 246789Sahrens zfs_vertex_sort_edges(zfs_vertex_t *zvp) 247789Sahrens { 248789Sahrens if (zvp->zv_edgecount == 0) 249789Sahrens return; 250789Sahrens 251789Sahrens qsort(zvp->zv_edges, zvp->zv_edgecount, sizeof (void *), 252789Sahrens zfs_edge_compare); 253789Sahrens } 254789Sahrens 255789Sahrens /* 256789Sahrens * Construct a new graph object. We allow the size to be specified as a 257789Sahrens * parameter so in the future we can size the hash according to the number of 258789Sahrens * datasets in the pool. 259789Sahrens */ 260789Sahrens static zfs_graph_t * 2612082Seschrock zfs_graph_create(libzfs_handle_t *hdl, size_t size) 262789Sahrens { 2632082Seschrock zfs_graph_t *zgp = zfs_alloc(hdl, sizeof (zfs_graph_t)); 2642082Seschrock 2652082Seschrock if (zgp == NULL) 2662082Seschrock return (NULL); 267789Sahrens 268789Sahrens zgp->zg_size = size; 2692082Seschrock if ((zgp->zg_hash = zfs_alloc(hdl, 2702082Seschrock size * sizeof (zfs_vertex_t *))) == NULL) { 2712082Seschrock free(zgp); 2722082Seschrock return (NULL); 2732082Seschrock } 274789Sahrens 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); 360*2474Seschrock 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 /* 373789Sahrens * Iterate over all children of the given dataset, adding any vertices as 3742082Seschrock * necessary. Returns 0 if no cloned snapshots were seen, -1 if there was an 375*2474Seschrock * error, or 1 otherwise. This is a simple recursive algorithm - the ZFS 376*2474Seschrock * namespace typically is very flat. We manually invoke the necessary ioctl() 377*2474Seschrock * calls to 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 }; 3832082Seschrock int ret = 0, err; 384789Sahrens zfs_vertex_t *zvp; 385789Sahrens 386789Sahrens /* 387789Sahrens * Look up the source vertex, and avoid it if we've seen it before. 388789Sahrens */ 3892082Seschrock zvp = zfs_graph_lookup(hdl, zgp, dataset, 0); 3902082Seschrock if (zvp == NULL) 3912082Seschrock return (-1); 392*2474Seschrock if (zvp->zv_visited == VISIT_SEEN) 393789Sahrens return (0); 394789Sahrens 395*2474Seschrock /* 396*2474Seschrock * We check the clone parent here instead of within the loop, so that if 397*2474Seschrock * the root dataset has been promoted from a clone, we find its parent 398*2474Seschrock * appropriately. 399*2474Seschrock */ 400*2474Seschrock (void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name)); 401*2474Seschrock if (ioctl(hdl->libzfs_fd, ZFS_IOC_OBJSET_STATS, &zc) == 0 && 402*2474Seschrock zc.zc_objset_stats.dds_clone_of[0] != '\0') { 403*2474Seschrock if (zfs_graph_add(hdl, zgp, zc.zc_objset_stats.dds_clone_of, 404*2474Seschrock zc.zc_name, zc.zc_objset_stats.dds_creation_txg) != 0) 405*2474Seschrock return (-1); 406*2474Seschrock } 407*2474Seschrock 408789Sahrens for ((void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name)); 4092082Seschrock ioctl(hdl->libzfs_fd, ZFS_IOC_DATASET_LIST_NEXT, &zc) == 0; 410789Sahrens (void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name))) { 411789Sahrens 412789Sahrens /* 413789Sahrens * Ignore private dataset names. 414789Sahrens */ 415789Sahrens if (dataset_name_hidden(zc.zc_name)) 416789Sahrens continue; 417789Sahrens 418789Sahrens /* 419789Sahrens * Get statistics for this dataset, to determine the type of the 420789Sahrens * dataset and clone statistics. If this fails, the dataset has 421789Sahrens * since been removed, and we're pretty much screwed anyway. 422789Sahrens */ 4232082Seschrock if (ioctl(hdl->libzfs_fd, ZFS_IOC_OBJSET_STATS, &zc) != 0) 424789Sahrens continue; 425789Sahrens 426789Sahrens /* 427789Sahrens * Add an edge between the parent and the child. 428789Sahrens */ 4292082Seschrock if (zfs_graph_add(hdl, zgp, dataset, zc.zc_name, 4302082Seschrock zc.zc_objset_stats.dds_creation_txg) != 0) 4312082Seschrock return (-1); 432789Sahrens 433789Sahrens /* 434789Sahrens * Iterate over all children 435789Sahrens */ 4362082Seschrock err = iterate_children(hdl, zgp, zc.zc_name); 4372082Seschrock if (err == -1) 4382082Seschrock return (-1); 4392082Seschrock else if (err == 1) 4402082Seschrock ret = 1; 441789Sahrens 442789Sahrens /* 443789Sahrens * Indicate if we found a dataset with a non-zero clone count. 444789Sahrens */ 445789Sahrens if (zc.zc_objset_stats.dds_num_clones != 0) 4462082Seschrock ret = 1; 447789Sahrens } 448789Sahrens 449789Sahrens /* 450789Sahrens * Now iterate over all snapshots. 451789Sahrens */ 452789Sahrens bzero(&zc, sizeof (zc)); 453789Sahrens 454789Sahrens for ((void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name)); 4552082Seschrock ioctl(hdl->libzfs_fd, ZFS_IOC_SNAPSHOT_LIST_NEXT, &zc) == 0; 456789Sahrens (void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name))) { 457789Sahrens 458789Sahrens /* 459789Sahrens * Get statistics for this dataset, to determine the type of the 460789Sahrens * dataset and clone statistics. If this fails, the dataset has 461789Sahrens * since been removed, and we're pretty much screwed anyway. 462789Sahrens */ 4632082Seschrock if (ioctl(hdl->libzfs_fd, ZFS_IOC_OBJSET_STATS, &zc) != 0) 464789Sahrens continue; 465789Sahrens 466789Sahrens /* 467789Sahrens * Add an edge between the parent and the child. 468789Sahrens */ 4692082Seschrock if (zfs_graph_add(hdl, zgp, dataset, zc.zc_name, 4702082Seschrock zc.zc_objset_stats.dds_creation_txg) != 0) 4712082Seschrock return (-1); 472789Sahrens 473789Sahrens /* 474789Sahrens * Indicate if we found a dataset with a non-zero clone count. 475789Sahrens */ 476789Sahrens if (zc.zc_objset_stats.dds_num_clones != 0) 4772082Seschrock ret = 1; 478789Sahrens } 479789Sahrens 480*2474Seschrock zvp->zv_visited = VISIT_SEEN; 481789Sahrens 482789Sahrens return (ret); 483789Sahrens } 484789Sahrens 485789Sahrens /* 486789Sahrens * Construct a complete graph of all necessary vertices. First, we iterate over 487789Sahrens * only our object's children. If we don't find any cloned snapshots, then we 488789Sahrens * simple return that. Otherwise, we have to start at the pool root and iterate 489789Sahrens * over all datasets. 490789Sahrens */ 491789Sahrens static zfs_graph_t * 4922082Seschrock construct_graph(libzfs_handle_t *hdl, const char *dataset) 493789Sahrens { 4942082Seschrock zfs_graph_t *zgp = zfs_graph_create(hdl, ZFS_GRAPH_SIZE); 495789Sahrens zfs_cmd_t zc = { 0 }; 4962082Seschrock int ret = 0; 4972082Seschrock 4982082Seschrock if (zgp == NULL) 4992082Seschrock return (zgp); 500789Sahrens 501789Sahrens /* 502789Sahrens * We need to explicitly check whether this dataset has clones or not, 503789Sahrens * since iterate_children() only checks the children. 504789Sahrens */ 505789Sahrens (void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name)); 5062082Seschrock (void) ioctl(hdl->libzfs_fd, ZFS_IOC_OBJSET_STATS, &zc); 507789Sahrens 508789Sahrens if (zc.zc_objset_stats.dds_num_clones != 0 || 5092082Seschrock (ret = iterate_children(hdl, zgp, dataset)) != 0) { 510789Sahrens /* 511789Sahrens * Determine pool name and try again. 512789Sahrens */ 513789Sahrens char *pool, *slash; 514789Sahrens 515789Sahrens if ((slash = strchr(dataset, '/')) != NULL || 516789Sahrens (slash = strchr(dataset, '@')) != NULL) { 5172082Seschrock pool = zfs_alloc(hdl, slash - dataset + 1); 5182082Seschrock if (pool == NULL) { 5192082Seschrock zfs_graph_destroy(zgp); 5202082Seschrock return (NULL); 5212082Seschrock } 522789Sahrens (void) strncpy(pool, dataset, slash - dataset); 523789Sahrens pool[slash - dataset] = '\0'; 524789Sahrens 5252082Seschrock if (iterate_children(hdl, zgp, pool) == -1 || 5262082Seschrock zfs_graph_add(hdl, zgp, pool, NULL, 0) != 0) { 5272082Seschrock free(pool); 5282082Seschrock zfs_graph_destroy(zgp); 5292082Seschrock return (NULL); 5302082Seschrock } 531789Sahrens 532789Sahrens free(pool); 533789Sahrens } 534789Sahrens } 5352082Seschrock 5362082Seschrock if (ret == -1 || zfs_graph_add(hdl, zgp, dataset, NULL, 0) != 0) { 5372082Seschrock zfs_graph_destroy(zgp); 5382082Seschrock return (NULL); 5392082Seschrock } 540789Sahrens 541789Sahrens return (zgp); 542789Sahrens } 543789Sahrens 544789Sahrens /* 545789Sahrens * Given a graph, do a recursive topological sort into the given array. This is 546789Sahrens * really just a depth first search, so that the deepest nodes appear first. 547789Sahrens * hijack the 'zv_visited' marker to avoid visiting the same vertex twice. 548789Sahrens */ 5492082Seschrock static int 550*2474Seschrock topo_sort(libzfs_handle_t *hdl, boolean_t allowrecursion, char **result, 551*2474Seschrock size_t *idx, zfs_vertex_t *zgv) 552789Sahrens { 553789Sahrens int i; 554789Sahrens 555*2474Seschrock if (zgv->zv_visited == VISIT_SORT_PRE && !allowrecursion) { 556*2474Seschrock /* 557*2474Seschrock * If we've already seen this vertex as part of our depth-first 558*2474Seschrock * search, then we have a cyclic dependency, and we must return 559*2474Seschrock * an error. 560*2474Seschrock */ 561*2474Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 562*2474Seschrock "recursive dependency at '%s'"), 563*2474Seschrock zgv->zv_dataset); 564*2474Seschrock return (zfs_error(hdl, EZFS_RECURSIVE, 565*2474Seschrock dgettext(TEXT_DOMAIN, 566*2474Seschrock "cannot determine dependent datasets"))); 567*2474Seschrock } else if (zgv->zv_visited >= VISIT_SORT_PRE) { 568*2474Seschrock /* 569*2474Seschrock * If we've already processed this as part of the topological 570*2474Seschrock * sort, then don't bother doing so again. 571*2474Seschrock */ 572*2474Seschrock return (0); 573*2474Seschrock } 574*2474Seschrock 575*2474Seschrock zgv->zv_visited = VISIT_SORT_PRE; 576*2474Seschrock 577789Sahrens /* avoid doing a search if we don't have to */ 578789Sahrens zfs_vertex_sort_edges(zgv); 5792082Seschrock for (i = 0; i < zgv->zv_edgecount; i++) { 580*2474Seschrock if (topo_sort(hdl, allowrecursion, result, idx, 581*2474Seschrock zgv->zv_edges[i]->ze_dest) != 0) 5822082Seschrock return (-1); 5832082Seschrock } 584789Sahrens 585789Sahrens /* we may have visited this in the course of the above */ 586*2474Seschrock if (zgv->zv_visited == VISIT_SORT_POST) 5872082Seschrock return (0); 588789Sahrens 5892082Seschrock if ((result[*idx] = zfs_alloc(hdl, 5902082Seschrock strlen(zgv->zv_dataset) + 1)) == NULL) 5912082Seschrock return (-1); 5922082Seschrock 593789Sahrens (void) strcpy(result[*idx], zgv->zv_dataset); 594789Sahrens *idx += 1; 595*2474Seschrock zgv->zv_visited = VISIT_SORT_POST; 5962082Seschrock return (0); 597789Sahrens } 598789Sahrens 599789Sahrens /* 600789Sahrens * The only public interface for this file. Do the dirty work of constructing a 601789Sahrens * child list for the given object. Construct the graph, do the toplogical 602789Sahrens * sort, and then return the array of strings to the caller. 603*2474Seschrock * 604*2474Seschrock * The 'allowrecursion' parameter controls behavior when cycles are found. If 605*2474Seschrock * it is set, the the cycle is ignored and the results returned as if the cycle 606*2474Seschrock * did not exist. If it is not set, then the routine will generate an error if 607*2474Seschrock * a cycle is found. 608789Sahrens */ 609*2474Seschrock int 610*2474Seschrock get_dependents(libzfs_handle_t *hdl, boolean_t allowrecursion, 611*2474Seschrock const char *dataset, char ***result, size_t *count) 612789Sahrens { 613789Sahrens zfs_graph_t *zgp; 614789Sahrens zfs_vertex_t *zvp; 615789Sahrens 6162082Seschrock if ((zgp = construct_graph(hdl, dataset)) == NULL) 617*2474Seschrock return (-1); 618789Sahrens 619*2474Seschrock if ((*result = zfs_alloc(hdl, 6202082Seschrock zgp->zg_nvertex * sizeof (char *))) == NULL) { 6212082Seschrock zfs_graph_destroy(zgp); 622*2474Seschrock return (-1); 6232082Seschrock } 6242082Seschrock 6252082Seschrock if ((zvp = zfs_graph_lookup(hdl, zgp, dataset, 0)) == NULL) { 626*2474Seschrock free(*result); 6272082Seschrock zfs_graph_destroy(zgp); 628*2474Seschrock return (-1); 6292082Seschrock } 630789Sahrens 631789Sahrens *count = 0; 632*2474Seschrock if (topo_sort(hdl, allowrecursion, *result, count, zvp) != 0) { 633*2474Seschrock free(*result); 6342082Seschrock zfs_graph_destroy(zgp); 635*2474Seschrock return (-1); 6362082Seschrock } 637789Sahrens 638789Sahrens /* 639789Sahrens * Get rid of the last entry, which is our starting vertex and not 640789Sahrens * strictly a dependent. 641789Sahrens */ 642789Sahrens assert(*count > 0); 643*2474Seschrock free((*result)[*count - 1]); 644789Sahrens (*count)--; 645789Sahrens 646789Sahrens zfs_graph_destroy(zgp); 647789Sahrens 648*2474Seschrock return (0); 649789Sahrens } 650