Btrfs: Make an unplug function that doesn't unplug every spindle
authorChris Mason <chris.mason@oracle.com>
Mon, 21 Apr 2008 14:03:05 +0000 (10:03 -0400)
committerChris Mason <chris.mason@oracle.com>
Thu, 25 Sep 2008 15:04:02 +0000 (11:04 -0400)
Signed-off-by: Chris Mason <chris.mason@oracle.com>
fs/btrfs/disk-io.c
fs/btrfs/inode.c
fs/btrfs/volumes.c
fs/btrfs/volumes.h

index c829612c797e9460ec20a379f6c6f5edb4366467..7f5aca35494d214bc80132902dc6a4e1583f2877 100644 (file)
@@ -913,18 +913,22 @@ static int btrfs_congested_fn(void *congested_data, int bdi_bits)
 
 void btrfs_unplug_io_fn(struct backing_dev_info *bdi, struct page *page)
 {
-       struct list_head *cur;
-       struct btrfs_device *device;
-       struct btrfs_fs_info *info;
+       struct inode *inode = page->mapping->host;
+       struct extent_map_tree *em_tree;
+       struct extent_map *em;
+       u64 offset = page_offset(page);
 
-       info = (struct btrfs_fs_info *)bdi->unplug_io_data;
-       list_for_each(cur, &info->fs_devices->devices) {
-               device = list_entry(cur, struct btrfs_device, dev_list);
-               bdi = blk_get_backing_dev_info(device->bdev);
-               if (bdi->unplug_io_fn) {
-                       bdi->unplug_io_fn(bdi, page);
-               }
-       }
+       em_tree = &BTRFS_I(inode)->extent_tree;
+       spin_lock(&em_tree->lock);
+       em = lookup_extent_mapping(em_tree, offset, PAGE_CACHE_SIZE);
+       spin_unlock(&em_tree->lock);
+       if (!em)
+               return;
+
+       offset = offset - em->start;
+       btrfs_unplug_page(&BTRFS_I(inode)->root->fs_info->mapping_tree,
+                         em->block_start + offset, page);
+       free_extent_map(em);
 }
 
 static int setup_bdi(struct btrfs_fs_info *info, struct backing_dev_info *bdi)
