aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs
diff options
context:
space:
mode:
authorJeff Mahoney <jeffm@suse.com>2014-05-27 12:59:57 -0400
committerChris Mason <clm@fb.com>2014-06-09 20:21:01 -0400
commitc1895442be01c58449e3bf9272f22062a670e08f (patch)
tree8a09bb69c59dfdbcff5869cb82490487ec0bf86e /fs/btrfs
parent7e3ae33efad1490d01040f552ef50e58ed6376ca (diff)
btrfs: allocate raid type kobjects dynamically
We are currently allocating space_info objects in an array when we allocate space_info. When a user does something like: # btrfs balance start -mconvert=raid1 -dconvert=raid1 /mnt # btrfs balance start -mconvert=single -dconvert=single /mnt -f # btrfs balance start -mconvert=raid1 -dconvert=raid1 / We can end up with memory corruption since the kobject hasn't been reinitialized properly and the name pointer was left set. The rationale behind allocating them statically was to avoid creating a separate kobject container that just contained the raid type. It used the index in the array to determine the index. Ultimately, though, this wastes more memory than it saves in all but the most complex scenarios and introduces kobject lifetime questions. This patch allocates the kobjects dynamically instead. Note that we also remove the kobject_get/put of the parent kobject since kobject_add and kobject_del do that internally. Signed-off-by: Jeff Mahoney <jeffm@suse.com> Reported-by: David Sterba <dsterba@suse.cz> Signed-off-by: Chris Mason <clm@fb.com>
Diffstat (limited to 'fs/btrfs')
-rw-r--r--fs/btrfs/ctree.h8
-rw-r--r--fs/btrfs/extent-tree.c39
-rw-r--r--fs/btrfs/sysfs.c5
3 files changed, 36 insertions, 16 deletions
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h
index 02895a126ab9..af523d695432 100644
--- a/fs/btrfs/ctree.h
+++ b/fs/btrfs/ctree.h
@@ -1123,6 +1123,12 @@ struct btrfs_qgroup_limit_item {
1123 __le64 rsv_excl; 1123 __le64 rsv_excl;
1124} __attribute__ ((__packed__)); 1124} __attribute__ ((__packed__));
1125 1125
1126/* For raid type sysfs entries */
1127struct raid_kobject {
1128 int raid_type;
1129 struct kobject kobj;
1130};
1131
1126struct btrfs_space_info { 1132struct btrfs_space_info {
1127 spinlock_t lock; 1133 spinlock_t lock;
1128 1134
@@ -1173,7 +1179,7 @@ struct btrfs_space_info {
1173 wait_queue_head_t wait; 1179 wait_queue_head_t wait;
1174 1180
1175 struct kobject kobj; 1181 struct kobject kobj;
1176 struct kobject block_group_kobjs[BTRFS_NR_RAID_TYPES]; 1182 struct kobject *block_group_kobjs[BTRFS_NR_RAID_TYPES];
1177}; 1183};
1178 1184
1179#define BTRFS_BLOCK_RSV_GLOBAL 1 1185#define BTRFS_BLOCK_RSV_GLOBAL 1
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c
index 6caddd5970e4..fafb3e53ecde 100644
--- a/fs/btrfs/extent-tree.c
+++ b/fs/btrfs/extent-tree.c
@@ -3497,10 +3497,8 @@ static int update_space_info(struct btrfs_fs_info *info, u64 flags,
3497 return ret; 3497 return ret;
3498 } 3498 }
3499 3499
3500 for (i = 0; i < BTRFS_NR_RAID_TYPES; i++) { 3500 for (i = 0; i < BTRFS_NR_RAID_TYPES; i++)
3501 INIT_LIST_HEAD(&found->block_groups[i]); 3501 INIT_LIST_HEAD(&found->block_groups[i]);
3502 kobject_init(&found->block_group_kobjs[i], &btrfs_raid_ktype);
3503 }
3504 init_rwsem(&found->groups_sem); 3502 init_rwsem(&found->groups_sem);
3505 spin_lock_init(&found->lock); 3503 spin_lock_init(&found->lock);
3506 found->flags = flags & BTRFS_BLOCK_GROUP_TYPE_MASK; 3504 found->flags = flags & BTRFS_BLOCK_GROUP_TYPE_MASK;
@@ -8586,8 +8584,9 @@ int btrfs_free_block_groups(struct btrfs_fs_info *info)
8586 list_del(&space_info->list); 8584 list_del(&space_info->list);
8587 for (i = 0; i < BTRFS_NR_RAID_TYPES; i++) { 8585 for (i = 0; i < BTRFS_NR_RAID_TYPES; i++) {
8588 struct kobject *kobj; 8586 struct kobject *kobj;
8589 kobj = &space_info->block_group_kobjs[i]; 8587 kobj = space_info->block_group_kobjs[i];
8590 if (kobj->parent) { 8588 space_info->block_group_kobjs[i] = NULL;
8589 if (kobj) {
8591 kobject_del(kobj); 8590 kobject_del(kobj);
8592 kobject_put(kobj); 8591 kobject_put(kobj);
8593 } 8592 }
@@ -8611,17 +8610,26 @@ static void __link_block_group(struct btrfs_space_info *space_info,
8611 up_write(&space_info->groups_sem); 8610 up_write(&space_info->groups_sem);
8612 8611
8613 if (first) { 8612 if (first) {
8614 struct kobject *kobj = &space_info->block_group_kobjs[index]; 8613 struct raid_kobject *rkobj;
8615 int ret; 8614 int ret;
8616 8615
8617 kobject_get(&space_info->kobj); /* put in release */ 8616 rkobj = kzalloc(sizeof(*rkobj), GFP_NOFS);
8618 ret = kobject_add(kobj, &space_info->kobj, "%s", 8617 if (!rkobj)
8619 get_raid_name(index)); 8618 goto out_err;
8619 rkobj->raid_type = index;
8620 kobject_init(&rkobj->kobj, &btrfs_raid_ktype);
8621 ret = kobject_add(&rkobj->kobj, &space_info->kobj,
8622 "%s", get_raid_name(index));
8620 if (ret) { 8623 if (ret) {
8621 pr_warn("BTRFS: failed to add kobject for block cache. ignoring.\n"); 8624 kobject_put(&rkobj->kobj);
8622 kobject_put(&space_info->kobj); 8625 goto out_err;
8623 } 8626 }
8627 space_info->block_group_kobjs[index] = &rkobj->kobj;
8624 } 8628 }
8629
8630 return;
8631out_err:
8632 pr_warn("BTRFS: failed to add kobject for block cache. ignoring.\n");
8625} 8633}
8626 8634
8627static struct btrfs_block_group_cache * 8635static struct btrfs_block_group_cache *
@@ -8956,6 +8964,7 @@ int btrfs_remove_block_group(struct btrfs_trans_handle *trans,
8956 struct btrfs_root *tree_root = root->fs_info->tree_root; 8964 struct btrfs_root *tree_root = root->fs_info->tree_root;
8957 struct btrfs_key key; 8965 struct btrfs_key key;
8958 struct inode *inode; 8966 struct inode *inode;
8967 struct kobject *kobj = NULL;
8959 int ret; 8968 int ret;
8960 int index; 8969 int index;
8961 int factor; 8970 int factor;
@@ -9055,11 +9064,15 @@ int btrfs_remove_block_group(struct btrfs_trans_handle *trans,
9055 */ 9064 */
9056 list_del_init(&block_group->list); 9065 list_del_init(&block_group->list);
9057 if (list_empty(&block_group->space_info->block_groups[index])) { 9066 if (list_empty(&block_group->space_info->block_groups[index])) {
9058 kobject_del(&block_group->space_info->block_group_kobjs[index]); 9067 kobj = block_group->space_info->block_group_kobjs[index];
9059 kobject_put(&block_group->space_info->block_group_kobjs[index]); 9068 block_group->space_info->block_group_kobjs[index] = NULL;
9060 clear_avail_alloc_bits(root->fs_info, block_group->flags); 9069 clear_avail_alloc_bits(root->fs_info, block_group->flags);
9061 } 9070 }
9062 up_write(&block_group->space_info->groups_sem); 9071 up_write(&block_group->space_info->groups_sem);
9072 if (kobj) {
9073 kobject_del(kobj);
9074 kobject_put(kobj);
9075 }
9063 9076
9064 if (block_group->cached == BTRFS_CACHE_STARTED) 9077 if (block_group->cached == BTRFS_CACHE_STARTED)
9065 wait_block_group_cache_done(block_group); 9078 wait_block_group_cache_done(block_group);
diff --git a/fs/btrfs/sysfs.c b/fs/btrfs/sysfs.c
index c0dfda5644f2..df39458f1487 100644
--- a/fs/btrfs/sysfs.c
+++ b/fs/btrfs/sysfs.c
@@ -254,6 +254,7 @@ static ssize_t global_rsv_reserved_show(struct kobject *kobj,
254BTRFS_ATTR(global_rsv_reserved, 0444, global_rsv_reserved_show); 254BTRFS_ATTR(global_rsv_reserved, 0444, global_rsv_reserved_show);
255 255
256#define to_space_info(_kobj) container_of(_kobj, struct btrfs_space_info, kobj) 256#define to_space_info(_kobj) container_of(_kobj, struct btrfs_space_info, kobj)
257#define to_raid_kobj(_kobj) container_of(_kobj, struct raid_kobject, kobj)
257 258
258static ssize_t raid_bytes_show(struct kobject *kobj, 259static ssize_t raid_bytes_show(struct kobject *kobj,
259 struct kobj_attribute *attr, char *buf); 260 struct kobj_attribute *attr, char *buf);
@@ -266,7 +267,7 @@ static ssize_t raid_bytes_show(struct kobject *kobj,
266{ 267{
267 struct btrfs_space_info *sinfo = to_space_info(kobj->parent); 268 struct btrfs_space_info *sinfo = to_space_info(kobj->parent);
268 struct btrfs_block_group_cache *block_group; 269 struct btrfs_block_group_cache *block_group;
269 int index = kobj - sinfo->block_group_kobjs; 270 int index = to_raid_kobj(kobj)->raid_type;
270 u64 val = 0; 271 u64 val = 0;
271 272
272 down_read(&sinfo->groups_sem); 273 down_read(&sinfo->groups_sem);
@@ -288,7 +289,7 @@ static struct attribute *raid_attributes[] = {
288 289
289static void release_raid_kobj(struct kobject *kobj) 290static void release_raid_kobj(struct kobject *kobj)
290{ 291{
291 kobject_put(kobj->parent); 292 kfree(to_raid_kobj(kobj));
292} 293}
293 294
294struct kobj_type btrfs_raid_ktype = { 295struct kobj_type btrfs_raid_ktype = {