usr/src/lib/libzfs/common/libzfs_graph.c
author rm160521
Fri, 15 Feb 2008 19:55:15 -0800
changeset 6027 68b03551f113
parent 5367 c40abbe796be
child 6148 1bbb9d6c89cb
permissions -rw-r--r--
6609196 'zfs destroy -r' can needlessly iterate over all filesystems in pool 6612830 zpool import shouldn't slowly iterate over all filesystems
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
789
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
     1
/*
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
     2
 * CDDL HEADER START
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
     3
 *
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
     4
 * The contents of this file are subject to the terms of the
1544
938876158511 PSARC 2006/077 zpool clear
eschrock
parents: 789
diff changeset
     5
 * Common Development and Distribution License (the "License").
938876158511 PSARC 2006/077 zpool clear
eschrock
parents: 789
diff changeset
     6
 * You may not use this file except in compliance with the License.
789
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
     7
 *
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
     8
 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
     9
 * or http://www.opensolaris.org/os/licensing.
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
    10
 * See the License for the specific language governing permissions
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
    11
 * and limitations under the License.
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
    12
 *
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
    13
 * When distributing Covered Code, include this CDDL HEADER in each
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
    14
 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
    15
 * If applicable, add the following below this CDDL HEADER, with the
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
    16
 * fields enclosed by brackets "[]" replaced with your own identifying
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
    17
 * information: Portions Copyright [yyyy] [name of copyright owner]
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
    18
 *
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
    19
 * CDDL HEADER END
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
    20
 */
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
    21
/*
6027
68b03551f113 6609196 'zfs destroy -r' can needlessly iterate over all filesystems in pool
rm160521
parents: 5367
diff changeset
    22
 * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
789
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
    23
 * Use is subject to license terms.
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
    24
 */
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
    25
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
    26
#pragma ident	"%Z%%M%	%I%	%E% SMI"
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
    27
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
    28
/*
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
    29
 * Iterate over all children of the current object.  This includes the normal
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
    30
 * dataset hierarchy, but also arbitrary hierarchies due to clones.  We want to
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
    31
 * walk all datasets in the pool, and construct a directed graph of the form:
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
    32
 *
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
    33
 * 			home
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
    34
 *                        |
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
    35
 *                   +----+----+
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
    36
 *                   |         |
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
    37
 *                   v         v             ws
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
    38
 *                  bar       baz             |
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
    39
 *                             |              |
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
    40
 *                             v              v
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
    41
 *                          @yesterday ----> foo
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
    42
 *
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
    43
 * In order to construct this graph, we have to walk every dataset in the pool,
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
    44
 * because the clone parent is stored as a property of the child, not the
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
    45
 * parent.  The parent only keeps track of the number of clones.
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
    46
 *
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
    47
 * In the normal case (without clones) this would be rather expensive.  To avoid
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
    48
 * unnecessary computation, we first try a walk of the subtree hierarchy
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
    49
 * starting from the initial node.  At each dataset, we construct a node in the
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
    50
 * graph and an edge leading from its parent.  If we don't see any snapshots
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
    51
 * with a non-zero clone count, then we are finished.
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
    52
 *
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
    53
 * If we do find a cloned snapshot, then we finish the walk of the current
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
    54
 * subtree, but indicate that we need to do a complete walk.  We then perform a
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
    55
 * global walk of all datasets, avoiding the subtree we already processed.
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
    56
 *
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
    57
 * At the end of this, we'll end up with a directed graph of all relevant (and
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
    58
 * possible some irrelevant) datasets in the system.  We need to both find our
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
    59
 * limiting subgraph and determine a safe ordering in which to destroy the
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
    60
 * datasets.  We do a topological ordering of our graph starting at our target
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
    61
 * dataset, and then walk the results in reverse.
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
    62
 *
2474
c001ad7e0c25 6368751 libzfs interface for mount/umounting all the file systems for a given pool
eschrock
parents: 2082
diff changeset
    63
 * It's possible for the graph to have cycles if, for example, the user renames
c001ad7e0c25 6368751 libzfs interface for mount/umounting all the file systems for a given pool
eschrock
parents: 2082
diff changeset
    64
 * a clone to be the parent of its origin snapshot.  The user can request to
c001ad7e0c25 6368751 libzfs interface for mount/umounting all the file systems for a given pool
eschrock
parents: 2082
diff changeset
    65
 * generate an error in this case, or ignore the cycle and continue.
c001ad7e0c25 6368751 libzfs interface for mount/umounting all the file systems for a given pool
eschrock
parents: 2082
diff changeset
    66
 *
789
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
    67
 * When removing datasets, we want to destroy the snapshots in chronological
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
    68
 * order (because this is the most efficient method).  In order to accomplish
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
    69
 * this, we store the creation transaction group with each vertex and keep each
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
    70
 * vertex's edges sorted according to this value.  The topological sort will
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
    71
 * automatically walk the snapshots in the correct order.
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
    72
 */
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
    73
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
    74
#include <assert.h>
2474
c001ad7e0c25 6368751 libzfs interface for mount/umounting all the file systems for a given pool
eschrock
parents: 2082
diff changeset
    75
#include <libintl.h>
789
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
    76
#include <stdio.h>
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
    77
#include <stdlib.h>
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
    78
#include <string.h>
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
    79
#include <strings.h>
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
    80
#include <unistd.h>
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
    81
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
    82
#include <libzfs.h>
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
    83
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
    84
#include "libzfs_impl.h"
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
    85
#include "zfs_namecheck.h"
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
    86
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
    87
#define	MIN_EDGECOUNT	4
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
    88
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
    89
/*
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
    90
 * Vertex structure.  Indexed by dataset name, this structure maintains a list
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
    91
 * of edges to other vertices.
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
    92
 */
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
    93
struct zfs_edge;
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
    94
typedef struct zfs_vertex {
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
    95
	char			zv_dataset[ZFS_MAXNAMELEN];
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
    96
	struct zfs_vertex	*zv_next;
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
    97
	int			zv_visited;
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
    98
	uint64_t		zv_txg;
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
    99
	struct zfs_edge		**zv_edges;
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   100
	int			zv_edgecount;
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   101
	int			zv_edgealloc;
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   102
} zfs_vertex_t;
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   103
2474
c001ad7e0c25 6368751 libzfs interface for mount/umounting all the file systems for a given pool
eschrock
parents: 2082
diff changeset
   104
enum {
c001ad7e0c25 6368751 libzfs interface for mount/umounting all the file systems for a given pool
eschrock
parents: 2082
diff changeset
   105
	VISIT_SEEN = 1,
c001ad7e0c25 6368751 libzfs interface for mount/umounting all the file systems for a given pool
eschrock
parents: 2082
diff changeset
   106
	VISIT_SORT_PRE,
c001ad7e0c25 6368751 libzfs interface for mount/umounting all the file systems for a given pool
eschrock
parents: 2082
diff changeset
   107
	VISIT_SORT_POST
c001ad7e0c25 6368751 libzfs interface for mount/umounting all the file systems for a given pool
eschrock
parents: 2082
diff changeset
   108
};
c001ad7e0c25 6368751 libzfs interface for mount/umounting all the file systems for a given pool
eschrock
parents: 2082
diff changeset
   109
