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*6027Srm160521 * 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; 129*6027Srm160521 const char *zg_root; 130*6027Srm160521 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 * 260*6027Srm160521 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 274*6027Srm160521 zgp->zg_root = dataset; 275*6027Srm160521 zgp->zg_clone_count = 0; 276*6027Srm160521 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 /* 375*6027Srm160521 * Iterate over all children of the given dataset, adding any vertices 376*6027Srm160521 * as necessary. Returns -1 if there was an error, or 0 otherwise. 377*6027Srm160521 * This is a simple recursive algorithm - the ZFS namespace typically 378*6027Srm160521 * is very flat. We manually invoke the necessary ioctl() calls to 379*6027Srm160521 * 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 /* 397*6027Srm160521 * 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 */ 414*6027Srm160521 zc.zc_objset_stats.dds_origin[0] = '\0'; 4152082Seschrock if (ioctl(hdl->libzfs_fd, ZFS_IOC_OBJSET_STATS, &zc) != 0) 416789Sahrens continue; 417789Sahrens 418*6027Srm160521 if (zc.zc_objset_stats.dds_origin[0] != '\0') { 419*6027Srm160521 if (zfs_graph_add(hdl, zgp, 420*6027Srm160521 zc.zc_objset_stats.dds_origin, zc.zc_name, 421*6027Srm160521 zc.zc_objset_stats.dds_creation_txg) != 0) 422*6027Srm160521 return (-1); 423*6027Srm160521 /* 424*6027Srm160521 * Count origins only if they are contained in the graph 425*6027Srm160521 */ 426*6027Srm160521 if (isa_child_of(zc.zc_objset_stats.dds_origin, 427*6027Srm160521 zgp->zg_root)) 428*6027Srm160521 zgp->zg_clone_count--; 429*6027Srm160521 } 430*6027Srm160521 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 /* 439*6027Srm160521 * Recursively visit child 440789Sahrens */ 441*6027Srm160521 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 469*6027Srm160521 zgp->zg_clone_count += zc.zc_objset_stats.dds_num_clones; 470789Sahrens } 471789Sahrens 4722474Seschrock zvp->zv_visited = VISIT_SEEN; 473789Sahrens 474*6027Srm160521 return (0); 475789Sahrens } 476789Sahrens 477789Sahrens /* 478*6027Srm160521 * Returns false if there are no snapshots with dependent clones in this 479*6027Srm160521 * subtree or if all of those clones are also in this subtree. Returns 480*6027Srm160521 * true if there is an error or there are external dependents. 481*6027Srm160521 */ 482*6027Srm160521 static boolean_t 483*6027Srm160521 external_dependents(libzfs_handle_t *hdl, zfs_graph_t *zgp, const char *dataset) 484*6027Srm160521 { 485*6027Srm160521 zfs_cmd_t zc = { 0 }; 486*6027Srm160521 487*6027Srm160521 /* 488*6027Srm160521 * Check whether this dataset is a clone or has clones since 489*6027Srm160521 * iterate_children() only checks the children. 490*6027Srm160521 */ 491*6027Srm160521 (void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name)); 492*6027Srm160521 if (ioctl(hdl->libzfs_fd, ZFS_IOC_OBJSET_STATS, &zc) != 0) 493*6027Srm160521 return (B_TRUE); 494*6027Srm160521 495*6027Srm160521 if (zc.zc_objset_stats.dds_origin[0] != '\0') { 496*6027Srm160521 if (zfs_graph_add(hdl, zgp, 497*6027Srm160521 zc.zc_objset_stats.dds_origin, zc.zc_name, 498*6027Srm160521 zc.zc_objset_stats.dds_creation_txg) != 0) 499*6027Srm160521 return (B_TRUE); 500*6027Srm160521 if (isa_child_of(zc.zc_objset_stats.dds_origin, dataset)) 501*6027Srm160521 zgp->zg_clone_count--; 502*6027Srm160521 } 503*6027Srm160521 504*6027Srm160521 if ((zc.zc_objset_stats.dds_num_clones) || 505*6027Srm160521 iterate_children(hdl, zgp, dataset)) 506*6027Srm160521 return (B_TRUE); 507*6027Srm160521 508*6027Srm160521 return (zgp->zg_clone_count != 0); 509*6027Srm160521 } 510*6027Srm160521 511*6027Srm160521 /* 512*6027Srm160521 * Construct a complete graph of all necessary vertices. First, iterate over 513*6027Srm160521 * only our object's children. If no cloned snapshots are found, or all of 514*6027Srm160521 * the cloned snapshots are in this subtree then return a graph of the subtree. 515*6027Srm160521 * 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 { 520*6027Srm160521 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 526*6027Srm160521 if ((strchr(dataset, '/') == NULL) || 527*6027Srm160521 (external_dependents(hdl, zgp, dataset))) { 528789Sahrens /* 529789Sahrens * Determine pool name and try again. 530789Sahrens */ 531789Sahrens char *pool, *slash; 532789Sahrens 533789Sahrens if ((slash = strchr(dataset, '/')) != NULL || 534789Sahrens (slash = strchr(dataset, '@')) != NULL) { 5352082Seschrock pool = zfs_alloc(hdl, slash - dataset + 1); 5362082Seschrock if (pool == NULL) { 5372082Seschrock zfs_graph_destroy(zgp); 5382082Seschrock return (NULL); 5392082Seschrock } 540789Sahrens (void) strncpy(pool, dataset, slash - dataset); 541789Sahrens pool[slash - dataset] = '\0'; 542789Sahrens 5432082Seschrock if (iterate_children(hdl, zgp, pool) == -1 || 5442082Seschrock zfs_graph_add(hdl, zgp, pool, NULL, 0) != 0) { 5452082Seschrock free(pool); 5462082Seschrock zfs_graph_destroy(zgp); 5472082Seschrock return (NULL); 5482082Seschrock } 549789Sahrens 550789Sahrens free(pool); 551789Sahrens } 552789Sahrens } 5532082Seschrock 5542082Seschrock if (ret == -1 || zfs_graph_add(hdl, zgp, dataset, NULL, 0) != 0) { 5552082Seschrock zfs_graph_destroy(zgp); 5562082Seschrock return (NULL); 5572082Seschrock } 558789Sahrens 559789Sahrens return (zgp); 560789Sahrens } 561789Sahrens 562789Sahrens /* 563789Sahrens * Given a graph, do a recursive topological sort into the given array. This is 564789Sahrens * really just a depth first search, so that the deepest nodes appear first. 565789Sahrens * hijack the 'zv_visited' marker to avoid visiting the same vertex twice. 566789Sahrens */ 5672082Seschrock static int 5682474Seschrock topo_sort(libzfs_handle_t *hdl, boolean_t allowrecursion, char **result, 5692474Seschrock size_t *idx, zfs_vertex_t *zgv) 570789Sahrens { 571789Sahrens int i; 572789Sahrens 5732474Seschrock if (zgv->zv_visited == VISIT_SORT_PRE && !allowrecursion) { 5742474Seschrock /* 5752474Seschrock * If we've already seen this vertex as part of our depth-first 5762474Seschrock * search, then we have a cyclic dependency, and we must return 5772474Seschrock * an error. 5782474Seschrock */ 5792474Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 5802474Seschrock "recursive dependency at '%s'"), 5812474Seschrock zgv->zv_dataset); 5822474Seschrock return (zfs_error(hdl, EZFS_RECURSIVE, 5832474Seschrock dgettext(TEXT_DOMAIN, 5842474Seschrock "cannot determine dependent datasets"))); 5852474Seschrock } else if (zgv->zv_visited >= VISIT_SORT_PRE) { 5862474Seschrock /* 5872474Seschrock * If we've already processed this as part of the topological 5882474Seschrock * sort, then don't bother doing so again. 5892474Seschrock */ 5902474Seschrock return (0); 5912474Seschrock } 5922474Seschrock 5932474Seschrock zgv->zv_visited = VISIT_SORT_PRE; 5942474Seschrock 595789Sahrens /* avoid doing a search if we don't have to */ 596789Sahrens zfs_vertex_sort_edges(zgv); 5972082Seschrock for (i = 0; i < zgv->zv_edgecount; i++) { 5982474Seschrock if (topo_sort(hdl, allowrecursion, result, idx, 5992474Seschrock zgv->zv_edges[i]->ze_dest) != 0) 6002082Seschrock return (-1); 6012082Seschrock } 602789Sahrens 603789Sahrens /* we may have visited this in the course of the above */ 6042474Seschrock if (zgv->zv_visited == VISIT_SORT_POST) 6052082Seschrock return (0); 606789Sahrens 6072082Seschrock if ((result[*idx] = zfs_alloc(hdl, 6082082Seschrock strlen(zgv->zv_dataset) + 1)) == NULL) 6092082Seschrock return (-1); 6102082Seschrock 611789Sahrens (void) strcpy(result[*idx], zgv->zv_dataset); 612789Sahrens *idx += 1; 6132474Seschrock zgv->zv_visited = VISIT_SORT_POST; 6142082Seschrock return (0); 615789Sahrens } 616789Sahrens 617789Sahrens /* 618789Sahrens * The only public interface for this file. Do the dirty work of constructing a 619789Sahrens * child list for the given object. Construct the graph, do the toplogical 620789Sahrens * sort, and then return the array of strings to the caller. 6212474Seschrock * 6222474Seschrock * The 'allowrecursion' parameter controls behavior when cycles are found. If 6232474Seschrock * it is set, the the cycle is ignored and the results returned as if the cycle 6242474Seschrock * did not exist. If it is not set, then the routine will generate an error if 6252474Seschrock * a cycle is found. 626789Sahrens */ 6272474Seschrock int 6282474Seschrock get_dependents(libzfs_handle_t *hdl, boolean_t allowrecursion, 6292474Seschrock const char *dataset, char ***result, size_t *count) 630789Sahrens { 631789Sahrens zfs_graph_t *zgp; 632789Sahrens zfs_vertex_t *zvp; 633789Sahrens 6342082Seschrock if ((zgp = construct_graph(hdl, dataset)) == NULL) 6352474Seschrock return (-1); 636789Sahrens 6372474Seschrock if ((*result = zfs_alloc(hdl, 6382082Seschrock zgp->zg_nvertex * sizeof (char *))) == NULL) { 6392082Seschrock zfs_graph_destroy(zgp); 6402474Seschrock return (-1); 6412082Seschrock } 6422082Seschrock 6432082Seschrock if ((zvp = zfs_graph_lookup(hdl, zgp, dataset, 0)) == NULL) { 6442474Seschrock free(*result); 6452082Seschrock zfs_graph_destroy(zgp); 6462474Seschrock return (-1); 6472082Seschrock } 648789Sahrens 649789Sahrens *count = 0; 6502474Seschrock if (topo_sort(hdl, allowrecursion, *result, count, zvp) != 0) { 6512474Seschrock free(*result); 6522082Seschrock zfs_graph_destroy(zgp); 6532474Seschrock return (-1); 6542082Seschrock } 655789Sahrens 656789Sahrens /* 657789Sahrens * Get rid of the last entry, which is our starting vertex and not 658789Sahrens * strictly a dependent. 659789Sahrens */ 660789Sahrens assert(*count > 0); 6612474Seschrock free((*result)[*count - 1]); 662789Sahrens (*count)--; 663789Sahrens 664789Sahrens zfs_graph_destroy(zgp); 665789Sahrens 6662474Seschrock return (0); 667789Sahrens } 668