mirror of
				https://git.proxmox.com/git/mirror_zfs
				synced 2025-11-04 08:36:37 +00:00 
			
		
		
		
	For dedup, special and log devices "zpool add -n" does not print correctly their vdev type: ~# zpool add -n pool dedup /tmp/dedup special /tmp/special log /tmp/log would update 'pool' to the following configuration: pool /tmp/normal /tmp/dedup /tmp/special /tmp/log This could lead storage administrators to modify their ZFS pools to unexpected and unintended vdev configurations. Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov> Signed-off-by: loli10K <ezomori.nozomu@gmail.com> Closes #9783 Closes #9390
		
			
				
	
	
		
			264 lines
		
	
	
		
			6.3 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			264 lines
		
	
	
		
			6.3 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/*
 | 
						|
 * CDDL HEADER START
 | 
						|
 *
 | 
						|
 * The contents of this file are subject to the terms of the
 | 
						|
 * Common Development and Distribution License (the "License").
 | 
						|
 * You may not use this file except in compliance with the License.
 | 
						|
 *
 | 
						|
 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 | 
						|
 * or http://www.opensolaris.org/os/licensing.
 | 
						|
 * See the License for the specific language governing permissions
 | 
						|
 * and limitations under the License.
 | 
						|
 *
 | 
						|
 * When distributing Covered Code, include this CDDL HEADER in each
 | 
						|
 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
 | 
						|
 * If applicable, add the following below this CDDL HEADER, with the
 | 
						|
 * fields enclosed by brackets "[]" replaced with your own identifying
 | 
						|
 * information: Portions Copyright [yyyy] [name of copyright owner]
 | 
						|
 *
 | 
						|
 * CDDL HEADER END
 | 
						|
 */
 | 
						|
/*
 | 
						|
 * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
 | 
						|
 * Copyright (c) 2012, 2017 by Delphix. All rights reserved.
 | 
						|
 */
 | 
						|
 | 
						|
/*
 | 
						|
 * This file is intended for functions that ought to be common between user
 | 
						|
 * land (libzfs) and the kernel. When many common routines need to be shared
 | 
						|
 * then a separate file should to be created.
 | 
						|
 */
 | 
						|
 | 
						|
#if !defined(_KERNEL)
 | 
						|
#include <string.h>
 | 
						|
#endif
 | 
						|
 | 
						|
#include <sys/types.h>
 | 
						|
#include <sys/fs/zfs.h>
 | 
						|
#include <sys/nvpair.h>
 | 
						|
#include "zfs_comutil.h"
 | 
						|
#include <sys/zfs_ratelimit.h>
 | 
						|
 | 
						|
/*
 | 
						|
 * Are there allocatable vdevs?
 | 
						|
 */
 | 
						|
boolean_t
 | 
						|
zfs_allocatable_devs(nvlist_t *nv)
 | 
						|
{
 | 
						|
	uint64_t is_log;
 | 
						|
	uint_t c;
 | 
						|
	nvlist_t **child;
 | 
						|
	uint_t children;
 | 
						|
 | 
						|
	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
 | 
						|
	    &child, &children) != 0) {
 | 
						|
		return (B_FALSE);
 | 
						|
	}
 | 
						|
	for (c = 0; c < children; c++) {
 | 
						|
		is_log = 0;
 | 
						|
		(void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG,
 | 
						|
		    &is_log);
 | 
						|
		if (!is_log)
 | 
						|
			return (B_TRUE);
 | 
						|
	}
 | 
						|
	return (B_FALSE);
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * Are there special vdevs?
 | 
						|
 */
 | 
						|
boolean_t
 | 
						|
