Branch data Line data Source code
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 : : #include <linux/genhd.h>
27 : :
28 : : #include "ctree.h"
29 : : #include "disk-io.h"
30 : : #include "transaction.h"
31 : : #include "sysfs.h"
32 : : #include "volumes.h"
33 : :
34 : : static inline struct btrfs_fs_info *to_fs_info(struct kobject *kobj);
35 : :
36 : : static u64 get_features(struct btrfs_fs_info *fs_info,
37 : : enum btrfs_feature_set set)
38 : : {
39 : : struct btrfs_super_block *disk_super = fs_info->super_copy;
40 [ # # ][ # # ]: 0 : if (set == FEAT_COMPAT)
[ # # # # ]
[ # # ]
41 : : return btrfs_super_compat_flags(disk_super);
42 [ # # ][ # # ]: 0 : else if (set == FEAT_COMPAT_RO)
[ # # ][ # # ]
[ # # ]
43 : : return btrfs_super_compat_ro_flags(disk_super);
44 : : else
45 : : return btrfs_super_incompat_flags(disk_super);
46 : : }
47 : :
48 : : static void set_features(struct btrfs_fs_info *fs_info,
49 : : enum btrfs_feature_set set, u64 features)
50 : : {
51 : : struct btrfs_super_block *disk_super = fs_info->super_copy;
52 [ # # ]: 0 : if (set == FEAT_COMPAT)
53 : : btrfs_set_super_compat_flags(disk_super, features);
54 [ # # ]: 0 : else if (set == FEAT_COMPAT_RO)
55 : : btrfs_set_super_compat_ro_flags(disk_super, features);
56 : : else
57 : : btrfs_set_super_incompat_flags(disk_super, features);
58 : : }
59 : :
60 : 0 : static int can_modify_feature(struct btrfs_feature_attr *fa)
61 : : {
62 : : int val = 0;
63 : : u64 set, clear;
64 [ # # # ]: 0 : switch (fa->feature_set) {
65 : : case FEAT_COMPAT:
66 : : set = BTRFS_FEATURE_COMPAT_SAFE_SET;
67 : : clear = BTRFS_FEATURE_COMPAT_SAFE_CLEAR;
68 : : break;
69 : : case FEAT_COMPAT_RO:
70 : : set = BTRFS_FEATURE_COMPAT_RO_SAFE_SET;
71 : : clear = BTRFS_FEATURE_COMPAT_RO_SAFE_CLEAR;
72 : : break;
73 : : case FEAT_INCOMPAT:
74 : : set = BTRFS_FEATURE_INCOMPAT_SAFE_SET;
75 : : clear = BTRFS_FEATURE_INCOMPAT_SAFE_CLEAR;
76 : : break;
77 : : default:
78 : 0 : printk(KERN_WARNING "btrfs: sysfs: unknown feature set %d\n",
79 : : fa->feature_set);
80 : : return 0;
81 : : }
82 : :
83 [ # # ]: 0 : if (set & fa->feature_bit)
84 : : val |= 1;
85 : : if (clear & fa->feature_bit)
86 : : val |= 2;
87 : :
88 : : return val;
89 : : }
90 : :
91 : 0 : static ssize_t btrfs_feature_attr_show(struct kobject *kobj,
92 : : struct kobj_attribute *a, char *buf)
93 : : {
94 : : int val = 0;
95 : 0 : struct btrfs_fs_info *fs_info = to_fs_info(kobj);
96 : 0 : struct btrfs_feature_attr *fa = to_btrfs_feature_attr(a);
97 [ # # ]: 0 : if (fs_info) {
98 : 0 : u64 features = get_features(fs_info, fa->feature_set);
99 [ # # ]: 0 : if (features & fa->feature_bit)
100 : : val = 1;
101 : : } else
102 : 0 : val = can_modify_feature(fa);
103 : :
104 : 0 : return snprintf(buf, PAGE_SIZE, "%d\n", val);
105 : : }
106 : :
107 : 0 : static ssize_t btrfs_feature_attr_store(struct kobject *kobj,
108 : : struct kobj_attribute *a,
109 : : const char *buf, size_t count)
110 : : {
111 : 0 : struct btrfs_fs_info *fs_info;
112 : : struct btrfs_feature_attr *fa = to_btrfs_feature_attr(a);
113 : : struct btrfs_trans_handle *trans;
114 : : u64 features, set, clear;
115 : : unsigned long val;
116 : : int ret;
117 : :
118 : : fs_info = to_fs_info(kobj);
119 [ # # ]: 0 : if (!fs_info)
120 : : return -EPERM;
121 : :
122 : 0 : ret = kstrtoul(skip_spaces(buf), 0, &val);
123 [ # # ]: 0 : if (ret)
124 : : return ret;
125 : :
126 [ # # ]: 0 : if (fa->feature_set == FEAT_COMPAT) {
127 : : set = BTRFS_FEATURE_COMPAT_SAFE_SET;
128 : : clear = BTRFS_FEATURE_COMPAT_SAFE_CLEAR;
129 [ # # ]: 0 : } else if (fa->feature_set == FEAT_COMPAT_RO) {
130 : : set = BTRFS_FEATURE_COMPAT_RO_SAFE_SET;
131 : : clear = BTRFS_FEATURE_COMPAT_RO_SAFE_CLEAR;
132 : : } else {
133 : : set = BTRFS_FEATURE_INCOMPAT_SAFE_SET;
134 : : clear = BTRFS_FEATURE_INCOMPAT_SAFE_CLEAR;
135 : : }
136 : :
137 : : features = get_features(fs_info, fa->feature_set);
138 : :
139 : : /* Nothing to do */
140 [ # # ][ # # ]: 0 : if ((val && (features & fa->feature_bit)) ||
[ # # ]
141 [ # # ]: 0 : (!val && !(features & fa->feature_bit)))
142 : 0 : return count;
143 : :
144 [ # # ][ # # ]: 0 : if ((val && !(set & fa->feature_bit)) ||
[ # # ]
145 : : (!val && !(clear & fa->feature_bit))) {
146 [ # # ]: 0 : btrfs_info(fs_info,
147 : : "%sabling feature %s on mounted fs is not supported.",
148 : : val ? "En" : "Dis", fa->kobj_attr.attr.name);
149 : 0 : return -EPERM;
150 : : }
151 : :
152 [ # # ]: 0 : btrfs_info(fs_info, "%s %s feature flag",
153 : : val ? "Setting" : "Clearing", fa->kobj_attr.attr.name);
154 : :
155 : 0 : trans = btrfs_start_transaction(fs_info->fs_root, 0);
156 [ # # ]: 0 : if (IS_ERR(trans))
157 : 0 : return PTR_ERR(trans);
158 : :
159 : : spin_lock(&fs_info->super_lock);
160 : 0 : features = get_features(fs_info, fa->feature_set);
161 [ # # ]: 0 : if (val)
162 : 0 : features |= fa->feature_bit;
163 : : else
164 : 0 : features &= ~fa->feature_bit;
165 : : set_features(fs_info, fa->feature_set, features);
166 : : spin_unlock(&fs_info->super_lock);
167 : :
168 : 0 : ret = btrfs_commit_transaction(trans, fs_info->fs_root);
169 [ # # ]: 0 : if (ret)
170 : : return ret;
171 : :
172 : 0 : return count;
173 : : }
174 : :
175 : 0 : static umode_t btrfs_feature_visible(struct kobject *kobj,
176 : : struct attribute *attr, int unused)
177 : : {
178 : 0 : struct btrfs_fs_info *fs_info = to_fs_info(kobj);
179 : 0 : umode_t mode = attr->mode;
180 : :
181 [ # # ]: 0 : if (fs_info) {
182 : : struct btrfs_feature_attr *fa;
183 : : u64 features;
184 : :
185 : : fa = attr_to_btrfs_feature_attr(attr);
186 : 0 : features = get_features(fs_info, fa->feature_set);
187 : :
188 [ # # ]: 0 : if (can_modify_feature(fa))
189 : 0 : mode |= S_IWUSR;
190 [ # # ]: 0 : else if (!(features & fa->feature_bit))
191 : : mode = 0;
192 : : }
193 : :
194 : 0 : return mode;
195 : : }
196 : :
197 : : BTRFS_FEAT_ATTR_INCOMPAT(mixed_backref, MIXED_BACKREF);
198 : : BTRFS_FEAT_ATTR_INCOMPAT(default_subvol, DEFAULT_SUBVOL);
199 : : BTRFS_FEAT_ATTR_INCOMPAT(mixed_groups, MIXED_GROUPS);
200 : : BTRFS_FEAT_ATTR_INCOMPAT(compress_lzo, COMPRESS_LZO);
201 : : BTRFS_FEAT_ATTR_INCOMPAT(big_metadata, BIG_METADATA);
202 : : BTRFS_FEAT_ATTR_INCOMPAT(extended_iref, EXTENDED_IREF);
203 : : BTRFS_FEAT_ATTR_INCOMPAT(raid56, RAID56);
204 : : BTRFS_FEAT_ATTR_INCOMPAT(skinny_metadata, SKINNY_METADATA);
205 : : BTRFS_FEAT_ATTR_INCOMPAT(no_holes, NO_HOLES);
206 : :
207 : : static struct attribute *btrfs_supported_feature_attrs[] = {
208 : : BTRFS_FEAT_ATTR_PTR(mixed_backref),
209 : : BTRFS_FEAT_ATTR_PTR(default_subvol),
210 : : BTRFS_FEAT_ATTR_PTR(mixed_groups),
211 : : BTRFS_FEAT_ATTR_PTR(compress_lzo),
212 : : BTRFS_FEAT_ATTR_PTR(big_metadata),
213 : : BTRFS_FEAT_ATTR_PTR(extended_iref),
214 : : BTRFS_FEAT_ATTR_PTR(raid56),
215 : : BTRFS_FEAT_ATTR_PTR(skinny_metadata),
216 : : BTRFS_FEAT_ATTR_PTR(no_holes),
217 : : NULL
218 : : };
219 : :
220 : : static const struct attribute_group btrfs_feature_attr_group = {
221 : : .name = "features",
222 : : .is_visible = btrfs_feature_visible,
223 : : .attrs = btrfs_supported_feature_attrs,
224 : : };
225 : :
226 : 0 : static ssize_t btrfs_show_u64(u64 *value_ptr, spinlock_t *lock, char *buf)
227 : : {
228 : : u64 val;
229 [ # # ]: 0 : if (lock)
230 : : spin_lock(lock);
231 : 0 : val = *value_ptr;
232 [ # # ]: 0 : if (lock)
233 : : spin_unlock(lock);
234 : 0 : return snprintf(buf, PAGE_SIZE, "%llu\n", val);
235 : : }
236 : :
237 : 0 : static ssize_t global_rsv_size_show(struct kobject *kobj,
238 : : struct kobj_attribute *ka, char *buf)
239 : : {
240 : 0 : struct btrfs_fs_info *fs_info = to_fs_info(kobj->parent);
241 : : struct btrfs_block_rsv *block_rsv = &fs_info->global_block_rsv;
242 : 0 : return btrfs_show_u64(&block_rsv->size, &block_rsv->lock, buf);
243 : : }
244 : : BTRFS_ATTR(global_rsv_size, 0444, global_rsv_size_show);
245 : :
246 : 0 : static ssize_t global_rsv_reserved_show(struct kobject *kobj,
247 : : struct kobj_attribute *a, char *buf)
248 : : {
249 : 0 : struct btrfs_fs_info *fs_info = to_fs_info(kobj->parent);
250 : : struct btrfs_block_rsv *block_rsv = &fs_info->global_block_rsv;
251 : 0 : return btrfs_show_u64(&block_rsv->reserved, &block_rsv->lock, buf);
252 : : }
253 : : BTRFS_ATTR(global_rsv_reserved, 0444, global_rsv_reserved_show);
254 : :
255 : : #define to_space_info(_kobj) container_of(_kobj, struct btrfs_space_info, kobj)
256 : :
257 : : static ssize_t raid_bytes_show(struct kobject *kobj,
258 : : struct kobj_attribute *attr, char *buf);
259 : : BTRFS_RAID_ATTR(total_bytes, raid_bytes_show);
260 : : BTRFS_RAID_ATTR(used_bytes, raid_bytes_show);
261 : :
262 : 0 : static ssize_t raid_bytes_show(struct kobject *kobj,
263 : : struct kobj_attribute *attr, char *buf)
264 : :
265 : : {
266 : 0 : struct btrfs_space_info *sinfo = to_space_info(kobj->parent);
267 : : struct btrfs_block_group_cache *block_group;
268 : 0 : int index = kobj - sinfo->block_group_kobjs;
269 : : u64 val = 0;
270 : :
271 : 0 : down_read(&sinfo->groups_sem);
272 [ # # ]: 0 : list_for_each_entry(block_group, &sinfo->block_groups[index], list) {
273 [ # # ]: 0 : if (&attr->attr == BTRFS_RAID_ATTR_PTR(total_bytes))
274 : 0 : val += block_group->key.offset;
275 : : else
276 : 0 : val += btrfs_block_group_used(&block_group->item);
277 : : }
278 : 0 : up_read(&sinfo->groups_sem);
279 : 0 : return snprintf(buf, PAGE_SIZE, "%llu\n", val);
280 : : }
281 : :
282 : : static struct attribute *raid_attributes[] = {
283 : : BTRFS_RAID_ATTR_PTR(total_bytes),
284 : : BTRFS_RAID_ATTR_PTR(used_bytes),
285 : : NULL
286 : : };
287 : :
288 : 0 : static void release_raid_kobj(struct kobject *kobj)
289 : : {
290 : 0 : kobject_put(kobj->parent);
291 : 0 : }
292 : :
293 : : struct kobj_type btrfs_raid_ktype = {
294 : : .sysfs_ops = &kobj_sysfs_ops,
295 : : .release = release_raid_kobj,
296 : : .default_attrs = raid_attributes,
297 : : };
298 : :
299 : : #define SPACE_INFO_ATTR(field) \
300 : : static ssize_t btrfs_space_info_show_##field(struct kobject *kobj, \
301 : : struct kobj_attribute *a, \
302 : : char *buf) \
303 : : { \
304 : : struct btrfs_space_info *sinfo = to_space_info(kobj); \
305 : : return btrfs_show_u64(&sinfo->field, &sinfo->lock, buf); \
306 : : } \
307 : : BTRFS_ATTR(field, 0444, btrfs_space_info_show_##field)
308 : :
309 : 0 : static ssize_t btrfs_space_info_show_total_bytes_pinned(struct kobject *kobj,
310 : : struct kobj_attribute *a,
311 : : char *buf)
312 : : {
313 : : struct btrfs_space_info *sinfo = to_space_info(kobj);
314 : 0 : s64 val = percpu_counter_sum(&sinfo->total_bytes_pinned);
315 : 0 : return snprintf(buf, PAGE_SIZE, "%lld\n", val);
316 : : }
317 : :
318 : 0 : SPACE_INFO_ATTR(flags);
319 : 0 : SPACE_INFO_ATTR(total_bytes);
320 : 0 : SPACE_INFO_ATTR(bytes_used);
321 : 0 : SPACE_INFO_ATTR(bytes_pinned);
322 : 0 : SPACE_INFO_ATTR(bytes_reserved);
323 : 0 : SPACE_INFO_ATTR(bytes_may_use);
324 : 0 : SPACE_INFO_ATTR(disk_used);
325 : 0 : SPACE_INFO_ATTR(disk_total);
326 : : BTRFS_ATTR(total_bytes_pinned, 0444, btrfs_space_info_show_total_bytes_pinned);
327 : :
328 : : static struct attribute *space_info_attrs[] = {
329 : : BTRFS_ATTR_PTR(flags),
330 : : BTRFS_ATTR_PTR(total_bytes),
331 : : BTRFS_ATTR_PTR(bytes_used),
332 : : BTRFS_ATTR_PTR(bytes_pinned),
333 : : BTRFS_ATTR_PTR(bytes_reserved),
334 : : BTRFS_ATTR_PTR(bytes_may_use),
335 : : BTRFS_ATTR_PTR(disk_used),
336 : : BTRFS_ATTR_PTR(disk_total),
337 : : BTRFS_ATTR_PTR(total_bytes_pinned),
338 : : NULL,
339 : : };
340 : :
341 : 0 : static void space_info_release(struct kobject *kobj)
342 : : {
343 : 0 : struct btrfs_space_info *sinfo = to_space_info(kobj);
344 : 0 : percpu_counter_destroy(&sinfo->total_bytes_pinned);
345 : 0 : kfree(sinfo);
346 : 0 : }
347 : :
348 : : struct kobj_type space_info_ktype = {
349 : : .sysfs_ops = &kobj_sysfs_ops,
350 : : .release = space_info_release,
351 : : .default_attrs = space_info_attrs,
352 : : };
353 : :
354 : : static const struct attribute *allocation_attrs[] = {
355 : : BTRFS_ATTR_PTR(global_rsv_reserved),
356 : : BTRFS_ATTR_PTR(global_rsv_size),
357 : : NULL,
358 : : };
359 : :
360 : 0 : static ssize_t btrfs_label_show(struct kobject *kobj,
361 : : struct kobj_attribute *a, char *buf)
362 : : {
363 : : struct btrfs_fs_info *fs_info = to_fs_info(kobj);
364 : 0 : return snprintf(buf, PAGE_SIZE, "%s\n", fs_info->super_copy->label);
365 : : }
366 : :
367 : 0 : static ssize_t btrfs_label_store(struct kobject *kobj,
368 : : struct kobj_attribute *a,
369 : : const char *buf, size_t len)
370 : : {
371 : : struct btrfs_fs_info *fs_info = to_fs_info(kobj);
372 : : struct btrfs_trans_handle *trans;
373 : 0 : struct btrfs_root *root = fs_info->fs_root;
374 : : int ret;
375 : :
376 [ # # ]: 0 : if (len >= BTRFS_LABEL_SIZE) {
377 : 0 : pr_err("BTRFS: unable to set label with more than %d bytes\n",
378 : : BTRFS_LABEL_SIZE - 1);
379 : 0 : return -EINVAL;
380 : : }
381 : :
382 : 0 : trans = btrfs_start_transaction(root, 0);
383 [ # # ]: 0 : if (IS_ERR(trans))
384 : 0 : return PTR_ERR(trans);
385 : :
386 : 0 : spin_lock(&root->fs_info->super_lock);
387 : 0 : strcpy(fs_info->super_copy->label, buf);
388 : 0 : spin_unlock(&root->fs_info->super_lock);
389 : 0 : ret = btrfs_commit_transaction(trans, root);
390 : :
391 [ # # ]: 0 : if (!ret)
392 : 0 : return len;
393 : :
394 : : return ret;
395 : : }
396 : : BTRFS_ATTR_RW(label, 0644, btrfs_label_show, btrfs_label_store);
397 : :
398 : : static struct attribute *btrfs_attrs[] = {
399 : : BTRFS_ATTR_PTR(label),
400 : : NULL,
401 : : };
402 : :
403 : 0 : static void btrfs_release_super_kobj(struct kobject *kobj)
404 : : {
405 : : struct btrfs_fs_info *fs_info = to_fs_info(kobj);
406 : 0 : complete(&fs_info->kobj_unregister);
407 : 0 : }
408 : :
409 : : static struct kobj_type btrfs_ktype = {
410 : : .sysfs_ops = &kobj_sysfs_ops,
411 : : .release = btrfs_release_super_kobj,
412 : : .default_attrs = btrfs_attrs,
413 : : };
414 : :
415 : : static inline struct btrfs_fs_info *to_fs_info(struct kobject *kobj)
416 : : {
417 [ # # ][ # # ]: 0 : if (kobj->ktype != &btrfs_ktype)
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
418 : : return NULL;
419 : 0 : return container_of(kobj, struct btrfs_fs_info, super_kobj);
420 : : }
421 : :
422 : : #define NUM_FEATURE_BITS 64
423 : : static char btrfs_unknown_feature_names[3][NUM_FEATURE_BITS][13];
424 : : static struct btrfs_feature_attr btrfs_feature_attrs[3][NUM_FEATURE_BITS];
425 : :
426 : : static u64 supported_feature_masks[3] = {
427 : : [FEAT_COMPAT] = BTRFS_FEATURE_COMPAT_SUPP,
428 : : [FEAT_COMPAT_RO] = BTRFS_FEATURE_COMPAT_RO_SUPP,
429 : : [FEAT_INCOMPAT] = BTRFS_FEATURE_INCOMPAT_SUPP,
430 : : };
431 : :
432 : 0 : static int addrm_unknown_feature_attrs(struct btrfs_fs_info *fs_info, bool add)
433 : : {
434 : : int set;
435 : :
436 [ # # ]: 0 : for (set = 0; set < FEAT_MAX; set++) {
437 : : int i;
438 : : struct attribute *attrs[2];
439 : 0 : struct attribute_group agroup = {
440 : : .name = "features",
441 : : .attrs = attrs,
442 : : };
443 : 0 : u64 features = get_features(fs_info, set);
444 : 0 : features &= ~supported_feature_masks[set];
445 : :
446 [ # # ]: 0 : if (!features)
447 : 0 : continue;
448 : :
449 : 0 : attrs[1] = NULL;
450 [ # # ]: 0 : for (i = 0; i < NUM_FEATURE_BITS; i++) {
451 : : struct btrfs_feature_attr *fa;
452 : :
453 [ # # ]: 0 : if (!(features & (1ULL << i)))
454 : 0 : continue;
455 : :
456 : 0 : fa = &btrfs_feature_attrs[set][i];
457 : 0 : attrs[0] = &fa->kobj_attr.attr;
458 [ # # ]: 0 : if (add) {
459 : : int ret;
460 : 0 : ret = sysfs_merge_group(&fs_info->super_kobj,
461 : : &agroup);
462 [ # # ]: 0 : if (ret)
463 : 0 : return ret;
464 : : } else
465 : 0 : sysfs_unmerge_group(&fs_info->super_kobj,
466 : : &agroup);
467 : : }
468 : :
469 : : }
470 : : return 0;
471 : : }
472 : :
473 : 0 : static void __btrfs_sysfs_remove_one(struct btrfs_fs_info *fs_info)
474 : : {
475 : 0 : kobject_del(&fs_info->super_kobj);
476 : 0 : kobject_put(&fs_info->super_kobj);
477 : 0 : wait_for_completion(&fs_info->kobj_unregister);
478 : 0 : }
479 : :
480 : 0 : void btrfs_sysfs_remove_one(struct btrfs_fs_info *fs_info)
481 : : {
482 [ # # ]: 0 : if (fs_info->space_info_kobj) {
483 : 0 : sysfs_remove_files(fs_info->space_info_kobj, allocation_attrs);
484 : 0 : kobject_del(fs_info->space_info_kobj);
485 : 0 : kobject_put(fs_info->space_info_kobj);
486 : : }
487 : 0 : kobject_del(fs_info->device_dir_kobj);
488 : 0 : kobject_put(fs_info->device_dir_kobj);
489 : 0 : addrm_unknown_feature_attrs(fs_info, false);
490 : 0 : sysfs_remove_group(&fs_info->super_kobj, &btrfs_feature_attr_group);
491 : 0 : __btrfs_sysfs_remove_one(fs_info);
492 : 0 : }
493 : :
494 : : const char * const btrfs_feature_set_names[3] = {
495 : : [FEAT_COMPAT] = "compat",
496 : : [FEAT_COMPAT_RO] = "compat_ro",
497 : : [FEAT_INCOMPAT] = "incompat",
498 : : };
499 : :
500 : 0 : char *btrfs_printable_features(enum btrfs_feature_set set, u64 flags)
501 : : {
502 : : size_t bufsize = 4096; /* safe max, 64 names * 64 bytes */
503 : : int len = 0;
504 : : int i;
505 : : char *str;
506 : :
507 : : str = kmalloc(bufsize, GFP_KERNEL);
508 [ # # ]: 0 : if (!str)
509 : : return str;
510 : :
511 [ # # ]: 0 : for (i = 0; i < ARRAY_SIZE(btrfs_feature_attrs[set]); i++) {
512 : : const char *name;
513 : :
514 [ # # ]: 0 : if (!(flags & (1ULL << i)))
515 : 0 : continue;
516 : :
517 : 0 : name = btrfs_feature_attrs[set][i].kobj_attr.attr.name;
518 [ # # ]: 0 : len += snprintf(str + len, bufsize - len, "%s%s",
519 : : len ? "," : "", name);
520 : : }
521 : :
522 : : return str;
523 : : }
524 : :
525 : 0 : static void init_feature_attrs(void)
526 : : {
527 : : struct btrfs_feature_attr *fa;
528 : : int set, i;
529 : :
530 : : BUILD_BUG_ON(ARRAY_SIZE(btrfs_unknown_feature_names) !=
531 : : ARRAY_SIZE(btrfs_feature_attrs));
532 : : BUILD_BUG_ON(ARRAY_SIZE(btrfs_unknown_feature_names[0]) !=
533 : : ARRAY_SIZE(btrfs_feature_attrs[0]));
534 : :
535 : 0 : memset(btrfs_feature_attrs, 0, sizeof(btrfs_feature_attrs));
536 : 0 : memset(btrfs_unknown_feature_names, 0,
537 : : sizeof(btrfs_unknown_feature_names));
538 : :
539 [ # # ]: 0 : for (i = 0; btrfs_supported_feature_attrs[i]; i++) {
540 : : struct btrfs_feature_attr *sfa;
541 : : struct attribute *a = btrfs_supported_feature_attrs[i];
542 : : int bit;
543 : : sfa = attr_to_btrfs_feature_attr(a);
544 [ # # ][ # # ]: 0 : bit = ilog2(sfa->feature_bit);
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
545 : 0 : fa = &btrfs_feature_attrs[sfa->feature_set][bit];
546 : :
547 : 0 : fa->kobj_attr.attr.name = sfa->kobj_attr.attr.name;
548 : : }
549 : :
550 [ # # ]: 0 : for (set = 0; set < FEAT_MAX; set++) {
551 [ # # ]: 0 : for (i = 0; i < ARRAY_SIZE(btrfs_feature_attrs[set]); i++) {
552 : 0 : char *name = btrfs_unknown_feature_names[set][i];
553 : 0 : fa = &btrfs_feature_attrs[set][i];
554 : :
555 [ # # ]: 0 : if (fa->kobj_attr.attr.name)
556 : 0 : continue;
557 : :
558 : 0 : snprintf(name, 13, "%s:%u",
559 : : btrfs_feature_set_names[set], i);
560 : :
561 : 0 : fa->kobj_attr.attr.name = name;
562 : 0 : fa->kobj_attr.attr.mode = S_IRUGO;
563 : 0 : fa->feature_set = set;
564 : 0 : fa->feature_bit = 1ULL << i;
565 : : }
566 : : }
567 : 0 : }
568 : :
569 : 0 : static int add_device_membership(struct btrfs_fs_info *fs_info)
570 : : {
571 : : int error = 0;
572 : 0 : struct btrfs_fs_devices *fs_devices = fs_info->fs_devices;
573 : : struct btrfs_device *dev;
574 : :
575 : 0 : fs_info->device_dir_kobj = kobject_create_and_add("devices",
576 : : &fs_info->super_kobj);
577 [ # # ]: 0 : if (!fs_info->device_dir_kobj)
578 : : return -ENOMEM;
579 : :
580 [ # # ]: 0 : list_for_each_entry(dev, &fs_devices->devices, dev_list) {
581 : : struct hd_struct *disk;
582 : : struct kobject *disk_kobj;
583 : :
584 [ # # ]: 0 : if (!dev->bdev)
585 : 0 : continue;
586 : :
587 : 0 : disk = dev->bdev->bd_part;
588 : 0 : disk_kobj = &part_to_dev(disk)->kobj;
589 : :
590 : 0 : error = sysfs_create_link(fs_info->device_dir_kobj,
591 : : disk_kobj, disk_kobj->name);
592 [ # # ]: 0 : if (error)
593 : : break;
594 : : }
595 : :
596 : 0 : return error;
597 : : }
598 : :
599 : : /* /sys/fs/btrfs/ entry */
600 : : static struct kset *btrfs_kset;
601 : :
602 : 0 : int btrfs_sysfs_add_one(struct btrfs_fs_info *fs_info)
603 : : {
604 : : int error;
605 : :
606 : : init_completion(&fs_info->kobj_unregister);
607 : 0 : fs_info->super_kobj.kset = btrfs_kset;
608 : 0 : error = kobject_init_and_add(&fs_info->super_kobj, &btrfs_ktype, NULL,
609 : 0 : "%pU", fs_info->fsid);
610 [ # # ]: 0 : if (error)
611 : : return error;
612 : :
613 : 0 : error = sysfs_create_group(&fs_info->super_kobj,
614 : : &btrfs_feature_attr_group);
615 [ # # ]: 0 : if (error) {
616 : 0 : __btrfs_sysfs_remove_one(fs_info);
617 : 0 : return error;
618 : : }
619 : :
620 : 0 : error = addrm_unknown_feature_attrs(fs_info, true);
621 [ # # ]: 0 : if (error)
622 : : goto failure;
623 : :
624 : 0 : error = add_device_membership(fs_info);
625 [ # # ]: 0 : if (error)
626 : : goto failure;
627 : :
628 : 0 : fs_info->space_info_kobj = kobject_create_and_add("allocation",
629 : : &fs_info->super_kobj);
630 [ # # ]: 0 : if (!fs_info->space_info_kobj) {
631 : : error = -ENOMEM;
632 : : goto failure;
633 : : }
634 : :
635 : 0 : error = sysfs_create_files(fs_info->space_info_kobj, allocation_attrs);
636 [ # # ]: 0 : if (error)
637 : : goto failure;
638 : :
639 : : return 0;
640 : : failure:
641 : 0 : btrfs_sysfs_remove_one(fs_info);
642 : 0 : return error;
643 : : }
644 : :
645 : 0 : int btrfs_init_sysfs(void)
646 : : {
647 : : int ret;
648 : 0 : btrfs_kset = kset_create_and_add("btrfs", NULL, fs_kobj);
649 [ # # ]: 0 : if (!btrfs_kset)
650 : : return -ENOMEM;
651 : :
652 : 0 : init_feature_attrs();
653 : :
654 : 0 : ret = sysfs_create_group(&btrfs_kset->kobj, &btrfs_feature_attr_group);
655 [ # # ]: 0 : if (ret) {
656 : 0 : kset_unregister(btrfs_kset);
657 : 0 : return ret;
658 : : }
659 : :
660 : : return 0;
661 : : }
662 : :
663 : 0 : void btrfs_exit_sysfs(void)
664 : : {
665 : 0 : sysfs_remove_group(&btrfs_kset->kobj, &btrfs_feature_attr_group);
666 : 0 : kset_unregister(btrfs_kset);
667 : 0 : }
668 : :
|