btrfs-progs: tests: convert misc/011-delete-missing-device to loopdevs
[platform/upstream/btrfs-progs.git] / fsfeatures.c
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public
4  * License v2 as published by the Free Software Foundation.
5  *
6  * This program is distributed in the hope that it will be useful,
7  * but WITHOUT ANY WARRANTY; without even the implied warranty of
8  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
9  * General Public License for more details.
10  *
11  * You should have received a copy of the GNU General Public
12  * License along with this program; if not, write to the
13  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
14  * Boston, MA 021110-1307, USA.
15  */
16
17 #include "kerncompat.h"
18 #include <sys/utsname.h>
19 #include <linux/version.h>
20 #include "fsfeatures.h"
21 #include "ctree.h"
22 #include "utils.h"
23
24 /*
25  * Insert a root item for temporary tree root
26  *
27  * Only used in make_btrfs_v2().
28  */
29 #define VERSION_TO_STRING3(a,b,c)       #a "." #b "." #c, KERNEL_VERSION(a,b,c)
30 #define VERSION_TO_STRING2(a,b)         #a "." #b, KERNEL_VERSION(a,b,0)
31
32 /*
33  * Feature stability status and versions: compat <= safe <= default
34  */
35 static const struct btrfs_fs_feature {
36         const char *name;
37         u64 flag;
38         const char *sysfs_name;
39         /*
40          * Compatibility with kernel of given version. Filesystem can be
41          * mounted.
42          */
43         const char *compat_str;
44         u32 compat_ver;
45         /*
46          * Considered safe for use, but is not on by default, even if the
47          * kernel supports the feature.
48          */
49         const char *safe_str;
50         u32 safe_ver;
51         /*
52          * Considered safe for use and will be turned on by default if
53          * supported by the running kernel.
54          */
55         const char *default_str;
56         u32 default_ver;
57         const char *desc;
58 } mkfs_features[] = {
59         { "mixed-bg", BTRFS_FEATURE_INCOMPAT_MIXED_GROUPS,
60                 "mixed_groups",
61                 VERSION_TO_STRING3(2,6,37),
62                 VERSION_TO_STRING3(2,6,37),
63                 NULL, 0,
64                 "mixed data and metadata block groups" },
65         { "extref", BTRFS_FEATURE_INCOMPAT_EXTENDED_IREF,
66                 "extended_iref",
67                 VERSION_TO_STRING2(3,7),
68                 VERSION_TO_STRING2(3,12),
69                 VERSION_TO_STRING2(3,12),
70                 "increased hardlink limit per file to 65536" },
71         { "raid56", BTRFS_FEATURE_INCOMPAT_RAID56,
72                 "raid56",
73                 VERSION_TO_STRING2(3,9),
74                 NULL, 0,
75                 NULL, 0,
76                 "raid56 extended format" },
77         { "skinny-metadata", BTRFS_FEATURE_INCOMPAT_SKINNY_METADATA,
78                 "skinny_metadata",
79                 VERSION_TO_STRING2(3,10),
80                 VERSION_TO_STRING2(3,18),
81                 VERSION_TO_STRING2(3,18),
82                 "reduced-size metadata extent refs" },
83         { "no-holes", BTRFS_FEATURE_INCOMPAT_NO_HOLES,
84                 "no_holes",
85                 VERSION_TO_STRING2(3,14),
86                 VERSION_TO_STRING2(4,0),
87                 NULL, 0,
88                 "no explicit hole extents for files" },
89         /* Keep this one last */
90         { "list-all", BTRFS_FEATURE_LIST_ALL, NULL }
91 };
92
93 static int parse_one_fs_feature(const char *name, u64 *flags)
94 {
95         int i;
96         int found = 0;
97
98         for (i = 0; i < ARRAY_SIZE(mkfs_features); i++) {
99                 if (name[0] == '^' &&
100                         !strcmp(mkfs_features[i].name, name + 1)) {
101                         *flags &= ~ mkfs_features[i].flag;
102                         found = 1;
103                 } else if (!strcmp(mkfs_features[i].name, name)) {
104                         *flags |= mkfs_features[i].flag;
105                         found = 1;
106                 }
107         }
108
109         return !found;
110 }
111
112 void btrfs_parse_features_to_string(char *buf, u64 flags)
113 {
114         int i;
115
116         buf[0] = 0;
117
118         for (i = 0; i < ARRAY_SIZE(mkfs_features); i++) {
119                 if (flags & mkfs_features[i].flag) {
120                         if (*buf)
121                                 strcat(buf, ", ");
122                         strcat(buf, mkfs_features[i].name);
123                 }
124         }
125 }
126
127 void btrfs_process_fs_features(u64 flags)
128 {
129         int i;
130
131         for (i = 0; i < ARRAY_SIZE(mkfs_features); i++) {
132                 if (flags & mkfs_features[i].flag) {
133                         printf("Turning ON incompat feature '%s': %s\n",
134                                 mkfs_features[i].name,
135                                 mkfs_features[i].desc);
136                 }
137         }
138 }
139
140 void btrfs_list_all_fs_features(u64 mask_disallowed)
141 {
142         int i;
143
144         fprintf(stderr, "Filesystem features available:\n");
145         for (i = 0; i < ARRAY_SIZE(mkfs_features) - 1; i++) {
146                 const struct btrfs_fs_feature *feat = &mkfs_features[i];
147
148                 if (feat->flag & mask_disallowed)
149                         continue;
150                 fprintf(stderr, "%-20s- %s (0x%llx", feat->name, feat->desc,
151                                 feat->flag);
152                 if (feat->compat_ver)
153                         fprintf(stderr, ", compat=%s", feat->compat_str);
154                 if (feat->safe_ver)
155                         fprintf(stderr, ", safe=%s", feat->safe_str);
156                 if (feat->default_ver)
157                         fprintf(stderr, ", default=%s", feat->default_str);
158                 fprintf(stderr, ")\n");
159         }
160 }
161
162 /*
163  * Return NULL if all features were parsed fine, otherwise return the name of
164  * the first unparsed.
165  */
166 char* btrfs_parse_fs_features(char *namelist, u64 *flags)
167 {
168         char *this_char;
169         char *save_ptr = NULL; /* Satisfy static checkers */
170
171         for (this_char = strtok_r(namelist, ",", &save_ptr);
172              this_char != NULL;
173              this_char = strtok_r(NULL, ",", &save_ptr)) {
174                 if (parse_one_fs_feature(this_char, flags))
175                         return this_char;
176         }
177
178         return NULL;
179 }
180
181 void print_kernel_version(FILE *stream, u32 version)
182 {
183         u32 v[3];
184
185         v[0] = version & 0xFF;
186         v[1] = (version >> 8) & 0xFF;
187         v[2] = version >> 16;
188         fprintf(stream, "%u.%u", v[2], v[1]);
189         if (v[0])
190                 fprintf(stream, ".%u", v[0]);
191 }
192
193 u32 get_running_kernel_version(void)
194 {
195         struct utsname utsbuf;
196         char *tmp;
197         char *saveptr = NULL;
198         u32 version;
199
200         uname(&utsbuf);
201         if (strcmp(utsbuf.sysname, "Linux") != 0) {
202                 error("unsupported system: %s", utsbuf.sysname);
203                 exit(1);
204         }
205         /* 1.2.3-4-name */
206         tmp = strchr(utsbuf.release, '-');
207         if (tmp)
208                 *tmp = 0;
209
210         tmp = strtok_r(utsbuf.release, ".", &saveptr);
211         if (!string_is_numerical(tmp))
212                 return (u32)-1;
213         version = atoi(tmp) << 16;
214         tmp = strtok_r(NULL, ".", &saveptr);
215         if (!string_is_numerical(tmp))
216                 return (u32)-1;
217         version |= atoi(tmp) << 8;
218         tmp = strtok_r(NULL, ".", &saveptr);
219         if (tmp) {
220                 if (!string_is_numerical(tmp))
221                         return (u32)-1;
222                 version |= atoi(tmp);
223         }
224
225         return version;
226 }
227