btrfs: get fs_info from eb in should_balance_chunk
[sfrench/cifs-2.6.git] / fs / btrfs / volumes.c
index 66b8b492d6f5bfd4cd5b16c19206e4a7b4ec57b9..4576f0e69d336183433f5f2d8e8c711997842397 100644 (file)
@@ -336,6 +336,7 @@ void btrfs_free_device(struct btrfs_device *device)
 {
        WARN_ON(!list_empty(&device->post_commit_list));
        rcu_string_free(device->name);
+       extent_io_tree_release(&device->alloc_state);
        bio_put(device->flush_bio);
        kfree(device);
 }
@@ -412,6 +413,7 @@ static struct btrfs_device *__alloc_device(void)
        btrfs_device_data_ordered_init(dev);
        INIT_RADIX_TREE(&dev->reada_zones, GFP_NOFS & ~__GFP_DIRECT_RECLAIM);
        INIT_RADIX_TREE(&dev->reada_extents, GFP_NOFS & ~__GFP_DIRECT_RECLAIM);
+       extent_io_tree_init(NULL, &dev->alloc_state, 0, NULL);
 
        return dev;
 }
@@ -1231,14 +1233,6 @@ again:
        mutex_unlock(&uuid_mutex);
 }
 
-static void free_device_rcu(struct rcu_head *head)
-{
-       struct btrfs_device *device;
-
-       device = container_of(head, struct btrfs_device, rcu);
-       btrfs_free_device(device);
-}
-
 static void btrfs_close_bdev(struct btrfs_device *device)
 {
        if (!device->bdev)
@@ -1286,7 +1280,8 @@ static void btrfs_close_one_device(struct btrfs_device *device)
        list_replace_rcu(&device->dev_list, &new_device->dev_list);
        new_device->fs_devices = device->fs_devices;
 
-       call_rcu(&device->rcu, free_device_rcu);
+       synchronize_rcu();
+       btrfs_free_device(device);
 }
 
 static int close_fs_devices(struct btrfs_fs_devices *fs_devices)
@@ -1506,58 +1501,29 @@ error_bdev_put:
        return device;
 }
 