789
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   110
/*
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   111
 * Edge structure.  Simply maintains a pointer to the destination vertex.  There
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   112
 * is no need to store the source vertex, since we only use edges in the context
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   113
 * of the source vertex.
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   114
 */
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   115
typedef struct zfs_edge {
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   116
	zfs_vertex_t		*ze_dest;
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   117
	struct zfs_edge		*ze_next;
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   118
} zfs_edge_t;
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   119
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   120
#define	ZFS_GRAPH_SIZE		1027	/* this could be dynamic some day */
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   121
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   122
/*
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   123
 * Graph structure.  Vertices are maintained in a hash indexed by dataset name.
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   124
 */
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   125
typedef struct zfs_graph {
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   126
	zfs_vertex_t		**zg_hash;
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   127
	size_t			zg_size;
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   128
	size_t			zg_nvertex;
6027
68b03551f113 6609196 'zfs destroy -r' can needlessly iterate over all filesystems in pool
rm160521
parents: 5367
diff changeset
   129
	const char		*zg_root;
68b03551f113 6609196 'zfs destroy -r' can needlessly iterate over all filesystems in pool
rm160521
parents: 5367
diff changeset
   130
	int			zg_clone_count;
789
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   131
} zfs_graph_t;
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   132
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   133
/*
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   134
 * Allocate a new edge pointing to the target vertex.
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   135
 */
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   136
static zfs_edge_t *
2082
76b439ec3ac1 PSARC 2006/223 ZFS Hot Spares
eschrock
parents: 1544
diff changeset
   137
zfs_edge_create(libzfs_handle_t *hdl, zfs_vertex_t *dest)
789
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   138
{
2082
76b439ec3ac1 PSARC 2006/223 ZFS Hot Spares
eschrock
parents: 1544
diff changeset
   139
	zfs_edge_t *zep = zfs_alloc(hdl, sizeof (zfs_edge_t));
76b439ec3ac1 PSARC 2006/223 ZFS Hot Spares
eschrock
parents: 1544
diff changeset
   140
76b439ec3ac1 PSARC 2006/223 ZFS Hot Spares
eschrock
parents: 1544
diff changeset
   141
	if (zep == NULL)
76b439ec3ac1 PSARC 2006/223 ZFS Hot Spares
eschrock
parents: 1544
diff changeset
   142
		return (NULL);
789
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   143
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   144
	zep->ze_dest = dest;
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   145
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   146
	return (zep);
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   147
}
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   148
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   149
/*
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   150
 * Destroy an edge.
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   151
 */
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   152
static void
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   153
zfs_edge_destroy(zfs_edge_t *zep)
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   154
{
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   155
	free(zep);
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   156
}
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   157
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   158
/*
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   159
 * Allocate a new vertex with the given name.
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   160
 */
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   161
static zfs_vertex_t *
2082
76b439ec3ac1 PSARC 2006/223 ZFS Hot Spares
eschrock
parents: 1544
diff changeset
   162
zfs_vertex_create(libzfs_handle_t *hdl, const char *dataset)
789
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   163
{
2082
76b439ec3ac1 PSARC 2006/223 ZFS Hot Spares
eschrock
parents: 1544
diff changeset
   164
	zfs_vertex_t *zvp = zfs_alloc(hdl, sizeof (zfs_vertex_t));
76b439ec3ac1 PSARC 2006/223 ZFS Hot Spares
eschrock
parents: 1544
diff changeset
   165
76b439ec3ac1 PSARC 2006/223 ZFS Hot Spares
eschrock
parents: 1544
diff changeset
   166
	if (zvp == NULL)
76b439ec3ac1 PSARC 2006/223 ZFS Hot Spares
eschrock
parents: 1544
diff changeset
   167
		return (NULL);
789
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   168
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   169
	assert(strlen(dataset) < ZFS_MAXNAMELEN);
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   170
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   171
	(void) strlcpy(zvp->zv_dataset, dataset, sizeof (zvp->zv_dataset));
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   172
2082
76b439ec3ac1 PSARC 2006/223 ZFS Hot Spares
eschrock
parents: 1544
diff changeset
   173
	if ((zvp->zv_edges = zfs_alloc(hdl,
76b439ec3ac1 PSARC 2006/223 ZFS Hot Spares
eschrock
parents: 1544
diff changeset
   174
	    MIN_EDGECOUNT * sizeof (void *))) == NULL) {
76b439ec3ac1 PSARC 2006/223 ZFS Hot Spares
eschrock
parents: 1544
diff changeset
   175
		free(zvp);
76b439ec3ac1 PSARC 2006/223 ZFS Hot Spares
eschrock
parents: 1544
diff changeset
   176
		return (NULL);
76b439ec3ac1 PSARC 2006/223 ZFS Hot Spares
eschrock
parents: 1544
diff changeset
   177
	}
76b439ec3ac1 PSARC 2006/223 ZFS Hot Spares
eschrock
parents: 1544
diff changeset
   178
789
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   179
	zvp->zv_edgealloc = MIN_EDGECOUNT;
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   180
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   181
	return (zvp);
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   182
}
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   183
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   184
/*
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   185
 * Destroy a vertex.  Frees up any associated edges.
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   186
 */
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   187
static void
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   188
zfs_vertex_destroy(zfs_vertex_t *zvp)
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   189
{
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   190
	int i;
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   191
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   192
	for (i = 0; i < zvp->zv_edgecount; i++)
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   193
		zfs_edge_destroy(zvp->zv_edges[i]);
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   194
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   195
	free(zvp->zv_edges);
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   196
	free(zvp);
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   197
}
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   198
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   199
/*
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   200
 * Given a vertex, add an edge to the destination vertex.
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   201
 */
2082
76b439ec3ac1 PSARC 2006/223 ZFS Hot Spares
eschrock
parents: 1544
diff changeset
   202
static int
76b439ec3ac1 PSARC 2006/223 ZFS Hot Spares
eschrock
parents: 1544
diff changeset
   203
zfs_vertex_add_edge(libzfs_handle_t *hdl, zfs_vertex_t *zvp,
76b439ec3ac1 PSARC 2006/223 ZFS Hot Spares
eschrock
parents: 1544
diff changeset
   204
    zfs_vertex_t *dest)
789
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   205
{
2082
76b439ec3ac1 PSARC 2006/223 ZFS Hot Spares
eschrock
parents: 1544
diff changeset
   206
	zfs_edge_t *zep = zfs_edge_create(hdl, dest);
76b439ec3ac1 PSARC 2006/223 ZFS Hot Spares
eschrock
parents: 1544
diff changeset
   207
76b439ec3ac1 PSARC 2006/223 ZFS Hot Spares
eschrock
parents: 1544
diff changeset
   208
	if (zep == NULL)
76b439ec3ac1 PSARC 2006/223 ZFS Hot Spares
eschrock
parents: 1544
diff changeset
   209
		return (-1);
789
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   210
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   211
	if (zvp->zv_edgecount == zvp->zv_edgealloc) {
2676
5cee47eddab6 PSARC 2006/486 ZFS canmount property
eschrock
parents: 2474
diff changeset
   212
		void *ptr;
789
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   213
2676
5cee47eddab6 PSARC 2006/486 ZFS canmount property
eschrock
parents: 2474
diff changeset
   214
		if ((ptr = zfs_realloc(hdl, zvp->zv_edges,
5cee47eddab6 PSARC 2006/486 ZFS canmount property
eschrock
parents: 2474
diff changeset
   215
		    zvp->zv_edgealloc * sizeof (void *),
5cee47eddab6 PSARC 2006/486 ZFS canmount property
eschrock
parents: 2474
diff changeset
   216
		    zvp->zv_edgealloc * 2 * sizeof (void *))) == NULL)
2082
76b439ec3ac1 PSARC 2006/223 ZFS Hot Spares
eschrock
parents: 1544
diff changeset
   217
			return (-1);
76b439ec3ac1 PSARC 2006/223 ZFS Hot Spares
eschrock
parents: 1544
diff changeset
   218
2676
5cee47eddab6 PSARC 2006/486 ZFS canmount property
eschrock
parents: 2474
diff changeset
   219
		zvp->zv_edges = ptr;
789
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   220
		zvp->zv_edgealloc *= 2;
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   221
	}
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   222
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   223
	zvp->zv_edges[zvp->zv_edgecount++] = zep;
2082
76b439ec3ac1 PSARC 2006/223 ZFS Hot Spares
eschrock
parents: 1544
diff changeset
   224
76b439ec3ac1 PSARC 2006/223 ZFS Hot Spares
eschrock
parents: 1544
diff changeset
   225
	return (0);
789
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   226
}
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   227
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   228
static int
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   229
zfs_edge_compare(const void *a, const void *b)
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   230
{
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   231
	const zfs_edge_t *ea = *((zfs_edge_t **)a);
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   232
	const zfs_edge_t *eb = *((zfs_edge_t **)b);
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   233
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   234
	if (ea->ze_dest->zv_txg < eb->ze_dest->zv_txg)
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   235
		return (-1);
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   236
	if (ea->ze_dest->zv_txg > eb->ze_dest->zv_txg)
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   237
		return (1);
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   238
	return (0);
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   239
}
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   240
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   241
/*
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   242
 * Sort the given vertex edges according to the creation txg of each vertex.
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   243
 */
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   244
static void
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   245
zfs_vertex_sort_edges(zfs_vertex_t *zvp)
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   246
{
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   247
	if (zvp->zv_edgecount == 0)
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   248
		return;
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   249
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   250
	qsort(zvp->zv_edges, zvp->zv_edgecount, sizeof (void *),
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   251
	    zfs_edge_compare);
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   252
}
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   253
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   254
/*
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   255
 * Construct a new graph object.  We allow the size to be specified as a
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   256
 * parameter so in the future we can size the hash according to the number of
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   257
 * datasets in the pool.
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   258
 */
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   259
static zfs_graph_t *
6027
68b03551f113 6609196 'zfs destroy -r' can needlessly iterate over all filesystems in pool
rm160521
parents: 5367
diff changeset
   260
