aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs/sysfs.c
diff options
context:
space:
mode:
authorJeff Mahoney <jeffm@suse.com>2013-11-21 10:37:16 -0500
committerChris Mason <clm@fb.com>2014-01-28 16:19:45 -0500
commite453d989e0bb33defaaa5be4e9f577cea946e2a6 (patch)
treef285b20b15933459db0b13282042acf3b0569dbf /fs/btrfs/sysfs.c
parent1b8e5df6d9b676f6d31fb098ffdc7d18732729d7 (diff)
btrfs: fix leaks during sysfs teardown
Filipe noticed that we were leaking the features attribute group after umount. His fix of just calling sysfs_remove_group() wasn't enough since that removes just the supported features and not the unsupported features. This patch changes the unknown feature handling to add them individually so we can skip the kmalloc and uses the same iteration to tear them down later. We also fix the error handling during mount so that we catch the failing creation of the per-super kobject, and handle proper teardown of a half-setup sysfs context. Tested properly with kmemleak enabled this time. Reported-by: Filipe David Borba Manana <fdmanana@gmail.com> Signed-off-by: Jeff Mahoney <jeffm@suse.com> Tested-by: Filipe David Borba Manana <fdmanana@gmail.com> Signed-off-by: Josef Bacik <jbacik@fb.com> Signed-off-by: Chris Mason <clm@fb.com>
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