btrfs: close devices without offloading to a temporary list
[sfrench/cifs-2.6.git] / fs / btrfs / volumes.c
index e034ad9e23b48b42826de6bed1a8f59d6e926a20..3c3359d7e91d8657b25dce3afea0e908fa9ad978 100644 (file)
@@ -8,15 +8,12 @@
 #include <linux/slab.h>
 #include <linux/buffer_head.h>
 #include <linux/blkdev.h>
-#include <linux/iocontext.h>
-#include <linux/capability.h>
 #include <linux/ratelimit.h>
 #include <linux/kthread.h>
 #include <linux/raid/pq.h>
 #include <linux/semaphore.h>
 #include <linux/uuid.h>
 #include <linux/list_sort.h>
-#include <asm/div64.h>
 #include "ctree.h"
 #include "extent_map.h"
 #include "disk-io.h"
@@ -1004,7 +1001,7 @@ static void btrfs_close_bdev(struct btrfs_device *device)
        blkdev_put(device->bdev, device->mode);
 }
 
-static void btrfs_prepare_close_one_device(struct btrfs_device *device)
+static void btrfs_close_one_device(struct btrfs_device *device)
 {
        struct btrfs_fs_devices *fs_devices = device->fs_devices;
        struct btrfs_device *new_device;
@@ -1022,6 +1019,8 @@ static void btrfs_prepare_close_one_device(struct btrfs_device *device)
        if (test_bit(BTRFS_DEV_STATE_MISSING, &device->dev_state))
                fs_devices->missing_devices--;
 
+       btrfs_close_bdev(device);
+
        new_device = btrfs_alloc_device(NULL, &device->devid,
                                        device->uuid);
        BUG_ON(IS_ERR(new_device)); /* -ENOMEM */
@@ -1035,39 +1034,23 @@ static void btrfs_prepare_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);
 }
 
 static int close_fs_devices(struct btrfs_fs_devices *fs_devices)
 {
        struct btrfs_device *device, *tmp;
-       struct list_head pending_put;
-
-       INIT_LIST_HEAD(&pending_put);
 
        if (--fs_devices->opened > 0)
                return 0;
 
        mutex_lock(&fs_devices->device_list_mutex);
        list_for_each_entry_safe(device, tmp, &fs_devices->devices, dev_list) {
-               btrfs_prepare_close_one_device(device);
-               list_add(&device->dev_list, &pending_put);
+               btrfs_close_one_device(device);
        }
        mutex_unlock(&fs_devices->device_list_mutex);
 
-       /*
-        * btrfs_show_devname() is using the device_list_mutex,
-        * sometimes call to blkdev_put() leads vfs calling
-        * into this func. So do put outside of device_list_mutex,
-        * as of now.
-        */
-       while (!list_empty(&pending_put)) {
-               device = list_first_entry(&pending_put,
-                               struct btrfs_device, dev_list);
-               list_del(&device->dev_list);
-               btrfs_close_bdev(device);
-               call_rcu(&device->rcu, free_device_rcu);
-       }
-
        WARN_ON(fs_devices->open_devices);
        WARN_ON(fs_devices->rw_devices);
        fs_devices->opened = 0;
@@ -1146,6 +1129,7 @@ int btrfs_open_devices(struct btrfs_fs_devices *fs_devices,
 {
        int ret;
 
+       mutex_lock(&uuid_mutex);
        mutex_lock(&fs_devices->device_list_mutex);
        if (fs_devices->opened) {
                fs_devices->opened++;
@@ -1155,6 +1139,7 @@ int btrfs_open_devices(struct btrfs_fs_devices *fs_devices,
                ret = open_fs_devices(fs_devices, flags, holder);
        }
        mutex_unlock(&fs_devices->device_list_mutex);
+       mutex_unlock(&uuid_mutex);
 
        return ret;
 }
@@ -1259,91 +1244,6 @@ error_bdev_put:
        return ret;
 }
 
-/* helper to account the used device space in the range */
-int btrfs_account_dev_extents_size(struct btrfs_device *device, u64 start,
-                                  u64 end, u64 *length)
-{
-       struct btrfs_key key;
-       struct btrfs_root *root = device->fs_info->dev_root;
-       struct btrfs_dev_extent *dev_extent;
-       struct btrfs_path *path;
-       u64 extent_end;
-       int ret;
-       int slot;
-       struct extent_buffer *l;
-
-       *length = 0;
-
-       if (start >= device->total_bytes ||
-               test_bit(BTRFS_DEV_STATE_REPLACE_TGT, &device->dev_state))
-               return 0;
-
-       path = btrfs_alloc_path();
-       if (!path)
-               return -ENOMEM;
-       path->reada = READA_FORWARD;
-
-       key.objectid = device->devid;
-       key.offset = start;
-       key.type = BTRFS_DEV_EXTENT_KEY;
-
-       ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
-       if (ret < 0)
-               goto out;
-       if (ret > 0) {
-               ret = btrfs_previous_item(root, path, key.objectid, key.type);
-               if (ret < 0)
-                       goto out;
-       }
-
-       while (1) {
-               l = path->nodes[0];
-               slot = path->slots[0];
-               if (slot >= btrfs_header_nritems(l)) {
-                       ret = btrfs_next_leaf(root, path);
-                       if (ret == 0)
-                               continue;
-                       if (ret < 0)
-                               goto out;
-
-                       break;
-               }
-               btrfs_item_key_to_cpu(l, &key, slot);
-
-               if (key.objectid < device->devid)
-                       goto next;
-
-               if (key.objectid > device->devid)
-                       break;
-
-               if (key.type != BTRFS_DEV_EXTENT_KEY)
-                       goto next;
-
-               dev_extent = btrfs_item_ptr(l, slot, struct btrfs_dev_extent);
-               extent_end = key.offset + btrfs_dev_extent_length(l,
-                                                                 dev_extent);
-               if (key.offset <= start && extent_end > end) {
-                       *length = end - start + 1;
-                       break;
-               } else if (key.offset <= start && extent_end > start)
-                       *length += extent_end - start;
-               else if (key.offset > start && extent_end <= end)
-                       *length += extent_end - key.offset;
-               else if (key.offset > start && key.offset <= end) {
-                       *length += end - key.offset + 1;
-                       break;
-               } else if (key.offset > end)
-                       break;
-
-next:
-               path->slots[0]++;
-       }
-       ret = 0;
-out:
-       btrfs_free_path(path);
-       return ret;
-}
-
 static int contains_pending_extent(struct btrfs_transaction *transaction,
                                   struct btrfs_device *device,
                                   u64 *start, u64 len)
@@ -2027,6 +1927,9 @@ int btrfs_rm_device(struct btrfs_fs_info *fs_info, const char *device_path,
 
        cur_devices->num_devices--;
        cur_devices->total_devices--;
+       /* Update total_devices of the parent fs_devices if it's seed */
+       if (cur_devices != fs_devices)
+               fs_devices->total_devices--;
 
        if (test_bit(BTRFS_DEV_STATE_MISSING, &device->dev_state))
                cur_devices->missing_devices--;
@@ -2405,15 +2308,15 @@ int btrfs_init_new_device(struct btrfs_fs_info *fs_info, const char *device_path
        struct btrfs_trans_handle *trans;
        struct btrfs_device *device;
        struct block_device *bdev;
-       struct list_head *devices;
        struct super_block *sb = fs_info->sb;
        struct rcu_string *name;
+       struct btrfs_fs_devices *fs_devices = fs_info->fs_devices;
        u64 tmp;
        int seeding_dev = 0;
        int ret = 0;
        bool unlocked = false;
 
-       if (sb_rdonly(sb) && !fs_info->fs_devices->seeding)
+       if (sb_rdonly(sb) && !fs_devices->seeding)
                return -EROFS;
 
        bdev = blkdev_get_by_path(device_path, FMODE_WRITE | FMODE_EXCL,
@@ -2421,7 +2324,7 @@ int btrfs_init_new_device(struct btrfs_fs_info *fs_info, const char *device_path
        if (IS_ERR(bdev))
                return PTR_ERR(bdev);
 
-       if (fs_info->fs_devices->seeding) {
+       if (fs_devices->seeding) {
                seeding_dev = 1;
                down_write(&sb->s_umount);
                mutex_lock(&uuid_mutex);
@@ -2429,18 +2332,16 @@ int btrfs_init_new_device(struct btrfs_fs_info *fs_info, const char *device_path
 
        filemap_write_and_wait(bdev->bd_inode->i_mapping);
 
-       devices = &fs_info->fs_devices->devices;
-
-       mutex_lock(&fs_info->fs_devices->device_list_mutex);
-       list_for_each_entry(device, devices, dev_list) {
+       mutex_lock(&fs_devices->device_list_mutex);
+       list_for_each_entry(device, &fs_devices->devices, dev_list) {
                if (device->bdev == bdev) {
                        ret = -EEXIST;
                        mutex_unlock(
-                               &fs_info->fs_devices->device_list_mutex);
+                               &fs_devices->device_list_mutex);
                        goto error;
                }
        }
-       mutex_unlock(&fs_info->fs_devices->device_list_mutex);
+       mutex_unlock(&fs_devices->device_list_mutex);
 
        device = btrfs_alloc_device(fs_info, NULL, NULL);
        if (IS_ERR(device)) {
@@ -2489,23 +2390,22 @@ int btrfs_init_new_device(struct btrfs_fs_info *fs_info, const char *device_path
                }
        }
 
-       device->fs_devices = fs_info->fs_devices;
+       device->fs_devices = fs_devices;
 
-       mutex_lock(&fs_info->fs_devices->device_list_mutex);
+       mutex_lock(&fs_devices->device_list_mutex);
        mutex_lock(&fs_info->chunk_mutex);
-       list_add_rcu(&device->dev_list, &fs_info->fs_devices->devices);
-       list_add(&device->dev_alloc_list,
-                &fs_info->fs_devices->alloc_list);
-       fs_info->fs_devices->num_devices++;
-       fs_info->fs_devices->open_devices++;
-       fs_info->fs_devices->rw_devices++;
-       fs_info->fs_devices->total_devices++;
-       fs_info->fs_devices->total_rw_bytes += device->total_bytes;
+       list_add_rcu(&device->dev_list, &fs_devices->devices);
+       list_add(&device->dev_alloc_list, &fs_devices->alloc_list);
+       fs_devices->num_devices++;
+       fs_devices->open_devices++;
+       fs_devices->rw_devices++;
+       fs_devices->total_devices++;
+       fs_devices->total_rw_bytes += device->total_bytes;
 
        atomic64_add(device->total_bytes, &fs_info->free_chunk_space);
 
        if (!blk_queue_nonrot(q))
-               fs_info->fs_devices->rotating = 1;
+               fs_devices->rotating = 1;
 
        tmp = btrfs_super_total_bytes(fs_info->super_copy);
        btrfs_set_super_total_bytes(fs_info->super_copy,
@@ -2515,7 +2415,7 @@ int btrfs_init_new_device(struct btrfs_fs_info *fs_info, const char *device_path
        btrfs_set_super_num_devices(fs_info->super_copy, tmp + 1);
 
        /* add sysfs device entry */
-       btrfs_sysfs_add_device_link(fs_info->fs_devices, device);
+       btrfs_sysfs_add_device_link(fs_devices, device);
 
        /*
         * we've got more storage, clear any full flags on the space
@@ -2524,7 +2424,7 @@ int btrfs_init_new_device(struct btrfs_fs_info *fs_info, const char *device_path
        btrfs_clear_space_info_full(fs_info);
 
        mutex_unlock(&fs_info->chunk_mutex);
-       mutex_unlock(&fs_info->fs_devices->device_list_mutex);
+       mutex_unlock(&fs_devices->device_list_mutex);
 
        if (seeding_dev) {
                mutex_lock(&fs_info->chunk_mutex);
@@ -2556,7 +2456,7 @@ int btrfs_init_new_device(struct btrfs_fs_info *fs_info, const char *device_path
                 */
                snprintf(fsid_buf, BTRFS_UUID_UNPARSED_SIZE, "%pU",
                                                fs_info->fsid);
-               if (kobject_rename(&fs_info->fs_devices->fsid_kobj, fsid_buf))
+               if (kobject_rename(&fs_devices->fsid_kobj, fsid_buf))
                        btrfs_warn(fs_info,
                                   "sysfs: failed to create fsid for sprout");
        }
@@ -2591,7 +2491,7 @@ int btrfs_init_new_device(struct btrfs_fs_info *fs_info, const char *device_path
        return ret;
 
 error_sysfs:
-       btrfs_sysfs_rm_device_link(fs_info->fs_devices, device);
+       btrfs_sysfs_rm_device_link(fs_devices, device);
 error_trans:
        if (seeding_dev)
                sb->s_flags |= SB_RDONLY;
@@ -2827,7 +2727,7 @@ int btrfs_remove_chunk(struct btrfs_trans_handle *trans,
        }
        map = em->map_lookup;
        mutex_lock(&fs_info->chunk_mutex);
-       check_system_chunk(trans, fs_info, map->type);
+       check_system_chunk(trans, map->type);
        mutex_unlock(&fs_info->chunk_mutex);
 
        /*
@@ -2883,7 +2783,7 @@ int btrfs_remove_chunk(struct btrfs_trans_handle *trans,
                }
        }
 
-       ret = btrfs_remove_block_group(trans, fs_info, chunk_offset, em);
+       ret = btrfs_remove_block_group(trans, chunk_offset, em);
        if (ret) {
                btrfs_abort_transaction(trans, ret);
                goto out;
@@ -3057,7 +2957,7 @@ static int btrfs_may_alloc_data_chunk(struct btrfs_fs_info *fs_info,
                        if (IS_ERR(trans))
                                return PTR_ERR(trans);
 
-                       ret = btrfs_force_chunk_alloc(trans, fs_info,
+                       ret = btrfs_force_chunk_alloc(trans,
                                                      BTRFS_BLOCK_GROUP_DATA);
                        btrfs_end_transaction(trans);
                        if (ret < 0)
@@ -4690,7 +4590,7 @@ static int __btrfs_alloc_chunk(struct btrfs_trans_handle *trans,
 
        if (type & BTRFS_BLOCK_GROUP_DATA) {
                max_stripe_size = SZ_1G;
-               max_chunk_size = 10 * max_stripe_size;
+               max_chunk_size = BTRFS_MAX_DATA_CHUNK_SIZE;
                if (!devs_max)
                        devs_max = BTRFS_MAX_DEVS(info);
        } else if (type & BTRFS_BLOCK_GROUP_METADATA) {
@@ -4898,7 +4798,7 @@ static int __btrfs_alloc_chunk(struct btrfs_trans_handle *trans,
        refcount_inc(&em->refs);
        write_unlock(&em_tree->lock);
 
-       ret = btrfs_make_block_group(trans, info, 0, type, start, num_bytes);
+       ret = btrfs_make_block_group(trans, 0, type, start, num_bytes);
        if (ret)
                goto error_del_extent;
 
@@ -5036,13 +4936,12 @@ out:
  * require modifying the chunk tree. This division is important for the
  * bootstrap process of adding storage to a seed btrfs.
  */
-int btrfs_alloc_chunk(struct btrfs_trans_handle *trans,
-                     struct btrfs_fs_info *fs_info, u64 type)
+int btrfs_alloc_chunk(struct btrfs_trans_handle *trans, u64 type)
 {
        u64 chunk_offset;
 
-       lockdep_assert_held(&fs_info->chunk_mutex);
-       chunk_offset = find_next_chunk(fs_info);
+       lockdep_assert_held(&trans->fs_info->chunk_mutex);
+       chunk_offset = find_next_chunk(trans->fs_info);
        return __btrfs_alloc_chunk(trans, chunk_offset, type);
 }
 
@@ -5173,7 +5072,7 @@ int btrfs_num_copies(struct btrfs_fs_info *fs_info, u64 logical, u64 len)
                /*
                 * There could be two corrupted data stripes, we need
                 * to loop retry in order to rebuild the correct data.
-                * 
+                *
                 * Fail a stripe at a time on every retry except the
                 * stripe under reconstruction.
                 */