diff options
author | Chris Mason <chris.mason@oracle.com> | 2008-04-28 15:29:52 -0400 |
---|---|---|
committer | Chris Mason <chris.mason@oracle.com> | 2008-09-25 11:04:02 -0400 |
commit | ec44a35cbeb26ab2da84cb280d778260f2312feb (patch) | |
tree | afd48a9769125095922c931e3ad77f207c8fb025 /fs/btrfs/volumes.c | |
parent | 788f20eb5affef584e75ea84bb80a4c3352a2c0e (diff) |
Btrfs: Add balance ioctl to restripe the chunks
Signed-off-by: Chris Mason <chris.mason@oracle.com>
Diffstat (limited to 'fs/btrfs/volumes.c')
-rw-r--r-- | fs/btrfs/volumes.c | 115 |
1 files changed, 106 insertions, 9 deletions
diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index b93c15aa17db..6476ecbf132e 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c | |||
@@ -869,6 +869,107 @@ out: | |||
869 | return 0; | 869 | return 0; |
870 | } | 870 | } |
871 | 871 | ||
872 | static u64 div_factor(u64 num, int factor) | ||
873 | { | ||
874 | if (factor == 10) | ||
875 | return num; | ||
876 | num *= factor; | ||
877 | do_div(num, 10); | ||
878 | return num; | ||
879 | } | ||
880 | |||
881 | |||
882 | int btrfs_balance(struct btrfs_root *dev_root) | ||
883 | { | ||
884 | int ret; | ||
885 | struct list_head *cur; | ||
886 | struct list_head *devices = &dev_root->fs_info->fs_devices->devices; | ||
887 | struct btrfs_device *device; | ||
888 | u64 old_size; | ||
889 | u64 size_to_free; | ||
890 | struct btrfs_path *path; | ||
891 | struct btrfs_key key; | ||
892 | struct btrfs_chunk *chunk; | ||
893 | struct btrfs_root *chunk_root = dev_root->fs_info->chunk_root; | ||
894 | struct btrfs_trans_handle *trans; | ||
895 | struct btrfs_key found_key; | ||
896 | |||
897 | |||
898 | dev_root = dev_root->fs_info->dev_root; | ||
899 | |||
900 | mutex_lock(&dev_root->fs_info->fs_mutex); | ||
901 | /* step one make some room on all the devices */ | ||
902 | list_for_each(cur, devices) { | ||
903 | device = list_entry(cur, struct btrfs_device, dev_list); | ||
904 | old_size = device->total_bytes; | ||
905 | size_to_free = div_factor(old_size, 1); | ||
906 | size_to_free = min(size_to_free, (u64)1 * 1024 * 1024); | ||
907 | if (device->total_bytes - device->bytes_used > size_to_free) | ||
908 | continue; | ||
909 | |||
910 | ret = btrfs_shrink_device(device, old_size - size_to_free); | ||
911 | BUG_ON(ret); | ||
912 | |||
913 | trans = btrfs_start_transaction(dev_root, 1); | ||
914 | BUG_ON(!trans); | ||
915 | |||
916 | ret = btrfs_grow_device(trans, device, old_size); | ||
917 | BUG_ON(ret); | ||
918 | |||
919 | btrfs_end_transaction(trans, dev_root); | ||
920 | } | ||
921 | |||
922 | /* step two, relocate all the chunks */ | ||
923 | path = btrfs_alloc_path(); | ||
924 | BUG_ON(!path); | ||
925 | |||
926 | key.objectid = BTRFS_FIRST_CHUNK_TREE_OBJECTID; | ||
927 | key.offset = (u64)-1; | ||
928 | key.type = BTRFS_CHUNK_ITEM_KEY; | ||
929 | |||
930 | while(1) { | ||
931 | ret = btrfs_search_slot(NULL, chunk_root, &key, path, 0, 0); | ||
932 | if (ret < 0) | ||
933 | goto error; | ||
934 | |||
935 | /* | ||
936 | * this shouldn't happen, it means the last relocate | ||
937 | * failed | ||
938 | */ | ||
939 | if (ret == 0) | ||
940 | break; | ||
941 | |||
942 | ret = btrfs_previous_item(chunk_root, path, 0, | ||
943 | BTRFS_CHUNK_ITEM_KEY); | ||
944 | if (ret) { | ||
945 | break; | ||
946 | } | ||
947 | btrfs_item_key_to_cpu(path->nodes[0], &found_key, | ||
948 | path->slots[0]); | ||
949 | if (found_key.objectid != key.objectid) | ||
950 | break; | ||
951 | chunk = btrfs_item_ptr(path->nodes[0], | ||
952 | path->slots[0], | ||
953 | struct btrfs_chunk); | ||
954 | key.offset = found_key.offset; | ||
955 | /* chunk zero is special */ | ||
956 | if (key.offset == 0) | ||
957 | break; | ||
958 | |||
959 | ret = btrfs_relocate_chunk(chunk_root, | ||
960 | chunk_root->root_key.objectid, | ||
961 | found_key.objectid, | ||
962 | found_key.offset); | ||
963 | BUG_ON(ret); | ||
964 | btrfs_release_path(chunk_root, path); | ||
965 | } | ||
966 | ret = 0; | ||
967 | error: | ||
968 | btrfs_free_path(path); | ||
969 | mutex_unlock(&dev_root->fs_info->fs_mutex); | ||
970 | return ret; | ||
971 | } | ||
972 | |||
872 | /* | 973 | /* |
873 | * shrinking a device means finding all of the device extents past | 974 | * shrinking a device means finding all of the device extents past |
874 | * the new size, and then following the back refs to the chunks. | 975 | * the new size, and then following the back refs to the chunks. |
@@ -985,15 +1086,6 @@ int btrfs_add_system_chunk(struct btrfs_trans_handle *trans, | |||
985 | return 0; | 1086 | return 0; |
986 | } | 1087 | } |
987 | 1088 | ||
988 | static u64 div_factor(u64 num, int factor) | ||
989 | { | ||
990 | if (factor == 10) | ||
991 | return num; | ||
992 | num *= factor; | ||
993 | do_div(num, 10); | ||
994 | return num; | ||
995 | } | ||
996 | |||
997 | static u64 chunk_bytes_by_type(u64 type, u64 calc_size, int num_stripes, | 1089 | static u64 chunk_bytes_by_type(u64 type, u64 calc_size, int num_stripes, |
998 | int sub_stripes) | 1090 | int sub_stripes) |
999 | { | 1091 | { |
@@ -1040,6 +1132,11 @@ int btrfs_alloc_chunk(struct btrfs_trans_handle *trans, | |||
1040 | int stripe_len = 64 * 1024; | 1132 | int stripe_len = 64 * 1024; |
1041 | struct btrfs_key key; | 1133 | struct btrfs_key key; |
1042 | 1134 | ||
1135 | if ((type & BTRFS_BLOCK_GROUP_RAID1) && | ||
1136 | (type & BTRFS_BLOCK_GROUP_DUP)) { | ||
1137 | WARN_ON(1); | ||
1138 | type &= ~BTRFS_BLOCK_GROUP_DUP; | ||
1139 | } | ||
1043 | dev_list = &extent_root->fs_info->fs_devices->alloc_list; | 1140 | dev_list = &extent_root->fs_info->fs_devices->alloc_list; |
1044 | if (list_empty(dev_list)) | 1141 | if (list_empty(dev_list)) |
1045 | return -ENOSPC; | 1142 | return -ENOSPC; |