]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blobdiff - fs/btrfs/reada.c
Btrfs: change core code of btrfs to support the device replace operations
[mirror_ubuntu-artful-kernel.git] / fs / btrfs / reada.c
index a955669519a265bbfb5f13de4723c87932f8047e..c705a48e676b28d3b76eb7c34184daa051e8f2eb 100644 (file)
@@ -27,6 +27,7 @@
 #include "volumes.h"
 #include "disk-io.h"
 #include "transaction.h"
+#include "dev-replace.h"
 
 #undef DEBUG
 
@@ -323,7 +324,6 @@ static struct reada_extent *reada_find_extent(struct btrfs_root *root,
        struct reada_extent *re = NULL;
        struct reada_extent *re_exist = NULL;
        struct btrfs_fs_info *fs_info = root->fs_info;
-       struct btrfs_mapping_tree *map_tree = &fs_info->mapping_tree;
        struct btrfs_bio *bbio = NULL;
        struct btrfs_device *dev;
        struct btrfs_device *prev_dev;
@@ -332,6 +332,7 @@ static struct reada_extent *reada_find_extent(struct btrfs_root *root,
        int nzones = 0;
        int i;
        unsigned long index = logical >> PAGE_CACHE_SHIFT;
+       int dev_replace_is_ongoing;
 
        spin_lock(&fs_info->reada_lock);
        re = radix_tree_lookup(&fs_info->reada_tree, index);
@@ -358,7 +359,7 @@ static struct reada_extent *reada_find_extent(struct btrfs_root *root,
         * map block
         */
        length = blocksize;
-       ret = btrfs_map_block(map_tree, REQ_WRITE, logical, &length, &bbio, 0);
+       ret = btrfs_map_block(fs_info, REQ_WRITE, logical, &length, &bbio, 0);
        if (ret || !bbio || length < blocksize)
                goto error;
 
@@ -393,6 +394,7 @@ static struct reada_extent *reada_find_extent(struct btrfs_root *root,
        }
 
        /* insert extent in reada_tree + all per-device trees, all or nothing */
+       btrfs_dev_replace_lock(&fs_info->dev_replace);
        spin_lock(&fs_info->reada_lock);
        ret = radix_tree_insert(&fs_info->reada_tree, index, re);
        if (ret == -EEXIST) {
@@ -400,13 +402,17 @@ static struct reada_extent *reada_find_extent(struct btrfs_root *root,
                BUG_ON(!re_exist);
                re_exist->refcnt++;
                spin_unlock(&fs_info->reada_lock);
+               btrfs_dev_replace_unlock(&fs_info->dev_replace);
                goto error;
        }
        if (ret) {
                spin_unlock(&fs_info->reada_lock);
+               btrfs_dev_replace_unlock(&fs_info->dev_replace);
                goto error;
        }
        prev_dev = NULL;
+       dev_replace_is_ongoing = btrfs_dev_replace_is_ongoing(
+                       &fs_info->dev_replace);
        for (i = 0; i < nzones; ++i) {
                dev = bbio->stripes[i].dev;
                if (dev == prev_dev) {
@@ -419,21 +425,36 @@ static struct reada_extent *reada_find_extent(struct btrfs_root *root,
                         */
                        continue;
                }
+               if (!dev->bdev) {
+                       /* cannot read ahead on missing device */
+                       continue;
+               }
+               if (dev_replace_is_ongoing &&
+                   dev == fs_info->dev_replace.tgtdev) {
+                       /*
+                        * as this device is selected for reading only as
+                        * a last resort, skip it for read ahead.
+                        */
+                       continue;
+               }
                prev_dev = dev;
                ret = radix_tree_insert(&dev->reada_extents, index, re);
                if (ret) {
                        while (--i >= 0) {
                                dev = bbio->stripes[i].dev;
                                BUG_ON(dev == NULL);
+                               /* ignore whether the entry was inserted */
                                radix_tree_delete(&dev->reada_extents, index);
                        }
                        BUG_ON(fs_info == NULL);
                        radix_tree_delete(&fs_info->reada_tree, index);
                        spin_unlock(&fs_info->reada_lock);
+                       btrfs_dev_replace_unlock(&fs_info->dev_replace);
                        goto error;
                }
        }
        spin_unlock(&fs_info->reada_lock);
+       btrfs_dev_replace_unlock(&fs_info->dev_replace);
 
        kfree(bbio);
        return re;
@@ -915,7 +936,10 @@ struct reada_control *btrfs_reada_add(struct btrfs_root *root,
        generation = btrfs_header_generation(node);
        free_extent_buffer(node);
 
-       reada_add_block(rc, start, &max_key, level, generation);
+       if (reada_add_block(rc, start, &max_key, level, generation)) {
+               kfree(rc);
+               return ERR_PTR(-ENOMEM);
+       }
 
        reada_start_machine(root->fs_info);