zfs_graph_create(libzfs_handle_t *hdl, const char *dataset, size_t size)
789
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   261
{
2082
76b439ec3ac1 PSARC 2006/223 ZFS Hot Spares
eschrock
parents: 1544
diff changeset
   262
	zfs_graph_t *zgp = zfs_alloc(hdl, sizeof (zfs_graph_t));
76b439ec3ac1 PSARC 2006/223 ZFS Hot Spares
eschrock
parents: 1544
diff changeset
   263
76b439ec3ac1 PSARC 2006/223 ZFS Hot Spares
eschrock
parents: 1544
diff changeset
   264
	if (zgp == NULL)
76b439ec3ac1 PSARC 2006/223 ZFS Hot Spares
eschrock
parents: 1544
diff changeset
   265
		return (NULL);
789
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   266
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   267
	zgp->zg_size = size;
2082
76b439ec3ac1 PSARC 2006/223 ZFS Hot Spares
eschrock
parents: 1544
diff changeset
   268
	if ((zgp->zg_hash = zfs_alloc(hdl,
76b439ec3ac1 PSARC 2006/223 ZFS Hot Spares
eschrock
parents: 1544
diff changeset
   269
	    size * sizeof (zfs_vertex_t *))) == NULL) {
76b439ec3ac1 PSARC 2006/223 ZFS Hot Spares
eschrock
parents: 1544
diff changeset
   270
		free(zgp);
76b439ec3ac1 PSARC 2006/223 ZFS Hot Spares
eschrock
parents: 1544
diff changeset
   271
		return (NULL);
76b439ec3ac1 PSARC 2006/223 ZFS Hot Spares
eschrock
parents: 1544
diff changeset
   272
	}
789
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   273
6027
68b03551f113 6609196 'zfs destroy -r' can needlessly iterate over all filesystems in pool
rm160521
parents: 5367
diff changeset
   274
	zgp->zg_root = dataset;
68b03551f113 6609196 'zfs destroy -r' can needlessly iterate over all filesystems in pool
rm160521
parents: 5367
diff changeset
   275
	zgp->zg_clone_count = 0;
68b03551f113 6609196 'zfs destroy -r' can needlessly iterate over all filesystems in pool
rm160521
parents: 5367
diff changeset
   276
789
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   277
	return (zgp);
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   278
}
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   279
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   280
/*
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   281
 * Destroy a graph object.  We have to iterate over all the hash chains,
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   282
 * destroying each vertex in the process.
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   283
 */
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   284
static void
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   285
zfs_graph_destroy(zfs_graph_t *zgp)
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   286
{
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   287
	int i;
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   288
	zfs_vertex_t *current, *next;
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   289
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   290
	for (i = 0; i < zgp->zg_size; i++) {
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   291
		current = zgp->zg_hash[i];
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   292
		while (current != NULL) {
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   293
			next = current->zv_next;
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   294
			zfs_vertex_destroy(current);
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   295
			current = next;
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   296
		}
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   297
	}
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   298
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   299
	free(zgp->zg_hash);
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   300
	free(zgp);
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   301
}
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   302
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   303
/*
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   304
 * Graph hash function.  Classic bernstein k=33 hash function, taken from
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   305
 * usr/src/cmd/sgs/tools/common/strhash.c
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   306
 */
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   307
static size_t
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   308
zfs_graph_hash(zfs_graph_t *zgp, const char *str)
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   309
{
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   310
	size_t hash = 5381;
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   311
	int c;
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   312
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   313
	while ((c = *str++) != 0)
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   314
		hash = ((hash << 5) + hash) + c; /* hash * 33 + c */
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   315
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   316
	return (hash % zgp->zg_size);
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   317
}
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   318
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   319
/*
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   320
 * Given a dataset name, finds the associated vertex, creating it if necessary.
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   321
 */
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   322
static zfs_vertex_t *
2082
76b439ec3ac1 PSARC 2006/223 ZFS Hot Spares
eschrock
parents: 1544
diff changeset
   323
zfs_graph_lookup(libzfs_handle_t *hdl, zfs_graph_t *zgp, const char *dataset,
76b439ec3ac1 PSARC 2006/223 ZFS Hot Spares
eschrock
parents: 1544
diff changeset
   324
    uint64_t txg)
789
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   325
{
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   326
	size_t idx = zfs_graph_hash(zgp, dataset);
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   327
	zfs_vertex_t *zvp;
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   328
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   329
	for (zvp = zgp->zg_hash[idx]; zvp != NULL; zvp = zvp->zv_next) {
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   330
		if (strcmp(zvp->zv_dataset, dataset) == 0) {
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   331
			if (zvp->zv_txg == 0)
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   332
				zvp->zv_txg = txg;
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   333
			return (zvp);
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   334
		}
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   335
	}
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   336
2082
76b439ec3ac1 PSARC 2006/223 ZFS Hot Spares
eschrock
parents: 1544
diff changeset
   337
	if ((zvp = zfs_vertex_create(hdl, dataset)) == NULL)
76b439ec3ac1 PSARC 2006/223 ZFS Hot Spares
eschrock
parents: 1544
diff changeset
   338
		return (NULL);
76b439ec3ac1 PSARC 2006/223 ZFS Hot Spares
eschrock
parents: 1544
diff changeset
   339
789
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   340
	zvp->zv_next = zgp->zg_hash[idx];
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   341
	zvp->zv_txg = txg;
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   342
	zgp->zg_hash[idx] = zvp;
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   343
	zgp->zg_nvertex++;
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   344
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   345
	return (zvp);
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   346
}
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   347
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   348
/*
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   349
 * Given two dataset names, create an edge between them.  For the source vertex,
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   350
 * mark 'zv_visited' to indicate that we have seen this vertex, and not simply
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   351
 * created it as a destination of another edge.  If 'dest' is NULL, then this
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   352
 * is an individual vertex (i.e. the starting vertex), so don't add an edge.
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   353
 */