index 5b1514e58de4ade6757cbfbc746c3b266670f94b..e875c7c8a647c220ba2a5a34975dd0ca5995692e 100644 (file)
@@ -313,13 +313,9 @@ int btrfs_merge_bio_hook(struct page *page, unsigned long offset,
        u64 logical = bio->bi_sector << 9;
        u64 length = 0;
        u64 map_length;
-       struct bio_vec *bvec;
-       int i;
        int ret;
 
-       bio_for_each_segment(bvec, bio, i) {
-               length += bvec->bv_len;
-       }
+       length = bio->bi_size;
        map_tree = &root->fs_info->mapping_tree;
        map_length = length;
        ret = btrfs_map_block(map_tree, READ, logical,
index 4fc92cf813d8e65a51c0da1d6078ad8c68f9284e..460240706505764f82169b2becea0a37b82488ce 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/sched.h>
 #include <linux/bio.h>
 #include <linux/buffer_head.h>
+#include <linux/blkdev.h>
 #include <asm/div64.h>
 #include "ctree.h"
 #include "extent_map.h"
@@ -930,9 +931,10 @@ int btrfs_num_copies(struct btrfs_mapping_tree *map_tree, u64 logical, u64 len)
        return ret;
 }
 
-int btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw,
-                   u64 logical, u64 *length,
-                   struct btrfs_multi_bio **multi_ret, int mirror_num)
+static int __btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw,
+                            u64 logical, u64 *length,
+                            struct btrfs_multi_bio **multi_ret,
+                            int mirror_num, struct page *unplug_page)
 {
        struct extent_map *em;
        struct map_lookup *map;
@@ -944,6 +946,7 @@ int btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw,
        int stripes_required = 1;
        int stripe_index;
        int i;
+       int num_stripes;
        struct btrfs_multi_bio *multi = NULL;
 
        if (multi_ret && !(rw & (1 << BIO_RW))) {
@@ -960,10 +963,14 @@ again:
        spin_lock(&em_tree->lock);
        em = lookup_extent_mapping(em_tree, logical, *length);
        spin_unlock(&em_tree->lock);
+
+       if (!em && unplug_page)
+               return 0;
+
        if (!em) {
                printk("unable to find logical %Lu\n", logical);
+               BUG();
        }
-       BUG_ON(!em);
 
        BUG_ON(em->start > logical || em->start + em->len < logical);
        map = (struct map_lookup *)em->bdev;
@@ -1010,14 +1017,15 @@ again:
        } else {
                *length = em->len - offset;
        }
-       if (!multi_ret)
+
+       if (!multi_ret && !unplug_page)
                goto out;
 
-       multi->num_stripes = 1;
+       num_stripes = 1;
        stripe_index = 0;
        if (map->type & BTRFS_BLOCK_GROUP_RAID1) {
-               if (rw & (1 << BIO_RW))
-                       multi->num_stripes = map->num_stripes;
+               if (unplug_page || (rw & (1 << BIO_RW)))
+                       num_stripes = map->num_stripes;
                else if (mirror_num) {
                        stripe_index = mirror_num - 1;
                } else {
@@ -1037,7 +1045,7 @@ again:
                }
        } else if (map->type & BTRFS_BLOCK_GROUP_DUP) {
                if (rw & (1 << BIO_RW))
-                       multi->num_stripes = map->num_stripes;
+                       num_stripes = map->num_stripes;
                else if (mirror_num)
                        stripe_index = mirror_num - 1;
        } else if (map->type & BTRFS_BLOCK_GROUP_RAID10) {
@@ -1047,8 +1055,8 @@ again:
                stripe_index = do_div(stripe_nr, factor);
                stripe_index *= map->sub_stripes;
 
-               if (rw & (1 << BIO_RW))
-                       multi->num_stripes = map->sub_stripes;
+               if (unplug_page || (rw & (1 << BIO_RW)))
+                       num_stripes = map->sub_stripes;
                else if (mirror_num)
                        stripe_index += mirror_num - 1;
                else
@@ -1063,19 +1071,50 @@ again:
        }
        BUG_ON(stripe_index >= map->num_stripes);
 
-       for (i = 0; i < multi->num_stripes; i++) {
-               multi->stripes[i].physical =
-                       map->stripes[stripe_index].physical + stripe_offset +
-                       stripe_nr * map->stripe_len;
-               multi->stripes[i].dev = map->stripes[stripe_index].dev;
+       for (i = 0; i < num_stripes; i++) {
+               if (unplug_page) {
+                       struct btrfs_device *device;
+                       struct backing_dev_info *bdi;
+
+                       device = map->stripes[stripe_index].dev;
+                       bdi = blk_get_backing_dev_info(device->bdev);
+                       if (bdi->unplug_io_fn) {
+                               bdi->unplug_io_fn(bdi, unplug_page);
+                       }
+               } else {
+                       multi->stripes[i].physical =
+                               map->stripes[stripe_index].physical +
+                               stripe_offset + stripe_nr * map->stripe_len;
+                       multi->stripes[i].dev = map->stripes[stripe_index].dev;
+               }
                stripe_index++;
        }
-       *multi_ret = multi;
+       if (multi_ret) {
+               *multi_ret = multi;
+               multi->num_stripes = num_stripes;
+       }
 out:
        free_extent_map(em);
        return 0;
 }
 
+int btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw,
+                     u64 logical, u64 *length,
+                     struct btrfs_multi_bio **multi_ret, int mirror_num)
+{
+       return __btrfs_map_block(map_tree, rw, logical, length, multi_ret,
+                                mirror_num, NULL);
+}
+
+int btrfs_unplug_page(struct btrfs_mapping_tree *map_tree,
+                     u64 logical, struct page *page)
+{
+       u64 length = PAGE_CACHE_SIZE;
+       return __btrfs_map_block(map_tree, READ, logical, &length,
+                                NULL, 0, page);
+}
+
+
 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,23)
 static void end_bio_multi_stripe(struct bio *bio, int err)
 #else
@@ -1122,16 +1161,12 @@ int btrfs_map_bio(struct btrfs_root *root, int rw, struct bio *bio,
        u64 logical = bio->bi_sector << 9;
        u64 length = 0;
        u64 map_length;
-       struct bio_vec *bvec;
        struct btrfs_multi_bio *multi = NULL;
-       int i;
        int ret;
        int dev_nr = 0;
        int total_devs = 1;
 
-       bio_for_each_segment(bvec, bio, i) {
-               length += bvec->bv_len;
-       }
+       length = bio->bi_size;
 
        map_tree = &root->fs_info->mapping_tree;
        map_length = length;
index f9cae30721716881086be83339c615852a6f4a8e..dfe7e8a9507ce38e8b63b4b8928493fcbbbd9e13 100644 (file)
@@ -119,4 +119,6 @@ int btrfs_add_device(struct btrfs_trans_handle *trans,
                     struct btrfs_device *device);
 int btrfs_cleanup_fs_uuids(void);
 int btrfs_num_copies(struct btrfs_mapping_tree *map_tree, u64 logical, u64 len);
+int btrfs_unplug_page(struct btrfs_mapping_tree *map_tree,
+                     u64 logical, struct page *page);
 #endif