]>
Commit | Line | Data |
---|---|---|
9ae529ec CS |
1 | /* |
2 | * CDDL HEADER START | |
3 | * | |
4 | * The contents of this file are subject to the terms of the | |
5 | * Common Development and Distribution License (the "License"). | |
6 | * You may not use this file except in compliance with the License. | |
7 | * | |
8 | * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE | |
9 | * or http://www.opensolaris.org/os/licensing. | |
10 | * See the License for the specific language governing permissions | |
11 | * and limitations under the License. | |
12 | * | |
13 | * When distributing Covered Code, include this CDDL HEADER in each | |
14 | * file and include the License file at usr/src/OPENSOLARIS.LICENSE. | |
15 | * If applicable, add the following below this CDDL HEADER, with the | |
16 | * fields enclosed by brackets "[]" replaced with your own identifying | |
17 | * information: Portions Copyright [yyyy] [name of copyright owner] | |
18 | * | |
19 | * CDDL HEADER END | |
20 | */ | |
21 | ||
22 | /* | |
241b5415 | 23 | * Copyright (c) 2011, 2015 by Delphix. All rights reserved. |
9759c60f | 24 | * Copyright (c) 2013 by Saso Kiselkov. All rights reserved. |
42db43e9 | 25 | * Copyright (c) 2013, Joyent, Inc. All rights reserved. |
62bdd5eb | 26 | * Copyright (c) 2014, Nexenta Systems, Inc. All rights reserved. |
9ae529ec CS |
27 | */ |
28 | ||
29 | #ifdef _KERNEL | |
30 | #include <sys/systm.h> | |
31 | #else | |
32 | #include <errno.h> | |
33 | #include <string.h> | |
34 | #endif | |
35 | #include <sys/debug.h> | |
36 | #include <sys/fs/zfs.h> | |
37 | #include <sys/inttypes.h> | |
38 | #include <sys/types.h> | |
39 | #include "zfeature_common.h" | |
40 | ||
41 | /* | |
42 | * Set to disable all feature checks while opening pools, allowing pools with | |
43 | * unsupported features to be opened. Set for testing only. | |
44 | */ | |
45 | boolean_t zfeature_checks_disable = B_FALSE; | |
46 | ||
47 | zfeature_info_t spa_feature_table[SPA_FEATURES]; | |
48 | ||
49 | /* | |
50 | * Valid characters for feature guids. This list is mainly for aesthetic | |
51 | * purposes and could be expanded in the future. There are different allowed | |
52 | * characters in the guids reverse dns portion (before the colon) and its | |
53 | * short name (after the colon). | |
54 | */ | |
55 | static int | |
56 | valid_char(char c, boolean_t after_colon) | |
57 | { | |
58 | return ((c >= 'a' && c <= 'z') || | |
59 | (c >= '0' && c <= '9') || | |
f1512ee6 MA |
60 | (after_colon && c == '_') || |
61 | (!after_colon && (c == '.' || c == '-'))); | |
9ae529ec CS |
62 | } |
63 | ||
64 | /* | |
65 | * Every feature guid must contain exactly one colon which separates a reverse | |
66 | * dns organization name from the feature's "short" name (e.g. | |
67 | * "com.company:feature_name"). | |
68 | */ | |
69 | boolean_t | |
70 | zfeature_is_valid_guid(const char *name) | |
71 | { | |
72 | int i; | |
73 | boolean_t has_colon = B_FALSE; | |
74 | ||
75 | i = 0; | |
76 | while (name[i] != '\0') { | |
77 | char c = name[i++]; | |
78 | if (c == ':') { | |
79 | if (has_colon) | |
80 | return (B_FALSE); | |
81 | has_colon = B_TRUE; | |
82 | continue; | |
83 | } | |
84 | if (!valid_char(c, has_colon)) | |
85 | return (B_FALSE); | |
86 | } | |
87 | ||
88 | return (has_colon); | |
89 | } | |
90 | ||
91 | boolean_t | |
92 | zfeature_is_supported(const char *guid) | |
93 | { | |
fa86b5db MA |
94 | spa_feature_t i; |
95 | ||
9ae529ec CS |
96 | if (zfeature_checks_disable) |
97 | return (B_TRUE); | |
98 | ||
9ae529ec CS |
99 | for (i = 0; i < SPA_FEATURES; i++) { |
100 | zfeature_info_t *feature = &spa_feature_table[i]; | |
fa86b5db MA |
101 | if (strcmp(guid, feature->fi_guid) == 0) |
102 | return (B_TRUE); | |
9ae529ec CS |
103 | } |
104 | ||
fa86b5db | 105 | return (B_FALSE); |
9ae529ec CS |
106 | } |
107 | ||
108 | int | |
fa86b5db | 109 | zfeature_lookup_name(const char *name, spa_feature_t *res) |
9ae529ec | 110 | { |
fa86b5db | 111 | spa_feature_t i; |
9ae529ec CS |
112 | |
113 | for (i = 0; i < SPA_FEATURES; i++) { | |
114 | zfeature_info_t *feature = &spa_feature_table[i]; | |
115 | if (strcmp(name, feature->fi_uname) == 0) { | |
116 | if (res != NULL) | |
fa86b5db | 117 | *res = i; |
9ae529ec CS |
118 | return (0); |
119 | } | |
120 | } | |
121 | ||
122 | return (ENOENT); | |
123 | } | |
124 | ||
b0bc7a84 | 125 | boolean_t |
e9aa730c GM |
126 | zfeature_depends_on(spa_feature_t fid, spa_feature_t check) |
127 | { | |
b0bc7a84 MG |
128 | zfeature_info_t *feature = &spa_feature_table[fid]; |
129 | int i; | |
130 | ||
131 | for (i = 0; feature->fi_depends[i] != SPA_FEATURE_NONE; i++) { | |
132 | if (feature->fi_depends[i] == check) | |
133 | return (B_TRUE); | |
134 | } | |
135 | return (B_FALSE); | |
136 | } | |
137 | ||
0bc63d83 GM |
138 | static boolean_t |
139 | deps_contains_feature(const spa_feature_t *deps, const spa_feature_t feature) | |
140 | { | |
141 | int i; | |
142 | ||
143 | for (i = 0; deps[i] != SPA_FEATURE_NONE; i++) | |
144 | if (deps[i] == feature) | |
145 | return (B_TRUE); | |
146 | ||
147 | return (B_FALSE); | |
148 | } | |
149 | ||
9ae529ec | 150 | static void |
fa86b5db | 151 | zfeature_register(spa_feature_t fid, const char *guid, const char *name, |
241b5415 | 152 | const char *desc, zfeature_flags_t flags, const spa_feature_t *deps) |
9ae529ec CS |
153 | { |
154 | zfeature_info_t *feature = &spa_feature_table[fid]; | |
fa86b5db | 155 | static spa_feature_t nodeps[] = { SPA_FEATURE_NONE }; |
9ae529ec CS |
156 | |
157 | ASSERT(name != NULL); | |
158 | ASSERT(desc != NULL); | |
241b5415 MA |
159 | ASSERT((flags & ZFEATURE_FLAG_READONLY_COMPAT) == 0 || |
160 | (flags & ZFEATURE_FLAG_MOS) == 0); | |
9ae529ec CS |
161 | ASSERT3U(fid, <, SPA_FEATURES); |
162 | ASSERT(zfeature_is_valid_guid(guid)); | |
163 | ||
164 | if (deps == NULL) | |
165 | deps = nodeps; | |
166 | ||
0bc63d83 GM |
167 | VERIFY(((flags & ZFEATURE_FLAG_PER_DATASET) == 0) || |
168 | (deps_contains_feature(deps, SPA_FEATURE_EXTENSIBLE_DATASET))); | |
169 | ||
fa86b5db | 170 | feature->fi_feature = fid; |
9ae529ec CS |
171 | feature->fi_guid = guid; |
172 | feature->fi_uname = name; | |
173 | feature->fi_desc = desc; | |
241b5415 | 174 | feature->fi_flags = flags; |
9ae529ec CS |
175 | feature->fi_depends = deps; |
176 | } | |
177 | ||
178 | void | |
179 | zpool_feature_init(void) | |
180 | { | |
181 | zfeature_register(SPA_FEATURE_ASYNC_DESTROY, | |
182 | "com.delphix:async_destroy", "async_destroy", | |
241b5415 MA |
183 | "Destroy filesystems asynchronously.", |
184 | ZFEATURE_FLAG_READONLY_COMPAT, NULL); | |
b0bc7a84 | 185 | |
753c3839 MA |
186 | zfeature_register(SPA_FEATURE_EMPTY_BPOBJ, |
187 | "com.delphix:empty_bpobj", "empty_bpobj", | |
241b5415 MA |
188 | "Snapshots use less space.", |
189 | ZFEATURE_FLAG_READONLY_COMPAT, NULL); | |
b0bc7a84 | 190 | |
9759c60f ED |
191 | zfeature_register(SPA_FEATURE_LZ4_COMPRESS, |
192 | "org.illumos:lz4_compress", "lz4_compress", | |
241b5415 MA |
193 | "LZ4 compression algorithm support.", |
194 | ZFEATURE_FLAG_ACTIVATE_ON_ENABLE, NULL); | |
b0bc7a84 | 195 | |
42db43e9 GDN |
196 | zfeature_register(SPA_FEATURE_MULTI_VDEV_CRASH_DUMP, |
197 | "com.joyent:multi_vdev_crash_dump", "multi_vdev_crash_dump", | |
198 | "Crash dumps to multiple vdev pools.", | |
199 | 0, NULL); | |
200 | ||
93cf2076 GW |
201 | zfeature_register(SPA_FEATURE_SPACEMAP_HISTOGRAM, |
202 | "com.delphix:spacemap_histogram", "spacemap_histogram", | |
241b5415 MA |
203 | "Spacemaps maintain space histograms.", |
204 | ZFEATURE_FLAG_READONLY_COMPAT, NULL); | |
b0bc7a84 MG |
205 | |
206 | zfeature_register(SPA_FEATURE_ENABLED_TXG, | |
207 | "com.delphix:enabled_txg", "enabled_txg", | |
241b5415 MA |
208 | "Record txg at which a feature is enabled", |
209 | ZFEATURE_FLAG_READONLY_COMPAT, NULL); | |
b0bc7a84 MG |
210 | |
211 | { | |
da536844 MA |
212 | static const spa_feature_t hole_birth_deps[] = { |
213 | SPA_FEATURE_ENABLED_TXG, | |
214 | SPA_FEATURE_NONE | |
215 | }; | |
b0bc7a84 MG |
216 | zfeature_register(SPA_FEATURE_HOLE_BIRTH, |
217 | "com.delphix:hole_birth", "hole_birth", | |
218 | "Retain hole birth txg for more precise zfs send", | |
241b5415 MA |
219 | ZFEATURE_FLAG_MOS | ZFEATURE_FLAG_ACTIVATE_ON_ENABLE, |
220 | hole_birth_deps); | |
b0bc7a84 MG |
221 | } |
222 | ||
fa86b5db MA |
223 | zfeature_register(SPA_FEATURE_EXTENSIBLE_DATASET, |
224 | "com.delphix:extensible_dataset", "extensible_dataset", | |
225 | "Enhanced dataset functionality, used by other features.", | |
241b5415 | 226 | 0, NULL); |
da536844 MA |
227 | |
228 | { | |
229 | static const spa_feature_t bookmarks_deps[] = { | |
230 | SPA_FEATURE_EXTENSIBLE_DATASET, | |
231 | SPA_FEATURE_NONE | |
232 | }; | |
233 | ||
234 | zfeature_register(SPA_FEATURE_BOOKMARKS, | |
235 | "com.delphix:bookmarks", "bookmarks", | |
236 | "\"zfs bookmark\" command", | |
241b5415 | 237 | ZFEATURE_FLAG_READONLY_COMPAT, bookmarks_deps); |
da536844 | 238 | } |
9b67f605 | 239 | |
788eb90c JJ |
240 | { |
241 | static const spa_feature_t filesystem_limits_deps[] = { | |
832805d9 BB |
242 | SPA_FEATURE_EXTENSIBLE_DATASET, |
243 | SPA_FEATURE_NONE | |
788eb90c JJ |
244 | }; |
245 | zfeature_register(SPA_FEATURE_FS_SS_LIMIT, | |
246 | "com.joyent:filesystem_limits", "filesystem_limits", | |
241b5415 MA |
247 | "Filesystem and snapshot limits.", |
248 | ZFEATURE_FLAG_READONLY_COMPAT, filesystem_limits_deps); | |
788eb90c JJ |
249 | } |
250 | ||
9b67f605 MA |
251 | zfeature_register(SPA_FEATURE_EMBEDDED_DATA, |
252 | "com.delphix:embedded_data", "embedded_data", | |
253 | "Blocks which compress very well use even less space.", | |
241b5415 MA |
254 | ZFEATURE_FLAG_MOS | ZFEATURE_FLAG_ACTIVATE_ON_ENABLE, |
255 | NULL); | |
f1512ee6 MA |
256 | |
257 | { | |
258 | static const spa_feature_t large_blocks_deps[] = { | |
259 | SPA_FEATURE_EXTENSIBLE_DATASET, | |
260 | SPA_FEATURE_NONE | |
261 | }; | |
262 | zfeature_register(SPA_FEATURE_LARGE_BLOCKS, | |
263 | "org.open-zfs:large_blocks", "large_blocks", | |
241b5415 MA |
264 | "Support for blocks larger than 128KB.", |
265 | ZFEATURE_FLAG_PER_DATASET, large_blocks_deps); | |
f1512ee6 | 266 | } |
50c957f7 NB |
267 | |
268 | { | |
269 | static const spa_feature_t large_dnode_deps[] = { | |
270 | SPA_FEATURE_EXTENSIBLE_DATASET, | |
271 | SPA_FEATURE_NONE | |
272 | }; | |
273 | zfeature_register(SPA_FEATURE_LARGE_DNODE, | |
274 | "org.zfsonlinux:large_dnode", "large_dnode", | |
275 | "Variable on-disk size of dnodes.", | |
276 | ZFEATURE_FLAG_PER_DATASET, large_dnode_deps); | |
277 | } | |
125a406e | 278 | |
279 | { | |
280 | static const spa_feature_t sha512_deps[] = { | |
281 | SPA_FEATURE_EXTENSIBLE_DATASET, | |
282 | SPA_FEATURE_NONE | |
283 | }; | |
3c67d83a TH |
284 | zfeature_register(SPA_FEATURE_SHA512, |
285 | "org.illumos:sha512", "sha512", | |
286 | "SHA-512/256 hash algorithm.", | |
125a406e | 287 | ZFEATURE_FLAG_PER_DATASET, sha512_deps); |
288 | } | |
289 | { | |
290 | static const spa_feature_t skein_deps[] = { | |
291 | SPA_FEATURE_EXTENSIBLE_DATASET, | |
292 | SPA_FEATURE_NONE | |
293 | }; | |
3c67d83a TH |
294 | zfeature_register(SPA_FEATURE_SKEIN, |
295 | "org.illumos:skein", "skein", | |
296 | "Skein hash algorithm.", | |
125a406e | 297 | ZFEATURE_FLAG_PER_DATASET, skein_deps); |
298 | } | |
299 | ||
300 | { | |
301 | static const spa_feature_t edonr_deps[] = { | |
302 | SPA_FEATURE_EXTENSIBLE_DATASET, | |
303 | SPA_FEATURE_NONE | |
304 | }; | |
3c67d83a TH |
305 | zfeature_register(SPA_FEATURE_EDONR, |
306 | "org.illumos:edonr", "edonr", | |
307 | "Edon-R hash algorithm.", | |
125a406e | 308 | ZFEATURE_FLAG_PER_DATASET, edonr_deps); |
309 | } | |
1de321e6 JX |
310 | { |
311 | static const spa_feature_t userobj_accounting_deps[] = { | |
312 | SPA_FEATURE_EXTENSIBLE_DATASET, | |
313 | SPA_FEATURE_NONE | |
314 | }; | |
315 | zfeature_register(SPA_FEATURE_USEROBJ_ACCOUNTING, | |
316 | "org.zfsonlinux:userobj_accounting", "userobj_accounting", | |
317 | "User/Group object accounting.", | |
318 | ZFEATURE_FLAG_READONLY_COMPAT | ZFEATURE_FLAG_PER_DATASET, | |
319 | userobj_accounting_deps); | |
320 | } | |
b5256303 TC |
321 | |
322 | { | |
323 | static const spa_feature_t encryption_deps[] = { | |
324 | SPA_FEATURE_EXTENSIBLE_DATASET, | |
325 | SPA_FEATURE_NONE | |
326 | }; | |
327 | zfeature_register(SPA_FEATURE_ENCRYPTION, | |
328 | "com.datto:encryption", "encryption", | |
329 | "Support for dataset level encryption", | |
330 | ZFEATURE_FLAG_PER_DATASET, encryption_deps); | |
331 | } | |
9ae529ec | 332 | } |
46364cb2 BB |
333 | |
334 | #if defined(_KERNEL) && defined(HAVE_SPL) | |
335 | EXPORT_SYMBOL(zfeature_lookup_name); | |
336 | EXPORT_SYMBOL(zfeature_is_supported); | |
337 | EXPORT_SYMBOL(zfeature_is_valid_guid); | |
338 | EXPORT_SYMBOL(zfeature_depends_on); | |
339 | EXPORT_SYMBOL(zpool_feature_init); | |
340 | EXPORT_SYMBOL(spa_feature_table); | |
341 | #endif |