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 * 63789Sahrens * When removing datasets, we want to destroy the snapshots in chronological 64789Sahrens * order (because this is the most efficient method). In order to accomplish 65789Sahrens * this, we store the creation transaction group with each vertex and keep each 66789Sahrens * vertex's edges sorted according to this value. The topological sort will 67789Sahrens * automatically walk the snapshots in the correct order. 68789Sahrens */ 69789Sahrens 70789Sahrens #include <assert.h> 71789Sahrens #include <stdio.h> 72789Sahrens #include <stdlib.h> 73789Sahrens #include <string.h> 74789Sahrens #include <strings.h> 75789Sahrens #include <unistd.h> 76789Sahrens 77789Sahrens #include <libzfs.h> 78789Sahrens 79789Sahrens #include "libzfs_impl.h" 80789Sahrens #include "zfs_namecheck.h" 81789Sahrens 82789Sahrens #define MIN_EDGECOUNT 4 83789Sahrens 84789Sahrens /* 85789Sahrens * Vertex structure. Indexed by dataset name, this structure maintains a list 86789Sahrens * of edges to other vertices. 87789Sahrens */ 88789Sahrens struct zfs_edge; 89789Sahrens typedef struct zfs_vertex { 90789Sahrens char zv_dataset[ZFS_MAXNAMELEN]; 91789Sahrens struct zfs_vertex *zv_next; 92789Sahrens int zv_visited; 93789Sahrens uint64_t zv_txg; 94789Sahrens struct zfs_edge **zv_edges; 95789Sahrens int zv_edgecount; 96789Sahrens int zv_edgealloc; 97789Sahrens } zfs_vertex_t; 98789Sahrens 99789Sahrens /* 100789Sahrens * Edge structure. Simply maintains a pointer to the destination vertex. There 101789Sahrens * is no need to store the source vertex, since we only use edges in the context 102789Sahrens * of the source vertex. 103789Sahrens */ 104789Sahrens typedef struct zfs_edge { 105789Sahrens zfs_vertex_t *ze_dest; 106789Sahrens struct zfs_edge *ze_next; 107789Sahrens } zfs_edge_t; 108789Sahrens 109789Sahrens #define ZFS_GRAPH_SIZE 1027 /* this could be dynamic some day */ 110789Sahrens 111789Sahrens /* 112789Sahrens * Graph structure. Vertices are maintained in a hash indexed by dataset name. 113789Sahrens */ 114789Sahrens typedef struct zfs_graph { 115789Sahrens zfs_vertex_t **zg_hash; 116789Sahrens size_t zg_size; 117789Sahrens size_t zg_nvertex; 118789Sahrens } zfs_graph_t; 119789Sahrens 120789Sahrens /* 121789Sahrens * Allocate a new edge pointing to the target vertex. 122789Sahrens */ 123789Sahrens static zfs_edge_t * 124*2082Seschrock zfs_edge_create(libzfs_handle_t *hdl, zfs_vertex_t *dest) 125789Sahrens { 126*2082Seschrock zfs_edge_t *zep = zfs_alloc(hdl, sizeof (zfs_edge_t)); 127*2082Seschrock 128*2082Seschrock if (zep == NULL) 129*2082Seschrock return (NULL); 130789Sahrens 131789Sahrens zep->ze_dest = dest; 132789Sahrens 133789Sahrens return (zep); 134789Sahrens } 135789Sahrens 136789Sahrens /* 137789Sahrens * Destroy an edge. 138789Sahrens */ 139789Sahrens static void 140789Sahrens zfs_edge_destroy(zfs_edge_t *zep) 141789Sahrens { 142789Sahrens free(zep); 143789Sahrens } 144789Sahrens 145789Sahrens /* 146789Sahrens * Allocate a new vertex with the given name. 147789Sahrens */ 148789Sahrens static zfs_vertex_t * 149*2082Seschrock zfs_vertex_create(libzfs_handle_t *hdl, const char *dataset) 150789Sahrens { 151*2082Seschrock zfs_vertex_t *zvp = zfs_alloc(hdl, sizeof (zfs_vertex_t)); 152*2082Seschrock 153*2082Seschrock if (zvp == NULL) 154*2082Seschrock return (NULL); 155789Sahrens 156789Sahrens assert(strlen(dataset) < ZFS_MAXNAMELEN); 157789Sahrens 158789Sahrens (void) strlcpy(zvp->zv_dataset, dataset, sizeof (zvp->zv_dataset)); 159789Sahrens 160*2082Seschrock if ((zvp->zv_edges = zfs_alloc(hdl, 161*2082Seschrock MIN_EDGECOUNT * sizeof (void *))) == NULL) { 162*2082Seschrock free(zvp); 163*2082Seschrock return (NULL); 164*2082Seschrock } 165*2082Seschrock 166789Sahrens zvp->zv_edgealloc = MIN_EDGECOUNT; 167789Sahrens 168789Sahrens return (zvp); 169789Sahrens } 170789Sahrens 171789Sahrens /* 172789Sahrens * Destroy a vertex. Frees up any associated edges. 173789Sahrens */ 174789Sahrens static void 175789Sahrens zfs_vertex_destroy(zfs_vertex_t *zvp) 176789Sahrens { 177789Sahrens int i; 178789Sahrens 179789Sahrens for (i = 0; i < zvp->zv_edgecount; i++) 180789Sahrens zfs_edge_destroy(zvp->zv_edges[i]); 181789Sahrens 182789Sahrens free(zvp->zv_edges); 183789Sahrens free(zvp); 184789Sahrens } 185789Sahrens 186789Sahrens /* 187789Sahrens * Given a vertex, add an edge to the destination vertex. 188789Sahrens */ 189*2082Seschrock static int 190*2082Seschrock zfs_vertex_add_edge(libzfs_handle_t *hdl, zfs_vertex_t *zvp, 191*2082Seschrock zfs_vertex_t *dest) 192789Sahrens { 193*2082Seschrock zfs_edge_t *zep = zfs_edge_create(hdl, dest); 194*2082Seschrock 195*2082Seschrock if (zep == NULL) 196*2082Seschrock return (-1); 197789Sahrens 198789Sahrens if (zvp->zv_edgecount == zvp->zv_edgealloc) { 199*2082Seschrock zfs_edge_t **newedges = zfs_alloc(hdl, zvp->zv_edgealloc * 2 * 200789Sahrens sizeof (void *)); 201789Sahrens 202*2082Seschrock if (newedges == NULL) 203*2082Seschrock return (-1); 204*2082Seschrock 205789Sahrens bcopy(zvp->zv_edges, newedges, 206789Sahrens zvp->zv_edgealloc * sizeof (void *)); 207789Sahrens 208789Sahrens zvp->zv_edgealloc *= 2; 209789Sahrens free(zvp->zv_edges); 210789Sahrens zvp->zv_edges = newedges; 211789Sahrens } 212789Sahrens 213789Sahrens zvp->zv_edges[zvp->zv_edgecount++] = zep; 214*2082Seschrock 215*2082Seschrock return (0); 216789Sahrens } 217789Sahrens 218789Sahrens static int 219789Sahrens zfs_edge_compare(const void *a, const void *b) 220789Sahrens { 221789Sahrens const zfs_edge_t *ea = *((zfs_edge_t **)a); 222789Sahrens const zfs_edge_t *eb = *((zfs_edge_t **)b); 223789Sahrens 224789Sahrens if (ea->ze_dest->zv_txg < eb->ze_dest->zv_txg) 225789Sahrens return (-1); 226789Sahrens if (ea->ze_dest->zv_txg > eb->ze_dest->zv_txg) 227789Sahrens return (1); 228789Sahrens return (0); 229789Sahrens } 230789Sahrens 231789Sahrens /* 232789Sahrens * Sort the given vertex edges according to the creation txg of each vertex. 233789Sahrens */ 234789Sahrens static void 235789Sahrens zfs_vertex_sort_edges(zfs_vertex_t *zvp) 236789Sahrens { 237789Sahrens if (zvp->zv_edgecount == 0) 238789Sahrens return; 239789Sahrens 240789Sahrens qsort(zvp->zv_edges, zvp->zv_edgecount, sizeof (void *), 241789Sahrens zfs_edge_compare); 242789Sahrens } 243789Sahrens 244789Sahrens /* 245789Sahrens * Construct a new graph object. We allow the size to be specified as a 246789Sahrens * parameter so in the future we can size the hash according to the number of 247789Sahrens * datasets in the pool. 248789Sahrens */ 249789Sahrens static zfs_graph_t * 250*2082Seschrock zfs_graph_create(libzfs_handle_t *hdl, size_t size) 251789Sahrens { 252*2082Seschrock zfs_graph_t *zgp = zfs_alloc(hdl, sizeof (zfs_graph_t)); 253*2082Seschrock 254*2082Seschrock if (zgp == NULL) 255*2082Seschrock return (NULL); 256789Sahrens 257789Sahrens zgp->zg_size = size; 258*2082Seschrock if ((zgp->zg_hash = zfs_alloc(hdl, 259*2082Seschrock size * sizeof (zfs_vertex_t *))) == NULL) { 260*2082Seschrock free(zgp); 261*2082Seschrock return (NULL); 262*2082Seschrock } 263789Sahrens 264789Sahrens return (zgp); 265789Sahrens } 266789Sahrens 267789Sahrens /* 268789Sahrens * Destroy a graph object. We have to iterate over all the hash chains, 269789Sahrens * destroying each vertex in the process. 270789Sahrens */ 271789Sahrens static void 272789Sahrens zfs_graph_destroy(zfs_graph_t *zgp) 273789Sahrens { 274789Sahrens int i; 275789Sahrens zfs_vertex_t *current, *next; 276789Sahrens 277789Sahrens for (i = 0; i < zgp->zg_size; i++) { 278789Sahrens current = zgp->zg_hash[i]; 279789Sahrens while (current != NULL) { 280789Sahrens next = current->zv_next; 281789Sahrens zfs_vertex_destroy(current); 282789Sahrens current = next; 283789Sahrens } 284789Sahrens } 285789Sahrens 286789Sahrens free(zgp->zg_hash); 287789Sahrens free(zgp); 288789Sahrens } 289789Sahrens 290789Sahrens /* 291789Sahrens * Graph hash function. Classic bernstein k=33 hash function, taken from 292789Sahrens * usr/src/cmd/sgs/tools/common/strhash.c 293789Sahrens */ 294789Sahrens static size_t 295789Sahrens zfs_graph_hash(zfs_graph_t *zgp, const char *str) 296789Sahrens { 297789Sahrens size_t hash = 5381; 298789Sahrens int c; 299789Sahrens 300789Sahrens while ((c = *str++) != 0) 301789Sahrens hash = ((hash << 5) + hash) + c; /* hash * 33 + c */ 302789Sahrens 303789Sahrens return (hash % zgp->zg_size); 304789Sahrens } 305789Sahrens 306789Sahrens /* 307789Sahrens * Given a dataset name, finds the associated vertex, creating it if necessary. 308789Sahrens */ 309789Sahrens static zfs_vertex_t * 310*2082Seschrock zfs_graph_lookup(libzfs_handle_t *hdl, zfs_graph_t *zgp, const char *dataset, 311*2082Seschrock uint64_t txg) 312789Sahrens { 313789Sahrens size_t idx = zfs_graph_hash(zgp, dataset); 314789Sahrens zfs_vertex_t *zvp; 315789Sahrens 316789Sahrens for (zvp = zgp->zg_hash[idx]; zvp != NULL; zvp = zvp->zv_next) { 317789Sahrens if (strcmp(zvp->zv_dataset, dataset) == 0) { 318789Sahrens if (zvp->zv_txg == 0) 319789Sahrens zvp->zv_txg = txg; 320789Sahrens return (zvp); 321789Sahrens } 322789Sahrens } 323789Sahrens 324*2082Seschrock if ((zvp = zfs_vertex_create(hdl, dataset)) == NULL) 325*2082Seschrock return (NULL); 326*2082Seschrock 327789Sahrens zvp->zv_next = zgp->zg_hash[idx]; 328789Sahrens zvp->zv_txg = txg; 329789Sahrens zgp->zg_hash[idx] = zvp; 330789Sahrens zgp->zg_nvertex++; 331789Sahrens 332789Sahrens return (zvp); 333789Sahrens } 334789Sahrens 335789Sahrens /* 336789Sahrens * Given two dataset names, create an edge between them. For the source vertex, 337789Sahrens * mark 'zv_visited' to indicate that we have seen this vertex, and not simply 338789Sahrens * created it as a destination of another edge. If 'dest' is NULL, then this 339789Sahrens * is an individual vertex (i.e. the starting vertex), so don't add an edge. 340789Sahrens */ 341*2082Seschrock static int 342*2082Seschrock zfs_graph_add(libzfs_handle_t *hdl, zfs_graph_t *zgp, const char *source, 343*2082Seschrock const char *dest, uint64_t txg) 344789Sahrens { 345789Sahrens zfs_vertex_t *svp, *dvp; 346789Sahrens 347*2082Seschrock if ((svp = zfs_graph_lookup(hdl, zgp, source, 0)) == NULL) 348*2082Seschrock return (-1); 349789Sahrens svp->zv_visited = 1; 350789Sahrens if (dest != NULL) { 351*2082Seschrock dvp = zfs_graph_lookup(hdl, zgp, dest, txg); 352*2082Seschrock if (dvp == NULL) 353*2082Seschrock return (-1); 354*2082Seschrock if (zfs_vertex_add_edge(hdl, svp, dvp) != 0) 355*2082Seschrock return (-1); 356789Sahrens } 357*2082Seschrock 358*2082Seschrock return (0); 359789Sahrens } 360789Sahrens 361789Sahrens /* 362789Sahrens * Iterate over all children of the given dataset, adding any vertices as 363*2082Seschrock * necessary. Returns 0 if no cloned snapshots were seen, -1 if there was an 364*2082Seschrock * error, or 1 otherwise. This is 365789Sahrens * a simple recursive algorithm - the ZFS namespace typically is very flat. We 366789Sahrens * manually invoke the necessary ioctl() calls to avoid the overhead and 367789Sahrens * additional semantics of zfs_open(). 368789Sahrens */ 369789Sahrens static int 370*2082Seschrock iterate_children(libzfs_handle_t *hdl, zfs_graph_t *zgp, const char *dataset) 371789Sahrens { 372789Sahrens zfs_cmd_t zc = { 0 }; 373*2082Seschrock int ret = 0, err; 374789Sahrens zfs_vertex_t *zvp; 375789Sahrens 376789Sahrens /* 377789Sahrens * Look up the source vertex, and avoid it if we've seen it before. 378789Sahrens */ 379*2082Seschrock zvp = zfs_graph_lookup(hdl, zgp, dataset, 0); 380*2082Seschrock if (zvp == NULL) 381*2082Seschrock return (-1); 382789Sahrens if (zvp->zv_visited) 383789Sahrens return (0); 384789Sahrens 385789Sahrens for ((void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name)); 386*2082Seschrock ioctl(hdl->libzfs_fd, ZFS_IOC_DATASET_LIST_NEXT, &zc) == 0; 387789Sahrens (void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name))) { 388789Sahrens 389789Sahrens /* 390789Sahrens * Ignore private dataset names. 391789Sahrens */ 392789Sahrens if (dataset_name_hidden(zc.zc_name)) 393789Sahrens continue; 394789Sahrens 395789Sahrens /* 396789Sahrens * Get statistics for this dataset, to determine the type of the 397789Sahrens * dataset and clone statistics. If this fails, the dataset has 398789Sahrens * since been removed, and we're pretty much screwed anyway. 399789Sahrens */ 400*2082Seschrock if (ioctl(hdl->libzfs_fd, ZFS_IOC_OBJSET_STATS, &zc) != 0) 401789Sahrens continue; 402789Sahrens 403789Sahrens /* 404789Sahrens * Add an edge between the parent and the child. 405789Sahrens */ 406*2082Seschrock if (zfs_graph_add(hdl, zgp, dataset, zc.zc_name, 407*2082Seschrock zc.zc_objset_stats.dds_creation_txg) != 0) 408*2082Seschrock return (-1); 409789Sahrens 410789Sahrens /* 411789Sahrens * If this dataset has a clone parent, add an appropriate edge. 412789Sahrens */ 413*2082Seschrock if (zc.zc_objset_stats.dds_clone_of[0] != '\0' && 414*2082Seschrock zfs_graph_add(hdl, zgp, zc.zc_objset_stats.dds_clone_of, 415*2082Seschrock zc.zc_name, zc.zc_objset_stats.dds_creation_txg) != 0) 416*2082Seschrock return (-1); 417789Sahrens 418789Sahrens /* 419789Sahrens * Iterate over all children 420789Sahrens */ 421*2082Seschrock err = iterate_children(hdl, zgp, zc.zc_name); 422*2082Seschrock if (err == -1) 423*2082Seschrock return (-1); 424*2082Seschrock else if (err == 1) 425*2082Seschrock ret = 1; 426789Sahrens 427789Sahrens /* 428789Sahrens * Indicate if we found a dataset with a non-zero clone count. 429789Sahrens */ 430789Sahrens if (zc.zc_objset_stats.dds_num_clones != 0) 431*2082Seschrock ret = 1; 432789Sahrens } 433789Sahrens 434789Sahrens /* 435789Sahrens * Now iterate over all snapshots. 436789Sahrens */ 437789Sahrens bzero(&zc, sizeof (zc)); 438789Sahrens 439789Sahrens for ((void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name)); 440*2082Seschrock ioctl(hdl->libzfs_fd, ZFS_IOC_SNAPSHOT_LIST_NEXT, &zc) == 0; 441789Sahrens (void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name))) { 442789Sahrens 443789Sahrens /* 444789Sahrens * Get statistics for this dataset, to determine the type of the 445789Sahrens * dataset and clone statistics. If this fails, the dataset has 446789Sahrens * since been removed, and we're pretty much screwed anyway. 447789Sahrens */ 448*2082Seschrock if (ioctl(hdl->libzfs_fd, ZFS_IOC_OBJSET_STATS, &zc) != 0) 449789Sahrens continue; 450789Sahrens 451789Sahrens /* 452789Sahrens * Add an edge between the parent and the child. 453789Sahrens */ 454*2082Seschrock if (zfs_graph_add(hdl, zgp, dataset, zc.zc_name, 455*2082Seschrock zc.zc_objset_stats.dds_creation_txg) != 0) 456*2082Seschrock return (-1); 457789Sahrens 458789Sahrens /* 459789Sahrens * Indicate if we found a dataset with a non-zero clone count. 460789Sahrens */ 461789Sahrens if (zc.zc_objset_stats.dds_num_clones != 0) 462*2082Seschrock ret = 1; 463789Sahrens } 464789Sahrens 465789Sahrens zvp->zv_visited = 1; 466789Sahrens 467789Sahrens return (ret); 468789Sahrens } 469789Sahrens 470789Sahrens /* 471789Sahrens * Construct a complete graph of all necessary vertices. First, we iterate over 472789Sahrens * only our object's children. If we don't find any cloned snapshots, then we 473789Sahrens * simple return that. Otherwise, we have to start at the pool root and iterate 474789Sahrens * over all datasets. 475789Sahrens */ 476789Sahrens static zfs_graph_t * 477*2082Seschrock construct_graph(libzfs_handle_t *hdl, const char *dataset) 478789Sahrens { 479*2082Seschrock zfs_graph_t *zgp = zfs_graph_create(hdl, ZFS_GRAPH_SIZE); 480789Sahrens zfs_cmd_t zc = { 0 }; 481*2082Seschrock int ret = 0; 482*2082Seschrock 483*2082Seschrock if (zgp == NULL) 484*2082Seschrock return (zgp); 485789Sahrens 486789Sahrens /* 487789Sahrens * We need to explicitly check whether this dataset has clones or not, 488789Sahrens * since iterate_children() only checks the children. 489789Sahrens */ 490789Sahrens (void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name)); 491*2082Seschrock (void) ioctl(hdl->libzfs_fd, ZFS_IOC_OBJSET_STATS, &zc); 492789Sahrens 493789Sahrens if (zc.zc_objset_stats.dds_num_clones != 0 || 494*2082Seschrock (ret = iterate_children(hdl, zgp, dataset)) != 0) { 495789Sahrens /* 496789Sahrens * Determine pool name and try again. 497789Sahrens */ 498789Sahrens char *pool, *slash; 499789Sahrens 500789Sahrens if ((slash = strchr(dataset, '/')) != NULL || 501789Sahrens (slash = strchr(dataset, '@')) != NULL) { 502*2082Seschrock pool = zfs_alloc(hdl, slash - dataset + 1); 503*2082Seschrock if (pool == NULL) { 504*2082Seschrock zfs_graph_destroy(zgp); 505*2082Seschrock return (NULL); 506*2082Seschrock } 507789Sahrens (void) strncpy(pool, dataset, slash - dataset); 508789Sahrens pool[slash - dataset] = '\0'; 509789Sahrens 510*2082Seschrock if (iterate_children(hdl, zgp, pool) == -1 || 511*2082Seschrock zfs_graph_add(hdl, zgp, pool, NULL, 0) != 0) { 512*2082Seschrock free(pool); 513*2082Seschrock zfs_graph_destroy(zgp); 514*2082Seschrock return (NULL); 515*2082Seschrock } 516789Sahrens 517789Sahrens free(pool); 518789Sahrens } 519789Sahrens } 520*2082Seschrock 521*2082Seschrock if (ret == -1 || zfs_graph_add(hdl, zgp, dataset, NULL, 0) != 0) { 522*2082Seschrock zfs_graph_destroy(zgp); 523*2082Seschrock return (NULL); 524*2082Seschrock } 525789Sahrens 526789Sahrens return (zgp); 527789Sahrens } 528789Sahrens 529789Sahrens /* 530789Sahrens * Given a graph, do a recursive topological sort into the given array. This is 531789Sahrens * really just a depth first search, so that the deepest nodes appear first. 532789Sahrens * hijack the 'zv_visited' marker to avoid visiting the same vertex twice. 533789Sahrens */ 534*2082Seschrock static int 535*2082Seschrock topo_sort(libzfs_handle_t *hdl, char **result, size_t *idx, zfs_vertex_t *zgv) 536789Sahrens { 537789Sahrens int i; 538789Sahrens 539789Sahrens /* avoid doing a search if we don't have to */ 540789Sahrens if (zgv->zv_visited == 2) 541*2082Seschrock return (0); 542789Sahrens 543789Sahrens zfs_vertex_sort_edges(zgv); 544*2082Seschrock for (i = 0; i < zgv->zv_edgecount; i++) { 545*2082Seschrock if (topo_sort(hdl, result, idx, zgv->zv_edges[i]->ze_dest) != 0) 546*2082Seschrock return (-1); 547*2082Seschrock } 548789Sahrens 549789Sahrens /* we may have visited this in the course of the above */ 550789Sahrens if (zgv->zv_visited == 2) 551*2082Seschrock return (0); 552789Sahrens 553*2082Seschrock if ((result[*idx] = zfs_alloc(hdl, 554*2082Seschrock strlen(zgv->zv_dataset) + 1)) == NULL) 555*2082Seschrock return (-1); 556*2082Seschrock 557789Sahrens (void) strcpy(result[*idx], zgv->zv_dataset); 558789Sahrens *idx += 1; 559789Sahrens zgv->zv_visited = 2; 560*2082Seschrock return (0); 561789Sahrens } 562789Sahrens 563789Sahrens /* 564789Sahrens * The only public interface for this file. Do the dirty work of constructing a 565789Sahrens * child list for the given object. Construct the graph, do the toplogical 566789Sahrens * sort, and then return the array of strings to the caller. 567789Sahrens */ 568789Sahrens char ** 569*2082Seschrock get_dependents(libzfs_handle_t *hdl, const char *dataset, size_t *count) 570789Sahrens { 571789Sahrens char **result; 572789Sahrens zfs_graph_t *zgp; 573789Sahrens zfs_vertex_t *zvp; 574789Sahrens 575*2082Seschrock if ((zgp = construct_graph(hdl, dataset)) == NULL) 576*2082Seschrock return (NULL); 577789Sahrens 578*2082Seschrock if ((result = zfs_alloc(hdl, 579*2082Seschrock zgp->zg_nvertex * sizeof (char *))) == NULL) { 580*2082Seschrock zfs_graph_destroy(zgp); 581*2082Seschrock return (NULL); 582*2082Seschrock } 583*2082Seschrock 584*2082Seschrock if ((zvp = zfs_graph_lookup(hdl, zgp, dataset, 0)) == NULL) { 585*2082Seschrock free(result); 586*2082Seschrock zfs_graph_destroy(zgp); 587*2082Seschrock return (NULL); 588*2082Seschrock } 589789Sahrens 590789Sahrens *count = 0; 591*2082Seschrock if (topo_sort(hdl, result, count, zvp) != 0) { 592*2082Seschrock free(result); 593*2082Seschrock zfs_graph_destroy(zgp); 594*2082Seschrock return (NULL); 595*2082Seschrock } 596789Sahrens 597789Sahrens /* 598789Sahrens * Get rid of the last entry, which is our starting vertex and not 599789Sahrens * strictly a dependent. 600789Sahrens */ 601789Sahrens assert(*count > 0); 602789Sahrens free(result[*count - 1]); 603789Sahrens (*count)--; 604789Sahrens 605789Sahrens zfs_graph_destroy(zgp); 606789Sahrens 607789Sahrens return (result); 608789Sahrens } 609