diff options
Diffstat (limited to 'fs/btrfs/extent-tree.c')
-rw-r--r-- | fs/btrfs/extent-tree.c | 102 |
1 files changed, 68 insertions, 34 deletions
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), |