2082
76b439ec3ac1 PSARC 2006/223 ZFS Hot Spares
eschrock
parents: 1544
diff changeset
   354
static int
76b439ec3ac1 PSARC 2006/223 ZFS Hot Spares
eschrock
parents: 1544
diff changeset
   355
zfs_graph_add(libzfs_handle_t *hdl, zfs_graph_t *zgp, const char *source,
76b439ec3ac1 PSARC 2006/223 ZFS Hot Spares
eschrock
parents: 1544
diff changeset
   356
    const char *dest, uint64_t txg)
789
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   357
{
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   358
	zfs_vertex_t *svp, *dvp;
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   359
2082
76b439ec3ac1 PSARC 2006/223 ZFS Hot Spares
eschrock
parents: 1544
diff changeset
   360
	if ((svp = zfs_graph_lookup(hdl, zgp, source, 0)) == NULL)
76b439ec3ac1 PSARC 2006/223 ZFS Hot Spares
eschrock
parents: 1544
diff changeset
   361
		return (-1);
2474
c001ad7e0c25 6368751 libzfs interface for mount/umounting all the file systems for a given pool
eschrock
parents: 2082
diff changeset
   362
	svp->zv_visited = VISIT_SEEN;
789
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   363
	if (dest != NULL) {
2082
76b439ec3ac1 PSARC 2006/223 ZFS Hot Spares
eschrock
parents: 1544
diff changeset
   364
		dvp = zfs_graph_lookup(hdl, zgp, dest, txg);
76b439ec3ac1 PSARC 2006/223 ZFS Hot Spares
eschrock
parents: 1544
diff changeset
   365
		if (dvp == NULL)
76b439ec3ac1 PSARC 2006/223 ZFS Hot Spares
eschrock
parents: 1544
diff changeset
   366
			return (-1);
76b439ec3ac1 PSARC 2006/223 ZFS Hot Spares
eschrock
parents: 1544
diff changeset
   367
		if (zfs_vertex_add_edge(hdl, svp, dvp) != 0)
76b439ec3ac1 PSARC 2006/223 ZFS Hot Spares
eschrock
parents: 1544
diff changeset
   368
			return (-1);
789
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   369
	}
2082
76b439ec3ac1 PSARC 2006/223 ZFS Hot Spares
eschrock
parents: 1544
diff changeset
   370
76b439ec3ac1 PSARC 2006/223 ZFS Hot Spares
eschrock
parents: 1544
diff changeset
   371
	return (0);
789
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   372
}
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   373
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   374
/*
6027
68b03551f113 6609196 'zfs destroy -r' can needlessly iterate over all filesystems in pool
rm160521
parents: 5367
diff changeset
   375
 * Iterate over all children of the given dataset, adding any vertices
68b03551f113 6609196 'zfs destroy -r' can needlessly iterate over all filesystems in pool
rm160521
parents: 5367
diff changeset
   376
 * as necessary.  Returns -1 if there was an error, or 0 otherwise.
68b03551f113 6609196 'zfs destroy -r' can needlessly iterate over all filesystems in pool
rm160521
parents: 5367
diff changeset
   377
 * This is a simple recursive algorithm - the ZFS namespace typically
68b03551f113 6609196 'zfs destroy -r' can needlessly iterate over all filesystems in pool
rm160521
parents: 5367
diff changeset
   378
 * is very flat.  We manually invoke the necessary ioctl() calls to
68b03551f113 6609196 'zfs destroy -r' can needlessly iterate over all filesystems in pool
rm160521
parents: 5367
diff changeset
   379
 * avoid the overhead and additional semantics of zfs_open().
789
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   380
 */
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   381
static int
2082
76b439ec3ac1 PSARC 2006/223 ZFS Hot Spares
eschrock
parents: 1544
diff changeset
   382
iterate_children(libzfs_handle_t *hdl, zfs_graph_t *zgp, const char *dataset)
789
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   383
{
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   384
	zfs_cmd_t zc = { 0 };
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   385
	zfs_vertex_t *zvp;
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   386
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   387
	/*
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   388
	 * Look up the source vertex, and avoid it if we've seen it before.
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   389
	 */
2082
76b439ec3ac1 PSARC 2006/223 ZFS Hot Spares
eschrock
parents: 1544
diff changeset
   390
	zvp = zfs_graph_lookup(hdl, zgp, dataset, 0);
76b439ec3ac1 PSARC 2006/223 ZFS Hot Spares
eschrock
parents: 1544
diff changeset
   391
	if (zvp == NULL)
76b439ec3ac1 PSARC 2006/223 ZFS Hot Spares
eschrock
parents: 1544
diff changeset
   392
		return (-1);
2474
c001ad7e0c25 6368751 libzfs interface for mount/umounting all the file systems for a given pool
eschrock
parents: 2082
diff changeset
   393
	if (zvp->zv_visited == VISIT_SEEN)
789
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   394
		return (0);
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   395
2474
c001ad7e0c25 6368751 libzfs interface for mount/umounting all the file systems for a given pool
eschrock
parents: 2082
diff changeset
   396
	/*
6027
68b03551f113 6609196 'zfs destroy -r' can needlessly iterate over all filesystems in pool
rm160521
parents: 5367
diff changeset
   397
	 * Iterate over all children
2474
c001ad7e0c25 6368751 libzfs interface for mount/umounting all the file systems for a given pool
eschrock
parents: 2082
diff changeset
   398
	 */
789
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   399
	for ((void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name));
2082
76b439ec3ac1 PSARC 2006/223 ZFS Hot Spares
eschrock
parents: 1544
diff changeset
   400
	    ioctl(hdl->libzfs_fd, ZFS_IOC_DATASET_LIST_NEXT, &zc) == 0;
789
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   401
	    (void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name))) {
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   402
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   403
		/*
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   404
		 * Ignore private dataset names.
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   405
		 */
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   406
		if (dataset_name_hidden(zc.zc_name))
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   407
			continue;
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   408
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   409
		/*
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   410
		 * Get statistics for this dataset, to determine the type of the
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   411
		 * dataset and clone statistics.  If this fails, the dataset has
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   412
		 * since been removed, and we're pretty much screwed anyway.
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   413
		 */
6027
68b03551f113 6609196 'zfs destroy -r' can needlessly iterate over all filesystems in pool
rm160521
parents: 5367
diff changeset
   414
		zc.zc_objset_stats.dds_origin[0] = '\0';
2082
76b439ec3ac1 PSARC 2006/223 ZFS Hot Spares
eschrock
parents: 1544
diff changeset
   415
		if (ioctl(hdl->libzfs_fd, ZFS_IOC_OBJSET_STATS, &zc) != 0)
789
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   416
			continue;
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   417
6027
68b03551f113 6609196 'zfs destroy -r' can needlessly iterate over all filesystems in pool
rm160521
parents: 5367
diff changeset
   418
		if (zc.zc_objset_stats.dds_origin[0] != '\0') {
68b03551f113 6609196 'zfs destroy -r' can needlessly iterate over all filesystems in pool
rm160521
parents: 5367
diff changeset
   419
			if (zfs_graph_add(hdl, zgp,
68b03551f113 6609196 'zfs destroy -r' can needlessly iterate over all filesystems in pool
rm160521
parents: 5367
diff changeset
   420
			    zc.zc_objset_stats.dds_origin, zc.zc_name,
68b03551f113 6609196 'zfs destroy -r' can needlessly iterate over all filesystems in pool
rm160521
parents: 5367
diff changeset
   421
			    zc.zc_objset_stats.dds_creation_txg) != 0)
68b03551f113 6609196 'zfs destroy -r' can needlessly iterate over all filesystems in pool
rm160521
parents: 5367
diff changeset
   422
				return (-1);
68b03551f113 6609196 'zfs destroy -r' can needlessly iterate over all filesystems in pool
rm160521
parents: 5367
diff changeset
   423
			/*
68b03551f113 6609196 'zfs destroy -r' can needlessly iterate over all filesystems in pool
rm160521
parents: 5367
diff changeset
   424
			 * Count origins only if they are contained in the graph
68b03551f113 6609196 'zfs destroy -r' can needlessly iterate over all filesystems in pool
rm160521
parents: 5367
diff changeset
   425
			 */
68b03551f113 6609196 'zfs destroy -r' can needlessly iterate over all filesystems in pool
rm160521
parents: 5367
diff changeset
   426
			if (isa_child_of(zc.zc_objset_stats.dds_origin,
68b03551f113 6609196 'zfs destroy -r' can needlessly iterate over all filesystems in pool
rm160521
parents: 5367
diff changeset
   427
			    zgp->zg_root))
68b03551f113 6609196 'zfs destroy -r' can needlessly iterate over all filesystems in pool
rm160521
parents: 5367
diff changeset
   428
				zgp->zg_clone_count--;
68b03551f113 6609196 'zfs destroy -r' can needlessly iterate over all filesystems in pool
rm160521
parents: 5367
diff changeset
   429
		}
68b03551f113 6609196 'zfs destroy -r' can needlessly iterate over all filesystems in pool
rm160521
parents: 5367
diff changeset
   430
789
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   431
		/*
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   432
		 * Add an edge between the parent and the child.
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   433
		 */
2082
76b439ec3ac1 PSARC 2006/223 ZFS Hot Spares
eschrock
parents: 1544
diff changeset
   434
		if (zfs_graph_add(hdl, zgp, dataset, zc.zc_name,
76b439ec3ac1 PSARC 2006/223 ZFS Hot Spares
eschrock
parents: 1544
diff changeset
   435
		    zc.zc_objset_stats.dds_creation_txg) != 0)
76b439ec3ac1 PSARC 2006/223 ZFS Hot Spares
eschrock
parents: 1544
diff changeset
   436
			return (-1);
789
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   437
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   438
		/*
6027
68b03551f113 6609196 'zfs destroy -r' can needlessly iterate over all filesystems in pool
rm160521
parents: 5367
diff changeset
   439
		 * Recursively visit child
789
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   440
		 */
6027
68b03551f113 6609196 'zfs destroy -r' can needlessly iterate over all filesystems in pool
rm160521
parents: 5367
diff changeset
   441
		if (iterate_children(hdl, zgp, zc.zc_name))
2082
76b439ec3ac1 PSARC 2006/223 ZFS Hot Spares
eschrock
parents: 1544
diff changeset
   442
			return (-1);
789
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   443
	}
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   444
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   445
	/*
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   446
	 * Now iterate over all snapshots.
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   447
	 */
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   448
	bzero(&zc, sizeof (zc));
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   449
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   450
	for ((void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name));
