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.
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.
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]
23 * Copyright (c) 2013 by Delphix. All rights reserved.
24 * Copyright (c) 2013 by Saso Kiselkov. All rights reserved.
25 * Copyright (c) 2014, Nexenta Systems, Inc. All rights reserved.
29 #include <sys/systm.h>
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"
41 * Set to disable all feature checks while opening pools, allowing pools with
42 * unsupported features to be opened. Set for testing only.
44 boolean_t zfeature_checks_disable
= B_FALSE
;
46 zfeature_info_t spa_feature_table
[SPA_FEATURES
];
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).
55 valid_char(char c
, boolean_t after_colon
)
57 return ((c
>= 'a' && c
<= 'z') ||
58 (c
>= '0' && c
<= '9') ||
59 (after_colon
&& c
== '_') ||
60 (!after_colon
&& (c
== '.' || c
== '-')));
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").
69 zfeature_is_valid_guid(const char *name
)
72 boolean_t has_colon
= B_FALSE
;
75 while (name
[i
] != '\0') {
83 if (!valid_char(c
, has_colon
))
91 zfeature_is_supported(const char *guid
)
95 if (zfeature_checks_disable
)
98 for (i
= 0; i
< SPA_FEATURES
; i
++) {
99 zfeature_info_t
*feature
= &spa_feature_table
[i
];
100 if (strcmp(guid
, feature
->fi_guid
) == 0)
108 zfeature_lookup_name(const char *name
, spa_feature_t
*res
)
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) {
125 zfeature_depends_on(spa_feature_t fid
, spa_feature_t check
) {
126 zfeature_info_t
*feature
= &spa_feature_table
[fid
];
129 for (i
= 0; feature
->fi_depends
[i
] != SPA_FEATURE_NONE
; i
++) {
130 if (feature
->fi_depends
[i
] == check
)
137 zfeature_register(spa_feature_t fid
, const char *guid
, const char *name
,
138 const char *desc
, boolean_t readonly
, boolean_t mos
,
139 boolean_t activate_on_enable
, const spa_feature_t
*deps
)
141 zfeature_info_t
*feature
= &spa_feature_table
[fid
];
142 static spa_feature_t nodeps
[] = { SPA_FEATURE_NONE
};
144 ASSERT(name
!= NULL
);
145 ASSERT(desc
!= NULL
);
146 ASSERT(!readonly
|| !mos
);
147 ASSERT3U(fid
, <, SPA_FEATURES
);
148 ASSERT(zfeature_is_valid_guid(guid
));
153 feature
->fi_feature
= fid
;
154 feature
->fi_guid
= guid
;
155 feature
->fi_uname
= name
;
156 feature
->fi_desc
= desc
;
157 feature
->fi_can_readonly
= readonly
;
158 feature
->fi_mos
= mos
;
159 feature
->fi_activate_on_enable
= activate_on_enable
;
160 feature
->fi_depends
= deps
;
164 zpool_feature_init(void)
166 zfeature_register(SPA_FEATURE_ASYNC_DESTROY
,
167 "com.delphix:async_destroy", "async_destroy",
168 "Destroy filesystems asynchronously.", B_TRUE
, B_FALSE
,
171 zfeature_register(SPA_FEATURE_EMPTY_BPOBJ
,
172 "com.delphix:empty_bpobj", "empty_bpobj",
173 "Snapshots use less space.", B_TRUE
, B_FALSE
,
176 zfeature_register(SPA_FEATURE_LZ4_COMPRESS
,
177 "org.illumos:lz4_compress", "lz4_compress",
178 "LZ4 compression algorithm support.", B_FALSE
, B_FALSE
,
181 zfeature_register(SPA_FEATURE_SPACEMAP_HISTOGRAM
,
182 "com.delphix:spacemap_histogram", "spacemap_histogram",
183 "Spacemaps maintain space histograms.", B_TRUE
, B_FALSE
,
186 zfeature_register(SPA_FEATURE_ENABLED_TXG
,
187 "com.delphix:enabled_txg", "enabled_txg",
188 "Record txg at which a feature is enabled", B_TRUE
, B_FALSE
,
192 static const spa_feature_t hole_birth_deps
[] = {
193 SPA_FEATURE_ENABLED_TXG
,
196 zfeature_register(SPA_FEATURE_HOLE_BIRTH
,
197 "com.delphix:hole_birth", "hole_birth",
198 "Retain hole birth txg for more precise zfs send",
199 B_FALSE
, B_TRUE
, B_TRUE
, hole_birth_deps
);
202 zfeature_register(SPA_FEATURE_EXTENSIBLE_DATASET
,
203 "com.delphix:extensible_dataset", "extensible_dataset",
204 "Enhanced dataset functionality, used by other features.",
205 B_FALSE
, B_FALSE
, B_FALSE
, NULL
);
208 static const spa_feature_t bookmarks_deps
[] = {
209 SPA_FEATURE_EXTENSIBLE_DATASET
,
213 zfeature_register(SPA_FEATURE_BOOKMARKS
,
214 "com.delphix:bookmarks", "bookmarks",
215 "\"zfs bookmark\" command",
216 B_TRUE
, B_FALSE
, B_FALSE
, bookmarks_deps
);
220 static const spa_feature_t filesystem_limits_deps
[] = {
221 SPA_FEATURE_EXTENSIBLE_DATASET
,
224 zfeature_register(SPA_FEATURE_FS_SS_LIMIT
,
225 "com.joyent:filesystem_limits", "filesystem_limits",
226 "Filesystem and snapshot limits.", B_TRUE
, B_FALSE
, B_FALSE
,
227 filesystem_limits_deps
);
230 zfeature_register(SPA_FEATURE_EMBEDDED_DATA
,
231 "com.delphix:embedded_data", "embedded_data",
232 "Blocks which compress very well use even less space.",
233 B_FALSE
, B_TRUE
, B_TRUE
, NULL
);
236 static const spa_feature_t large_blocks_deps
[] = {
237 SPA_FEATURE_EXTENSIBLE_DATASET
,
240 zfeature_register(SPA_FEATURE_LARGE_BLOCKS
,
241 "org.open-zfs:large_blocks", "large_blocks",
242 "Support for blocks larger than 128KB.", B_FALSE
, B_FALSE
, B_FALSE
,