]> git.proxmox.com Git - mirror_zfs.git/blob - module/zcommon/zfeature_common.c
Add zfs module feature and property info to sysfs
[mirror_zfs.git] / module / zcommon / zfeature_common.c
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 /*
23 * Copyright (c) 2011, 2017 by Delphix. All rights reserved.
24 * Copyright (c) 2013 by Saso Kiselkov. All rights reserved.
25 * Copyright (c) 2013, Joyent, Inc. All rights reserved.
26 * Copyright (c) 2014, Nexenta Systems, Inc. All rights reserved.
27 */
28
29 #ifndef _KERNEL
30 #include <errno.h>
31 #include <string.h>
32 #include <sys/stat.h>
33 #endif
34 #include <sys/debug.h>
35 #include <sys/fs/zfs.h>
36 #include <sys/inttypes.h>
37 #include <sys/types.h>
38 #include <sys/zfs_sysfs.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') ||
60 (after_colon && c == '_') ||
61 (!after_colon && (c == '.' || c == '-')));
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 {
94 if (zfeature_checks_disable)
95 return (B_TRUE);
96
97 for (spa_feature_t i = 0; i < SPA_FEATURES; i++) {
98 zfeature_info_t *feature = &spa_feature_table[i];
99 if (strcmp(guid, feature->fi_guid) == 0)
100 return (B_TRUE);
101 }
102 return (B_FALSE);
103 }
104
105 int
106 zfeature_lookup_guid(const char *guid, spa_feature_t *res)
107 {
108 for (spa_feature_t i = 0; i < SPA_FEATURES; i++) {
109 zfeature_info_t *feature = &spa_feature_table[i];
110 if (!feature->fi_zfs_mod_supported)
111 continue;
112 if (strcmp(guid, feature->fi_guid) == 0) {
113 if (res != NULL)
114 *res = i;
115 return (0);
116 }
117 }
118
119 return (ENOENT);
120 }
121
122 int
123 zfeature_lookup_name(const char *name, spa_feature_t *res)
124 {
125 for (spa_feature_t i = 0; i < SPA_FEATURES; i++) {
126 zfeature_info_t *feature = &spa_feature_table[i];
127 if (!feature->fi_zfs_mod_supported)
128 continue;
129 if (strcmp(name, feature->fi_uname) == 0) {
130 if (res != NULL)
131 *res = i;
132 return (0);
133 }
134 }
135
136 return (ENOENT);
137 }
138
139 boolean_t
140 zfeature_depends_on(spa_feature_t fid, spa_feature_t check)
141 {
142 zfeature_info_t *feature = &spa_feature_table[fid];
143
144 for (int i = 0; feature->fi_depends[i] != SPA_FEATURE_NONE; i++) {
145 if (feature->fi_depends[i] == check)
146 return (B_TRUE);
147 }
148 return (B_FALSE);
149 }
150
151 static boolean_t
152 deps_contains_feature(const spa_feature_t *deps, const spa_feature_t feature)
153 {
154 for (int i = 0; deps[i] != SPA_FEATURE_NONE; i++)
155 if (deps[i] == feature)
156 return (B_TRUE);
157
158 return (B_FALSE);
159 }
160
161 static boolean_t
162 zfs_mod_supported_feature(const char *name)
163 {
164 /*
165 * The zfs module spa_feature_table[], whether in-kernel or in
166 * libzpool, always supports all the features. libzfs needs to
167 * query the running module, via sysfs, to determine which
168 * features are supported.
169 */
170 #if defined(_KERNEL) || defined(LIB_ZPOOL_BUILD)
171 return (B_TRUE);
172 #else
173 struct stat64 statbuf;
174 char *path;
175 boolean_t supported = B_FALSE;
176 int len;
177
178 len = asprintf(&path, "%s/%s/%s", ZFS_SYSFS_DIR,
179 ZFS_SYSFS_POOL_FEATURES, name);
180
181 if (len > 0) {
182 supported = !!(stat64(path, &statbuf) == 0);
183 free(path);
184 }
185 return (supported);
186 #endif
187 }
188
189 static void
190 zfeature_register(spa_feature_t fid, const char *guid, const char *name,
191 const char *desc, zfeature_flags_t flags, const spa_feature_t *deps)
192 {
193 zfeature_info_t *feature = &spa_feature_table[fid];
194 static spa_feature_t nodeps[] = { SPA_FEATURE_NONE };
195
196 ASSERT(name != NULL);
197 ASSERT(desc != NULL);
198 ASSERT((flags & ZFEATURE_FLAG_READONLY_COMPAT) == 0 ||
199 (flags & ZFEATURE_FLAG_MOS) == 0);
200 ASSERT3U(fid, <, SPA_FEATURES);
201 ASSERT(zfeature_is_valid_guid(guid));
202
203 if (deps == NULL)
204 deps = nodeps;
205
206 VERIFY(((flags & ZFEATURE_FLAG_PER_DATASET) == 0) ||
207 (deps_contains_feature(deps, SPA_FEATURE_EXTENSIBLE_DATASET)));
208
209 feature->fi_feature = fid;
210 feature->fi_guid = guid;
211 feature->fi_uname = name;
212 feature->fi_desc = desc;
213 feature->fi_flags = flags;
214 feature->fi_depends = deps;
215 feature->fi_zfs_mod_supported = zfs_mod_supported_feature(guid);
216 }
217
218 void
219 zpool_feature_init(void)
220 {
221 zfeature_register(SPA_FEATURE_ASYNC_DESTROY,
222 "com.delphix:async_destroy", "async_destroy",
223 "Destroy filesystems asynchronously.",
224 ZFEATURE_FLAG_READONLY_COMPAT, NULL);
225
226 zfeature_register(SPA_FEATURE_EMPTY_BPOBJ,
227 "com.delphix:empty_bpobj", "empty_bpobj",
228 "Snapshots use less space.",
229 ZFEATURE_FLAG_READONLY_COMPAT, NULL);
230
231 zfeature_register(SPA_FEATURE_LZ4_COMPRESS,
232 "org.illumos:lz4_compress", "lz4_compress",
233 "LZ4 compression algorithm support.",
234 ZFEATURE_FLAG_ACTIVATE_ON_ENABLE, NULL);
235
236 zfeature_register(SPA_FEATURE_MULTI_VDEV_CRASH_DUMP,
237 "com.joyent:multi_vdev_crash_dump", "multi_vdev_crash_dump",
238 "Crash dumps to multiple vdev pools.",
239 0, NULL);
240
241 zfeature_register(SPA_FEATURE_SPACEMAP_HISTOGRAM,
242 "com.delphix:spacemap_histogram", "spacemap_histogram",
243 "Spacemaps maintain space histograms.",
244 ZFEATURE_FLAG_READONLY_COMPAT, NULL);
245
246 zfeature_register(SPA_FEATURE_ENABLED_TXG,
247 "com.delphix:enabled_txg", "enabled_txg",
248 "Record txg at which a feature is enabled",
249 ZFEATURE_FLAG_READONLY_COMPAT, NULL);
250
251 {
252 static const spa_feature_t hole_birth_deps[] = {
253 SPA_FEATURE_ENABLED_TXG,
254 SPA_FEATURE_NONE
255 };
256 zfeature_register(SPA_FEATURE_HOLE_BIRTH,
257 "com.delphix:hole_birth", "hole_birth",
258 "Retain hole birth txg for more precise zfs send",
259 ZFEATURE_FLAG_MOS | ZFEATURE_FLAG_ACTIVATE_ON_ENABLE,
260 hole_birth_deps);
261 }
262
263 zfeature_register(SPA_FEATURE_POOL_CHECKPOINT,
264 "com.delphix:zpool_checkpoint", "zpool_checkpoint",
265 "Pool state can be checkpointed, allowing rewind later.",
266 ZFEATURE_FLAG_READONLY_COMPAT, NULL);
267
268 zfeature_register(SPA_FEATURE_SPACEMAP_V2,
269 "com.delphix:spacemap_v2", "spacemap_v2",
270 "Space maps representing large segments are more efficient.",
271 ZFEATURE_FLAG_READONLY_COMPAT | ZFEATURE_FLAG_ACTIVATE_ON_ENABLE,
272 NULL);
273
274 zfeature_register(SPA_FEATURE_EXTENSIBLE_DATASET,
275 "com.delphix:extensible_dataset", "extensible_dataset",
276 "Enhanced dataset functionality, used by other features.",
277 0, NULL);
278
279 {
280 static const spa_feature_t bookmarks_deps[] = {
281 SPA_FEATURE_EXTENSIBLE_DATASET,
282 SPA_FEATURE_NONE
283 };
284
285 zfeature_register(SPA_FEATURE_BOOKMARKS,
286 "com.delphix:bookmarks", "bookmarks",
287 "\"zfs bookmark\" command",
288 ZFEATURE_FLAG_READONLY_COMPAT, bookmarks_deps);
289 }
290
291 {
292 static const spa_feature_t filesystem_limits_deps[] = {
293 SPA_FEATURE_EXTENSIBLE_DATASET,
294 SPA_FEATURE_NONE
295 };
296 zfeature_register(SPA_FEATURE_FS_SS_LIMIT,
297 "com.joyent:filesystem_limits", "filesystem_limits",
298 "Filesystem and snapshot limits.",
299 ZFEATURE_FLAG_READONLY_COMPAT, filesystem_limits_deps);
300 }
301
302 zfeature_register(SPA_FEATURE_EMBEDDED_DATA,
303 "com.delphix:embedded_data", "embedded_data",
304 "Blocks which compress very well use even less space.",
305 ZFEATURE_FLAG_MOS | ZFEATURE_FLAG_ACTIVATE_ON_ENABLE,
306 NULL);
307
308 {
309 static const spa_feature_t large_blocks_deps[] = {
310 SPA_FEATURE_EXTENSIBLE_DATASET,
311 SPA_FEATURE_NONE
312 };
313 zfeature_register(SPA_FEATURE_LARGE_BLOCKS,
314 "org.open-zfs:large_blocks", "large_blocks",
315 "Support for blocks larger than 128KB.",
316 ZFEATURE_FLAG_PER_DATASET, large_blocks_deps);
317 }
318
319 {
320 static const spa_feature_t large_dnode_deps[] = {
321 SPA_FEATURE_EXTENSIBLE_DATASET,
322 SPA_FEATURE_NONE
323 };
324 zfeature_register(SPA_FEATURE_LARGE_DNODE,
325 "org.zfsonlinux:large_dnode", "large_dnode",
326 "Variable on-disk size of dnodes.",
327 ZFEATURE_FLAG_PER_DATASET, large_dnode_deps);
328 }
329
330 {
331 static const spa_feature_t sha512_deps[] = {
332 SPA_FEATURE_EXTENSIBLE_DATASET,
333 SPA_FEATURE_NONE
334 };
335 zfeature_register(SPA_FEATURE_SHA512,
336 "org.illumos:sha512", "sha512",
337 "SHA-512/256 hash algorithm.",
338 ZFEATURE_FLAG_PER_DATASET, sha512_deps);
339 }
340 {
341 static const spa_feature_t skein_deps[] = {
342 SPA_FEATURE_EXTENSIBLE_DATASET,
343 SPA_FEATURE_NONE
344 };
345 zfeature_register(SPA_FEATURE_SKEIN,
346 "org.illumos:skein", "skein",
347 "Skein hash algorithm.",
348 ZFEATURE_FLAG_PER_DATASET, skein_deps);
349 }
350
351 {
352 static const spa_feature_t edonr_deps[] = {
353 SPA_FEATURE_EXTENSIBLE_DATASET,
354 SPA_FEATURE_NONE
355 };
356 zfeature_register(SPA_FEATURE_EDONR,
357 "org.illumos:edonr", "edonr",
358 "Edon-R hash algorithm.",
359 ZFEATURE_FLAG_PER_DATASET, edonr_deps);
360 }
361 zfeature_register(SPA_FEATURE_DEVICE_REMOVAL,
362 "com.delphix:device_removal", "device_removal",
363 "Top-level vdevs can be removed, reducing logical pool size.",
364 ZFEATURE_FLAG_MOS, NULL);
365 {
366 static const spa_feature_t obsolete_counts_deps[] = {
367 SPA_FEATURE_EXTENSIBLE_DATASET,
368 SPA_FEATURE_DEVICE_REMOVAL,
369 SPA_FEATURE_NONE
370 };
371 zfeature_register(SPA_FEATURE_OBSOLETE_COUNTS,
372 "com.delphix:obsolete_counts", "obsolete_counts",
373 "Reduce memory used by removed devices when their blocks are "
374 "freed or remapped.",
375 ZFEATURE_FLAG_READONLY_COMPAT, obsolete_counts_deps);
376 }
377 {
378 static const spa_feature_t userobj_accounting_deps[] = {
379 SPA_FEATURE_EXTENSIBLE_DATASET,
380 SPA_FEATURE_NONE
381 };
382 zfeature_register(SPA_FEATURE_USEROBJ_ACCOUNTING,
383 "org.zfsonlinux:userobj_accounting", "userobj_accounting",
384 "User/Group object accounting.",
385 ZFEATURE_FLAG_READONLY_COMPAT | ZFEATURE_FLAG_PER_DATASET,
386 userobj_accounting_deps);
387 }
388
389 {
390 static const spa_feature_t encryption_deps[] = {
391 SPA_FEATURE_EXTENSIBLE_DATASET,
392 SPA_FEATURE_NONE
393 };
394 zfeature_register(SPA_FEATURE_ENCRYPTION,
395 "com.datto:encryption", "encryption",
396 "Support for dataset level encryption",
397 ZFEATURE_FLAG_PER_DATASET, encryption_deps);
398 }
399
400 {
401 static const spa_feature_t project_quota_deps[] = {
402 SPA_FEATURE_EXTENSIBLE_DATASET,
403 SPA_FEATURE_NONE
404 };
405 zfeature_register(SPA_FEATURE_PROJECT_QUOTA,
406 "org.zfsonlinux:project_quota", "project_quota",
407 "space/object accounting based on project ID.",
408 ZFEATURE_FLAG_READONLY_COMPAT | ZFEATURE_FLAG_PER_DATASET,
409 project_quota_deps);
410 }
411 }
412
413 #if defined(_KERNEL)
414 EXPORT_SYMBOL(zfeature_lookup_guid);
415 EXPORT_SYMBOL(zfeature_lookup_name);
416 EXPORT_SYMBOL(zfeature_is_supported);
417 EXPORT_SYMBOL(zfeature_is_valid_guid);
418 EXPORT_SYMBOL(zfeature_depends_on);
419 EXPORT_SYMBOL(zpool_feature_init);
420 EXPORT_SYMBOL(spa_feature_table);
421 #endif