2082
76b439ec3ac1 PSARC 2006/223 ZFS Hot Spares
eschrock
parents: 1544
diff changeset
   451
	    ioctl(hdl->libzfs_fd, ZFS_IOC_SNAPSHOT_LIST_NEXT, &zc) == 0;
789
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   452
	    (void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name))) {
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   453
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   454
		/*
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   455
		 * Get statistics for this dataset, to determine the type of the
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   456
		 * dataset and clone statistics.  If this fails, the dataset has
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   457
		 * since been removed, and we're pretty much screwed anyway.
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   458
		 */
2082
76b439ec3ac1 PSARC 2006/223 ZFS Hot Spares
eschrock
parents: 1544
diff changeset
   459
		if (ioctl(hdl->libzfs_fd, ZFS_IOC_OBJSET_STATS, &zc) != 0)
789
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   460
			continue;
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   461
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   462
		/*
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   463
		 * Add an edge between the parent and the child.
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   464
		 */
2082
76b439ec3ac1 PSARC 2006/223 ZFS Hot Spares
eschrock
parents: 1544
diff changeset
   465
		if (zfs_graph_add(hdl, zgp, dataset, zc.zc_name,
76b439ec3ac1 PSARC 2006/223 ZFS Hot Spares
eschrock
parents: 1544
diff changeset
   466
		    zc.zc_objset_stats.dds_creation_txg) != 0)
76b439ec3ac1 PSARC 2006/223 ZFS Hot Spares
eschrock
parents: 1544
diff changeset
   467
			return (-1);
789
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   468
6027
68b03551f113 6609196 'zfs destroy -r' can needlessly iterate over all filesystems in pool
rm160521
parents: 5367
diff changeset
   469
		zgp->zg_clone_count += zc.zc_objset_stats.dds_num_clones;
789
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   470
	}
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   471
2474
c001ad7e0c25 6368751 libzfs interface for mount/umounting all the file systems for a given pool
eschrock
parents: 2082
diff changeset
   472
	zvp->zv_visited = VISIT_SEEN;
789
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   473
6027
68b03551f113 6609196 'zfs destroy -r' can needlessly iterate over all filesystems in pool
rm160521
parents: 5367
diff changeset
   474
	return (0);
789
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   475
}
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   476
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   477
/*
6027
68b03551f113 6609196 'zfs destroy -r' can needlessly iterate over all filesystems in pool
rm160521
parents: 5367
diff changeset
   478
 * Returns false if there are no snapshots with dependent clones in this
68b03551f113 6609196 'zfs destroy -r' can needlessly iterate over all filesystems in pool
rm160521
parents: 5367
diff changeset
   479
 * subtree or if all of those clones are also in this subtree.  Returns
68b03551f113 6609196 'zfs destroy -r' can needlessly iterate over all filesystems in pool
rm160521
parents: 5367
diff changeset
   480
 * true if there is an error or there are external dependents.
68b03551f113 6609196 'zfs destroy -r' can needlessly iterate over all filesystems in pool
rm160521
parents: 5367
diff changeset
   481
 */
68b03551f113 6609196 'zfs destroy -r' can needlessly iterate over all filesystems in pool
rm160521
parents: 5367
diff changeset
   482
static boolean_t
68b03551f113 6609196 'zfs destroy -r' can needlessly iterate over all filesystems in pool
rm160521
parents: 5367
diff changeset
   483
external_dependents(libzfs_handle_t *hdl, zfs_graph_t *zgp, const char *dataset)
68b03551f113 6609196 'zfs destroy -r' can needlessly iterate over all filesystems in pool
rm160521
parents: 5367
diff changeset
   484
{
68b03551f113 6609196 'zfs destroy -r' can needlessly iterate over all filesystems in pool
rm160521
parents: 5367
diff changeset
   485
	zfs_cmd_t zc = { 0 };
68b03551f113 6609196 'zfs destroy -r' can needlessly iterate over all filesystems in pool
rm160521
parents: 5367
diff changeset
   486
68b03551f113 6609196 'zfs destroy -r' can needlessly iterate over all filesystems in pool
rm160521
parents: 5367
diff changeset
   487
	/*
68b03551f113 6609196 'zfs destroy -r' can needlessly iterate over all filesystems in pool
rm160521
parents: 5367
diff changeset
   488
	 * Check whether this dataset is a clone or has clones since
68b03551f113 6609196 'zfs destroy -r' can needlessly iterate over all filesystems in pool
rm160521
parents: 5367
diff changeset
   489
	 * iterate_children() only checks the children.
68b03551f113 6609196 'zfs destroy -r' can needlessly iterate over all filesystems in pool
rm160521
parents: 5367
diff changeset
   490
	 */
68b03551f113 6609196 'zfs destroy -r' can needlessly iterate over all filesystems in pool
rm160521
parents: 5367
diff changeset
   491
	(void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name));
