xref: /freebsd/sys/contrib/openzfs/module/zcommon/zfs_comutil.c (revision 22649d4dba730d46244fd2dff4fd174903c8379f)
1 // SPDX-License-Identifier: CDDL-1.0
2 /*
3  * This file and its contents are supplied under the terms of the
4  * Common Development and Distribution License ("CDDL"), version 1.0.
5  * You may only use this file in accordance with the terms of version
6  * 1.0 of the CDDL.
7  *
8  * A full copy of the text of the CDDL should have accompanied this
9  * source.  A copy of the CDDL is also available via the Internet at
10  * https://opensource.org/license/CDDL-1.0.
11  */
12 /*
13  * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
14  * Copyright (c) 2012, 2017 by Delphix. All rights reserved.
15  */
16 
17 /*
18  * This file is intended for functions that ought to be common between user
19  * land (libzfs) and the kernel. When many common routines need to be shared
20  * then a separate file should be created.
21  */
22 
23 #if !defined(_KERNEL)
24 #include <string.h>
25 #endif
26 
27 #include <sys/types.h>
28 #include <sys/fs/zfs.h>
29 #include <sys/nvpair.h>
30 #include "zfs_comutil.h"
31 #include <sys/zfs_ratelimit.h>
32 
33 /*
34  * Are there allocatable vdevs?
35  */
36 boolean_t
zfs_allocatable_devs(nvlist_t * nv)37 zfs_allocatable_devs(nvlist_t *nv)
38 {
39 	uint64_t is_log;
40 	uint_t c;
41 	nvlist_t **child;
42 	uint_t children;
43 
44 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
45 	    &child, &children) != 0) {
46 		return (B_FALSE);
47 	}
48 	for (c = 0; c < children; c++) {
49 		is_log = 0;
50 		(void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG,
51 		    &is_log);
52 		if (!is_log)
53 			return (B_TRUE);
54 	}
55 	return (B_FALSE);
56 }
57 
58 /*
59  * Are there special vdevs?
60  */
61 boolean_t
zfs_special_devs(nvlist_t * nv,const char * type)62 zfs_special_devs(nvlist_t *nv, const char *type)
63 {
64 	const char *bias;
65 	uint_t c;
66 	nvlist_t **child;
67 	uint_t children;
68 
69 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
70 	    &child, &children) != 0) {
71 		return (B_FALSE);
72 	}
73 	for (c = 0; c < children; c++) {
74 		if (nvlist_lookup_string(child[c], ZPOOL_CONFIG_ALLOCATION_BIAS,
75 		    &bias) == 0) {
76 			if (strcmp(bias, VDEV_ALLOC_BIAS_SPECIAL) == 0 ||
77 			    strcmp(bias, VDEV_ALLOC_BIAS_DEDUP) == 0) {
78 				if (type == NULL ||
79 				    (type != NULL && strcmp(bias, type) == 0))
80 					return (B_TRUE);
81 			}
82 		}
83 	}
84 	return (B_FALSE);
85 }
86 
87 void
zpool_get_load_policy(nvlist_t * nvl,zpool_load_policy_t * zlpp)88 zpool_get_load_policy(nvlist_t *nvl, zpool_load_policy_t *zlpp)
89 {
90 	nvlist_t *policy;
91 	nvpair_t *elem;
92 	const char *nm;
93 
94 	/* Defaults */
95 	zlpp->zlp_rewind = ZPOOL_NO_REWIND;
96 	zlpp->zlp_maxmeta = 0;
97 	zlpp->zlp_maxdata = UINT64_MAX;
98 	zlpp->zlp_txg = UINT64_MAX;
99 
100 	if (nvl == NULL)
101 		return;
102 
103 	elem = NULL;
104 	while ((elem = nvlist_next_nvpair(nvl, elem)) != NULL) {
105 		nm = nvpair_name(elem);
106 		if (strcmp(nm, ZPOOL_LOAD_POLICY) == 0) {
107 			if (nvpair_value_nvlist(elem, &policy) == 0)
108 				zpool_get_load_policy(policy, zlpp);
109 			return;
110 		} else if (strcmp(nm, ZPOOL_LOAD_REWIND_POLICY) == 0) {
111 			if (nvpair_value_uint32(elem, &zlpp->zlp_rewind) == 0)
112 				if (zlpp->zlp_rewind & ~ZPOOL_REWIND_POLICIES)
113 					zlpp->zlp_rewind = ZPOOL_NO_REWIND;
114 		} else if (strcmp(nm, ZPOOL_LOAD_REQUEST_TXG) == 0) {
115 			(void) nvpair_value_uint64(elem, &zlpp->zlp_txg);
116 		} else if (strcmp(nm, ZPOOL_LOAD_META_THRESH) == 0) {
117 			(void) nvpair_value_uint64(elem, &zlpp->zlp_maxmeta);
118 		} else if (strcmp(nm, ZPOOL_LOAD_DATA_THRESH) == 0) {
119 			(void) nvpair_value_uint64(elem, &zlpp->zlp_maxdata);
120 		}
121 	}
122 	if (zlpp->zlp_rewind == 0)
123 		zlpp->zlp_rewind = ZPOOL_NO_REWIND;
124 }
125 
126 typedef struct zfs_version_spa_map {
127 	int	version_zpl;
128 	int	version_spa;
129 } zfs_version_spa_map_t;
130 
131 /*
132  * Keep this table in monotonically increasing version number order.
133  */
134 static zfs_version_spa_map_t zfs_version_table[] = {
135 	{ZPL_VERSION_INITIAL, SPA_VERSION_INITIAL},
136 	{ZPL_VERSION_DIRENT_TYPE, SPA_VERSION_INITIAL},
137 	{ZPL_VERSION_FUID, SPA_VERSION_FUID},
138 	{ZPL_VERSION_USERSPACE, SPA_VERSION_USERSPACE},
139 	{ZPL_VERSION_SA, SPA_VERSION_SA},
140 	{0, 0}
141 };
142 
143 /*
144  * Return the max zpl version for a corresponding spa version
145  * -1 is returned if no mapping exists.
146  */
147 int
zfs_zpl_version_map(int spa_version)148 zfs_zpl_version_map(int spa_version)
149 {
150 	int version = -1;
151 
152 	for (int i = 0; zfs_version_table[i].version_spa; i++)
153 		if (spa_version >= zfs_version_table[i].version_spa)
154 			version = zfs_version_table[i].version_zpl;
155 
156 	return (version);
157 }
158 
159 /*
160  * Return the min spa version for a corresponding spa version
161  * -1 is returned if no mapping exists.
162  */
163 int
zfs_spa_version_map(int zpl_version)164 zfs_spa_version_map(int zpl_version)
165 {
166 	for (int i = 0; zfs_version_table[i].version_zpl; i++)
167 		if (zfs_version_table[i].version_zpl >= zpl_version)
168 			return (zfs_version_table[i].version_spa);
169 
170 	return (-1);
171 }
172 
173 /*
174  * This is the table of legacy internal event names; it should not be modified.
175  * The internal events are now stored in the history log as strings.
176  */
177 const char *const zfs_history_event_names[ZFS_NUM_LEGACY_HISTORY_EVENTS] = {
178 	"invalid event",
179 	"pool create",
180 	"vdev add",
181 	"pool remove",
182 	"pool destroy",
183 	"pool export",
184 	"pool import",
185 	"vdev attach",
186 	"vdev replace",
187 	"vdev detach",
188 	"vdev online",
189 	"vdev offline",
190 	"vdev upgrade",
191 	"pool clear",
192 	"pool scrub",
193 	"pool property set",
194 	"create",
195 	"clone",
196 	"destroy",
197 	"destroy_begin_sync",
198 	"inherit",
199 	"property set",
200 	"quota set",
201 	"permission update",
202 	"permission remove",
203 	"permission who remove",
204 	"promote",
205 	"receive",
206 	"rename",
207 	"reservation set",
208 	"replay_inc_sync",
209 	"replay_full_sync",
210 	"rollback",
211 	"snapshot",
212 	"filesystem version upgrade",
213 	"refquota set",
214 	"refreservation set",
215 	"pool scrub done",
216 	"user hold",
217 	"user release",
218 	"pool split",
219 };
220 
221 boolean_t
zfs_dataset_name_hidden(const char * name)222 zfs_dataset_name_hidden(const char *name)
223 {
224 	/*
225 	 * Skip over datasets that are not visible in this zone,
226 	 * internal datasets (which have a $ in their name), and
227 	 * temporary datasets (which have a % in their name).
228 	 */
229 	if (strpbrk(name, "$%") != NULL)
230 		return (B_TRUE);
231 	if (!INGLOBALZONE(curproc) && !zone_dataset_visible(name, NULL))
232 		return (B_TRUE);
233 	return (B_FALSE);
234 }
235 
236 #if defined(_KERNEL)
237 EXPORT_SYMBOL(zfs_allocatable_devs);
238 EXPORT_SYMBOL(zfs_special_devs);
239 EXPORT_SYMBOL(zpool_get_load_policy);
240 EXPORT_SYMBOL(zfs_zpl_version_map);
241 EXPORT_SYMBOL(zfs_spa_version_map);
242 EXPORT_SYMBOL(zfs_history_event_names);
243 EXPORT_SYMBOL(zfs_dataset_name_hidden);
244 #endif
245