]>
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 | /* | |
23 | * Copyright (c) 2012 by Delphix. All rights reserved. | |
9759c60f | 24 | * Copyright (c) 2013 by Saso Kiselkov. All rights reserved. |
9ae529ec CS |
25 | */ |
26 | ||
27 | #ifdef _KERNEL | |
28 | #include <sys/systm.h> | |
29 | #else | |
30 | #include <errno.h> | |
31 | #include <string.h> | |
32 | #endif | |
33 | #include <sys/debug.h> | |
34 | #include <sys/fs/zfs.h> | |
35 | #include <sys/inttypes.h> | |
36 | #include <sys/types.h> | |
37 | #include "zfeature_common.h" | |
38 | ||
39 | /* | |
40 | * Set to disable all feature checks while opening pools, allowing pools with | |
41 | * unsupported features to be opened. Set for testing only. | |
42 | */ | |
43 | boolean_t zfeature_checks_disable = B_FALSE; | |
44 | ||
45 | zfeature_info_t spa_feature_table[SPA_FEATURES]; | |
46 | ||
47 | /* | |
48 | * Valid characters for feature guids. This list is mainly for aesthetic | |
49 | * purposes and could be expanded in the future. There are different allowed | |
50 | * characters in the guids reverse dns portion (before the colon) and its | |
51 | * short name (after the colon). | |
52 | */ | |
53 | static int | |
54 | valid_char(char c, boolean_t after_colon) | |
55 | { | |
56 | return ((c >= 'a' && c <= 'z') || | |
57 | (c >= '0' && c <= '9') || | |
58 | c == (after_colon ? '_' : '.')); | |
59 | } | |
60 | ||
61 | /* | |
62 | * Every feature guid must contain exactly one colon which separates a reverse | |
63 | * dns organization name from the feature's "short" name (e.g. | |
64 | * "com.company:feature_name"). | |
65 | */ | |
66 | boolean_t | |
67 | zfeature_is_valid_guid(const char *name) | |
68 | { | |
69 | int i; | |
70 | boolean_t has_colon = B_FALSE; | |
71 | ||
72 | i = 0; | |
73 | while (name[i] != '\0') { | |
74 | char c = name[i++]; | |
75 | if (c == ':') { | |
76 | if (has_colon) | |
77 | return (B_FALSE); | |
78 | has_colon = B_TRUE; | |
79 | continue; | |
80 | } | |
81 | if (!valid_char(c, has_colon)) | |
82 | return (B_FALSE); | |
83 | } | |
84 | ||
85 | return (has_colon); | |
86 | } | |
87 | ||
88 | boolean_t | |
89 | zfeature_is_supported(const char *guid) | |
90 | { | |
91 | if (zfeature_checks_disable) | |
92 | return (B_TRUE); | |
93 | ||
94 | return (0 == zfeature_lookup_guid(guid, NULL)); | |
95 | } | |
96 | ||
97 | int | |
98 | zfeature_lookup_guid(const char *guid, zfeature_info_t **res) | |
99 | { | |
100 | int i; | |
101 | ||
102 | for (i = 0; i < SPA_FEATURES; i++) { | |
103 | zfeature_info_t *feature = &spa_feature_table[i]; | |
104 | if (strcmp(guid, feature->fi_guid) == 0) { | |
105 | if (res != NULL) | |
106 | *res = feature; | |
107 | return (0); | |
108 | } | |
109 | } | |
110 | ||
111 | return (ENOENT); | |
112 | } | |
113 | ||
114 | int | |
115 | zfeature_lookup_name(const char *name, zfeature_info_t **res) | |
116 | { | |
117 | int i; | |
118 | ||
119 | for (i = 0; i < SPA_FEATURES; i++) { | |
120 | zfeature_info_t *feature = &spa_feature_table[i]; | |
121 | if (strcmp(name, feature->fi_uname) == 0) { | |
122 | if (res != NULL) | |
123 | *res = feature; | |
124 | return (0); | |
125 | } | |
126 | } | |
127 | ||
128 | return (ENOENT); | |
129 | } | |
130 | ||
131 | static void | |
132 | zfeature_register(int fid, const char *guid, const char *name, const char *desc, | |
133 | boolean_t readonly, boolean_t mos, zfeature_info_t **deps) | |
134 | { | |
135 | zfeature_info_t *feature = &spa_feature_table[fid]; | |
136 | static zfeature_info_t *nodeps[] = { NULL }; | |
137 | ||
138 | ASSERT(name != NULL); | |
139 | ASSERT(desc != NULL); | |
140 | ASSERT(!readonly || !mos); | |
141 | ASSERT3U(fid, <, SPA_FEATURES); | |
142 | ASSERT(zfeature_is_valid_guid(guid)); | |
143 | ||
144 | if (deps == NULL) | |
145 | deps = nodeps; | |
146 | ||
147 | feature->fi_guid = guid; | |
148 | feature->fi_uname = name; | |
149 | feature->fi_desc = desc; | |
150 | feature->fi_can_readonly = readonly; | |
151 | feature->fi_mos = mos; | |
152 | feature->fi_depends = deps; | |
153 | } | |
154 | ||
155 | void | |
156 | zpool_feature_init(void) | |
157 | { | |
158 | zfeature_register(SPA_FEATURE_ASYNC_DESTROY, | |
159 | "com.delphix:async_destroy", "async_destroy", | |
160 | "Destroy filesystems asynchronously.", B_TRUE, B_FALSE, NULL); | |
753c3839 MA |
161 | zfeature_register(SPA_FEATURE_EMPTY_BPOBJ, |
162 | "com.delphix:empty_bpobj", "empty_bpobj", | |
163 | "Snapshots use less space.", B_TRUE, B_FALSE, NULL); | |
9759c60f ED |
164 | zfeature_register(SPA_FEATURE_LZ4_COMPRESS, |
165 | "org.illumos:lz4_compress", "lz4_compress", | |
166 | "LZ4 compression algorithm support.", B_FALSE, B_FALSE, NULL); | |
9ae529ec | 167 | } |