68b03551f113 6609196 'zfs destroy -r' can needlessly iterate over all filesystems in pool
rm160521
parents: 5367
diff changeset
   492
	if (ioctl(hdl->libzfs_fd, ZFS_IOC_OBJSET_STATS, &zc) != 0)
68b03551f113 6609196 'zfs destroy -r' can needlessly iterate over all filesystems in pool
rm160521
parents: 5367
diff changeset
   493
		return (B_TRUE);
68b03551f113 6609196 'zfs destroy -r' can needlessly iterate over all filesystems in pool
rm160521
parents: 5367
diff changeset
   494
68b03551f113 6609196 'zfs destroy -r' can needlessly iterate over all filesystems in pool
rm160521
parents: 5367
diff changeset
   495
	if (zc.zc_objset_stats.dds_origin[0] != '\0') {
68b03551f113 6609196 'zfs destroy -r' can needlessly iterate over all filesystems in pool
rm160521
parents: 5367
diff changeset
   496
		if (zfs_graph_add(hdl, zgp,
68b03551f113 6609196 'zfs destroy -r' can needlessly iterate over all filesystems in pool
rm160521
parents: 5367
diff changeset
   497
		    zc.zc_objset_stats.dds_origin, zc.zc_name,
68b03551f113 6609196 'zfs destroy -r' can needlessly iterate over all filesystems in pool
rm160521
parents: 5367
diff changeset
   498
		    zc.zc_objset_stats.dds_creation_txg) != 0)
68b03551f113 6609196 'zfs destroy -r' can needlessly iterate over all filesystems in pool
rm160521
parents: 5367
diff changeset
   499
			return (B_TRUE);
68b03551f113 6609196 'zfs destroy -r' can needlessly iterate over all filesystems in pool
rm160521
parents: 5367
diff changeset
   500
		if (isa_child_of(zc.zc_objset_stats.dds_origin, dataset))
68b03551f113 6609196 'zfs destroy -r' can needlessly iterate over all filesystems in pool
rm160521
parents: 5367
diff changeset
   501
			zgp->zg_clone_count--;
68b03551f113 6609196 'zfs destroy -r' can needlessly iterate over all filesystems in pool
rm160521
parents: 5367
diff changeset
   502
	}
68b03551f113 6609196 'zfs destroy -r' can needlessly iterate over all filesystems in pool
rm160521
parents: 5367
diff changeset
   503
68b03551f113 6609196 'zfs destroy -r' can needlessly iterate over all filesystems in pool
rm160521
parents: 5367
diff changeset
   504
	if ((zc.zc_objset_stats.dds_num_clones) ||
68b03551f113 6609196 'zfs destroy -r' can needlessly iterate over all filesystems in pool
rm160521
parents: 5367
diff changeset
   505
	    iterate_children(hdl, zgp, dataset))
68b03551f113 6609196 'zfs destroy -r' can needlessly iterate over all filesystems in pool
rm160521
parents: 5367
diff changeset
   506
		return (B_TRUE);
68b03551f113 6609196 'zfs destroy -r' can needlessly iterate over all filesystems in pool
rm160521
parents: 5367
diff changeset
   507
68b03551f113 6609196 'zfs destroy -r' can needlessly iterate over all filesystems in pool
rm160521
parents: 5367
diff changeset
   508
	return (zgp->zg_clone_count != 0);
68b03551f113 6609196 'zfs destroy -r' can needlessly iterate over all filesystems in pool
rm160521
parents: 5367
diff changeset
   509
}
68b03551f113 6609196 'zfs destroy -r' can needlessly iterate over all filesystems in pool
rm160521
parents: 5367
diff changeset
   510
68b03551f113 6609196 'zfs destroy -r' can needlessly iterate over all filesystems in pool
rm160521
parents: 5367
diff changeset
   511
/*
68b03551f113 6609196 'zfs destroy -r' can needlessly iterate over all filesystems in pool
rm160521
parents: 5367
diff changeset
   512
 * Construct a complete graph of all necessary vertices.  First, iterate over
68b03551f113 6609196 'zfs destroy -r' can needlessly iterate over all filesystems in pool
rm160521
parents: 5367
diff changeset
   513
 * only our object's children.  If no cloned snapshots are found, or all of
68b03551f113 6609196 'zfs destroy -r' can needlessly iterate over all filesystems in pool
rm160521
parents: 5367
diff changeset
   514
 * the cloned snapshots are in this subtree then return a graph of the subtree.
68b03551f113 6609196 'zfs destroy -r' can needlessly iterate over all filesystems in pool
rm160521
parents: 5367
diff changeset
   515
 * Otherwise, start at the root of the pool and iterate over all datasets.
789
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   516
 */
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   517
static zfs_graph_t *
2082
76b439ec3ac1 PSARC 2006/223 ZFS Hot Spares
eschrock
parents: 1544
diff changeset
   518
construct_graph(libzfs_handle_t *hdl, const char *dataset)
789
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   519
{
6027
68b03551f113 6609196 'zfs destroy -r' can needlessly iterate over all filesystems in pool
rm160521
parents: 5367
diff changeset
   520
	zfs_graph_t *zgp = zfs_graph_create(hdl, dataset, ZFS_GRAPH_SIZE);
2082
76b439ec3ac1 PSARC 2006/223 ZFS Hot Spares
eschrock
parents: 1544
diff changeset
   521
	int ret = 0;
76b439ec3ac1 PSARC 2006/223 ZFS Hot Spares
eschrock
parents: 1544
diff changeset
   522
76b439ec3ac1 PSARC 2006/223 ZFS Hot Spares
eschrock
parents: 1544
diff changeset
   523
	if (zgp == NULL)
76b439ec3ac1 PSARC 2006/223 ZFS Hot Spares
eschrock
parents: 1544
diff changeset
   524
		return (zgp);
789
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   525
6027
68b03551f113 6609196 'zfs destroy -r' can needlessly iterate over all filesystems in pool
rm160521
parents: 5367
diff changeset
   526
	if ((strchr(dataset, '/') == NULL) ||
68b03551f113 6609196 'zfs destroy -r' can needlessly iterate over all filesystems in pool
rm160521
parents: 5367
diff changeset
   527
	    (external_dependents(hdl, zgp, dataset))) {
789
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   528
		/*
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   529
		 * Determine pool name and try again.
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   530
		 */
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   531
		char *pool, *slash;
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   532
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   533
		if ((slash = strchr(dataset, '/')) != NULL ||
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   534
		    (slash = strchr(dataset, '@')) != NULL) {
2082
76b439ec3ac1 PSARC 2006/223 ZFS Hot Spares
eschrock
parents: 1544
diff changeset
   535
			pool = zfs_alloc(hdl, slash - dataset + 1);
76b439ec3ac1 PSARC 2006/223 ZFS Hot Spares
eschrock
parents: 1544
diff changeset
   536
			if (pool == NULL) {
76b439ec3ac1 PSARC 2006/223 ZFS Hot Spares
eschrock
parents: 1544
diff changeset
   537
				zfs_graph_destroy(zgp);
76b439ec3ac1 PSARC 2006/223 ZFS Hot Spares
eschrock
parents: 1544
diff changeset
   538
				return (NULL);
76b439ec3ac1 PSARC 2006/223 ZFS Hot Spares
eschrock
parents: 1544
diff changeset
   539
			}
789
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   540
			(void) strncpy(pool, dataset, slash - dataset);
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   541
			pool[slash - dataset] = '\0';
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   542
2082
76b439ec3ac1 PSARC 2006/223 ZFS Hot Spares
eschrock
parents: 1544
diff changeset
   543
			if (iterate_children(hdl, zgp, pool) == -1 ||
76b439ec3ac1 PSARC 2006/223 ZFS Hot Spares
eschrock
parents: 1544
diff changeset
   544
			    zfs_graph_add(hdl, zgp, pool, NULL, 0) != 0) {
76b439ec3ac1 PSARC 2006/223 ZFS Hot Spares
eschrock
parents: 1544
diff changeset
   545
				free(pool);
76b439ec3ac1 PSARC 2006/223 ZFS Hot Spares
eschrock
parents: 1544
diff changeset
   546
				zfs_graph_destroy(zgp);
76b439ec3ac1 PSARC 2006/223 ZFS Hot Spares
eschrock
parents: 1544
diff changeset
   547
				return (NULL);
76b439ec3ac1 PSARC 2006/223 ZFS Hot Spares
eschrock
parents: 1544
diff changeset
   548
			}
789
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   549
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   550
			free(pool);
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   551
		}
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   552
	}
2082
76b439ec3ac1 PSARC 2006/223 ZFS Hot Spares
eschrock
parents: 1544
diff changeset
   553
76b439ec3ac1 PSARC 2006/223 ZFS Hot Spares
eschrock
parents: 1544
diff changeset
   554
	if (ret == -1 || zfs_graph_add(hdl, zgp, dataset, NULL, 0) != 0) {
76b439ec3ac1 PSARC 2006/223 ZFS Hot Spares
eschrock
parents: 1544
diff changeset
   555
		zfs_graph_destroy(zgp);
76b439ec3ac1 PSARC 2006/223 ZFS Hot Spares
eschrock
parents: 1544
diff changeset
   556
		return (NULL);
76b439ec3ac1 PSARC 2006/223 ZFS Hot Spares
eschrock
parents: 1544
diff changeset
   557
	}
789
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   558
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   559
	return (zgp);
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   560
}
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   561
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   562
/*
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   563
 * Given a graph, do a recursive topological sort into the given array.  This is
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   564
 * really just a depth first search, so that the deepest nodes appear first.
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   565
 * hijack the 'zv_visited' marker to avoid visiting the same vertex twice.
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   566
 */
