diff options
author | Chris Mason <chris.mason@oracle.com> | 2008-04-18 11:55:51 -0400 |
---|---|---|
committer | Chris Mason <chris.mason@oracle.com> | 2008-09-25 11:04:02 -0400 |
commit | a40a90a0420abd5ff86a0917facd3293ebb6a9b6 (patch) | |
tree | 48a7690c7d73a3638d409ff9594e9e9116467a18 /fs/btrfs/volumes.c | |
parent | 9b3f68b90674419add8be1c0aa740dcdf04f44cc (diff) |
Btrfs: Fix chunk allocation when some devices don't have enough room for stripes
Signed-off-by: Chris Mason <chris.mason@oracle.com>
Diffstat (limited to 'fs/btrfs/volumes.c')
-rw-r--r-- | fs/btrfs/volumes.c | 45 |
1 files changed, 29 insertions, 16 deletions
diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index e3ddd7fb8edd..fe5b00986d22 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c | |||
@@ -664,7 +664,7 @@ int btrfs_alloc_chunk(struct btrfs_trans_handle *trans, | |||
664 | struct extent_map_tree *em_tree; | 664 | struct extent_map_tree *em_tree; |
665 | struct map_lookup *map; | 665 | struct map_lookup *map; |
666 | struct extent_map *em; | 666 | struct extent_map *em; |
667 | int min_chunk_size = 8 * 1024 * 1024; | 667 | int min_stripe_size = 1 * 1024 * 1024; |
668 | u64 physical; | 668 | u64 physical; |
669 | u64 calc_size = 1024 * 1024 * 1024; | 669 | u64 calc_size = 1024 * 1024 * 1024; |
670 | u64 max_chunk_size = calc_size; | 670 | u64 max_chunk_size = calc_size; |
@@ -673,6 +673,7 @@ int btrfs_alloc_chunk(struct btrfs_trans_handle *trans, | |||
673 | u64 max_avail = 0; | 673 | u64 max_avail = 0; |
674 | u64 percent_max; | 674 | u64 percent_max; |
675 | int num_stripes = 1; | 675 | int num_stripes = 1; |
676 | int min_stripes = 1; | ||
676 | int sub_stripes = 0; | 677 | int sub_stripes = 0; |
677 | int looped = 0; | 678 | int looped = 0; |
678 | int ret; | 679 | int ret; |
@@ -683,15 +684,20 @@ int btrfs_alloc_chunk(struct btrfs_trans_handle *trans, | |||
683 | if (list_empty(dev_list)) | 684 | if (list_empty(dev_list)) |
684 | return -ENOSPC; | 685 | return -ENOSPC; |
685 | 686 | ||
686 | if (type & (BTRFS_BLOCK_GROUP_RAID0)) | 687 | if (type & (BTRFS_BLOCK_GROUP_RAID0)) { |
687 | num_stripes = btrfs_super_num_devices(&info->super_copy); | 688 | num_stripes = btrfs_super_num_devices(&info->super_copy); |
688 | if (type & (BTRFS_BLOCK_GROUP_DUP)) | 689 | min_stripes = 2; |
690 | } | ||
691 | if (type & (BTRFS_BLOCK_GROUP_DUP)) { | ||
689 | num_stripes = 2; | 692 | num_stripes = 2; |
693 | min_stripes = 2; | ||
694 | } | ||
690 | if (type & (BTRFS_BLOCK_GROUP_RAID1)) { | 695 | if (type & (BTRFS_BLOCK_GROUP_RAID1)) { |
691 | num_stripes = min_t(u64, 2, | 696 | num_stripes = min_t(u64, 2, |
692 | btrfs_super_num_devices(&info->super_copy)); | 697 | btrfs_super_num_devices(&info->super_copy)); |
693 | if (num_stripes < 2) | 698 | if (num_stripes < 2) |
694 | return -ENOSPC; | 699 | return -ENOSPC; |
700 | min_stripes = 2; | ||
695 | } | 701 | } |
696 | if (type & (BTRFS_BLOCK_GROUP_RAID10)) { | 702 | if (type & (BTRFS_BLOCK_GROUP_RAID10)) { |
697 | num_stripes = btrfs_super_num_devices(&info->super_copy); | 703 | num_stripes = btrfs_super_num_devices(&info->super_copy); |
@@ -699,22 +705,26 @@ int btrfs_alloc_chunk(struct btrfs_trans_handle *trans, | |||
699 | return -ENOSPC; | 705 | return -ENOSPC; |
700 | num_stripes &= ~(u32)1; | 706 | num_stripes &= ~(u32)1; |
701 | sub_stripes = 2; | 707 | sub_stripes = 2; |
708 | min_stripes = 4; | ||
702 | } | 709 | } |
703 | 710 | ||
704 | if (type & BTRFS_BLOCK_GROUP_DATA) { | 711 | if (type & BTRFS_BLOCK_GROUP_DATA) { |
705 | max_chunk_size = 10 * calc_size; | 712 | max_chunk_size = 10 * calc_size; |
706 | min_chunk_size = 256 * 1024 * 1024; | 713 | min_stripe_size = 64 * 1024 * 1024; |
707 | } else if (type & BTRFS_BLOCK_GROUP_METADATA) { | 714 | } else if (type & BTRFS_BLOCK_GROUP_METADATA) { |
708 | max_chunk_size = 4 * calc_size; | 715 | max_chunk_size = 4 * calc_size; |
709 | min_chunk_size = 64 * 1024 * 1024; | 716 | min_stripe_size = 32 * 1024 * 1024; |
710 | } else { | 717 | } else if (type & BTRFS_BLOCK_GROUP_SYSTEM) { |
711 | min_chunk_size = 32 * 1024 * 1024; | 718 | calc_size = 8 * 1024 * 1024; |
719 | max_chunk_size = calc_size * 2; | ||
720 | min_stripe_size = 1 * 1024 * 1024; | ||
712 | } | 721 | } |
713 | 722 | ||
714 | /* we don't want a chunk larger than 10% of the FS */ | 723 | /* we don't want a chunk larger than 10% of the FS */ |
715 | percent_max = div_factor(btrfs_super_total_bytes(&info->super_copy), 1); | 724 | percent_max = div_factor(btrfs_super_total_bytes(&info->super_copy), 1); |
716 | max_chunk_size = min(percent_max, max_chunk_size); | 725 | max_chunk_size = min(percent_max, max_chunk_size); |
717 | 726 | ||
727 | again: | ||
718 | if (calc_size * num_stripes > max_chunk_size) { | 728 | if (calc_size * num_stripes > max_chunk_size) { |
719 | calc_size = max_chunk_size; | 729 | calc_size = max_chunk_size; |
720 | do_div(calc_size, num_stripes); | 730 | do_div(calc_size, num_stripes); |
@@ -722,12 +732,8 @@ int btrfs_alloc_chunk(struct btrfs_trans_handle *trans, | |||
722 | calc_size *= stripe_len; | 732 | calc_size *= stripe_len; |
723 | } | 733 | } |
724 | /* we don't want tiny stripes */ | 734 | /* we don't want tiny stripes */ |
725 | *num_bytes = chunk_bytes_by_type(type, calc_size, | 735 | calc_size = max_t(u64, min_stripe_size, calc_size); |
726 | num_stripes, sub_stripes); | ||
727 | calc_size = max_t(u64, chunk_bytes_by_type(type, min_chunk_size, | ||
728 | num_stripes, sub_stripes), calc_size); | ||
729 | 736 | ||
730 | again: | ||
731 | do_div(calc_size, stripe_len); | 737 | do_div(calc_size, stripe_len); |
732 | calc_size *= stripe_len; | 738 | calc_size *= stripe_len; |
733 | 739 | ||
@@ -746,19 +752,27 @@ again: | |||
746 | 752 | ||
747 | avail = device->total_bytes - device->bytes_used; | 753 | avail = device->total_bytes - device->bytes_used; |
748 | cur = cur->next; | 754 | cur = cur->next; |
749 | if (avail > max_avail) | ||
750 | max_avail = avail; | ||
751 | if (avail >= min_free) { | 755 | if (avail >= min_free) { |
752 | list_move_tail(&device->dev_list, &private_devs); | 756 | list_move_tail(&device->dev_list, &private_devs); |
753 | index++; | 757 | index++; |
754 | if (type & BTRFS_BLOCK_GROUP_DUP) | 758 | if (type & BTRFS_BLOCK_GROUP_DUP) |
755 | index++; | 759 | index++; |
756 | } | 760 | } else if (avail > max_avail) |
761 | max_avail = avail; | ||
757 | if (cur == dev_list) | 762 | if (cur == dev_list) |
758 | break; | 763 | break; |
759 | } | 764 | } |
760 | if (index < num_stripes) { | 765 | if (index < num_stripes) { |
761 | list_splice(&private_devs, dev_list); | 766 | list_splice(&private_devs, dev_list); |
767 | if (index >= min_stripes) { | ||
768 | num_stripes = index; | ||
769 | if (type & (BTRFS_BLOCK_GROUP_RAID10)) { | ||
770 | num_stripes /= sub_stripes; | ||
771 | num_stripes *= sub_stripes; | ||
772 | } | ||
773 | looped = 1; | ||
774 | goto again; | ||
775 | } | ||
762 | if (!looped && max_avail > 0) { | 776 | if (!looped && max_avail > 0) { |
763 | looped = 1; | 777 | looped = 1; |
764 | calc_size = max_avail; | 778 | calc_size = max_avail; |
@@ -766,7 +780,6 @@ again: | |||
766 | } | 780 | } |
767 | return -ENOSPC; | 781 | return -ENOSPC; |
768 | } | 782 | } |
769 | |||
770 | key.objectid = BTRFS_FIRST_CHUNK_TREE_OBJECTID; | 783 | key.objectid = BTRFS_FIRST_CHUNK_TREE_OBJECTID; |
771 | key.type = BTRFS_CHUNK_ITEM_KEY; | 784 | key.type = BTRFS_CHUNK_ITEM_KEY; |
772 | ret = find_next_chunk(chunk_root, BTRFS_FIRST_CHUNK_TREE_OBJECTID, | 785 | ret = find_next_chunk(chunk_root, BTRFS_FIRST_CHUNK_TREE_OBJECTID, |