-static int contains_pending_extent(struct btrfs_transaction *transaction,
-                                  struct btrfs_device *device,
-                                  u64 *start, u64 len)
+/*
+ * Try to find a chunk that intersects [start, start + len] range and when one
+ * such is found, record the end of it in *start
+ */
+static bool contains_pending_extent(struct btrfs_device *device, u64 *start,
+                                   u64 len)
 {
-       struct btrfs_fs_info *fs_info = device->fs_info;
-       struct extent_map *em;
-       struct list_head *search_list = &fs_info->pinned_chunks;
-       int ret = 0;
-       u64 physical_start = *start;
+       u64 physical_start, physical_end;
 
-       if (transaction)
-               search_list = &transaction->pending_chunks;
-again:
-       list_for_each_entry(em, search_list, list) {
-               struct map_lookup *map;
-               int i;
+       lockdep_assert_held(&device->fs_info->chunk_mutex);
 
-               map = em->map_lookup;
-               for (i = 0; i < map->num_stripes; i++) {
-                       u64 end;
+       if (!find_first_extent_bit(&device->alloc_state, *start,
+                                  &physical_start, &physical_end,
+                                  CHUNK_ALLOCATED, NULL)) {
 
-                       if (map->stripes[i].dev != device)
-                               continue;
-                       if (map->stripes[i].physical >= physical_start + len ||
-                           map->stripes[i].physical + em->orig_block_len <=
-                           physical_start)
-                               continue;
-                       /*
-                        * Make sure that while processing the pinned list we do
-                        * not override our *start with a lower value, because
-                        * we can have pinned chunks that fall within this
-                        * device hole and that have lower physical addresses
-                        * than the pending chunks we processed before. If we
-                        * do not take this special care we can end up getting
-                        * 2 pending chunks that start at the same physical
-                        * device offsets because the end offset of a pinned
-                        * chunk can be equal to the start offset of some
-                        * pending chunk.
-                        */
-                       end = map->stripes[i].physical + em->orig_block_len;
-                       if (end > *start) {
-                               *start = end;
-                               ret = 1;
-                       }
+               if (in_range(physical_start, *start, len) ||
+                   in_range(*start, physical_start,
+                            physical_end - physical_start)) {
+                       *start = physical_end + 1;
+                       return true;
                }
        }
-       if (search_list != &fs_info->pinned_chunks) {
-               search_list = &fs_info->pinned_chunks;
-               goto again;
-       }
-
-       return ret;
+       return false;
 }
 
 
@@ -1582,8 +1548,7 @@ again:
  * But if we don't find suitable free space, it is used to store the size of
  * the max free space.
  */
-int find_free_dev_extent_start(struct btrfs_transaction *transaction,
-                              struct btrfs_device *device, u64 num_bytes,
+int find_free_dev_extent_start(struct btrfs_device *device, u64 num_bytes,
                               u64 search_start, u64 *start, u64 *len)
 {
        struct btrfs_fs_info *fs_info = device->fs_info;
@@ -1668,15 +1633,12 @@ again:
                         * Have to check before we set max_hole_start, otherwise
                         * we could end up sending back this offset anyway.
                         */
-                       if (contains_pending_extent(transaction, device,
-                                                   &search_start,
+                       if (contains_pending_extent(device, &search_start,
                                                    hole_size)) {
-                               if (key.offset >= search_start) {
+                               if (key.offset >= search_start)
                                        hole_size = key.offset - search_start;
-                               } else {
-                                       WARN_ON_ONCE(1);
+                               else
                                        hole_size = 0;
-                               }
                        }
 
                        if (hole_size > max_hole_size) {
@@ -1717,8 +1679,7 @@ next:
        if (search_end > search_start) {
                hole_size = search_end - search_start;
 
-               if (contains_pending_extent(transaction, device, &search_start,
-                                           hole_size)) {
+               if (contains_pending_extent(device, &search_start, hole_size)) {
                        btrfs_release_path(path);
                        goto again;
                }
@@ -1743,13 +1704,11 @@ out:
        return ret;
 }
 
-int find_free_dev_extent(struct btrfs_trans_handle *trans,
-                        struct btrfs_device *device, u64 num_bytes,
+int find_free_dev_extent(struct btrfs_device *device, u64 num_bytes,
                         u64 *start, u64 *len)
 {
        /* FIXME use last free of some kind */
-       return find_free_dev_extent_start(trans->transaction, device,
-                                         num_bytes, 0, start, len);
+       return find_free_dev_extent_start(device, num_bytes, 0, start, len);
 }
 
 static int btrfs_free_dev_extent(struct btrfs_trans_handle *trans,
@@ -2243,7 +2202,8 @@ int btrfs_rm_device(struct btrfs_fs_info *fs_info, const char *device_path,
                btrfs_scratch_superblocks(device->bdev, device->name->str);
 
        btrfs_close_bdev(device);
-       call_rcu(&device->rcu, free_device_rcu);
+       synchronize_rcu();
+       btrfs_free_device(device);
 
        if (cur_devices->open_devices == 0) {
                while (fs_devices) {
@@ -2311,7 +2271,8 @@ void btrfs_rm_dev_replace_free_srcdev(struct btrfs_fs_info *fs_info,
        }
 
        btrfs_close_bdev(srcdev);
-       call_rcu(&srcdev->rcu, free_device_rcu);
+       synchronize_rcu();
+       btrfs_free_device(srcdev);
 
        /* if this is no devs we rather delete the fs_devices */
        if (!fs_devices->num_devices) {
@@ -2369,7 +2330,8 @@ void btrfs_destroy_dev_replace_tgtdev(struct btrfs_device *tgtdev)
        btrfs_scratch_superblocks(tgtdev->bdev, tgtdev->name->str);
 
        btrfs_close_bdev(tgtdev);
-       call_rcu(&tgtdev->rcu, free_device_rcu);
+       synchronize_rcu();
+       btrfs_free_device(tgtdev);
 }
 
 static struct btrfs_device *btrfs_find_device_by_path(
@@ -3599,10 +3561,10 @@ static int chunk_soft_convert_filter(u64 chunk_type,
        return 0;
 }
 
-static int should_balance_chunk(struct btrfs_fs_info *fs_info,
-                               struct extent_buffer *leaf,
+static int should_balance_chunk(struct extent_buffer *leaf,
                                struct btrfs_chunk *chunk, u64 chunk_offset)
 {
+       struct btrfs_fs_info *fs_info = leaf->fs_info;
        struct btrfs_balance_control *bctl = fs_info->balance_ctl;
        struct btrfs_balance_args *bargs = NULL;
        u64 chunk_type = btrfs_chunk_type(leaf, chunk);
@@ -3782,8 +3744,7 @@ again:
                        spin_unlock(&fs_info->balance_lock);
                }
 
-               ret = should_balance_chunk(fs_info, leaf, chunk,
-                                          found_key.offset);
+               ret = should_balance_chunk(leaf, chunk, found_key.offset);
 
                btrfs_release_path(path);
                if (!ret) {
@@ -4760,7 +4721,7 @@ int btrfs_shrink_device(struct btrfs_device *device, u64 new_size)
         * in-memory chunks are synced to disk so that the loop below sees them
         * and relocates them accordingly.
         */
-       if (contains_pending_extent(trans->transaction, device, &start, diff)) {
+       if (contains_pending_extent(device, &start, diff)) {
                mutex_unlock(&fs_info->chunk_mutex);
                ret = btrfs_commit_transaction(trans);
                if (ret)
@@ -5059,7 +5020,7 @@ static int __btrfs_alloc_chunk(struct btrfs_trans_handle *trans,
                if (total_avail == 0)
                        continue;
 
-               ret = find_free_dev_extent(trans, device,
+               ret = find_free_dev_extent(device,
                                           max_stripe_size * dev_stripes,
                                           &dev_offset, &max_avail);
                if (ret && ret != -ENOSPC)
@@ -5193,9 +5154,6 @@ static int __btrfs_alloc_chunk(struct btrfs_trans_handle *trans,
                free_extent_map(em);
                goto error;
        }
-
-       list_add_tail(&em->list, &trans->transaction->pending_chunks);
-       refcount_inc(&em->refs);
        write_unlock(&em_tree->lock);
 
        ret = btrfs_make_block_group(trans, 0, type, start, chunk_size);
@@ -5228,8 +5186,6 @@ error_del_extent:
        free_extent_map(em);
        /* One for the tree reference */
        free_extent_map(em);
-       /* One for the pending_chunks list reference */
-       free_extent_map(em);
 error:
        kfree(devices_info);
        return ret;