]>
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. |
62bdd5eb | 25 | * Copyright (c) 2014, Nexenta Systems, Inc. All rights reserved. |
9ae529ec CS |
26 | */ |
27 | ||
28 | #ifdef _KERNEL | |
29 | #include <sys/systm.h> | |
30 | #else | |
31 | #include <errno.h> | |
32 | #include <string.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 "zfeature_common.h" | |
39 | ||
40 | /* | |
41 | * Set to disable all feature checks while opening pools, allowing pools with | |
42 | * unsupported features to be opened. Set for testing only. | |
43 | */ | |
44 | boolean_t zfeature_checks_disable = B_FALSE; | |
45 | ||
46 | zfeature_info_t spa_feature_table[SPA_FEATURES]; | |
47 | ||
48 | /* | |
49 | * Valid characters for feature guids. This list is mainly for aesthetic | |
50 | * purposes and could be expanded in the future. There are different allowed | |
51 | * characters in the guids reverse dns portion (before the colon) and its | |
52 | * short name (after the colon). | |
53 | */ | |
54 | static int | |
55 | valid_char(char c, boolean_t after_colon) | |
56 | { | |
57 | return ((c >= 'a' && c <= 'z') || | |
58 | (c >= '0' && c <= '9') || | |
f1512ee6 MA |
59 | (after_colon && c == '_') || |
60 | (!after_colon && (c == '.' || c == '-'))); | |
9ae529ec CS |
61 | } |
62 | ||
63 | /* | |
64 | * Every feature guid must contain exactly one colon which separates a reverse | |
65 | * dns organization name from the feature's "short" name (e.g. | |
66 | * "com.company:feature_name"). | |
67 | */ | |
68 | boolean_t | |
69 | zfeature_is_valid_guid(const char *name) | |
70 | { | |
71 | int i; | |
72 | boolean_t has_colon = B_FALSE; | |
73 | ||
74 | i = 0; | |
75 | while (name[i] != '\0') { | |
76 | char c = name[i++]; | |
77 | if (c == ':') { | |
78 | if (has_colon) | |
79 | return (B_FALSE); | |
80 | has_colon = B_TRUE; | |
81 | continue; | |
82 | } | |
83 | if (!valid_char(c, has_colon)) | |
84 | return (B_FALSE); | |
85 | } | |
86 | ||
87 | return (has_colon); | |
88 | } | |
89 | ||
90 | boolean_t | |
91 | zfeature_is_supported(const char *guid) | |
92 | { | |
fa86b5db MA |
93 | spa_feature_t i; |
94 | ||
9ae529ec CS |
95 | if (zfeature_checks_disable) |
96 | return (B_TRUE); | |
97 | ||
9ae529ec CS |
98 | for (i = 0; i < SPA_FEATURES; i++) { |
99 | zfeature_info_t *feature = &spa_feature_table[i]; | |
fa86b5db MA |
100 | if (strcmp(guid, feature->fi_guid) == 0) |
101 | return (B_TRUE); | |
9ae529ec CS |
102 | } |
103 | ||
fa86b5db | 104 | return (B_FALSE); |
9ae529ec CS |
105 | } |
106 | ||
107 | int | |
fa86b5db | 108 | zfeature_lookup_name(const char *name, spa_feature_t *res) |
9ae529ec | 109 | { |
fa86b5db | 110 | spa_feature_t i; |
9ae529ec CS |
111 | |
112 | for (i = 0; i < SPA_FEATURES; i++) { | |
113 | zfeature_info_t *feature = &spa_feature_table[i]; | |
114 | if (strcmp(name, feature->fi_uname) == 0) { | |
115 | if (res != NULL) | |
fa86b5db | 116 | *res = i; |
9ae529ec CS |
117 | return (0); |
118 | } | |
119 | } | |
120 | ||
121 | return (ENOENT); | |
122 | } | |
123 | ||
b0bc7a84 MG |
124 | boolean_t |
125 | zfeature_depends_on(spa_feature_t fid, spa_feature_t check) { | |
126 | zfeature_info_t *feature = &spa_feature_table[fid]; | |
127 | int i; | |
128 | ||
129 | for (i = 0; feature->fi_depends[i] != SPA_FEATURE_NONE; i++) { | |
130 | if (feature->fi_depends[i] == check) | |
131 | return (B_TRUE); | |
132 | } | |
133 | return (B_FALSE); | |
134 | } | |
135 | ||
9ae529ec | 136 | static void |
fa86b5db | 137 | zfeature_register(spa_feature_t fid, const char *guid, const char *name, |
241b5415 | 138 | const char *desc, zfeature_flags_t flags, const spa_feature_t *deps) |
9ae529ec CS |
139 | { |
140 | zfeature_info_t *feature = &spa_feature_table[fid]; | |
fa86b5db | 141 | static spa_feature_t nodeps[] = { SPA_FEATURE_NONE }; |
9ae529ec CS |
142 | |
143 | ASSERT(name != NULL); | |
144 | ASSERT(desc != NULL); | |
241b5415 MA |
145 | ASSERT((flags & ZFEATURE_FLAG_READONLY_COMPAT) == 0 || |
146 | (flags & ZFEATURE_FLAG_MOS) == 0); | |
9ae529ec CS |
147 | ASSERT3U(fid, <, SPA_FEATURES); |
148 | ASSERT(zfeature_is_valid_guid(guid)); | |
149 | ||
150 | if (deps == NULL) | |
151 | deps = nodeps; | |
152 | ||
fa86b5db | 153 | feature->fi_feature = fid; |
9ae529ec CS |
154 | feature->fi_guid = guid; |
155 | feature->fi_uname = name; | |
156 | feature->fi_desc = desc; | |
241b5415 | 157 | feature->fi_flags = flags; |
9ae529ec CS |
158 | feature->fi_depends = deps; |
159 | } | |
160 | ||
161 | void | |
162 | zpool_feature_init(void) | |
163 | { | |
164 | zfeature_register(SPA_FEATURE_ASYNC_DESTROY, | |
165 | "com.delphix:async_destroy", "async_destroy", | |
241b5415 MA |
166 | "Destroy filesystems asynchronously.", |
167 | ZFEATURE_FLAG_READONLY_COMPAT, NULL); | |
b0bc7a84 | 168 | |
753c3839 MA |
169 | zfeature_register(SPA_FEATURE_EMPTY_BPOBJ, |
170 | "com.delphix:empty_bpobj", "empty_bpobj", | |
241b5415 MA |
171 | "Snapshots use less space.", |
172 | ZFEATURE_FLAG_READONLY_COMPAT, NULL); | |
b0bc7a84 | 173 | |
9759c60f ED |
174 | zfeature_register(SPA_FEATURE_LZ4_COMPRESS, |
175 | "org.illumos:lz4_compress", "lz4_compress", | |
241b5415 MA |
176 | "LZ4 compression algorithm support.", |
177 | ZFEATURE_FLAG_ACTIVATE_ON_ENABLE, NULL); | |
b0bc7a84 | 178 | |
93cf2076 GW |
179 | zfeature_register(SPA_FEATURE_SPACEMAP_HISTOGRAM, |
180 | "com.delphix:spacemap_histogram", "spacemap_histogram", | |
241b5415 MA |
181 | "Spacemaps maintain space histograms.", |
182 | ZFEATURE_FLAG_READONLY_COMPAT, NULL); | |
b0bc7a84 MG |
183 | |
184 | zfeature_register(SPA_FEATURE_ENABLED_TXG, | |
185 | "com.delphix:enabled_txg", "enabled_txg", | |
241b5415 MA |
186 | "Record txg at which a feature is enabled", |
187 | ZFEATURE_FLAG_READONLY_COMPAT, NULL); | |
b0bc7a84 MG |
188 | |
189 | { | |
da536844 MA |
190 | static const spa_feature_t hole_birth_deps[] = { |
191 | SPA_FEATURE_ENABLED_TXG, | |
192 | SPA_FEATURE_NONE | |
193 | }; | |
b0bc7a84 MG |
194 | zfeature_register(SPA_FEATURE_HOLE_BIRTH, |
195 | "com.delphix:hole_birth", "hole_birth", | |
196 | "Retain hole birth txg for more precise zfs send", | |
241b5415 MA |
197 | ZFEATURE_FLAG_MOS | ZFEATURE_FLAG_ACTIVATE_ON_ENABLE, |
198 | hole_birth_deps); | |
b0bc7a84 MG |
199 | } |
200 | ||
fa86b5db MA |
201 | zfeature_register(SPA_FEATURE_EXTENSIBLE_DATASET, |
202 | "com.delphix:extensible_dataset", "extensible_dataset", | |
203 | "Enhanced dataset functionality, used by other features.", | |
241b5415 | 204 | 0, NULL); |
da536844 MA |
205 | |
206 | { | |
207 | static const spa_feature_t bookmarks_deps[] = { | |
208 | SPA_FEATURE_EXTENSIBLE_DATASET, | |
209 | SPA_FEATURE_NONE | |
210 | }; | |
211 | ||
212 | zfeature_register(SPA_FEATURE_BOOKMARKS, | |
213 | "com.delphix:bookmarks", "bookmarks", | |
214 | "\"zfs bookmark\" command", | |
241b5415 | 215 | ZFEATURE_FLAG_READONLY_COMPAT, bookmarks_deps); |
da536844 | 216 | } |
9b67f605 | 217 | |
788eb90c JJ |
218 | { |
219 | static const spa_feature_t filesystem_limits_deps[] = { | |
220 | SPA_FEATURE_EXTENSIBLE_DATASET, | |
221 | SPA_FEATURE_NONE | |
222 | }; | |
223 | zfeature_register(SPA_FEATURE_FS_SS_LIMIT, | |
224 | "com.joyent:filesystem_limits", "filesystem_limits", | |
241b5415 MA |
225 | "Filesystem and snapshot limits.", |
226 | ZFEATURE_FLAG_READONLY_COMPAT, filesystem_limits_deps); | |
788eb90c JJ |
227 | } |
228 | ||
9b67f605 MA |
229 | zfeature_register(SPA_FEATURE_EMBEDDED_DATA, |
230 | "com.delphix:embedded_data", "embedded_data", | |
231 | "Blocks which compress very well use even less space.", | |
241b5415 MA |
232 | ZFEATURE_FLAG_MOS | ZFEATURE_FLAG_ACTIVATE_ON_ENABLE, |
233 | NULL); | |
f1512ee6 MA |
234 | |
235 | { | |
236 | static const spa_feature_t large_blocks_deps[] = { | |
237 | SPA_FEATURE_EXTENSIBLE_DATASET, | |
238 | SPA_FEATURE_NONE | |
239 | }; | |
240 | zfeature_register(SPA_FEATURE_LARGE_BLOCKS, | |
241 | "org.open-zfs:large_blocks", "large_blocks", | |
241b5415 MA |
242 | "Support for blocks larger than 128KB.", |
243 | ZFEATURE_FLAG_PER_DATASET, large_blocks_deps); | |
f1512ee6 | 244 | } |
50c957f7 NB |
245 | |
246 | { | |
247 | static const spa_feature_t large_dnode_deps[] = { | |
248 | SPA_FEATURE_EXTENSIBLE_DATASET, | |
249 | SPA_FEATURE_NONE | |
250 | }; | |
251 | zfeature_register(SPA_FEATURE_LARGE_DNODE, | |
252 | "org.zfsonlinux:large_dnode", "large_dnode", | |
253 | "Variable on-disk size of dnodes.", | |
254 | ZFEATURE_FLAG_PER_DATASET, large_dnode_deps); | |
255 | } | |
125a406e | 256 | |
257 | { | |
258 | static const spa_feature_t sha512_deps[] = { | |
259 | SPA_FEATURE_EXTENSIBLE_DATASET, | |
260 | SPA_FEATURE_NONE | |
261 | }; | |
3c67d83a TH |
262 | zfeature_register(SPA_FEATURE_SHA512, |
263 | "org.illumos:sha512", "sha512", | |
264 | "SHA-512/256 hash algorithm.", | |
125a406e | 265 | ZFEATURE_FLAG_PER_DATASET, sha512_deps); |
266 | } | |
267 | { | |
268 | static const spa_feature_t skein_deps[] = { | |
269 | SPA_FEATURE_EXTENSIBLE_DATASET, | |
270 | SPA_FEATURE_NONE | |
271 | }; | |
3c67d83a TH |
272 | zfeature_register(SPA_FEATURE_SKEIN, |
273 | "org.illumos:skein", "skein", | |
274 | "Skein hash algorithm.", | |
125a406e | 275 | ZFEATURE_FLAG_PER_DATASET, skein_deps); |
276 | } | |
277 | ||
278 | { | |
279 | static const spa_feature_t edonr_deps[] = { | |
280 | SPA_FEATURE_EXTENSIBLE_DATASET, | |
281 | SPA_FEATURE_NONE | |
282 | }; | |
3c67d83a TH |
283 | zfeature_register(SPA_FEATURE_EDONR, |
284 | "org.illumos:edonr", "edonr", | |
285 | "Edon-R hash algorithm.", | |
125a406e | 286 | ZFEATURE_FLAG_PER_DATASET, edonr_deps); |
287 | } | |
1de321e6 JX |
288 | { |
289 | static const spa_feature_t userobj_accounting_deps[] = { | |
290 | SPA_FEATURE_EXTENSIBLE_DATASET, | |
291 | SPA_FEATURE_NONE | |
292 | }; | |
293 | zfeature_register(SPA_FEATURE_USEROBJ_ACCOUNTING, | |
294 | "org.zfsonlinux:userobj_accounting", "userobj_accounting", | |
295 | "User/Group object accounting.", | |
296 | ZFEATURE_FLAG_READONLY_COMPAT | ZFEATURE_FLAG_PER_DATASET, | |
297 | userobj_accounting_deps); | |
298 | } | |
9ae529ec | 299 | } |