2082
76b439ec3ac1 PSARC 2006/223 ZFS Hot Spares
eschrock
parents: 1544
diff changeset
   567
static int
2474
c001ad7e0c25 6368751 libzfs interface for mount/umounting all the file systems for a given pool
eschrock
parents: 2082
diff changeset
   568
topo_sort(libzfs_handle_t *hdl, boolean_t allowrecursion, char **result,
c001ad7e0c25 6368751 libzfs interface for mount/umounting all the file systems for a given pool
eschrock
parents: 2082
diff changeset
   569
    size_t *idx, zfs_vertex_t *zgv)
789
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   570
{
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   571
	int i;
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   572
2474
c001ad7e0c25 6368751 libzfs interface for mount/umounting all the file systems for a given pool
eschrock
parents: 2082
diff changeset
   573
	if (zgv->zv_visited == VISIT_SORT_PRE && !allowrecursion) {
c001ad7e0c25 6368751 libzfs interface for mount/umounting all the file systems for a given pool
eschrock
parents: 2082
diff changeset
   574
		/*
c001ad7e0c25 6368751 libzfs interface for mount/umounting all the file systems for a given pool
eschrock
parents: 2082
diff changeset
   575
		 * If we've already seen this vertex as part of our depth-first
c001ad7e0c25 6368751 libzfs interface for mount/umounting all the file systems for a given pool
eschrock
parents: 2082
diff changeset
   576
		 * search, then we have a cyclic dependency, and we must return
c001ad7e0c25 6368751 libzfs interface for mount/umounting all the file systems for a given pool
eschrock
parents: 2082
diff changeset
   577
		 * an error.
c001ad7e0c25 6368751 libzfs interface for mount/umounting all the file systems for a given pool
eschrock
parents: 2082
diff changeset
   578
		 */
c001ad7e0c25 6368751 libzfs interface for mount/umounting all the file systems for a given pool
eschrock
parents: 2082
diff changeset
   579
		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
c001ad7e0c25 6368751 libzfs interface for mount/umounting all the file systems for a given pool
eschrock
parents: 2082
diff changeset
   580
		    "recursive dependency at '%s'"),
c001ad7e0c25 6368751 libzfs interface for mount/umounting all the file systems for a given pool
eschrock
parents: 2082
diff changeset
   581
		    zgv->zv_dataset);
c001ad7e0c25 6368751 libzfs interface for mount/umounting all the file systems for a given pool
eschrock
parents: 2082
diff changeset
   582
		return (zfs_error(hdl, EZFS_RECURSIVE,
c001ad7e0c25 6368751 libzfs interface for mount/umounting all the file systems for a given pool
eschrock
parents: 2082
diff changeset
   583
		    dgettext(TEXT_DOMAIN,
c001ad7e0c25 6368751 libzfs interface for mount/umounting all the file systems for a given pool
eschrock
parents: 2082
diff changeset
   584
		    "cannot determine dependent datasets")));
c001ad7e0c25 6368751 libzfs interface for mount/umounting all the file systems for a given pool
eschrock
parents: 2082
diff changeset
   585
	} else if (zgv->zv_visited >= VISIT_SORT_PRE) {
c001ad7e0c25 6368751 libzfs interface for mount/umounting all the file systems for a given pool
eschrock
parents: 2082
diff changeset
   586
		/*
c001ad7e0c25 6368751 libzfs interface for mount/umounting all the file systems for a given pool
eschrock
parents: 2082
diff changeset
   587
		 * If we've already processed this as part of the topological
c001ad7e0c25 6368751 libzfs interface for mount/umounting all the file systems for a given pool
eschrock
parents: 2082
diff changeset
   588
		 * sort, then don't bother doing so again.
c001ad7e0c25 6368751 libzfs interface for mount/umounting all the file systems for a given pool
eschrock
parents: 2082
diff changeset
   589
		 */
c001ad7e0c25 6368751 libzfs interface for mount/umounting all the file systems for a given pool
eschrock
parents: 2082
diff changeset
   590
		return (0);
c001ad7e0c25 6368751 libzfs interface for mount/umounting all the file systems for a given pool
eschrock
parents: 2082
diff changeset
   591
	}
c001ad7e0c25 6368751 libzfs interface for mount/umounting all the file systems for a given pool
eschrock
parents: 2082
diff changeset
   592
c001ad7e0c25 6368751 libzfs interface for mount/umounting all the file systems for a given pool
eschrock
parents: 2082
diff changeset
   593
	zgv->zv_visited = VISIT_SORT_PRE;
c001ad7e0c25 6368751 libzfs interface for mount/umounting all the file systems for a given pool
eschrock
parents: 2082
diff changeset
   594
789
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   595
	/* avoid doing a search if we don't have to */
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   596
	zfs_vertex_sort_edges(zgv);
2082
76b439ec3ac1 PSARC 2006/223 ZFS Hot Spares
eschrock
parents: 1544
diff changeset
   597
	for (i = 0; i < zgv->zv_edgecount; i++) {
2474
c001ad7e0c25 6368751 libzfs interface for mount/umounting all the file systems for a given pool
eschrock
parents: 2082
diff changeset
   598
		if (topo_sort(hdl, allowrecursion, result, idx,
c001ad7e0c25 6368751 libzfs interface for mount/umounting all the file systems for a given pool
eschrock
parents: 2082
diff changeset
   599
		    zgv->zv_edges[i]->ze_dest) != 0)
2082
76b439ec3ac1 PSARC 2006/223 ZFS Hot Spares
eschrock
parents: 1544
diff changeset
   600
			return (-1);
76b439ec3ac1 PSARC 2006/223 ZFS Hot Spares
eschrock
parents: 1544
diff changeset
   601
	}
