Btrfs: Make an unplug function that doesn't unplug every spindle

Signed-off-by: Chris Mason <chris.mason@oracle.com>
This commit is contained in:
Chris Mason 2008-04-21 10:03:05 -04:00
parent 4ef64eae28
commit f2d8d74d78
4 changed files with 75 additions and 38 deletions

View 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) void btrfs_unplug_io_fn(struct backing_dev_info *bdi, struct page *page)
{ {
struct list_head *cur; struct inode *inode = page->mapping->host;
struct btrfs_device *device; struct extent_map_tree *em_tree;
struct btrfs_fs_info *info; struct extent_map *em;
u64 offset = page_offset(page);
info = (struct btrfs_fs_info *)bdi->unplug_io_data; em_tree = &BTRFS_I(inode)->extent_tree;
list_for_each(cur, &info->fs_devices->devices) { spin_lock(&em_tree->lock);
device = list_entry(cur, struct btrfs_device, dev_list); em = lookup_extent_mapping(em_tree, offset, PAGE_CACHE_SIZE);
bdi = blk_get_backing_dev_info(device->bdev); spin_unlock(&em_tree->lock);
if (bdi->unplug_io_fn) { if (!em)
bdi->unplug_io_fn(bdi, page); 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) static int setup_bdi(struct btrfs_fs_info *info, struct backing_dev_info *bdi)

View file

@ -313,13 +313,9 @@ int btrfs_merge_bio_hook(struct page *page, unsigned long offset,
u64 logical = bio->bi_sector << 9; u64 logical = bio->bi_sector << 9;
u64 length = 0; u64 length = 0;
u64 map_length; u64 map_length;
struct bio_vec *bvec;
int i;
int ret; int ret;
bio_for_each_segment(bvec, bio, i) { length = bio->bi_size;
length += bvec->bv_len;
}
map_tree = &root->fs_info->mapping_tree; map_tree = &root->fs_info->mapping_tree;
map_length = length; map_length = length;
ret = btrfs_map_block(map_tree, READ, logical, ret = btrfs_map_block(map_tree, READ, logical,

View file

@ -18,6 +18,7 @@
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/bio.h> #include <linux/bio.h>
#include <linux/buffer_head.h> #include <linux/buffer_head.h>
#include <linux/blkdev.h>
#include <asm/div64.h> #include <asm/div64.h>
#include "ctree.h" #include "ctree.h"
#include "extent_map.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; return ret;
} }
int btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw, static int __btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw,
u64 logical, u64 *length, u64 logical, u64 *length,
struct btrfs_multi_bio **multi_ret, int mirror_num) struct btrfs_multi_bio **multi_ret,
int mirror_num, struct page *unplug_page)
{ {
struct extent_map *em; struct extent_map *em;
struct map_lookup *map; 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 stripes_required = 1;
int stripe_index; int stripe_index;
int i; int i;
int num_stripes;
struct btrfs_multi_bio *multi = NULL; struct btrfs_multi_bio *multi = NULL;
if (multi_ret && !(rw & (1 << BIO_RW))) { if (multi_ret && !(rw & (1 << BIO_RW))) {
@ -960,10 +963,14 @@ again:
spin_lock(&em_tree->lock); spin_lock(&em_tree->lock);
em = lookup_extent_mapping(em_tree, logical, *length); em = lookup_extent_mapping(em_tree, logical, *length);
spin_unlock(&em_tree->lock); spin_unlock(&em_tree->lock);
if (!em && unplug_page)
return 0;
if (!em) { if (!em) {
printk("unable to find logical %Lu\n", logical); printk("unable to find logical %Lu\n", logical);
BUG();
} }
BUG_ON(!em);
BUG_ON(em->start > logical || em->start + em->len < logical); BUG_ON(em->start > logical || em->start + em->len < logical);
map = (struct map_lookup *)em->bdev; map = (struct map_lookup *)em->bdev;
@ -1010,14 +1017,15 @@ again:
} else { } else {
*length = em->len - offset; *length = em->len - offset;
} }
if (!multi_ret)
if (!multi_ret && !unplug_page)
goto out; goto out;
multi->num_stripes = 1; num_stripes = 1;
stripe_index = 0; stripe_index = 0;
if (map->type & BTRFS_BLOCK_GROUP_RAID1) { if (map->type & BTRFS_BLOCK_GROUP_RAID1) {
if (rw & (1 << BIO_RW)) if (unplug_page || (rw & (1 << BIO_RW)))
multi->num_stripes = map->num_stripes; num_stripes = map->num_stripes;
else if (mirror_num) { else if (mirror_num) {
stripe_index = mirror_num - 1; stripe_index = mirror_num - 1;
} else { } else {
@ -1037,7 +1045,7 @@ again:
} }
} else if (map->type & BTRFS_BLOCK_GROUP_DUP) { } else if (map->type & BTRFS_BLOCK_GROUP_DUP) {
if (rw & (1 << BIO_RW)) if (rw & (1 << BIO_RW))
multi->num_stripes = map->num_stripes; num_stripes = map->num_stripes;
else if (mirror_num) else if (mirror_num)
stripe_index = mirror_num - 1; stripe_index = mirror_num - 1;
} else if (map->type & BTRFS_BLOCK_GROUP_RAID10) { } else if (map->type & BTRFS_BLOCK_GROUP_RAID10) {
@ -1047,8 +1055,8 @@ again:
stripe_index = do_div(stripe_nr, factor); stripe_index = do_div(stripe_nr, factor);
stripe_index *= map->sub_stripes; stripe_index *= map->sub_stripes;
if (rw & (1 << BIO_RW)) if (unplug_page || (rw & (1 << BIO_RW)))
multi->num_stripes = map->sub_stripes; num_stripes = map->sub_stripes;
else if (mirror_num) else if (mirror_num)
stripe_index += mirror_num - 1; stripe_index += mirror_num - 1;
else else
@ -1063,19 +1071,50 @@ again:
} }
BUG_ON(stripe_index >= map->num_stripes); BUG_ON(stripe_index >= map->num_stripes);
for (i = 0; i < multi->num_stripes; i++) { for (i = 0; i < num_stripes; i++) {
multi->stripes[i].physical = if (unplug_page) {
map->stripes[stripe_index].physical + stripe_offset + struct btrfs_device *device;
stripe_nr * map->stripe_len; struct backing_dev_info *bdi;
multi->stripes[i].dev = map->stripes[stripe_index].dev;
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++; stripe_index++;
} }
*multi_ret = multi; if (multi_ret) {
*multi_ret = multi;
multi->num_stripes = num_stripes;
}
out: out:
free_extent_map(em); free_extent_map(em);
return 0; 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) #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,23)
static void end_bio_multi_stripe(struct bio *bio, int err) static void end_bio_multi_stripe(struct bio *bio, int err)
#else #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 logical = bio->bi_sector << 9;
u64 length = 0; u64 length = 0;
u64 map_length; u64 map_length;
struct bio_vec *bvec;
struct btrfs_multi_bio *multi = NULL; struct btrfs_multi_bio *multi = NULL;
int i;
int ret; int ret;
int dev_nr = 0; int dev_nr = 0;
int total_devs = 1; int total_devs = 1;
bio_for_each_segment(bvec, bio, i) { length = bio->bi_size;
length += bvec->bv_len;
}
map_tree = &root->fs_info->mapping_tree; map_tree = &root->fs_info->mapping_tree;
map_length = length; map_length = length;

View file

@ -119,4 +119,6 @@ int btrfs_add_device(struct btrfs_trans_handle *trans,
struct btrfs_device *device); struct btrfs_device *device);
int btrfs_cleanup_fs_uuids(void); int btrfs_cleanup_fs_uuids(void);
int btrfs_num_copies(struct btrfs_mapping_tree *map_tree, u64 logical, u64 len); 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 #endif