diff options
author | Chris Mason <chris.mason@oracle.com> | 2008-04-18 10:29:51 -0400 |
---|---|---|
committer | Chris Mason <chris.mason@oracle.com> | 2008-09-25 11:04:02 -0400 |
commit | 9b3f68b90674419add8be1c0aa740dcdf04f44cc (patch) | |
tree | ef8d0f51cffa1079e8cbc34af749605a3dcb05da /fs/btrfs/volumes.c | |
parent | 7b13b7b119c932a5eca486db4113f4c1fe3b97a8 (diff) |
Btrfs: Calculate appropriate chunk sizes for both small and large filesystems
Signed-off-by: Chris Mason <chris.mason@oracle.com>
Diffstat (limited to 'fs/btrfs/volumes.c')
-rw-r--r-- | fs/btrfs/volumes.c | 68 |
1 files changed, 61 insertions, 7 deletions
diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index 93aa36e2436e..e3ddd7fb8edd 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c | |||
@@ -627,6 +627,27 @@ int btrfs_add_system_chunk(struct btrfs_trans_handle *trans, | |||
627 | return 0; | 627 | return 0; |
628 | } | 628 | } |
629 | 629 | ||
630 | static u64 div_factor(u64 num, int factor) | ||
631 | { | ||
632 | if (factor == 10) | ||
633 | return num; | ||
634 | num *= factor; | ||
635 | do_div(num, 10); | ||
636 | return num; | ||
637 | } | ||
638 | |||
639 | static u64 chunk_bytes_by_type(u64 type, u64 calc_size, int num_stripes, | ||
640 | int sub_stripes) | ||
641 | { | ||
642 | if (type & (BTRFS_BLOCK_GROUP_RAID1 | BTRFS_BLOCK_GROUP_DUP)) | ||
643 | return calc_size; | ||
644 | else if (type & BTRFS_BLOCK_GROUP_RAID10) | ||
645 | return calc_size * (num_stripes / sub_stripes); | ||
646 | else | ||
647 | return calc_size * num_stripes; | ||
648 | } | ||
649 | |||
650 | |||
630 | int btrfs_alloc_chunk(struct btrfs_trans_handle *trans, | 651 | int btrfs_alloc_chunk(struct btrfs_trans_handle *trans, |
631 | struct btrfs_root *extent_root, u64 *start, | 652 | struct btrfs_root *extent_root, u64 *start, |
632 | u64 *num_bytes, u64 type) | 653 | u64 *num_bytes, u64 type) |
@@ -643,11 +664,14 @@ int btrfs_alloc_chunk(struct btrfs_trans_handle *trans, | |||
643 | struct extent_map_tree *em_tree; | 664 | struct extent_map_tree *em_tree; |
644 | struct map_lookup *map; | 665 | struct map_lookup *map; |
645 | struct extent_map *em; | 666 | struct extent_map *em; |
667 | int min_chunk_size = 8 * 1024 * 1024; | ||
646 | u64 physical; | 668 | u64 physical; |
647 | u64 calc_size = 1024 * 1024 * 1024; | 669 | u64 calc_size = 1024 * 1024 * 1024; |
648 | u64 min_free = calc_size; | 670 | u64 max_chunk_size = calc_size; |
671 | u64 min_free; | ||
649 | u64 avail; | 672 | u64 avail; |
650 | u64 max_avail = 0; | 673 | u64 max_avail = 0; |
674 | u64 percent_max; | ||
651 | int num_stripes = 1; | 675 | int num_stripes = 1; |
652 | int sub_stripes = 0; | 676 | int sub_stripes = 0; |
653 | int looped = 0; | 677 | int looped = 0; |
@@ -666,6 +690,8 @@ int btrfs_alloc_chunk(struct btrfs_trans_handle *trans, | |||
666 | if (type & (BTRFS_BLOCK_GROUP_RAID1)) { | 690 | if (type & (BTRFS_BLOCK_GROUP_RAID1)) { |
667 | num_stripes = min_t(u64, 2, | 691 | num_stripes = min_t(u64, 2, |
668 | btrfs_super_num_devices(&info->super_copy)); | 692 | btrfs_super_num_devices(&info->super_copy)); |
693 | if (num_stripes < 2) | ||
694 | return -ENOSPC; | ||
669 | } | 695 | } |
670 | if (type & (BTRFS_BLOCK_GROUP_RAID10)) { | 696 | if (type & (BTRFS_BLOCK_GROUP_RAID10)) { |
671 | num_stripes = btrfs_super_num_devices(&info->super_copy); | 697 | num_stripes = btrfs_super_num_devices(&info->super_copy); |
@@ -674,13 +700,45 @@ int btrfs_alloc_chunk(struct btrfs_trans_handle *trans, | |||
674 | num_stripes &= ~(u32)1; | 700 | num_stripes &= ~(u32)1; |
675 | sub_stripes = 2; | 701 | sub_stripes = 2; |
676 | } | 702 | } |
703 | |||
704 | if (type & BTRFS_BLOCK_GROUP_DATA) { | ||
705 | max_chunk_size = 10 * calc_size; | ||
706 | min_chunk_size = 256 * 1024 * 1024; | ||
707 | } else if (type & BTRFS_BLOCK_GROUP_METADATA) { | ||
708 | max_chunk_size = 4 * calc_size; | ||
709 | min_chunk_size = 64 * 1024 * 1024; | ||
710 | } else { | ||
711 | min_chunk_size = 32 * 1024 * 1024; | ||
712 | } | ||
713 | |||
714 | /* 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); | ||
716 | max_chunk_size = min(percent_max, max_chunk_size); | ||
717 | |||
718 | if (calc_size * num_stripes > max_chunk_size) { | ||
719 | calc_size = max_chunk_size; | ||
720 | do_div(calc_size, num_stripes); | ||
721 | do_div(calc_size, stripe_len); | ||
722 | calc_size *= stripe_len; | ||
723 | } | ||
724 | /* we don't want tiny stripes */ | ||
725 | *num_bytes = chunk_bytes_by_type(type, 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 | |||
677 | again: | 730 | again: |
731 | do_div(calc_size, stripe_len); | ||
732 | calc_size *= stripe_len; | ||
733 | |||
678 | INIT_LIST_HEAD(&private_devs); | 734 | INIT_LIST_HEAD(&private_devs); |
679 | cur = dev_list->next; | 735 | cur = dev_list->next; |
680 | index = 0; | 736 | index = 0; |
681 | 737 | ||
682 | if (type & BTRFS_BLOCK_GROUP_DUP) | 738 | if (type & BTRFS_BLOCK_GROUP_DUP) |
683 | min_free = calc_size * 2; | 739 | min_free = calc_size * 2; |
740 | else | ||
741 | min_free = calc_size; | ||
684 | 742 | ||
685 | /* build a private list of devices we will allocate from */ | 743 | /* build a private list of devices we will allocate from */ |
686 | while(index < num_stripes) { | 744 | while(index < num_stripes) { |
@@ -727,13 +785,9 @@ again: | |||
727 | } | 785 | } |
728 | 786 | ||
729 | stripes = &chunk->stripe; | 787 | stripes = &chunk->stripe; |
788 | *num_bytes = chunk_bytes_by_type(type, calc_size, | ||
789 | num_stripes, sub_stripes); | ||
730 | 790 | ||
731 | if (type & (BTRFS_BLOCK_GROUP_RAID1 | BTRFS_BLOCK_GROUP_DUP)) | ||
732 | *num_bytes = calc_size; | ||
733 | else if (type & BTRFS_BLOCK_GROUP_RAID10) | ||
734 | *num_bytes = calc_size * (num_stripes / sub_stripes); | ||
735 | else | ||
736 | *num_bytes = calc_size * num_stripes; | ||
737 | 791 | ||
738 | index = 0; | 792 | index = 0; |
739 | printk("new chunk type %Lu start %Lu size %Lu\n", type, key.offset, *num_bytes); | 793 | printk("new chunk type %Lu start %Lu size %Lu\n", type, key.offset, *num_bytes); |