blob: 4a2f23ee163fb1c9970707a816834c53e1e7e5d4 [file] [log] [blame]
Chris Mason6cbd5572007-06-12 09:07:21 -04001/*
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
Josef Bacik58176a92007-08-29 15:47:34 -040019#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>
Josef Bacik58176a92007-08-29 15:47:34 -040024#include <linux/kobject.h>
Jeff Mahoney79da4fa2013-11-01 13:07:00 -040025#include <linux/bug.h>
Josef Bacik58176a92007-08-29 15:47:34 -040026
Chris Masonbae45de2007-04-04 21:22:22 -040027#include "ctree.h"
28#include "disk-io.h"
29#include "transaction.h"
Jeff Mahoney079b72b2013-11-01 13:06:57 -040030#include "sysfs.h"
31
Jeff Mahoney510d7362013-11-01 13:06:59 -040032static inline struct btrfs_fs_info *to_fs_info(struct kobject *kobj);
Jeff Mahoney5ac1d202013-11-01 13:06:58 -040033
Jeff Mahoney510d7362013-11-01 13:06:59 -040034static u64 get_features(struct btrfs_fs_info *fs_info,
35 enum btrfs_feature_set set)
Jeff Mahoney5ac1d202013-11-01 13:06:58 -040036{
Jeff Mahoney510d7362013-11-01 13:06:59 -040037 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);
Jeff Mahoney5ac1d202013-11-01 13:06:58 -040044}
45
Jeff Mahoney079b72b2013-11-01 13:06:57 -040046static ssize_t btrfs_feature_attr_show(struct kobject *kobj,
47 struct kobj_attribute *a, char *buf)
48{
Jeff Mahoney510d7362013-11-01 13:06:59 -040049 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
61static 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;
Jeff Mahoney079b72b2013-11-01 13:06:57 -040079}
80
81BTRFS_FEAT_ATTR_INCOMPAT(mixed_backref, MIXED_BACKREF);
82BTRFS_FEAT_ATTR_INCOMPAT(default_subvol, DEFAULT_SUBVOL);
83BTRFS_FEAT_ATTR_INCOMPAT(mixed_groups, MIXED_GROUPS);
84BTRFS_FEAT_ATTR_INCOMPAT(compress_lzo, COMPRESS_LZO);
85BTRFS_FEAT_ATTR_INCOMPAT(compress_lzov2, COMPRESS_LZOv2);
86BTRFS_FEAT_ATTR_INCOMPAT(big_metadata, BIG_METADATA);
87BTRFS_FEAT_ATTR_INCOMPAT(extended_iref, EXTENDED_IREF);
88BTRFS_FEAT_ATTR_INCOMPAT(raid56, RAID56);
89BTRFS_FEAT_ATTR_INCOMPAT(skinny_metadata, SKINNY_METADATA);
90
91static 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
104static const struct attribute_group btrfs_feature_attr_group = {
105 .name = "features",
Jeff Mahoney510d7362013-11-01 13:06:59 -0400106 .is_visible = btrfs_feature_visible,
Jeff Mahoney079b72b2013-11-01 13:06:57 -0400107 .attrs = btrfs_supported_feature_attrs,
108};
Josef Bacik58176a92007-08-29 15:47:34 -0400109
Jeff Mahoney510d7362013-11-01 13:06:59 -0400110static 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
116static struct kobj_type btrfs_ktype = {
117 .sysfs_ops = &kobj_sysfs_ops,
118 .release = btrfs_release_super_kobj,
119};
120
121static 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}
Josef Bacik58176a92007-08-29 15:47:34 -0400127
Jeff Mahoney5ac1d202013-11-01 13:06:58 -0400128void 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
Jeff Mahoney79da4fa2013-11-01 13:07:00 -0400135const 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
142static char btrfs_unknown_feature_names[3][NUM_FEATURE_BITS][13];
143static struct btrfs_feature_attr btrfs_feature_attrs[3][NUM_FEATURE_BITS];
144
145static 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
183static 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
189static 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
Jeff Mahoney510d7362013-11-01 13:06:59 -0400230/* /sys/fs/btrfs/ entry */
231static struct kset *btrfs_kset;
232
Jeff Mahoney5ac1d202013-11-01 13:06:58 -0400233int btrfs_sysfs_add_one(struct btrfs_fs_info *fs_info)
234{
235 int error;
236
237 init_completion(&fs_info->kobj_unregister);
Jeff Mahoney510d7362013-11-01 13:06:59 -0400238 fs_info->super_kobj.kset = btrfs_kset;
Jeff Mahoney5ac1d202013-11-01 13:06:58 -0400239 error = kobject_init_and_add(&fs_info->super_kobj, &btrfs_ktype, NULL,
240 "%pU", fs_info->fsid);
Jeff Mahoney510d7362013-11-01 13:06:59 -0400241
242 error = sysfs_create_group(&fs_info->super_kobj,
243 &btrfs_feature_attr_group);
244 if (error)
Jeff Mahoney79da4fa2013-11-01 13:07:00 -0400245 goto failure;
246
247 error = add_unknown_feature_attrs(fs_info);
248 if (error)
249 goto failure;
250
251 return 0;
252failure:
253 btrfs_sysfs_remove_one(fs_info);
Jeff Mahoney5ac1d202013-11-01 13:06:58 -0400254 return error;
255}
256
Christoph Hellwigb2141072008-09-05 16:43:31 -0400257int btrfs_init_sysfs(void)
Josef Bacik58176a92007-08-29 15:47:34 -0400258{
Jeff Mahoney079b72b2013-11-01 13:06:57 -0400259 int ret;
Greg KHe3fe4e72008-02-20 14:14:16 -0500260 btrfs_kset = kset_create_and_add("btrfs", NULL, fs_kobj);
261 if (!btrfs_kset)
262 return -ENOMEM;
Jeff Mahoney079b72b2013-11-01 13:06:57 -0400263
Jeff Mahoney79da4fa2013-11-01 13:07:00 -0400264 init_feature_attrs();
265
Jeff Mahoney079b72b2013-11-01 13:06:57 -0400266 ret = sysfs_create_group(&btrfs_kset->kobj, &btrfs_feature_attr_group);
267 if (ret) {
268 kset_unregister(btrfs_kset);
269 return ret;
270 }
271
Greg KHe3fe4e72008-02-20 14:14:16 -0500272 return 0;
Josef Bacik58176a92007-08-29 15:47:34 -0400273}
274
Christoph Hellwigb2141072008-09-05 16:43:31 -0400275void btrfs_exit_sysfs(void)
Josef Bacik58176a92007-08-29 15:47:34 -0400276{
Jeff Mahoney079b72b2013-11-01 13:06:57 -0400277 sysfs_remove_group(&btrfs_kset->kobj, &btrfs_feature_attr_group);
Greg KHe3fe4e72008-02-20 14:14:16 -0500278 kset_unregister(btrfs_kset);
Josef Bacik58176a92007-08-29 15:47:34 -0400279}
Chris Mason55d47412008-02-20 16:02:51 -0500280