diff options
author | Chris Mason <chris.mason@oracle.com> | 2008-03-25 16:50:33 -0400 |
---|---|---|
committer | Chris Mason <chris.mason@oracle.com> | 2008-09-25 11:04:01 -0400 |
commit | 593060d756e0c2382d59cf00d5f3b9e3a336c408 (patch) | |
tree | c102f8abd9210eeba8ae4e7f6626b80cfed1b8d8 /fs/btrfs | |
parent | 8a4b83cc8bd75fca29ac68615896d9e92820e7c2 (diff) |
Btrfs: Implement raid0 when multiple devices are present
Signed-off-by: Chris Mason <chris.mason@oracle.com>
Diffstat (limited to 'fs/btrfs')
-rw-r--r-- | fs/btrfs/ctree.h | 3 | ||||
-rw-r--r-- | fs/btrfs/disk-io.c | 2 | ||||
-rw-r--r-- | fs/btrfs/extent-tree.c | 102 | ||||
-rw-r--r-- | fs/btrfs/inode.c | 2 | ||||
-rw-r--r-- | fs/btrfs/volumes.c | 130 |
5 files changed, 173 insertions, 66 deletions
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index 7556f8319c60..f43dfe7ffe6d 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h | |||
@@ -413,6 +413,7 @@ struct btrfs_csum_item { | |||
413 | #define BTRFS_BLOCK_GROUP_DATA (1 << 0) | 413 | #define BTRFS_BLOCK_GROUP_DATA (1 << 0) |
414 | #define BTRFS_BLOCK_GROUP_SYSTEM (1 << 1) | 414 | #define BTRFS_BLOCK_GROUP_SYSTEM (1 << 1) |
415 | #define BTRFS_BLOCK_GROUP_METADATA (1 << 2) | 415 | #define BTRFS_BLOCK_GROUP_METADATA (1 << 2) |
416 | #define BTRFS_BLOCK_GROUP_RAID0 (1 << 3) | ||
416 | 417 | ||
417 | 418 | ||
418 | struct btrfs_block_group_item { | 419 | struct btrfs_block_group_item { |
@@ -498,6 +499,8 @@ struct btrfs_fs_info { | |||
498 | u64 delalloc_bytes; | 499 | u64 delalloc_bytes; |
499 | u64 last_alloc; | 500 | u64 last_alloc; |
500 | u64 last_data_alloc; | 501 | u64 last_data_alloc; |
502 | int extra_data_alloc_bits; | ||
503 | int extra_alloc_bits; | ||
501 | }; | 504 | }; |
502 | 505 | ||
503 | /* | 506 | /* |
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index f971a29e4f20..d8474796dea2 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c | |||
@@ -736,6 +736,8 @@ struct btrfs_root *open_ctree(struct super_block *sb, | |||
736 | fs_info->total_pinned = 0; | 736 | fs_info->total_pinned = 0; |
737 | fs_info->last_alloc = 0; | 737 | fs_info->last_alloc = 0; |
738 | fs_info->last_data_alloc = 0; | 738 | fs_info->last_data_alloc = 0; |
739 | fs_info->extra_alloc_bits = 0; | ||
740 | fs_info->extra_data_alloc_bits = 0; | ||
739 | 741 | ||
740 | #if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,18) | 742 | #if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,18) |
741 | INIT_WORK(&fs_info->trans_work, btrfs_transaction_cleaner, fs_info); | 743 | INIT_WORK(&fs_info->trans_work, btrfs_transaction_cleaner, fs_info); |
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index e9ef644ff56f..c226656f29b7 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c | |||
@@ -172,7 +172,7 @@ struct btrfs_block_group_cache *btrfs_lookup_block_group(struct | |||
172 | 172 | ||
173 | static int block_group_bits(struct btrfs_block_group_cache *cache, u64 bits) | 173 | static int block_group_bits(struct btrfs_block_group_cache *cache, u64 bits) |
174 | { | 174 | { |
175 | return (cache->flags & bits); | 175 | return (cache->flags & bits) == bits; |
176 | } | 176 | } |
177 | 177 | ||
178 | static int noinline find_search_start(struct btrfs_root *root, | 178 | static int noinline find_search_start(struct btrfs_root *root, |
@@ -1010,6 +1010,35 @@ static struct btrfs_space_info *__find_space_info(struct btrfs_fs_info *info, | |||
1010 | 1010 | ||
1011 | } | 1011 | } |
1012 | 1012 | ||
1013 | static int update_space_info(struct btrfs_fs_info *info, u64 flags, | ||
1014 | u64 total_bytes, u64 bytes_used, | ||
1015 | struct btrfs_space_info **space_info) | ||
1016 | { | ||
1017 | struct btrfs_space_info *found; | ||
1018 | |||
1019 | found = __find_space_info(info, flags); | ||
1020 | if (found) { | ||
1021 | found->total_bytes += total_bytes; | ||
1022 | found->bytes_used += bytes_used; | ||
1023 | WARN_ON(found->total_bytes < found->bytes_used); | ||
1024 | *space_info = found; | ||
1025 | return 0; | ||
1026 | } | ||
1027 | found = kmalloc(sizeof(*found), GFP_NOFS); | ||
1028 | if (!found) | ||
1029 | return -ENOMEM; | ||
1030 | |||
1031 | list_add(&found->list, &info->space_info); | ||
1032 | found->flags = flags; | ||
1033 | found->total_bytes = total_bytes; | ||
1034 | found->bytes_used = bytes_used; | ||
1035 | found->bytes_pinned = 0; | ||
1036 | found->full = 0; | ||
1037 | *space_info = found; | ||
1038 | return 0; | ||
1039 | } | ||
1040 | |||
1041 | |||
1013 | static int do_chunk_alloc(struct btrfs_trans_handle *trans, | 1042 | static int do_chunk_alloc(struct btrfs_trans_handle *trans, |
1014 | struct btrfs_root *extent_root, u64 alloc_bytes, | 1043 | struct btrfs_root *extent_root, u64 alloc_bytes, |
1015 | u64 flags) | 1044 | u64 flags) |
@@ -1021,6 +1050,11 @@ static int do_chunk_alloc(struct btrfs_trans_handle *trans, | |||
1021 | int ret; | 1050 | int ret; |
1022 | 1051 | ||
1023 | space_info = __find_space_info(extent_root->fs_info, flags); | 1052 | space_info = __find_space_info(extent_root->fs_info, flags); |
1053 | if (!space_info) { | ||
1054 | ret = update_space_info(extent_root->fs_info, flags, | ||
1055 | 0, 0, &space_info); | ||
1056 | BUG_ON(ret); | ||
1057 | } | ||
1024 | BUG_ON(!space_info); | 1058 | BUG_ON(!space_info); |
1025 | 1059 | ||
1026 | if (space_info->full) | 1060 | if (space_info->full) |
@@ -1044,6 +1078,17 @@ printk("space info full %Lu\n", flags); | |||
1044 | extent_root->fs_info->chunk_root->root_key.objectid, | 1078 | extent_root->fs_info->chunk_root->root_key.objectid, |
1045 | start, num_bytes); | 1079 | start, num_bytes); |
1046 | BUG_ON(ret); | 1080 | BUG_ON(ret); |
1081 | |||
1082 | if (flags & BTRFS_BLOCK_GROUP_RAID0) { | ||
1083 | if (flags & BTRFS_BLOCK_GROUP_DATA) { | ||
1084 | extent_root->fs_info->extra_data_alloc_bits = | ||
1085 | BTRFS_BLOCK_GROUP_RAID0; | ||
1086 | } | ||
1087 | if (flags & BTRFS_BLOCK_GROUP_METADATA) { | ||
1088 | extent_root->fs_info->extra_alloc_bits = | ||
1089 | BTRFS_BLOCK_GROUP_RAID0; | ||
1090 | } | ||
1091 | } | ||
1047 | return 0; | 1092 | return 0; |
1048 | } | 1093 | } |
1049 | 1094 | ||
@@ -1655,24 +1700,31 @@ int btrfs_alloc_extent(struct btrfs_trans_handle *trans, | |||
1655 | struct btrfs_extent_ref *ref; | 1700 | struct btrfs_extent_ref *ref; |
1656 | struct btrfs_path *path; | 1701 | struct btrfs_path *path; |
1657 | struct btrfs_key keys[2]; | 1702 | struct btrfs_key keys[2]; |
1703 | int extra_chunk_alloc_bits = 0; | ||
1658 | 1704 | ||
1659 | if (data) { | 1705 | if (data) { |
1660 | data = BTRFS_BLOCK_GROUP_DATA; | 1706 | data = BTRFS_BLOCK_GROUP_DATA | info->extra_data_alloc_bits; |
1661 | } else if (root == root->fs_info->chunk_root) { | 1707 | } else if (root == root->fs_info->chunk_root) { |
1662 | data = BTRFS_BLOCK_GROUP_SYSTEM; | 1708 | data = BTRFS_BLOCK_GROUP_SYSTEM; |
1663 | } else { | 1709 | } else { |
1664 | data = BTRFS_BLOCK_GROUP_METADATA; | 1710 | data = BTRFS_BLOCK_GROUP_METADATA | info->extra_alloc_bits; |
1665 | } | 1711 | } |
1712 | if (btrfs_super_num_devices(&info->super_copy) > 1 && | ||
1713 | !(data & BTRFS_BLOCK_GROUP_SYSTEM)) | ||
1714 | extra_chunk_alloc_bits = BTRFS_BLOCK_GROUP_RAID0; | ||
1666 | 1715 | ||
1667 | if (root->ref_cows) { | 1716 | if (root->ref_cows) { |
1668 | if (data != BTRFS_BLOCK_GROUP_METADATA) { | 1717 | if (!(data & BTRFS_BLOCK_GROUP_METADATA)) { |
1669 | ret = do_chunk_alloc(trans, root->fs_info->extent_root, | 1718 | ret = do_chunk_alloc(trans, root->fs_info->extent_root, |
1670 | 2 * 1024 * 1024, | 1719 | 2 * 1024 * 1024, |
1671 | BTRFS_BLOCK_GROUP_METADATA); | 1720 | BTRFS_BLOCK_GROUP_METADATA | |
1721 | info->extra_alloc_bits | | ||
1722 | extra_chunk_alloc_bits); | ||
1672 | BUG_ON(ret); | 1723 | BUG_ON(ret); |
1673 | } | 1724 | } |
1674 | ret = do_chunk_alloc(trans, root->fs_info->extent_root, | 1725 | ret = do_chunk_alloc(trans, root->fs_info->extent_root, |
1675 | num_bytes + 2 * 1024 * 1024, data); | 1726 | num_bytes + 2 * 1024 * 1024, data | |
1727 | extra_chunk_alloc_bits); | ||
1676 | BUG_ON(ret); | 1728 | BUG_ON(ret); |
1677 | } | 1729 | } |
1678 | 1730 | ||
@@ -2627,34 +2679,6 @@ error: | |||
2627 | return ret; | 2679 | return ret; |
2628 | } | 2680 | } |
2629 | 2681 | ||
2630 | static int update_space_info(struct btrfs_fs_info *info, u64 flags, | ||
2631 | u64 total_bytes, u64 bytes_used, | ||
2632 | struct btrfs_space_info **space_info) | ||
2633 | { | ||
2634 | struct btrfs_space_info *found; | ||
2635 | |||
2636 | found = __find_space_info(info, flags); | ||
2637 | if (found) { | ||
2638 | found->total_bytes += total_bytes; | ||
2639 | found->bytes_used += bytes_used; | ||
2640 | WARN_ON(found->total_bytes < found->bytes_used); | ||
2641 | *space_info = found; | ||
2642 | return 0; | ||
2643 | } | ||
2644 | found = kmalloc(sizeof(*found), GFP_NOFS); | ||
2645 | if (!found) | ||
2646 | return -ENOMEM; | ||
2647 | |||
2648 | list_add(&found->list, &info->space_info); | ||
2649 | found->flags = flags; | ||
2650 | found->total_bytes = total_bytes; | ||
2651 | found->bytes_used = bytes_used; | ||
2652 | found->bytes_pinned = 0; | ||
2653 | found->full = 0; | ||
2654 | *space_info = found; | ||
2655 | return 0; | ||
2656 | } | ||
2657 | |||
2658 | int btrfs_read_block_groups(struct btrfs_root *root) | 2682 | int btrfs_read_block_groups(struct btrfs_root *root) |
2659 | { | 2683 | { |
2660 | struct btrfs_path *path; | 2684 | struct btrfs_path *path; |
@@ -2712,6 +2736,16 @@ int btrfs_read_block_groups(struct btrfs_root *root) | |||
2712 | } else if (cache->flags & BTRFS_BLOCK_GROUP_METADATA) { | 2736 | } else if (cache->flags & BTRFS_BLOCK_GROUP_METADATA) { |
2713 | bit = BLOCK_GROUP_METADATA; | 2737 | bit = BLOCK_GROUP_METADATA; |
2714 | } | 2738 | } |
2739 | if (cache->flags & BTRFS_BLOCK_GROUP_RAID0) { | ||
2740 | if (cache->flags & BTRFS_BLOCK_GROUP_DATA) { | ||
2741 | info->extra_data_alloc_bits = | ||
2742 | BTRFS_BLOCK_GROUP_RAID0; | ||
2743 | } | ||
2744 | if (cache->flags & BTRFS_BLOCK_GROUP_METADATA) { | ||
2745 | info->extra_alloc_bits = | ||
2746 | BTRFS_BLOCK_GROUP_RAID0; | ||
2747 | } | ||
2748 | } | ||
2715 | 2749 | ||
2716 | ret = update_space_info(info, cache->flags, found_key.offset, | 2750 | ret = update_space_info(info, cache->flags, found_key.offset, |
2717 | btrfs_block_group_used(&cache->item), | 2751 | btrfs_block_group_used(&cache->item), |
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 5140d6801846..db60d85598ce 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c | |||
@@ -317,8 +317,6 @@ int btrfs_merge_bio_hook(struct page *page, unsigned long offset, | |||
317 | map_length = length; | 317 | map_length = length; |
318 | ret = btrfs_map_block(map_tree, logical, &physical, &map_length, &dev); | 318 | ret = btrfs_map_block(map_tree, logical, &physical, &map_length, &dev); |
319 | if (map_length < length + size) { | 319 | if (map_length < length + size) { |
320 | printk("merge bio hook logical %Lu bio len %Lu physical %Lu " | ||
321 | "len %Lu\n", logical, length, physical, map_length); | ||
322 | return 1; | 320 | return 1; |
323 | } | 321 | } |
324 | return 0; | 322 | return 0; |
diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index 263f01cc3db4..d8fce32a3bbc 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c | |||
@@ -18,6 +18,7 @@ | |||
18 | #include <linux/sched.h> | 18 | #include <linux/sched.h> |
19 | #include <linux/bio.h> | 19 | #include <linux/bio.h> |
20 | #include <linux/buffer_head.h> | 20 | #include <linux/buffer_head.h> |
21 | #include <asm/div64.h> | ||
21 | #include "ctree.h" | 22 | #include "ctree.h" |
22 | #include "extent_map.h" | 23 | #include "extent_map.h" |
23 | #include "disk-io.h" | 24 | #include "disk-io.h" |
@@ -25,10 +26,24 @@ | |||
25 | #include "print-tree.h" | 26 | #include "print-tree.h" |
26 | #include "volumes.h" | 27 | #include "volumes.h" |
27 | 28 | ||
28 | struct map_lookup { | 29 | struct stripe { |
29 | struct btrfs_device *dev; | 30 | struct btrfs_device *dev; |
30 | u64 physical; | 31 | u64 physical; |
31 | }; | 32 | }; |
33 | |||
34 | struct map_lookup { | ||
35 | u64 type; | ||
36 | int io_align; | ||
37 | int io_width; | ||
38 | int stripe_len; | ||
39 | int sector_size; | ||
40 | int num_stripes; | ||
41 | struct stripe stripes[]; | ||
42 | }; | ||
43 | |||
44 | #define map_lookup_size(n) (sizeof(struct map_lookup) + \ | ||
45 | (sizeof(struct stripe) * (n))) | ||
46 | |||
32 | static DEFINE_MUTEX(uuid_mutex); | 47 | static DEFINE_MUTEX(uuid_mutex); |
33 | static LIST_HEAD(fs_uuids); | 48 | static LIST_HEAD(fs_uuids); |
34 | 49 | ||
@@ -592,6 +607,7 @@ int btrfs_alloc_chunk(struct btrfs_trans_handle *trans, | |||
592 | u64 *num_bytes, u64 type) | 607 | u64 *num_bytes, u64 type) |
593 | { | 608 | { |
594 | u64 dev_offset; | 609 | u64 dev_offset; |
610 | struct btrfs_fs_info *info = extent_root->fs_info; | ||
595 | struct btrfs_root *chunk_root = extent_root->fs_info->chunk_root; | 611 | struct btrfs_root *chunk_root = extent_root->fs_info->chunk_root; |
596 | struct btrfs_stripe *stripes; | 612 | struct btrfs_stripe *stripes; |
597 | struct btrfs_device *device = NULL; | 613 | struct btrfs_device *device = NULL; |
@@ -610,10 +626,18 @@ int btrfs_alloc_chunk(struct btrfs_trans_handle *trans, | |||
610 | int looped = 0; | 626 | int looped = 0; |
611 | int ret; | 627 | int ret; |
612 | int index; | 628 | int index; |
629 | int stripe_len = 64 * 1024; | ||
613 | struct btrfs_key key; | 630 | struct btrfs_key key; |
614 | 631 | ||
615 | if (list_empty(dev_list)) | 632 | if (list_empty(dev_list)) |
616 | return -ENOSPC; | 633 | return -ENOSPC; |
634 | |||
635 | if (type & BTRFS_BLOCK_GROUP_RAID0) | ||
636 | num_stripes = btrfs_super_num_devices(&info->super_copy); | ||
637 | if (type & BTRFS_BLOCK_GROUP_DATA) | ||
638 | stripe_len = 64 * 1024; | ||
639 | if (type & (BTRFS_BLOCK_GROUP_METADATA | BTRFS_BLOCK_GROUP_SYSTEM)) | ||
640 | stripe_len = 32 * 1024; | ||
617 | again: | 641 | again: |
618 | INIT_LIST_HEAD(&private_devs); | 642 | INIT_LIST_HEAD(&private_devs); |
619 | cur = dev_list->next; | 643 | cur = dev_list->next; |
@@ -650,9 +674,15 @@ again: | |||
650 | if (!chunk) | 674 | if (!chunk) |
651 | return -ENOMEM; | 675 | return -ENOMEM; |
652 | 676 | ||
677 | map = kmalloc(map_lookup_size(num_stripes), GFP_NOFS); | ||
678 | if (!map) { | ||
679 | kfree(chunk); | ||
680 | return -ENOMEM; | ||
681 | } | ||
682 | |||
653 | stripes = &chunk->stripe; | 683 | stripes = &chunk->stripe; |
654 | 684 | ||
655 | *num_bytes = calc_size; | 685 | *num_bytes = calc_size * num_stripes; |
656 | index = 0; | 686 | index = 0; |
657 | while(index < num_stripes) { | 687 | while(index < num_stripes) { |
658 | BUG_ON(list_empty(&private_devs)); | 688 | BUG_ON(list_empty(&private_devs)); |
@@ -669,6 +699,8 @@ printk("alloc chunk size %Lu from dev %Lu\n", calc_size, device->devid); | |||
669 | ret = btrfs_update_device(trans, device); | 699 | ret = btrfs_update_device(trans, device); |
670 | BUG_ON(ret); | 700 | BUG_ON(ret); |
671 | 701 | ||
702 | map->stripes[index].dev = device; | ||
703 | map->stripes[index].physical = dev_offset; | ||
672 | btrfs_set_stack_stripe_devid(stripes + index, device->devid); | 704 | btrfs_set_stack_stripe_devid(stripes + index, device->devid); |
673 | btrfs_set_stack_stripe_offset(stripes + index, dev_offset); | 705 | btrfs_set_stack_stripe_offset(stripes + index, dev_offset); |
674 | physical = dev_offset; | 706 | physical = dev_offset; |
@@ -680,12 +712,18 @@ printk("alloc chunk size %Lu from dev %Lu\n", calc_size, device->devid); | |||
680 | key.offset = *num_bytes; | 712 | key.offset = *num_bytes; |
681 | key.type = BTRFS_CHUNK_ITEM_KEY; | 713 | key.type = BTRFS_CHUNK_ITEM_KEY; |
682 | btrfs_set_stack_chunk_owner(chunk, extent_root->root_key.objectid); | 714 | btrfs_set_stack_chunk_owner(chunk, extent_root->root_key.objectid); |
683 | btrfs_set_stack_chunk_stripe_len(chunk, 64 * 1024); | 715 | btrfs_set_stack_chunk_stripe_len(chunk, stripe_len); |
684 | btrfs_set_stack_chunk_type(chunk, type); | 716 | btrfs_set_stack_chunk_type(chunk, type); |
685 | btrfs_set_stack_chunk_num_stripes(chunk, num_stripes); | 717 | btrfs_set_stack_chunk_num_stripes(chunk, num_stripes); |
686 | btrfs_set_stack_chunk_io_align(chunk, extent_root->sectorsize); | 718 | btrfs_set_stack_chunk_io_align(chunk, stripe_len); |
687 | btrfs_set_stack_chunk_io_width(chunk, extent_root->sectorsize); | 719 | btrfs_set_stack_chunk_io_width(chunk, stripe_len); |
688 | btrfs_set_stack_chunk_sector_size(chunk, extent_root->sectorsize); | 720 | btrfs_set_stack_chunk_sector_size(chunk, extent_root->sectorsize); |
721 | map->sector_size = extent_root->sectorsize; | ||
722 | map->stripe_len = stripe_len; | ||
723 | map->io_align = stripe_len; | ||
724 | map->io_width = stripe_len; | ||
725 | map->type = type; | ||
726 | map->num_stripes = num_stripes; | ||
689 | 727 | ||
690 | ret = btrfs_insert_item(trans, chunk_root, &key, chunk, | 728 | ret = btrfs_insert_item(trans, chunk_root, &key, chunk, |
691 | btrfs_chunk_item_size(num_stripes)); | 729 | btrfs_chunk_item_size(num_stripes)); |
@@ -695,25 +733,11 @@ printk("alloc chunk size %Lu from dev %Lu\n", calc_size, device->devid); | |||
695 | em = alloc_extent_map(GFP_NOFS); | 733 | em = alloc_extent_map(GFP_NOFS); |
696 | if (!em) | 734 | if (!em) |
697 | return -ENOMEM; | 735 | return -ENOMEM; |
698 | map = kmalloc(sizeof(*map), GFP_NOFS); | ||
699 | if (!map) { | ||
700 | free_extent_map(em); | ||
701 | return -ENOMEM; | ||
702 | } | ||
703 | |||
704 | em->bdev = (struct block_device *)map; | 736 | em->bdev = (struct block_device *)map; |
705 | em->start = key.objectid; | 737 | em->start = key.objectid; |
706 | em->len = key.offset; | 738 | em->len = key.offset; |
707 | em->block_start = 0; | 739 | em->block_start = 0; |
708 | 740 | ||
709 | map->physical = physical; | ||
710 | map->dev = device; | ||
711 | |||
712 | if (!map->dev) { | ||
713 | kfree(map); | ||
714 | free_extent_map(em); | ||
715 | return -EIO; | ||
716 | } | ||
717 | kfree(chunk); | 741 | kfree(chunk); |
718 | 742 | ||
719 | em_tree = &extent_root->fs_info->mapping_tree.map_tree; | 743 | em_tree = &extent_root->fs_info->mapping_tree.map_tree; |
@@ -758,6 +782,9 @@ int btrfs_map_block(struct btrfs_mapping_tree *map_tree, | |||
758 | struct map_lookup *map; | 782 | struct map_lookup *map; |
759 | struct extent_map_tree *em_tree = &map_tree->map_tree; | 783 | struct extent_map_tree *em_tree = &map_tree->map_tree; |
760 | u64 offset; | 784 | u64 offset; |
785 | u64 stripe_offset; | ||
786 | u64 stripe_nr; | ||
787 | int stripe_index; | ||
761 | 788 | ||
762 | 789 | ||
763 | spin_lock(&em_tree->lock); | 790 | spin_lock(&em_tree->lock); |
@@ -767,9 +794,40 @@ int btrfs_map_block(struct btrfs_mapping_tree *map_tree, | |||
767 | BUG_ON(em->start > logical || em->start + em->len < logical); | 794 | BUG_ON(em->start > logical || em->start + em->len < logical); |
768 | map = (struct map_lookup *)em->bdev; | 795 | map = (struct map_lookup *)em->bdev; |
769 | offset = logical - em->start; | 796 | offset = logical - em->start; |
770 | *phys = map->physical + offset; | 797 | |
771 | *length = em->len - offset; | 798 | stripe_nr = offset; |
772 | *dev = map->dev; | 799 | /* |
800 | * stripe_nr counts the total number of stripes we have to stride | ||
801 | * to get to this block | ||
802 | */ | ||
803 | do_div(stripe_nr, map->stripe_len); | ||
804 | |||
805 | stripe_offset = stripe_nr * map->stripe_len; | ||
806 | BUG_ON(offset < stripe_offset); | ||
807 | |||
808 | /* stripe_offset is the offset of this block in its stripe*/ | ||
809 | stripe_offset = offset - stripe_offset; | ||
810 | |||
811 | /* | ||
812 | * after this do_div call, stripe_nr is the number of stripes | ||
813 | * on this device we have to walk to find the data, and | ||
814 | * stripe_index is the number of our device in the stripe array | ||
815 | */ | ||
816 | stripe_index = do_div(stripe_nr, map->num_stripes); | ||
817 | |||
818 | BUG_ON(stripe_index >= map->num_stripes); | ||
819 | |||
820 | *phys = map->stripes[stripe_index].physical + stripe_offset + | ||
821 | stripe_nr * map->stripe_len; | ||
822 | |||
823 | if (map->type & BTRFS_BLOCK_GROUP_RAID0) { | ||
824 | /* we limit the length of each bio to what fits in a stripe */ | ||
825 | *length = min_t(u64, em->len - offset, | ||
826 | map->stripe_len - stripe_offset); | ||
827 | } else { | ||
828 | *length = em->len - offset; | ||
829 | } | ||
830 | *dev = map->stripes[stripe_index].dev; | ||
773 | free_extent_map(em); | 831 | free_extent_map(em); |
774 | spin_unlock(&em_tree->lock); | 832 | spin_unlock(&em_tree->lock); |
775 | return 0; | 833 | return 0; |
@@ -822,7 +880,9 @@ static int read_one_chunk(struct btrfs_root *root, struct btrfs_key *key, | |||
822 | u64 logical; | 880 | u64 logical; |
823 | u64 length; | 881 | u64 length; |
824 | u64 devid; | 882 | u64 devid; |
883 | int num_stripes; | ||
825 | int ret; | 884 | int ret; |
885 | int i; | ||
826 | 886 | ||
827 | logical = key->objectid; | 887 | logical = key->objectid; |
828 | length = key->offset; | 888 | length = key->offset; |
@@ -846,7 +906,8 @@ static int read_one_chunk(struct btrfs_root *root, struct btrfs_key *key, | |||
846 | em = alloc_extent_map(GFP_NOFS); | 906 | em = alloc_extent_map(GFP_NOFS); |
847 | if (!em) | 907 | if (!em) |
848 | return -ENOMEM; | 908 | return -ENOMEM; |
849 | map = kmalloc(sizeof(*map), GFP_NOFS); | 909 | num_stripes = btrfs_chunk_num_stripes(leaf, chunk); |
910 | map = kmalloc(map_lookup_size(num_stripes), GFP_NOFS); | ||
850 | if (!map) { | 911 | if (!map) { |
851 | free_extent_map(em); | 912 | free_extent_map(em); |
852 | return -ENOMEM; | 913 | return -ENOMEM; |
@@ -857,13 +918,22 @@ static int read_one_chunk(struct btrfs_root *root, struct btrfs_key *key, | |||
857 | em->len = length; | 918 | em->len = length; |
858 | em->block_start = 0; | 919 | em->block_start = 0; |
859 | 920 | ||
860 | map->physical = btrfs_stripe_offset_nr(leaf, chunk, 0); | 921 | map->num_stripes = num_stripes; |
861 | devid = btrfs_stripe_devid_nr(leaf, chunk, 0); | 922 | map->io_width = btrfs_chunk_io_width(leaf, chunk); |
862 | map->dev = btrfs_find_device(root, devid); | 923 | map->io_align = btrfs_chunk_io_align(leaf, chunk); |
863 | if (!map->dev) { | 924 | map->sector_size = btrfs_chunk_sector_size(leaf, chunk); |
864 | kfree(map); | 925 | map->stripe_len = btrfs_chunk_stripe_len(leaf, chunk); |
865 | free_extent_map(em); | 926 | map->type = btrfs_chunk_type(leaf, chunk); |
866 | return -EIO; | 927 | for (i = 0; i < num_stripes; i++) { |
928 | map->stripes[i].physical = | ||
929 | btrfs_stripe_offset_nr(leaf, chunk, i); | ||
930 | devid = btrfs_stripe_devid_nr(leaf, chunk, i); | ||
931 | map->stripes[i].dev = btrfs_find_device(root, devid); | ||
932 | if (!map->stripes[i].dev) { | ||
933 | kfree(map); | ||
934 | free_extent_map(em); | ||
935 | return -EIO; | ||
936 | } | ||
867 | } | 937 | } |
868 | 938 | ||
869 | spin_lock(&map_tree->map_tree.lock); | 939 | spin_lock(&map_tree->map_tree.lock); |