Commit 064e38aaded5269e573ac1c765284fd65c8ebd13

Authored by 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

Showing 2 changed files Side-by-side Diff

fs/btrfs/extent-tree.c
... ... @@ -2622,7 +2622,18 @@
2622 2622 search_start);
2623 2623 if (block_group && block_group_bits(block_group, data)) {
2624 2624 down_read(&space_info->groups_sem);
2625   - goto have_block_group;
  2625 + if (list_empty(&block_group->list) ||
  2626 + block_group->ro) {
  2627 + /*
  2628 + * someone is removing this block group,
  2629 + * we can't jump into the have_block_group
  2630 + * target because our list pointers are not
  2631 + * valid
  2632 + */
  2633 + btrfs_put_block_group(block_group);
  2634 + up_read(&space_info->groups_sem);
  2635 + } else
  2636 + goto have_block_group;
2626 2637 } else if (block_group) {
2627 2638 btrfs_put_block_group(block_group);
2628 2639 }
... ... @@ -2656,6 +2667,13 @@
2656 2667 * people trying to start a new cluster
2657 2668 */
2658 2669 spin_lock(&last_ptr->refill_lock);
  2670 + if (last_ptr->block_group &&
  2671 + (last_ptr->block_group->ro ||
  2672 + !block_group_bits(last_ptr->block_group, data))) {
  2673 + offset = 0;
  2674 + goto refill_cluster;
  2675 + }
  2676 +
2659 2677 offset = btrfs_alloc_from_cluster(block_group, last_ptr,
2660 2678 num_bytes, search_start);
2661 2679 if (offset) {
2662 2680  
... ... @@ -2681,10 +2699,17 @@
2681 2699  
2682 2700 last_ptr_loop = 1;
2683 2701 search_start = block_group->key.objectid;
  2702 + /*
  2703 + * we know this block group is properly
  2704 + * in the list because
  2705 + * btrfs_remove_block_group, drops the
  2706 + * cluster before it removes the block
  2707 + * group from the list
  2708 + */
2684 2709 goto have_block_group;
2685 2710 }
2686 2711 spin_unlock(&last_ptr->lock);
2687   -
  2712 +refill_cluster:
2688 2713 /*
2689 2714 * this cluster didn't work out, free it and
2690 2715 * start over
... ... @@ -5968,6 +5993,7 @@
5968 5993 {
5969 5994 struct btrfs_path *path;
5970 5995 struct btrfs_block_group_cache *block_group;
  5996 + struct btrfs_free_cluster *cluster;
5971 5997 struct btrfs_key key;
5972 5998 int ret;
5973 5999  
... ... @@ -5979,6 +6005,21 @@
5979 6005  
5980 6006 memcpy(&key, &block_group->key, sizeof(key));
5981 6007  
  6008 + /* make sure this block group isn't part of an allocation cluster */
  6009 + cluster = &root->fs_info->data_alloc_cluster;
  6010 + spin_lock(&cluster->refill_lock);
  6011 + btrfs_return_cluster_to_free_space(block_group, cluster);
  6012 + spin_unlock(&cluster->refill_lock);
  6013 +
  6014 + /*
  6015 + * make sure this block group isn't part of a metadata
  6016 + * allocation cluster
  6017 + */
  6018 + cluster = &root->fs_info->meta_alloc_cluster;
  6019 + spin_lock(&cluster->refill_lock);
  6020 + btrfs_return_cluster_to_free_space(block_group, cluster);
  6021 + spin_unlock(&cluster->refill_lock);
  6022 +
5982 6023 path = btrfs_alloc_path();
5983 6024 BUG_ON(!path);
5984 6025  
... ... @@ -5988,7 +6029,11 @@
5988 6029 spin_unlock(&root->fs_info->block_group_cache_lock);
5989 6030 btrfs_remove_free_space_cache(block_group);
5990 6031 down_write(&block_group->space_info->groups_sem);
5991   - list_del(&block_group->list);
  6032 + /*
  6033 + * we must use list_del_init so people can check to see if they
  6034 + * are still on the list after taking the semaphore
  6035 + */
  6036 + list_del_init(&block_group->list);
5992 6037 up_write(&block_group->space_info->groups_sem);
5993 6038  
5994 6039 spin_lock(&block_group->space_info->lock);
... ... @@ -1440,6 +1440,7 @@
1440 1440 device->io_align = root->sectorsize;
1441 1441 device->sector_size = root->sectorsize;
1442 1442 device->total_bytes = i_size_read(bdev->bd_inode);
  1443 + device->disk_total_bytes = device->total_bytes;
1443 1444 device->dev_root = root->fs_info->dev_root;
1444 1445 device->bdev = bdev;
1445 1446 device->in_fs_metadata = 1;