Commit 064e38aa authored by Linus Torvalds's avatar Linus Torvalds

Merge git://git.kernel.org/pub/scm/linux/kernel/git/mason/btrfs-unstable

* git://git.kernel.org/pub/scm/linux/kernel/git/mason/btrfs-unstable:
  Btrfs: Fix oops and use after free during space balancing
  Btrfs: set device->total_disk_bytes when adding new device
parents cd24f8c1 44fb5511
...@@ -2622,7 +2622,18 @@ static noinline int find_free_extent(struct btrfs_trans_handle *trans, ...@@ -2622,7 +2622,18 @@ static noinline int find_free_extent(struct btrfs_trans_handle *trans,
search_start); search_start);
if (block_group && block_group_bits(block_group, data)) { if (block_group && block_group_bits(block_group, data)) {
down_read(&space_info->groups_sem); down_read(&space_info->groups_sem);
goto have_block_group; if (list_empty(&block_group->list) ||
block_group->ro) {
/*
* someone is removing this block group,
* we can't jump into the have_block_group
* target because our list pointers are not
* valid
*/
btrfs_put_block_group(block_group);
up_read(&space_info->groups_sem);
} else
goto have_block_group;
} else if (block_group) { } else if (block_group) {
btrfs_put_block_group(block_group); btrfs_put_block_group(block_group);
} }
...@@ -2656,6 +2667,13 @@ static noinline int find_free_extent(struct btrfs_trans_handle *trans, ...@@ -2656,6 +2667,13 @@ static noinline int find_free_extent(struct btrfs_trans_handle *trans,
* people trying to start a new cluster * people trying to start a new cluster
*/ */
spin_lock(&last_ptr->refill_lock); spin_lock(&last_ptr->refill_lock);
if (last_ptr->block_group &&
(last_ptr->block_group->ro ||
!block_group_bits(last_ptr->block_group, data))) {
offset = 0;
goto refill_cluster;
}
offset = btrfs_alloc_from_cluster(block_group, last_ptr, offset = btrfs_alloc_from_cluster(block_group, last_ptr,
num_bytes, search_start); num_bytes, search_start);
if (offset) { if (offset) {
...@@ -2681,10 +2699,17 @@ static noinline int find_free_extent(struct btrfs_trans_handle *trans, ...@@ -2681,10 +2699,17 @@ static noinline int find_free_extent(struct btrfs_trans_handle *trans,
last_ptr_loop = 1; last_ptr_loop = 1;
search_start = block_group->key.objectid; search_start = block_group->key.objectid;
/*
* we know this block group is properly
* in the list because
* btrfs_remove_block_group, drops the
* cluster before it removes the block
* group from the list
*/
goto have_block_group; goto have_block_group;
} }
spin_unlock(&last_ptr->lock); spin_unlock(&last_ptr->lock);
refill_cluster:
/* /*
* this cluster didn't work out, free it and * this cluster didn't work out, free it and
* start over * start over
...@@ -5968,6 +5993,7 @@ int btrfs_remove_block_group(struct btrfs_trans_handle *trans, ...@@ -5968,6 +5993,7 @@ int btrfs_remove_block_group(struct btrfs_trans_handle *trans,
{ {
struct btrfs_path *path; struct btrfs_path *path;
struct btrfs_block_group_cache *block_group; struct btrfs_block_group_cache *block_group;
struct btrfs_free_cluster *cluster;
struct btrfs_key key; struct btrfs_key key;
int ret; int ret;
...@@ -5979,6 +6005,21 @@ int btrfs_remove_block_group(struct btrfs_trans_handle *trans, ...@@ -5979,6 +6005,21 @@ int btrfs_remove_block_group(struct btrfs_trans_handle *trans,
memcpy(&key, &block_group->key, sizeof(key)); memcpy(&key, &block_group->key, sizeof(key));
/* make sure this block group isn't part of an allocation cluster */
cluster = &root->fs_info->data_alloc_cluster;
spin_lock(&cluster->refill_lock);
btrfs_return_cluster_to_free_space(block_group, cluster);
spin_unlock(&cluster->refill_lock);
/*
* make sure this block group isn't part of a metadata
* allocation cluster
*/
cluster = &root->fs_info->meta_alloc_cluster;
spin_lock(&cluster->refill_lock);
btrfs_return_cluster_to_free_space(block_group, cluster);
spin_unlock(&cluster->refill_lock);
path = btrfs_alloc_path(); path = btrfs_alloc_path();
BUG_ON(!path); BUG_ON(!path);
...@@ -5988,7 +6029,11 @@ int btrfs_remove_block_group(struct btrfs_trans_handle *trans, ...@@ -5988,7 +6029,11 @@ int btrfs_remove_block_group(struct btrfs_trans_handle *trans,
spin_unlock(&root->fs_info->block_group_cache_lock); spin_unlock(&root->fs_info->block_group_cache_lock);
btrfs_remove_free_space_cache(block_group); btrfs_remove_free_space_cache(block_group);
down_write(&block_group->space_info->groups_sem); down_write(&block_group->space_info->groups_sem);
list_del(&block_group->list); /*
* we must use list_del_init so people can check to see if they
* are still on the list after taking the semaphore
*/
list_del_init(&block_group->list);
up_write(&block_group->space_info->groups_sem); up_write(&block_group->space_info->groups_sem);
spin_lock(&block_group->space_info->lock); spin_lock(&block_group->space_info->lock);
......
...@@ -1440,6 +1440,7 @@ int btrfs_init_new_device(struct btrfs_root *root, char *device_path) ...@@ -1440,6 +1440,7 @@ int btrfs_init_new_device(struct btrfs_root *root, char *device_path)
device->io_align = root->sectorsize; device->io_align = root->sectorsize;
device->sector_size = root->sectorsize; device->sector_size = root->sectorsize;
device->total_bytes = i_size_read(bdev->bd_inode); device->total_bytes = i_size_read(bdev->bd_inode);
device->disk_total_bytes = device->total_bytes;
device->dev_root = root->fs_info->dev_root; device->dev_root = root->fs_info->dev_root;
device->bdev = bdev; device->bdev = bdev;
device->in_fs_metadata = 1; device->in_fs_metadata = 1;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment