4a2f23ee163fb1c9970707a816834c53e1e7e5d4
[cascardo/linux.git] / fs / btrfs / sysfs.c
1 /*
2  * Copyright (C) 2007 Oracle.  All rights reserved.
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public
6  * License v2 as published by the Free Software Foundation.
7  *
8  * This program is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11  * General Public License for more details.
12  *
13  * You should have received a copy of the GNU General Public
14  * License along with this program; if not, write to the
15  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
16  * Boston, MA 021110-1307, USA.
17  */
18
19 #include <linux/sched.h>
20 #include <linux/slab.h>
21 #include <linux/spinlock.h>
22 #include <linux/completion.h>
23 #include <linux/buffer_head.h>
24 #include <linux/kobject.h>
25 #include <linux/bug.h>
26
27 #include "ctree.h"
28 #include "disk-io.h"
29 #include "transaction.h"
30 #include "sysfs.h"
31
32 static inline struct btrfs_fs_info *to_fs_info(struct kobject *kobj);
33
34 static u64 get_features(struct btrfs_fs_info *fs_info,
35                         enum btrfs_feature_set set)
36 {
37         struct btrfs_super_block *disk_super = fs_info->super_copy;
38         if (set == FEAT_COMPAT)
39                 return btrfs_super_compat_flags(disk_super);
40         else if (set == FEAT_COMPAT_RO)
41                 return btrfs_super_compat_ro_flags(disk_super);
42         else
43                 return btrfs_super_incompat_flags(disk_super);
44 }
45
46 static ssize_t btrfs_feature_attr_show(struct kobject *kobj,
47                                        struct kobj_attribute *a, char *buf)
48 {
49         int val = 0;
50         struct btrfs_fs_info *fs_info = to_fs_info(kobj);
51         if (fs_info) {
52                 struct btrfs_feature_attr *fa = to_btrfs_feature_attr(a);
53                 u64 features = get_features(fs_info, fa->feature_set);
54                 if (features & fa->feature_bit)
55                         val = 1;
56         }
57
58         return snprintf(buf, PAGE_SIZE, "%d\n", val);
59 }
60
61 static umode_t btrfs_feature_visible(struct kobject *kobj,
62                                      struct attribute *attr, int unused)
63 {
64         struct btrfs_fs_info *fs_info = to_fs_info(kobj);
65         umode_t mode = attr->mode;
66
67         if (fs_info) {
68                 struct btrfs_feature_attr *fa;
69                 u64 features;
70
71                 fa = attr_to_btrfs_feature_attr(attr);
72                 features = get_features(fs_info, fa->feature_set);
73
74                 if (!(features & fa->feature_bit))
75                         mode = 0;
76         }
77
78         return mode;
79 }
80
81 BTRFS_FEAT_ATTR_INCOMPAT(mixed_backref, MIXED_BACKREF);
82 BTRFS_FEAT_ATTR_INCOMPAT(default_subvol, DEFAULT_SUBVOL);
83 BTRFS_FEAT_ATTR_INCOMPAT(mixed_groups, MIXED_GROUPS);
84 BTRFS_FEAT_ATTR_INCOMPAT(compress_lzo, COMPRESS_LZO);
85 BTRFS_FEAT_ATTR_INCOMPAT(compress_lzov2, COMPRESS_LZOv2);
86 BTRFS_FEAT_ATTR_INCOMPAT(big_metadata, BIG_METADATA);
87 BTRFS_FEAT_ATTR_INCOMPAT(extended_iref, EXTENDED_IREF);
88 BTRFS_FEAT_ATTR_INCOMPAT(raid56, RAID56);
89 BTRFS_FEAT_ATTR_INCOMPAT(skinny_metadata, SKINNY_METADATA);
90
91 static struct attribute *btrfs_supported_feature_attrs[] = {
92         BTRFS_FEAT_ATTR_PTR(mixed_backref),
93         BTRFS_FEAT_ATTR_PTR(default_subvol),
94         BTRFS_FEAT_ATTR_PTR(mixed_groups),
95         BTRFS_FEAT_ATTR_PTR(compress_lzo),
96         BTRFS_FEAT_ATTR_PTR(compress_lzov2),
97         BTRFS_FEAT_ATTR_PTR(big_metadata),
98         BTRFS_FEAT_ATTR_PTR(extended_iref),
99         BTRFS_FEAT_ATTR_PTR(raid56),
100         BTRFS_FEAT_ATTR_PTR(skinny_metadata),
101         NULL
102 };
103
104 static const struct attribute_group btrfs_feature_attr_group = {
105         .name = "features",
106         .is_visible = btrfs_feature_visible,
107         .attrs = btrfs_supported_feature_attrs,
108 };
109
110 static void btrfs_release_super_kobj(struct kobject *kobj)
111 {
112         struct btrfs_fs_info *fs_info = to_fs_info(kobj);
113         complete(&fs_info->kobj_unregister);
114 }
115
116 static struct kobj_type btrfs_ktype = {
117         .sysfs_ops      = &kobj_sysfs_ops,
118         .release        = btrfs_release_super_kobj,
119 };
120
121 static inline struct btrfs_fs_info *to_fs_info(struct kobject *kobj)
122 {
123         if (kobj->ktype != &btrfs_ktype)
124                 return NULL;
125         return container_of(kobj, struct btrfs_fs_info, super_kobj);
126 }
127
128 void btrfs_sysfs_remove_one(struct btrfs_fs_info *fs_info)
129 {
130         kobject_del(&fs_info->super_kobj);
131         kobject_put(&fs_info->super_kobj);
132         wait_for_completion(&fs_info->kobj_unregister);
133 }
134
135 const char * const btrfs_feature_set_names[3] = {
136         [FEAT_COMPAT]    = "compat",
137         [FEAT_COMPAT_RO] = "compat_ro",
138         [FEAT_INCOMPAT]  = "incompat",
139 };
140
141 #define NUM_FEATURE_BITS 64
142 static char btrfs_unknown_feature_names[3][NUM_FEATURE_BITS][13];
143 static struct btrfs_feature_attr btrfs_feature_attrs[3][NUM_FEATURE_BITS];
144
145 static void init_feature_attrs(void)
146 {
147         struct btrfs_feature_attr *fa;
148         int set, i;
149
150         BUILD_BUG_ON(ARRAY_SIZE(btrfs_unknown_feature_names) !=
151                      ARRAY_SIZE(btrfs_feature_attrs));
152         BUILD_BUG_ON(ARRAY_SIZE(btrfs_unknown_feature_names[0]) !=
153                      ARRAY_SIZE(btrfs_feature_attrs[0]));
154
155         for (i = 0; btrfs_supported_feature_attrs[i]; i++) {
156                 struct btrfs_feature_attr *sfa;
157                 struct attribute *a = btrfs_supported_feature_attrs[i];
158                 sfa = attr_to_btrfs_feature_attr(a);
159                 fa = &btrfs_feature_attrs[sfa->feature_set][sfa->feature_bit];
160
161                 fa->kobj_attr.attr.name = sfa->kobj_attr.attr.name;
162         }
163
164         for (set = 0; set < FEAT_MAX; set++) {
165                 for (i = 0; i < ARRAY_SIZE(btrfs_feature_attrs[set]); i++) {
166                         char *name = btrfs_unknown_feature_names[set][i];
167                         fa = &btrfs_feature_attrs[set][i];
168
169                         if (fa->kobj_attr.attr.name)
170                                 continue;
171
172                         snprintf(name, 13, "%s:%u",
173                                  btrfs_feature_set_names[set], i);
174
175                         fa->kobj_attr.attr.name = name;
176                         fa->kobj_attr.attr.mode = S_IRUGO;
177                         fa->feature_set = set;
178                         fa->feature_bit = 1ULL << i;
179                 }
180         }
181 }
182
183 static u64 supported_feature_masks[3] = {
184         [FEAT_COMPAT]    = BTRFS_FEATURE_COMPAT_SUPP,
185         [FEAT_COMPAT_RO] = BTRFS_FEATURE_COMPAT_RO_SUPP,
186         [FEAT_INCOMPAT]  = BTRFS_FEATURE_INCOMPAT_SUPP,
187 };
188
189 static int add_unknown_feature_attrs(struct btrfs_fs_info *fs_info)
190 {
191         int set;
192
193         for (set = 0; set < FEAT_MAX; set++) {
194                 int i, count, ret, index = 0;
195                 struct attribute **attrs;
196                 struct attribute_group agroup = {
197                         .name = "features",
198                 };
199                 u64 features = get_features(fs_info, set);
200                 features &= ~supported_feature_masks[set];
201
202                 count = hweight64(features);
203
204                 if (!count)
205                         continue;
206
207                 attrs = kcalloc(count + 1, sizeof(void *), GFP_KERNEL);
208
209                 for (i = 0; i < NUM_FEATURE_BITS; i++) {
210                         struct btrfs_feature_attr *fa;
211
212                         if (!(features & (1ULL << i)))
213                                 continue;
214
215                         fa = &btrfs_feature_attrs[set][i];
216                         attrs[index++] = &fa->kobj_attr.attr;
217                 }
218
219                 attrs[index] = NULL;
220                 agroup.attrs = attrs;
221
222                 ret = sysfs_merge_group(&fs_info->super_kobj, &agroup);
223                 kfree(attrs);
224                 if (ret)
225                         return ret;
226         }
227         return 0;
228 }
229
230 /* /sys/fs/btrfs/ entry */
231 static struct kset *btrfs_kset;
232
233 int btrfs_sysfs_add_one(struct btrfs_fs_info *fs_info)
234 {
235         int error;
236
237         init_completion(&fs_info->kobj_unregister);
238         fs_info->super_kobj.kset = btrfs_kset;
239         error = kobject_init_and_add(&fs_info->super_kobj, &btrfs_ktype, NULL,
240                                      "%pU", fs_info->fsid);
241
242         error = sysfs_create_group(&fs_info->super_kobj,
243                                    &btrfs_feature_attr_group);
244         if (error)
245                 goto failure;
246
247         error = add_unknown_feature_attrs(fs_info);
248         if (error)
249                 goto failure;
250
251         return 0;
252 failure:
253         btrfs_sysfs_remove_one(fs_info);
254         return error;
255 }
256
257 int btrfs_init_sysfs(void)
258 {
259         int ret;
260         btrfs_kset = kset_create_and_add("btrfs", NULL, fs_kobj);
261         if (!btrfs_kset)
262                 return -ENOMEM;
263
264         init_feature_attrs();
265
266         ret = sysfs_create_group(&btrfs_kset->kobj, &btrfs_feature_attr_group);
267         if (ret) {
268                 kset_unregister(btrfs_kset);
269                 return ret;
270         }
271
272         return 0;
273 }
274
275 void btrfs_exit_sysfs(void)
276 {
277         sysfs_remove_group(&btrfs_kset->kobj, &btrfs_feature_attr_group);
278         kset_unregister(btrfs_kset);
279 }
280