Example #1
0
/*
 * Returns false if there are no snapshots with dependent clones in this
 * subtree or if all of those clones are also in this subtree.  Returns
 * true if there is an error or there are external dependents.
 */
static boolean_t
external_dependents(libzfs_handle_t *hdl, zfs_graph_t *zgp, const char *dataset)
{
	zfs_cmd_t zc = { 0 };

	/*
	 * Check whether this dataset is a clone or has clones since
	 * iterate_children() only checks the children.
	 */
	(void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name));
	if (ioctl(hdl->libzfs_fd, ZFS_IOC_OBJSET_STATS, &zc) != 0)
		return (B_TRUE);

	if (zc.zc_objset_stats.dds_origin[0] != '\0') {
		if (zfs_graph_add(hdl, zgp,
		    zc.zc_objset_stats.dds_origin, zc.zc_name,
		    zc.zc_objset_stats.dds_creation_txg) != 0)
			return (B_TRUE);
		if (isa_child_of(zc.zc_objset_stats.dds_origin, dataset))
			zgp->zg_clone_count--;
	}

	if ((zc.zc_objset_stats.dds_num_clones) ||
	    iterate_children(hdl, zgp, dataset))
		return (B_TRUE);

	return (zgp->zg_clone_count != 0);
}
Example #2
0
/*
 * If we rename a filesystem, child filesystem handles are no longer valid
 * since we identify each dataset by its name in the ZFS namespace.  As a
 * result, we have to go through and fix up all the names appropriately.  We
 * could do this automatically if libzfs kept track of all open handles, but
 * this is a lot less work.
 */
void
changelist_rename(prop_changelist_t *clp, const char *src, const char *dst)
{
	prop_changenode_t *cn;
	char newname[ZFS_MAXNAMELEN];

	for (cn = uu_list_first(clp->cl_list); cn != NULL;
	    cn = uu_list_next(clp->cl_list, cn)) {
		/*
		 * Do not rename a clone that's not in the source hierarchy.
		 */
		if (!isa_child_of(cn->cn_handle->zfs_name, src))
			continue;

		/*
		 * Destroy the previous mountpoint if needed.
		 */
		remove_mountpoint(cn->cn_handle);

		(void) strlcpy(newname, dst, sizeof (newname));
		(void) strcat(newname, cn->cn_handle->zfs_name + strlen(src));

		(void) strlcpy(cn->cn_handle->zfs_name, newname,
		    sizeof (cn->cn_handle->zfs_name));
	}
}
Example #3
0
/*
 * Iterate over all children of the given dataset, adding any vertices
 * as necessary.  Returns -1 if there was an error, or 0 otherwise.
 * This is a simple recursive algorithm - the ZFS namespace typically
 * is very flat.  We manually invoke the necessary ioctl() calls to
 * avoid the overhead and additional semantics of zfs_open().
 */
static int
iterate_children(libzfs_handle_t *hdl, zfs_graph_t *zgp, const char *dataset)
{
	zfs_cmd_t zc = { 0 };
	zfs_vertex_t *zvp;

	/*
	 * Look up the source vertex, and avoid it if we've seen it before.
	 */
	zvp = zfs_graph_lookup(hdl, zgp, dataset, 0);
	if (zvp == NULL)
		return (-1);
	if (zvp->zv_visited == VISIT_SEEN)
		return (0);

	/*
	 * Iterate over all children
	 */
	for ((void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name));
	    ioctl(hdl->libzfs_fd, ZFS_IOC_DATASET_LIST_NEXT, &zc) == 0;
	    (void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name))) {

		/*
		 * Ignore private dataset names.
		 */
		if (dataset_name_hidden(zc.zc_name))
			continue;

		/*
		 * Get statistics for this dataset, to determine the type of the
		 * dataset and clone statistics.  If this fails, the dataset has
		 * since been removed, and we're pretty much screwed anyway.
		 */
		zc.zc_objset_stats.dds_origin[0] = '\0';
		if (ioctl(hdl->libzfs_fd, ZFS_IOC_OBJSET_STATS, &zc) != 0)
			continue;

		if (zc.zc_objset_stats.dds_origin[0] != '\0') {
			if (zfs_graph_add(hdl, zgp,
			    zc.zc_objset_stats.dds_origin, zc.zc_name,
			    zc.zc_objset_stats.dds_creation_txg) != 0)
				return (-1);
			/*
			 * Count origins only if they are contained in the graph
			 */
			if (isa_child_of(zc.zc_objset_stats.dds_origin,
			    zgp->zg_root))
				zgp->zg_clone_count--;
		}

		/*
		 * Add an edge between the parent and the child.
		 */
		if (zfs_graph_add(hdl, zgp, dataset, zc.zc_name,
		    zc.zc_objset_stats.dds_creation_txg) != 0)
			return (-1);

		/*
		 * Recursively visit child
		 */
		if (iterate_children(hdl, zgp, zc.zc_name))
			return (-1);
	}

	/*
	 * Now iterate over all snapshots.
	 */
	bzero(&zc, sizeof (zc));

	for ((void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name));
	    ioctl(hdl->libzfs_fd, ZFS_IOC_SNAPSHOT_LIST_NEXT, &zc) == 0;
	    (void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name))) {

		/*
		 * Get statistics for this dataset, to determine the type of the
		 * dataset and clone statistics.  If this fails, the dataset has
		 * since been removed, and we're pretty much screwed anyway.
		 */
		if (ioctl(hdl->libzfs_fd, ZFS_IOC_OBJSET_STATS, &zc) != 0)
			continue;

		/*
		 * Add an edge between the parent and the child.
		 */
		if (zfs_graph_add(hdl, zgp, dataset, zc.zc_name,
		    zc.zc_objset_stats.dds_creation_txg) != 0)
			return (-1);

		zgp->zg_clone_count += zc.zc_objset_stats.dds_num_clones;
	}

	zvp->zv_visited = VISIT_SEEN;

	return (0);
}