789
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   602
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   603
	/* we may have visited this in the course of the above */
2474
c001ad7e0c25 6368751 libzfs interface for mount/umounting all the file systems for a given pool
eschrock
parents: 2082
diff changeset
   604
	if (zgv->zv_visited == VISIT_SORT_POST)
2082
76b439ec3ac1 PSARC 2006/223 ZFS Hot Spares
eschrock
parents: 1544
diff changeset
   605
		return (0);
789
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   606
2082
76b439ec3ac1 PSARC 2006/223 ZFS Hot Spares
eschrock
parents: 1544
diff changeset
   607
	if ((result[*idx] = zfs_alloc(hdl,
76b439ec3ac1 PSARC 2006/223 ZFS Hot Spares
eschrock
parents: 1544
diff changeset
   608
	    strlen(zgv->zv_dataset) + 1)) == NULL)
76b439ec3ac1 PSARC 2006/223 ZFS Hot Spares
eschrock
parents: 1544
diff changeset
   609
		return (-1);
76b439ec3ac1 PSARC 2006/223 ZFS Hot Spares
eschrock
parents: 1544
diff changeset
   610
789
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   611
	(void) strcpy(result[*idx], zgv->zv_dataset);
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   612
	*idx += 1;
2474
c001ad7e0c25 6368751 libzfs interface for mount/umounting all the file systems for a given pool
eschrock
parents: 2082
diff changeset
   613
	zgv->zv_visited = VISIT_SORT_POST;
2082
76b439ec3ac1 PSARC 2006/223 ZFS Hot Spares
eschrock
parents: 1544
diff changeset
   614
	return (0);
789
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   615
}
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   616
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   617
/*
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   618
 * The only public interface for this file.  Do the dirty work of constructing a
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   619
 * child list for the given object.  Construct the graph, do the toplogical
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   620
 * sort, and then return the array of strings to the caller.
2474
c001ad7e0c25 6368751 libzfs interface for mount/umounting all the file systems for a given pool
eschrock
parents: 2082
diff changeset
   621
 *
c001ad7e0c25 6368751 libzfs interface for mount/umounting all the file systems for a given pool
eschrock
parents: 2082
diff changeset
   622
 * The 'allowrecursion' parameter controls behavior when cycles are found.  If
c001ad7e0c25 6368751 libzfs interface for mount/umounting all the file systems for a given pool
eschrock
parents: 2082
diff changeset
   623
 * it is set, the the cycle is ignored and the results returned as if the cycle
c001ad7e0c25 6368751 libzfs interface for mount/umounting all the file systems for a given pool
eschrock
parents: 2082
diff changeset
   624
 * did not exist.  If it is not set, then the routine will generate an error if
c001ad7e0c25 6368751 libzfs interface for mount/umounting all the file systems for a given pool
eschrock
parents: 2082
diff changeset
   625
 * a cycle is found.
789
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   626
 */
2474
c001ad7e0c25 6368751 libzfs interface for mount/umounting all the file systems for a given pool
eschrock
parents: 2082
diff changeset
   627
int
c001ad7e0c25 6368751 libzfs interface for mount/umounting all the file systems for a given pool
eschrock
parents: 2082
diff changeset
   628
get_dependents(libzfs_handle_t *hdl, boolean_t allowrecursion,
c001ad7e0c25 6368751 libzfs interface for mount/umounting all the file systems for a given pool
eschrock
parents: 2082
diff changeset
   629
    const char *dataset, char ***result, size_t *count)
789
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   630
{
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   631
	zfs_graph_t *zgp;
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   632
	zfs_vertex_t *zvp;
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   633
2082
76b439ec3ac1 PSARC 2006/223 ZFS Hot Spares
eschrock
parents: 1544
diff changeset
   634
	if ((zgp = construct_graph(hdl, dataset)) == NULL)
2474
c001ad7e0c25 6368751 libzfs interface for mount/umounting all the file systems for a given pool
eschrock
parents: 2082
diff changeset
   635
		return (-1);
789
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   636
2474
c001ad7e0c25 6368751 libzfs interface for mount/umounting all the file systems for a given pool
eschrock
parents: 2082
diff changeset
   637
	if ((*result = zfs_alloc(hdl,
2082
76b439ec3ac1 PSARC 2006/223 ZFS Hot Spares
eschrock
parents: 1544
diff changeset
   638
	    zgp->zg_nvertex * sizeof (char *))) == NULL) {
76b439ec3ac1 PSARC 2006/223 ZFS Hot Spares
eschrock
parents: 1544
diff changeset
   639
		zfs_graph_destroy(zgp);
2474
c001ad7e0c25 6368751 libzfs interface for mount/umounting all the file systems for a given pool
eschrock
parents: 2082
diff changeset
   640
		return (-1);
2082
76b439ec3ac1 PSARC 2006/223 ZFS Hot Spares
eschrock
parents: 1544
diff changeset
   641
	}
76b439ec3ac1 PSARC 2006/223 ZFS Hot Spares
eschrock
parents: 1544
diff changeset
   642
76b439ec3ac1 PSARC 2006/223 ZFS Hot Spares
eschrock
parents: 1544
diff changeset
   643
	if ((zvp = zfs_graph_lookup(hdl, zgp, dataset, 0)) == NULL) {
2474
c001ad7e0c25 6368751 libzfs interface for mount/umounting all the file systems for a given pool
eschrock
parents: 2082
diff changeset
   644
		free(*result);
2082
76b439ec3ac1 PSARC 2006/223 ZFS Hot Spares
eschrock
parents: 1544
diff changeset
   645
		zfs_graph_destroy(zgp);
2474
c001ad7e0c25 6368751 libzfs interface for mount/umounting all the file systems for a given pool
eschrock
parents: 2082
diff changeset
   646
		return (-1);
2082
76b439ec3ac1 PSARC 2006/223 ZFS Hot Spares
eschrock
parents: 1544
diff changeset
   647
	}
789
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   648
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   649
	*count = 0;
2474
c001ad7e0c25 6368751 libzfs interface for mount/umounting all the file systems for a given pool
eschrock
parents: 2082
diff changeset
   650
	if (topo_sort(hdl, allowrecursion, *result, count, zvp) != 0) {
c001ad7e0c25 6368751 libzfs interface for mount/umounting all the file systems for a given pool
eschrock
parents: 2082
diff changeset
   651
		free(*result);
2082
76b439ec3ac1 PSARC 2006/223 ZFS Hot Spares
eschrock
parents: 1544
diff changeset
   652
		zfs_graph_destroy(zgp);
2474
c001ad7e0c25 6368751 libzfs interface for mount/umounting all the file systems for a given pool
eschrock
parents: 2082
diff changeset
   653
		return (-1);
2082
76b439ec3ac1 PSARC 2006/223 ZFS Hot Spares
eschrock
parents: 1544
diff changeset
   654
	}
789
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   655
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   656
	/*
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   657
	 * Get rid of the last entry, which is our starting vertex and not
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   658
	 * strictly a dependent.
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   659
	 */
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   660
	assert(*count > 0);
2474
c001ad7e0c25 6368751 libzfs interface for mount/umounting all the file systems for a given pool
eschrock
parents: 2082
diff changeset
   661
	free((*result)[*count - 1]);
789
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   662
	(*count)--;
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   663
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   664
	zfs_graph_destroy(zgp);
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   665
2474
c001ad7e0c25 6368751 libzfs interface for mount/umounting all the file systems for a given pool
eschrock
parents: 2082
diff changeset
   666
	return (0);
789
b348f31ed315 PSARC 2002/240 ZFS
ahrens
parents:
diff changeset
   667
}