aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs/sysfs.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/btrfs/sysfs.c')
-rw-r--r--fs/btrfs/sysfs.c133
1 files changed, 73 insertions, 60 deletions
diff --git a/fs/btrfs/sysfs.c b/fs/btrfs/sysfs.c
index b535285642dc..f25deb9c132c 100644
--- a/fs/btrfs/sysfs.c
+++ b/fs/btrfs/sysfs.c
@@ -419,28 +419,84 @@ static inline struct btrfs_fs_info *to_fs_info(struct kobject *kobj)
419 return container_of(kobj, struct btrfs_fs_info, super_kobj); 419 return container_of(kobj, struct btrfs_fs_info, super_kobj);
420} 420}
421 421
422void btrfs_sysfs_remove_one(struct btrfs_fs_info *fs_info) 422#define NUM_FEATURE_BITS 64
423static char btrfs_unknown_feature_names[3][NUM_FEATURE_BITS][13];
424static struct btrfs_feature_attr btrfs_feature_attrs[3][NUM_FEATURE_BITS];
425
426static 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
432static int addrm_unknown_feature_attrs(struct btrfs_fs_info *fs_info, bool add)
433{
434 int set;
435
436 for (set = 0; set < FEAT_MAX; set++) {
437 int i;
438 struct attribute *attrs[2];
439 struct attribute_group agroup = {
440 .name = "features",
441 .attrs = attrs,
442 };
443 u64 features = get_features(fs_info, set);
444 features &= ~supported_feature_masks[set];
445
446 if (!features)
447 continue;
448
449 attrs[1] = NULL;
450 for (i = 0; i < NUM_FEATURE_BITS; i++) {
451 struct btrfs_feature_attr *fa;
452
453 if (!(features & (1ULL << i)))
454 continue;
455
456 fa = &btrfs_feature_attrs[set][i];
457 attrs[0] = &fa->kobj_attr.attr;
458 if (add) {
459 int ret;
460 ret = sysfs_merge_group(&fs_info->super_kobj,
461 &agroup);
462 if (ret)
463 return ret;
464 } else
465 sysfs_unmerge_group(&fs_info->super_kobj,
466 &agroup);
467 }
468
469 }
470 return 0;
471}
472
473static void __btrfs_sysfs_remove_one(struct btrfs_fs_info *fs_info)
423{ 474{
424 sysfs_remove_files(fs_info->space_info_kobj, allocation_attrs);
425 kobject_del(fs_info->device_dir_kobj);
426 kobject_put(fs_info->device_dir_kobj);
427 kobject_del(fs_info->space_info_kobj);
428 kobject_put(fs_info->space_info_kobj);
429 kobject_del(&fs_info->super_kobj); 475 kobject_del(&fs_info->super_kobj);
430 kobject_put(&fs_info->super_kobj); 476 kobject_put(&fs_info->super_kobj);
431 wait_for_completion(&fs_info->kobj_unregister); 477 wait_for_completion(&fs_info->kobj_unregister);
432} 478}
433 479
480void btrfs_sysfs_remove_one(struct btrfs_fs_info *fs_info)
481{
482 if (fs_info->space_info_kobj) {
483 sysfs_remove_files(fs_info->space_info_kobj, allocation_attrs);
484 kobject_del(fs_info->space_info_kobj);
485 kobject_put(fs_info->space_info_kobj);
486 }
487 kobject_del(fs_info->device_dir_kobj);
488 kobject_put(fs_info->device_dir_kobj);
489 addrm_unknown_feature_attrs(fs_info, false);
490 sysfs_remove_group(&fs_info->super_kobj, &btrfs_feature_attr_group);
491 __btrfs_sysfs_remove_one(fs_info);
492}
493
434const char * const btrfs_feature_set_names[3] = { 494const char * const btrfs_feature_set_names[3] = {
435 [FEAT_COMPAT] = "compat", 495 [FEAT_COMPAT] = "compat",
436 [FEAT_COMPAT_RO] = "compat_ro", 496 [FEAT_COMPAT_RO] = "compat_ro",
437 [FEAT_INCOMPAT] = "incompat", 497 [FEAT_INCOMPAT] = "incompat",
438}; 498};
439 499
440#define NUM_FEATURE_BITS 64
441static char btrfs_unknown_feature_names[3][NUM_FEATURE_BITS][13];
442static struct btrfs_feature_attr btrfs_feature_attrs[3][NUM_FEATURE_BITS];
443
444char *btrfs_printable_features(enum btrfs_feature_set set, u64 flags) 500char *btrfs_printable_features(enum btrfs_feature_set set, u64 flags)
445{ 501{
446 size_t bufsize = 4096; /* safe max, 64 names * 64 bytes */ 502 size_t bufsize = 4096; /* safe max, 64 names * 64 bytes */
@@ -510,53 +566,6 @@ static void init_feature_attrs(void)
510 } 566 }
511} 567}
512 568
513static u64 supported_feature_masks[3] = {
514 [FEAT_COMPAT] = BTRFS_FEATURE_COMPAT_SUPP,
515 [FEAT_COMPAT_RO] = BTRFS_FEATURE_COMPAT_RO_SUPP,
516 [FEAT_INCOMPAT] = BTRFS_FEATURE_INCOMPAT_SUPP,
517};
518
519static int add_unknown_feature_attrs(struct btrfs_fs_info *fs_info)
520{
521 int set;
522
523 for (set = 0; set < FEAT_MAX; set++) {
524 int i, count, ret, index = 0;
525 struct attribute **attrs;
526 struct attribute_group agroup = {
527 .name = "features",
528 };
529 u64 features = get_features(fs_info, set);
530 features &= ~supported_feature_masks[set];
531
532 count = hweight64(features);
533
534 if (!count)
535 continue;
536
537 attrs = kcalloc(count + 1, sizeof(void *), GFP_KERNEL);
538
539 for (i = 0; i < NUM_FEATURE_BITS; i++) {
540 struct btrfs_feature_attr *fa;
541
542 if (!(features & (1ULL << i)))
543 continue;
544
545 fa = &btrfs_feature_attrs[set][i];
546 attrs[index++] = &fa->kobj_attr.attr;
547 }
548
549 attrs[index] = NULL;
550 agroup.attrs = attrs;
551
552 ret = sysfs_merge_group(&fs_info->super_kobj, &agroup);
553 kfree(attrs);
554 if (ret)
555 return ret;
556 }
557 return 0;
558}
559
560static int add_device_membership(struct btrfs_fs_info *fs_info) 569static int add_device_membership(struct btrfs_fs_info *fs_info)
561{ 570{
562 int error = 0; 571 int error = 0;
@@ -592,13 +601,17 @@ int btrfs_sysfs_add_one(struct btrfs_fs_info *fs_info)
592 fs_info->super_kobj.kset = btrfs_kset; 601 fs_info->super_kobj.kset = btrfs_kset;
593 error = kobject_init_and_add(&fs_info->super_kobj, &btrfs_ktype, NULL, 602 error = kobject_init_and_add(&fs_info->super_kobj, &btrfs_ktype, NULL,
594 "%pU", fs_info->fsid); 603 "%pU", fs_info->fsid);
604 if (error)
605 return error;
595 606
596 error = sysfs_create_group(&fs_info->super_kobj, 607 error = sysfs_create_group(&fs_info->super_kobj,
597 &btrfs_feature_attr_group); 608 &btrfs_feature_attr_group);
598 if (error) 609 if (error) {
599 goto failure; 610 __btrfs_sysfs_remove_one(fs_info);
611 return error;
612 }
600 613
601 error = add_unknown_feature_attrs(fs_info); 614 error = addrm_unknown_feature_attrs(fs_info, true);
602 if (error) 615 if (error)
603 goto failure; 616 goto failure;
604 617