zfs_special_devs(nvlist_t *nv, char *type)
 | 
						|
{
 | 
						|
	char *bias;
 | 
						|
	uint_t c;
 | 
						|
	nvlist_t **child;
 | 
						|
	uint_t children;
 | 
						|
 | 
						|
	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
 | 
						|
	    &child, &children) != 0) {
 | 
						|
		return (B_FALSE);
 | 
						|
	}
 | 
						|
	for (c = 0; c < children; c++) {
 | 
						|
		if (nvlist_lookup_string(child[c], ZPOOL_CONFIG_ALLOCATION_BIAS,
 | 
						|
		    &bias) == 0) {
 | 
						|
			if (strcmp(bias, VDEV_ALLOC_BIAS_SPECIAL) == 0 ||
 | 
						|
			    strcmp(bias, VDEV_ALLOC_BIAS_DEDUP) == 0) {
 | 
						|
				if (type != NULL && strcmp(bias, type) == 0) {
 | 
						|
					return (B_TRUE);
 | 
						|
				} else if (type == NULL) {
 | 
						|
					return (B_TRUE);
 | 
						|
				}
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
	return (B_FALSE);
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
zpool_get_load_policy(nvlist_t *nvl, zpool_load_policy_t *zlpp)
 | 
						|
{
 | 
						|
	nvlist_t *policy;
 | 
						|
	nvpair_t *elem;
 | 
						|
	char *nm;
 | 
						|
 | 
						|
	/* Defaults */
 | 
						|
	zlpp->zlp_rewind = ZPOOL_NO_REWIND;
 | 
						|
	zlpp->zlp_maxmeta = 0;
 | 
						|
	zlpp->zlp_maxdata = UINT64_MAX;
 | 
						|
	zlpp->zlp_txg = UINT64_MAX;
 | 
						|
 | 
						|
	if (nvl == NULL)
 | 
						|
		return;
 | 
						|
 | 
						|
	elem = NULL;
 | 
						|
	while ((elem = nvlist_next_nvpair(nvl, elem)) != NULL) {
 | 
						|
		nm = nvpair_name(elem);
 | 
						|
		if (strcmp(nm, ZPOOL_LOAD_POLICY) == 0) {
 | 
						|
			if (nvpair_value_nvlist(elem, &policy) == 0)
 | 
						|
				zpool_get_load_policy(policy, zlpp);
 | 
						|
			return;
 | 
						|
		} else if (strcmp(nm, ZPOOL_LOAD_REWIND_POLICY) == 0) {
 | 
						|
			if (nvpair_value_uint32(elem, &zlpp->zlp_rewind) == 0)
 | 
						|
				if (zlpp->zlp_rewind & ~ZPOOL_REWIND_POLICIES)
 | 
						|
					zlpp->zlp_rewind = ZPOOL_NO_REWIND;
 | 
						|
		} else if (strcmp(nm, ZPOOL_LOAD_REQUEST_TXG) == 0) {
 | 
						|
			(void) nvpair_value_uint64(elem, &zlpp->zlp_txg);
 | 
						|
		} else if (strcmp(nm, ZPOOL_LOAD_META_THRESH) == 0) {
 | 
						|
			(void) nvpair_value_uint64(elem, &zlpp->zlp_maxmeta);
 | 
						|
		} else if (strcmp(nm, ZPOOL_LOAD_DATA_THRESH) == 0) {
 | 
						|
			(void) nvpair_value_uint64(elem, &zlpp->zlp_maxdata);
 | 
						|
		}
 | 
						|
	}
 | 
						|
	if (zlpp->zlp_rewind == 0)
 | 
						|
		zlpp->zlp_rewind = ZPOOL_NO_REWIND;
 | 
						|
}
 | 
						|
 | 
						|
typedef struct zfs_version_spa_map {
 | 
						|
	int	version_zpl;
 | 
						|
	int	version_spa;
 | 
						|
} zfs_version_spa_map_t;
 | 
						|
 | 
						|
/*
 | 
						|
 * Keep this table in monotonically increasing version number order.
 | 
						|
 */
 | 
						|
static zfs_version_spa_map_t zfs_version_table[] = {
 | 
						|
	{ZPL_VERSION_INITIAL, SPA_VERSION_INITIAL},
 | 
						|
	{ZPL_VERSION_DIRENT_TYPE, SPA_VERSION_INITIAL},
 | 
						|
	{ZPL_VERSION_FUID, SPA_VERSION_FUID},
 | 
						|
	{ZPL_VERSION_USERSPACE, SPA_VERSION_USERSPACE},
 | 
						|
	{ZPL_VERSION_SA, SPA_VERSION_SA},
 | 
						|
	{0, 0}
 | 
						|
};
 | 
						|
 | 
						|
/*
 | 
						|
 * Return the max zpl version for a corresponding spa version
 | 
						|
 * -1 is returned if no mapping exists.
 | 
						|
 */
 | 
						|
int
 | 
						|
zfs_zpl_version_map(int spa_version)
 | 
						|
{
 | 
						|
	int i;
 | 
						|
	int version = -1;
 | 
						|
 | 
						|
	for (i = 0; zfs_version_table[i].version_spa; i++) {
 | 
						|
		if (spa_version >= zfs_version_table[i].version_spa)
 | 
						|
			version = zfs_version_table[i].version_zpl;
 | 
						|
	}
 | 
						|
 | 
						|
	return (version);
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * Return the min spa version for a corresponding spa version
 | 
						|
 * -1 is returned if no mapping exists.
 | 
						|
 */
 | 
						|
int
 | 
						|
zfs_spa_version_map(int zpl_version)
 | 
						|
{
 | 
						|
	int i;
 | 
						|
	int version = -1;
 | 
						|
 | 
						|
	for (i = 0; zfs_version_table[i].version_zpl; i++) {
 | 
						|
		if (zfs_version_table[i].version_zpl >= zpl_version)
 | 
						|
			return (zfs_version_table[i].version_spa);
 | 
						|
	}
 | 
						|
 | 
						|
	return (version);
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * This is the table of legacy internal event names; it should not be modified.
 | 
						|
 * The internal events are now stored in the history log as strings.
 | 
						|
 */
 | 
						|
const char *zfs_history_event_names[ZFS_NUM_LEGACY_HISTORY_EVENTS] = {
 | 
						|
	"invalid event",
 | 
						|
	"pool create",
 | 
						|
	"vdev add",
 | 
						|
	"pool remove",
 | 
						|
	"pool destroy",
 | 
						|
	"pool export",
 | 
						|
	"pool import",
 | 
						|
	"vdev attach",
 | 
						|
	"vdev replace",
 | 
						|
	"vdev detach",
 | 
						|
	"vdev online",
 | 
						|
	"vdev offline",
 | 
						|
	"vdev upgrade",
 | 
						|
	"pool clear",
 | 
						|
	"pool scrub",
 | 
						|
	"pool property set",
 | 
						|
	"create",
 | 
						|
	"clone",
 | 
						|
	"destroy",
 | 
						|
	"destroy_begin_sync",
 | 
						|
	"inherit",
 | 
						|
	"property set",
 | 
						|
	"quota set",
 | 
						|
	"permission update",
 | 
						|
	"permission remove",
 | 
						|
	"permission who remove",
 | 
						|
	"promote",
 | 
						|
	"receive",
 | 
						|
	"rename",
 | 
						|
	"reservation set",
 | 
						|
	"replay_inc_sync",
 | 
						|
	"replay_full_sync",
 | 
						|
	"rollback",
 | 
						|
	"snapshot",
 | 
						|
	"filesystem version upgrade",
 | 
						|
	"refquota set",
 | 
						|
	"refreservation set",
 | 
						|
	"pool scrub done",
 | 
						|
	"user hold",
 | 
						|
	"user release",
 | 
						|
	"pool split",
 | 
						|
};
 | 
						|
 | 
						|
boolean_t
 | 
						|
zfs_dataset_name_hidden(const char *name)
 | 
						|
{
 | 
						|
	/*
 | 
						|
	 * Skip over datasets that are not visible in this zone,
 | 
						|
	 * internal datasets (which have a $ in their name), and
 | 
						|
	 * temporary datasets (which have a % in their name).
 | 
						|
	 */
 | 
						|
	if (strchr(name, '$') != NULL)
 | 
						|
		return (B_TRUE);
 | 
						|
	if (strchr(name, '%') != NULL)
 | 
						|
		return (B_TRUE);
 | 
						|
	if (!INGLOBALZONE(curproc) && !zone_dataset_visible(name, NULL))
 | 
						|
		return (B_TRUE);
 | 
						|
	return (B_FALSE);
 | 
						|
}
 | 
						|
 | 
						|
#if defined(_KERNEL)
 | 
						|
EXPORT_SYMBOL(zfs_allocatable_devs);
 | 
						|
EXPORT_SYMBOL(zfs_special_devs);
 | 
						|
EXPORT_SYMBOL(zpool_get_load_policy);
 | 
						|
EXPORT_SYMBOL(zfs_zpl_version_map);
 | 
						|
EXPORT_SYMBOL(zfs_spa_version_map);
 | 
						|
EXPORT_SYMBOL(zfs_history_event_names);
 | 
						|
EXPORT_SYMBOL(zfs_dataset_name_hidden);
 | 
						|
#endif
 |