diff options
Diffstat (limited to 'fs')
-rw-r--r-- | fs/btrfs/extent-tree.c | 15 | ||||
-rw-r--r-- | fs/btrfs/transaction.c | 9 | ||||
-rw-r--r-- | fs/btrfs/transaction.h | 1 | ||||
-rw-r--r-- | fs/btrfs/volumes.c | 304 | ||||
-rw-r--r-- | fs/btrfs/volumes.h | 6 |
5 files changed, 166 insertions, 169 deletions
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index 11ba82e43e8b..0236de711989 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c | |||
@@ -7950,6 +7950,7 @@ int btrfs_can_relocate(struct btrfs_root *root, u64 bytenr) | |||
7950 | struct btrfs_space_info *space_info; | 7950 | struct btrfs_space_info *space_info; |
7951 | struct btrfs_fs_devices *fs_devices = root->fs_info->fs_devices; | 7951 | struct btrfs_fs_devices *fs_devices = root->fs_info->fs_devices; |
7952 | struct btrfs_device *device; | 7952 | struct btrfs_device *device; |
7953 | struct btrfs_trans_handle *trans; | ||
7953 | u64 min_free; | 7954 | u64 min_free; |
7954 | u64 dev_min = 1; | 7955 | u64 dev_min = 1; |
7955 | u64 dev_nr = 0; | 7956 | u64 dev_nr = 0; |
@@ -8036,6 +8037,13 @@ int btrfs_can_relocate(struct btrfs_root *root, u64 bytenr) | |||
8036 | do_div(min_free, dev_min); | 8037 | do_div(min_free, dev_min); |
8037 | } | 8038 | } |
8038 | 8039 | ||
8040 | /* We need to do this so that we can look at pending chunks */ | ||
8041 | trans = btrfs_join_transaction(root); | ||
8042 | if (IS_ERR(trans)) { | ||
8043 | ret = PTR_ERR(trans); | ||
8044 | goto out; | ||
8045 | } | ||
8046 | |||
8039 | mutex_lock(&root->fs_info->chunk_mutex); | 8047 | mutex_lock(&root->fs_info->chunk_mutex); |
8040 | list_for_each_entry(device, &fs_devices->alloc_list, dev_alloc_list) { | 8048 | list_for_each_entry(device, &fs_devices->alloc_list, dev_alloc_list) { |
8041 | u64 dev_offset; | 8049 | u64 dev_offset; |
@@ -8046,7 +8054,7 @@ int btrfs_can_relocate(struct btrfs_root *root, u64 bytenr) | |||
8046 | */ | 8054 | */ |
8047 | if (device->total_bytes > device->bytes_used + min_free && | 8055 | if (device->total_bytes > device->bytes_used + min_free && |
8048 | !device->is_tgtdev_for_dev_replace) { | 8056 | !device->is_tgtdev_for_dev_replace) { |
8049 | ret = find_free_dev_extent(device, min_free, | 8057 | ret = find_free_dev_extent(trans, device, min_free, |
8050 | &dev_offset, NULL); | 8058 | &dev_offset, NULL); |
8051 | if (!ret) | 8059 | if (!ret) |
8052 | dev_nr++; | 8060 | dev_nr++; |
@@ -8058,6 +8066,7 @@ int btrfs_can_relocate(struct btrfs_root *root, u64 bytenr) | |||
8058 | } | 8066 | } |
8059 | } | 8067 | } |
8060 | mutex_unlock(&root->fs_info->chunk_mutex); | 8068 | mutex_unlock(&root->fs_info->chunk_mutex); |
8069 | btrfs_end_transaction(trans, root); | ||
8061 | out: | 8070 | out: |
8062 | btrfs_put_block_group(block_group); | 8071 | btrfs_put_block_group(block_group); |
8063 | return ret; | 8072 | return ret; |
@@ -8423,6 +8432,10 @@ void btrfs_create_pending_block_groups(struct btrfs_trans_handle *trans, | |||
8423 | sizeof(item)); | 8432 | sizeof(item)); |
8424 | if (ret) | 8433 | if (ret) |
8425 | btrfs_abort_transaction(trans, extent_root, ret); | 8434 | btrfs_abort_transaction(trans, extent_root, ret); |
8435 | ret = btrfs_finish_chunk_alloc(trans, extent_root, | ||
8436 | key.objectid, key.offset); | ||
8437 | if (ret) | ||
8438 | btrfs_abort_transaction(trans, extent_root, ret); | ||
8426 | } | 8439 | } |
8427 | } | 8440 | } |
8428 | 8441 | ||
diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c index bcfa32c91b5d..d58cce77fc6c 100644 --- a/fs/btrfs/transaction.c +++ b/fs/btrfs/transaction.c | |||
@@ -63,6 +63,14 @@ static void put_transaction(struct btrfs_transaction *transaction) | |||
63 | if (atomic_dec_and_test(&transaction->use_count)) { | 63 | if (atomic_dec_and_test(&transaction->use_count)) { |
64 | BUG_ON(!list_empty(&transaction->list)); | 64 | BUG_ON(!list_empty(&transaction->list)); |
65 | WARN_ON(transaction->delayed_refs.root.rb_node); | 65 | WARN_ON(transaction->delayed_refs.root.rb_node); |
66 | while (!list_empty(&transaction->pending_chunks)) { | ||
67 | struct extent_map *em; | ||
68 | |||
69 | em = list_first_entry(&transaction->pending_chunks, | ||
70 | struct extent_map, list); | ||
71 | list_del_init(&em->list); | ||
72 | free_extent_map(em); | ||
73 | } | ||
66 | kmem_cache_free(btrfs_transaction_cachep, transaction); | 74 | kmem_cache_free(btrfs_transaction_cachep, transaction); |
67 | } | 75 | } |
68 | } | 76 | } |
@@ -202,6 +210,7 @@ loop: | |||
202 | 210 | ||
203 | INIT_LIST_HEAD(&cur_trans->pending_snapshots); | 211 | INIT_LIST_HEAD(&cur_trans->pending_snapshots); |
204 | INIT_LIST_HEAD(&cur_trans->ordered_operations); | 212 | INIT_LIST_HEAD(&cur_trans->ordered_operations); |
213 | INIT_LIST_HEAD(&cur_trans->pending_chunks); | ||
205 | list_add_tail(&cur_trans->list, &fs_info->trans_list); | 214 | list_add_tail(&cur_trans->list, &fs_info->trans_list); |
206 | extent_io_tree_init(&cur_trans->dirty_pages, | 215 | extent_io_tree_init(&cur_trans->dirty_pages, |
207 | fs_info->btree_inode->i_mapping); | 216 | fs_info->btree_inode->i_mapping); |
diff --git a/fs/btrfs/transaction.h b/fs/btrfs/transaction.h index 66d2a6ccbf05..005b0375d18c 100644 --- a/fs/btrfs/transaction.h +++ b/fs/btrfs/transaction.h | |||
@@ -56,6 +56,7 @@ struct btrfs_transaction { | |||
56 | wait_queue_head_t commit_wait; | 56 | wait_queue_head_t commit_wait; |
57 | struct list_head pending_snapshots; | 57 | struct list_head pending_snapshots; |
58 | struct list_head ordered_operations; | 58 | struct list_head ordered_operations; |
59 | struct list_head pending_chunks; | ||
59 | struct btrfs_delayed_ref_root delayed_refs; | 60 | struct btrfs_delayed_ref_root delayed_refs; |
60 | int aborted; | 61 | int aborted; |
61 | }; | 62 | }; |
diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index 7789598eeb75..b2d1eacc07c9 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c | |||
@@ -982,6 +982,35 @@ out: | |||
982 | return ret; | 982 | return ret; |
983 | } | 983 | } |
984 | 984 | ||
985 | static int contains_pending_extent(struct btrfs_trans_handle *trans, | ||
986 | struct btrfs_device *device, | ||
987 | u64 *start, u64 len) | ||
988 | { | ||
989 | struct extent_map *em; | ||
990 | int ret = 0; | ||
991 | |||
992 | list_for_each_entry(em, &trans->transaction->pending_chunks, list) { | ||
993 | struct map_lookup *map; | ||
994 | int i; | ||
995 | |||
996 | map = (struct map_lookup *)em->bdev; | ||
997 | for (i = 0; i < map->num_stripes; i++) { | ||
998 | if (map->stripes[i].dev != device) | ||
999 | continue; | ||
1000 | if (map->stripes[i].physical >= *start + len || | ||
1001 | map->stripes[i].physical + em->orig_block_len <= | ||
1002 | *start) | ||
1003 | continue; | ||
1004 | *start = map->stripes[i].physical + | ||
1005 | em->orig_block_len; | ||
1006 | ret = 1; | ||
1007 | } | ||
1008 | } | ||
1009 | |||
1010 | return ret; | ||
1011 | } | ||
1012 | |||
1013 | |||
985 | /* | 1014 | /* |
986 | * find_free_dev_extent - find free space in the specified device | 1015 | * find_free_dev_extent - find free space in the specified device |
987 | * @device: the device which we search the free space in | 1016 | * @device: the device which we search the free space in |
@@ -1002,7 +1031,8 @@ out: | |||
1002 | * But if we don't find suitable free space, it is used to store the size of | 1031 | * But if we don't find suitable free space, it is used to store the size of |
1003 | * the max free space. | 1032 | * the max free space. |
1004 | */ | 1033 | */ |
1005 | int find_free_dev_extent(struct btrfs_device *device, u64 num_bytes, | 1034 | int find_free_dev_extent(struct btrfs_trans_handle *trans, |
1035 | struct btrfs_device *device, u64 num_bytes, | ||
1006 | u64 *start, u64 *len) | 1036 | u64 *start, u64 *len) |
1007 | { | 1037 | { |
1008 | struct btrfs_key key; | 1038 | struct btrfs_key key; |
@@ -1026,21 +1056,22 @@ int find_free_dev_extent(struct btrfs_device *device, u64 num_bytes, | |||
1026 | */ | 1056 | */ |
1027 | search_start = max(root->fs_info->alloc_start, 1024ull * 1024); | 1057 | search_start = max(root->fs_info->alloc_start, 1024ull * 1024); |
1028 | 1058 | ||
1059 | path = btrfs_alloc_path(); | ||
1060 | if (!path) | ||
1061 | return -ENOMEM; | ||
1062 | again: | ||
1029 | max_hole_start = search_start; | 1063 | max_hole_start = search_start; |
1030 | max_hole_size = 0; | 1064 | max_hole_size = 0; |
1031 | hole_size = 0; | 1065 | hole_size = 0; |
1032 | 1066 | ||
1033 | if (search_start >= search_end || device->is_tgtdev_for_dev_replace) { | 1067 | if (search_start >= search_end || device->is_tgtdev_for_dev_replace) { |
1034 | ret = -ENOSPC; | 1068 | ret = -ENOSPC; |
1035 | goto error; | 1069 | goto out; |
1036 | } | 1070 | } |
1037 | 1071 | ||
1038 | path = btrfs_alloc_path(); | ||
1039 | if (!path) { | ||
1040 | ret = -ENOMEM; | ||
1041 | goto error; | ||
1042 | } | ||
1043 | path->reada = 2; | 1072 | path->reada = 2; |
1073 | path->search_commit_root = 1; | ||
1074 | path->skip_locking = 1; | ||
1044 | 1075 | ||
1045 | key.objectid = device->devid; | 1076 | key.objectid = device->devid; |
1046 | key.offset = search_start; | 1077 | key.offset = search_start; |
@@ -1081,6 +1112,15 @@ int find_free_dev_extent(struct btrfs_device *device, u64 num_bytes, | |||
1081 | if (key.offset > search_start) { | 1112 | if (key.offset > search_start) { |
1082 | hole_size = key.offset - search_start; | 1113 | hole_size = key.offset - search_start; |
1083 | 1114 | ||
1115 | /* | ||
1116 | * Have to check before we set max_hole_start, otherwise | ||
1117 | * we could end up sending back this offset anyway. | ||
1118 | */ | ||
1119 | if (contains_pending_extent(trans, device, | ||
1120 | &search_start, | ||
1121 | hole_size)) | ||
1122 | hole_size = 0; | ||
1123 | |||
1084 | if (hole_size > max_hole_size) { | 1124 | if (hole_size > max_hole_size) { |
1085 | max_hole_start = search_start; | 1125 | max_hole_start = search_start; |
1086 | max_hole_size = hole_size; | 1126 | max_hole_size = hole_size; |
@@ -1124,6 +1164,11 @@ next: | |||
1124 | max_hole_size = hole_size; | 1164 | max_hole_size = hole_size; |
1125 | } | 1165 | } |
1126 | 1166 | ||
1167 | if (contains_pending_extent(trans, device, &search_start, hole_size)) { | ||
1168 | btrfs_release_path(path); | ||
1169 | goto again; | ||
1170 | } | ||
1171 | |||
1127 | /* See above. */ | 1172 | /* See above. */ |
1128 | if (hole_size < num_bytes) | 1173 | if (hole_size < num_bytes) |
1129 | ret = -ENOSPC; | 1174 | ret = -ENOSPC; |
@@ -1132,7 +1177,6 @@ next: | |||
1132 | 1177 | ||
1133 | out: | 1178 | out: |
1134 | btrfs_free_path(path); | 1179 | btrfs_free_path(path); |
1135 | error: | ||
1136 | *start = max_hole_start; | 1180 | *start = max_hole_start; |
1137 | if (len) | 1181 | if (len) |
1138 | *len = max_hole_size; | 1182 | *len = max_hole_size; |
@@ -1244,47 +1288,22 @@ out: | |||
1244 | return ret; | 1288 | return ret; |
1245 | } | 1289 | } |
1246 | 1290 | ||
1247 | static noinline int find_next_chunk(struct btrfs_root *root, | 1291 | static u64 find_next_chunk(struct btrfs_fs_info *fs_info) |
1248 | u64 objectid, u64 *offset) | ||
1249 | { | 1292 | { |
1250 | struct btrfs_path *path; | 1293 | struct extent_map_tree *em_tree; |
1251 | int ret; | 1294 | struct extent_map *em; |
1252 | struct btrfs_key key; | 1295 | struct rb_node *n; |
1253 | struct btrfs_chunk *chunk; | 1296 | u64 ret = 0; |
1254 | struct btrfs_key found_key; | ||
1255 | |||
1256 | path = btrfs_alloc_path(); | ||
1257 | if (!path) | ||
1258 | return -ENOMEM; | ||
1259 | |||
1260 | key.objectid = objectid; | ||
1261 | key.offset = (u64)-1; | ||
1262 | key.type = BTRFS_CHUNK_ITEM_KEY; | ||
1263 | |||
1264 | ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); | ||
1265 | if (ret < 0) | ||
1266 | goto error; | ||
1267 | |||
1268 | BUG_ON(ret == 0); /* Corruption */ | ||
1269 | 1297 | ||
1270 | ret = btrfs_previous_item(root, path, 0, BTRFS_CHUNK_ITEM_KEY); | 1298 | em_tree = &fs_info->mapping_tree.map_tree; |
1271 | if (ret) { | 1299 | read_lock(&em_tree->lock); |
1272 | *offset = 0; | 1300 | n = rb_last(&em_tree->map); |
1273 | } else { | 1301 | if (n) { |
1274 | btrfs_item_key_to_cpu(path->nodes[0], &found_key, | 1302 | em = rb_entry(n, struct extent_map, rb_node); |
1275 | path->slots[0]); | 1303 | ret = em->start + em->len; |
1276 | if (found_key.objectid != objectid) | ||
1277 | *offset = 0; | ||
1278 | else { | ||
1279 | chunk = btrfs_item_ptr(path->nodes[0], path->slots[0], | ||
1280 | struct btrfs_chunk); | ||
1281 | *offset = found_key.offset + | ||
1282 | btrfs_chunk_length(path->nodes[0], chunk); | ||
1283 | } | ||
1284 | } | 1304 | } |
1285 | ret = 0; | 1305 | read_unlock(&em_tree->lock); |
1286 | error: | 1306 | |
1287 | btrfs_free_path(path); | ||
1288 | return ret; | 1307 | return ret; |
1289 | } | 1308 | } |
1290 | 1309 | ||
@@ -3666,10 +3685,8 @@ static void check_raid56_incompat_flag(struct btrfs_fs_info *info, u64 type) | |||
3666 | } | 3685 | } |
3667 | 3686 | ||
3668 | static int __btrfs_alloc_chunk(struct btrfs_trans_handle *trans, | 3687 | static int __btrfs_alloc_chunk(struct btrfs_trans_handle *trans, |
3669 | struct btrfs_root *extent_root, | 3688 | struct btrfs_root *extent_root, u64 start, |
3670 | struct map_lookup **map_ret, | 3689 | u64 type) |
3671 | u64 *num_bytes_out, u64 *stripe_size_out, | ||
3672 | u64 start, u64 type) | ||
3673 | { | 3690 | { |
3674 | struct btrfs_fs_info *info = extent_root->fs_info; | 3691 | struct btrfs_fs_info *info = extent_root->fs_info; |
3675 | struct btrfs_fs_devices *fs_devices = info->fs_devices; | 3692 | struct btrfs_fs_devices *fs_devices = info->fs_devices; |
@@ -3776,7 +3793,7 @@ static int __btrfs_alloc_chunk(struct btrfs_trans_handle *trans, | |||
3776 | if (total_avail == 0) | 3793 | if (total_avail == 0) |
3777 | continue; | 3794 | continue; |
3778 | 3795 | ||
3779 | ret = find_free_dev_extent(device, | 3796 | ret = find_free_dev_extent(trans, device, |
3780 | max_stripe_size * dev_stripes, | 3797 | max_stripe_size * dev_stripes, |
3781 | &dev_offset, &max_avail); | 3798 | &dev_offset, &max_avail); |
3782 | if (ret && ret != -ENOSPC) | 3799 | if (ret && ret != -ENOSPC) |
@@ -3888,12 +3905,8 @@ static int __btrfs_alloc_chunk(struct btrfs_trans_handle *trans, | |||
3888 | map->type = type; | 3905 | map->type = type; |
3889 | map->sub_stripes = sub_stripes; | 3906 | map->sub_stripes = sub_stripes; |
3890 | 3907 | ||
3891 | *map_ret = map; | ||
3892 | num_bytes = stripe_size * data_stripes; | 3908 | num_bytes = stripe_size * data_stripes; |
3893 | 3909 | ||
3894 | *stripe_size_out = stripe_size; | ||
3895 | *num_bytes_out = num_bytes; | ||
3896 | |||
3897 | trace_btrfs_chunk_alloc(info->chunk_root, map, start, num_bytes); | 3910 | trace_btrfs_chunk_alloc(info->chunk_root, map, start, num_bytes); |
3898 | 3911 | ||
3899 | em = alloc_extent_map(); | 3912 | em = alloc_extent_map(); |
@@ -3906,38 +3919,26 @@ static int __btrfs_alloc_chunk(struct btrfs_trans_handle *trans, | |||
3906 | em->len = num_bytes; | 3919 | em->len = num_bytes; |
3907 | em->block_start = 0; | 3920 | em->block_start = 0; |
3908 | em->block_len = em->len; | 3921 | em->block_len = em->len; |
3922 | em->orig_block_len = stripe_size; | ||
3909 | 3923 | ||
3910 | em_tree = &extent_root->fs_info->mapping_tree.map_tree; | 3924 | em_tree = &extent_root->fs_info->mapping_tree.map_tree; |
3911 | write_lock(&em_tree->lock); | 3925 | write_lock(&em_tree->lock); |
3912 | ret = add_extent_mapping(em_tree, em, 0); | 3926 | ret = add_extent_mapping(em_tree, em, 0); |
3927 | if (!ret) { | ||
3928 | list_add_tail(&em->list, &trans->transaction->pending_chunks); | ||
3929 | atomic_inc(&em->refs); | ||
3930 | } | ||
3913 | write_unlock(&em_tree->lock); | 3931 | write_unlock(&em_tree->lock); |
3914 | if (ret) { | 3932 | if (ret) { |
3915 | free_extent_map(em); | 3933 | free_extent_map(em); |
3916 | goto error; | 3934 | goto error; |
3917 | } | 3935 | } |
3918 | 3936 | ||
3919 | for (i = 0; i < map->num_stripes; ++i) { | ||
3920 | struct btrfs_device *device; | ||
3921 | u64 dev_offset; | ||
3922 | |||
3923 | device = map->stripes[i].dev; | ||
3924 | dev_offset = map->stripes[i].physical; | ||
3925 | |||
3926 | ret = btrfs_alloc_dev_extent(trans, device, | ||
3927 | info->chunk_root->root_key.objectid, | ||
3928 | BTRFS_FIRST_CHUNK_TREE_OBJECTID, | ||
3929 | start, dev_offset, stripe_size); | ||
3930 | if (ret) | ||
3931 | goto error_dev_extent; | ||
3932 | } | ||
3933 | |||
3934 | ret = btrfs_make_block_group(trans, extent_root, 0, type, | 3937 | ret = btrfs_make_block_group(trans, extent_root, 0, type, |
3935 | BTRFS_FIRST_CHUNK_TREE_OBJECTID, | 3938 | BTRFS_FIRST_CHUNK_TREE_OBJECTID, |
3936 | start, num_bytes); | 3939 | start, num_bytes); |
3937 | if (ret) { | 3940 | if (ret) |
3938 | i = map->num_stripes - 1; | 3941 | goto error_del_extent; |
3939 | goto error_dev_extent; | ||
3940 | } | ||
3941 | 3942 | ||
3942 | free_extent_map(em); | 3943 | free_extent_map(em); |
3943 | check_raid56_incompat_flag(extent_root->fs_info, type); | 3944 | check_raid56_incompat_flag(extent_root->fs_info, type); |
@@ -3945,18 +3946,7 @@ static int __btrfs_alloc_chunk(struct btrfs_trans_handle *trans, | |||
3945 | kfree(devices_info); | 3946 | kfree(devices_info); |
3946 | return 0; | 3947 | return 0; |
3947 | 3948 | ||
3948 | error_dev_extent: | 3949 | error_del_extent: |
3949 | for (; i >= 0; i--) { | ||
3950 | struct btrfs_device *device; | ||
3951 | int err; | ||
3952 | |||
3953 | device = map->stripes[i].dev; | ||
3954 | err = btrfs_free_dev_extent(trans, device, start); | ||
3955 | if (err) { | ||
3956 | btrfs_abort_transaction(trans, extent_root, err); | ||
3957 | break; | ||
3958 | } | ||
3959 | } | ||
3960 | write_lock(&em_tree->lock); | 3950 | write_lock(&em_tree->lock); |
3961 | remove_extent_mapping(em_tree, em); | 3951 | remove_extent_mapping(em_tree, em); |
3962 | write_unlock(&em_tree->lock); | 3952 | write_unlock(&em_tree->lock); |
@@ -3971,33 +3961,68 @@ error: | |||
3971 | return ret; | 3961 | return ret; |
3972 | } | 3962 | } |
3973 | 3963 | ||
3974 | static int __finish_chunk_alloc(struct btrfs_trans_handle *trans, | 3964 | int btrfs_finish_chunk_alloc(struct btrfs_trans_handle *trans, |
3975 | struct btrfs_root *extent_root, | 3965 | struct btrfs_root *extent_root, |
3976 | struct map_lookup *map, u64 chunk_offset, | 3966 | u64 chunk_offset, u64 chunk_size) |
3977 | u64 chunk_size, u64 stripe_size) | ||
3978 | { | 3967 | { |
3979 | u64 dev_offset; | ||
3980 | struct btrfs_key key; | 3968 | struct btrfs_key key; |
3981 | struct btrfs_root *chunk_root = extent_root->fs_info->chunk_root; | 3969 | struct btrfs_root *chunk_root = extent_root->fs_info->chunk_root; |
3982 | struct btrfs_device *device; | 3970 | struct btrfs_device *device; |
3983 | struct btrfs_chunk *chunk; | 3971 | struct btrfs_chunk *chunk; |
3984 | struct btrfs_stripe *stripe; | 3972 | struct btrfs_stripe *stripe; |
3985 | size_t item_size = btrfs_chunk_item_size(map->num_stripes); | 3973 | struct extent_map_tree *em_tree; |
3986 | int index = 0; | 3974 | struct extent_map *em; |
3975 | struct map_lookup *map; | ||
3976 | size_t item_size; | ||
3977 | u64 dev_offset; | ||
3978 | u64 stripe_size; | ||
3979 | int i = 0; | ||
3987 | int ret; | 3980 | int ret; |
3988 | 3981 | ||
3982 | em_tree = &extent_root->fs_info->mapping_tree.map_tree; | ||
3983 | read_lock(&em_tree->lock); | ||
3984 | em = lookup_extent_mapping(em_tree, chunk_offset, chunk_size); | ||
3985 | read_unlock(&em_tree->lock); | ||
3986 | |||
3987 | if (!em) { | ||
3988 | btrfs_crit(extent_root->fs_info, "unable to find logical " | ||
3989 | "%Lu len %Lu", chunk_offset, chunk_size); | ||
3990 | return -EINVAL; | ||
3991 | } | ||
3992 | |||
3993 | if (em->start != chunk_offset || em->len != chunk_size) { | ||
3994 | btrfs_crit(extent_root->fs_info, "found a bad mapping, wanted" | ||
3995 | " %Lu-%Lu, found %Lu-%Lu\n", chunk_offset, | ||
3996 | chunk_size, em->start, em->len); | ||
3997 | free_extent_map(em); | ||
3998 | return -EINVAL; | ||
3999 | } | ||
4000 | |||
4001 | map = (struct map_lookup *)em->bdev; | ||
4002 | item_size = btrfs_chunk_item_size(map->num_stripes); | ||
4003 | stripe_size = em->orig_block_len; | ||
4004 | |||
3989 | chunk = kzalloc(item_size, GFP_NOFS); | 4005 | chunk = kzalloc(item_size, GFP_NOFS); |
3990 | if (!chunk) | 4006 | if (!chunk) { |
3991 | return -ENOMEM; | 4007 | ret = -ENOMEM; |
4008 | goto out; | ||
4009 | } | ||
4010 | |||
4011 | for (i = 0; i < map->num_stripes; i++) { | ||
4012 | device = map->stripes[i].dev; | ||
4013 | dev_offset = map->stripes[i].physical; | ||
3992 | 4014 | ||
3993 | index = 0; | ||
3994 | while (index < map->num_stripes) { | ||
3995 | device = map->stripes[index].dev; | ||
3996 | device->bytes_used += stripe_size; | 4015 | device->bytes_used += stripe_size; |
3997 | ret = btrfs_update_device(trans, device); | 4016 | ret = btrfs_update_device(trans, device); |
3998 | if (ret) | 4017 | if (ret) |
3999 | goto out_free; | 4018 | goto out; |
4000 | index++; | 4019 | ret = btrfs_alloc_dev_extent(trans, device, |
4020 | chunk_root->root_key.objectid, | ||
4021 | BTRFS_FIRST_CHUNK_TREE_OBJECTID, | ||
4022 | chunk_offset, dev_offset, | ||
4023 | stripe_size); | ||
4024 | if (ret) | ||
4025 | goto out; | ||
4001 | } | 4026 | } |
4002 | 4027 | ||
4003 | spin_lock(&extent_root->fs_info->free_chunk_lock); | 4028 | spin_lock(&extent_root->fs_info->free_chunk_lock); |
@@ -4005,17 +4030,15 @@ static int __finish_chunk_alloc(struct btrfs_trans_handle *trans, | |||
4005 | map->num_stripes); | 4030 | map->num_stripes); |
4006 | spin_unlock(&extent_root->fs_info->free_chunk_lock); | 4031 | spin_unlock(&extent_root->fs_info->free_chunk_lock); |
4007 | 4032 | ||
4008 | index = 0; | ||
4009 | stripe = &chunk->stripe; | 4033 | stripe = &chunk->stripe; |
4010 | while (index < map->num_stripes) { | 4034 | for (i = 0; i < map->num_stripes; i++) { |
4011 | device = map->stripes[index].dev; | 4035 | device = map->stripes[i].dev; |
4012 | dev_offset = map->stripes[index].physical; | 4036 | dev_offset = map->stripes[i].physical; |
4013 | 4037 | ||
4014 | btrfs_set_stack_stripe_devid(stripe, device->devid); | 4038 | btrfs_set_stack_stripe_devid(stripe, device->devid); |
4015 | btrfs_set_stack_stripe_offset(stripe, dev_offset); | 4039 | btrfs_set_stack_stripe_offset(stripe, dev_offset); |
4016 | memcpy(stripe->dev_uuid, device->uuid, BTRFS_UUID_SIZE); | 4040 | memcpy(stripe->dev_uuid, device->uuid, BTRFS_UUID_SIZE); |
4017 | stripe++; | 4041 | stripe++; |
4018 | index++; | ||
4019 | } | 4042 | } |
4020 | 4043 | ||
4021 | btrfs_set_stack_chunk_length(chunk, chunk_size); | 4044 | btrfs_set_stack_chunk_length(chunk, chunk_size); |
@@ -4033,7 +4056,6 @@ static int __finish_chunk_alloc(struct btrfs_trans_handle *trans, | |||
4033 | key.offset = chunk_offset; | 4056 | key.offset = chunk_offset; |
4034 | 4057 | ||
4035 | ret = btrfs_insert_item(trans, chunk_root, &key, chunk, item_size); | 4058 | ret = btrfs_insert_item(trans, chunk_root, &key, chunk, item_size); |
4036 | |||
4037 | if (ret == 0 && map->type & BTRFS_BLOCK_GROUP_SYSTEM) { | 4059 | if (ret == 0 && map->type & BTRFS_BLOCK_GROUP_SYSTEM) { |
4038 | /* | 4060 | /* |
4039 | * TODO: Cleanup of inserted chunk root in case of | 4061 | * TODO: Cleanup of inserted chunk root in case of |
@@ -4043,8 +4065,9 @@ static int __finish_chunk_alloc(struct btrfs_trans_handle *trans, | |||
4043 | item_size); | 4065 | item_size); |
4044 | } | 4066 | } |
4045 | 4067 | ||
4046 | out_free: | 4068 | out: |
4047 | kfree(chunk); | 4069 | kfree(chunk); |
4070 | free_extent_map(em); | ||
4048 | return ret; | 4071 | return ret; |
4049 | } | 4072 | } |
4050 | 4073 | ||
@@ -4059,27 +4082,9 @@ int btrfs_alloc_chunk(struct btrfs_trans_handle *trans, | |||
4059 | struct btrfs_root *extent_root, u64 type) | 4082 | struct btrfs_root *extent_root, u64 type) |
4060 | { | 4083 | { |
4061 | u64 chunk_offset; | 4084 | u64 chunk_offset; |
4062 | u64 chunk_size; | ||
4063 | u64 stripe_size; | ||
4064 | struct map_lookup *map; | ||
4065 | struct btrfs_root *chunk_root = extent_root->fs_info->chunk_root; | ||
4066 | int ret; | ||
4067 | 4085 | ||
4068 | ret = find_next_chunk(chunk_root, BTRFS_FIRST_CHUNK_TREE_OBJECTID, | 4086 | chunk_offset = find_next_chunk(extent_root->fs_info); |
4069 | &chunk_offset); | 4087 | return __btrfs_alloc_chunk(trans, extent_root, chunk_offset, type); |
4070 | if (ret) | ||
4071 | return ret; | ||
4072 | |||
4073 | ret = __btrfs_alloc_chunk(trans, extent_root, &map, &chunk_size, | ||
4074 | &stripe_size, chunk_offset, type); | ||
4075 | if (ret) | ||
4076 | return ret; | ||
4077 | |||
4078 | ret = __finish_chunk_alloc(trans, extent_root, map, chunk_offset, | ||
4079 | chunk_size, stripe_size); | ||
4080 | if (ret) | ||
4081 | return ret; | ||
4082 | return 0; | ||
4083 | } | 4088 | } |
4084 | 4089 | ||
4085 | static noinline int init_first_rw_device(struct btrfs_trans_handle *trans, | 4090 | static noinline int init_first_rw_device(struct btrfs_trans_handle *trans, |
@@ -4088,66 +4093,31 @@ static noinline int init_first_rw_device(struct btrfs_trans_handle *trans, | |||
4088 | { | 4093 | { |
4089 | u64 chunk_offset; | 4094 | u64 chunk_offset; |
4090 | u64 sys_chunk_offset; | 4095 | u64 sys_chunk_offset; |
4091 | u64 chunk_size; | ||
4092 | u64 sys_chunk_size; | ||
4093 | u64 stripe_size; | ||
4094 | u64 sys_stripe_size; | ||
4095 | u64 alloc_profile; | 4096 | u64 alloc_profile; |
4096 | struct map_lookup *map; | ||
4097 | struct map_lookup *sys_map; | ||
4098 | struct btrfs_fs_info *fs_info = root->fs_info; | 4097 | struct btrfs_fs_info *fs_info = root->fs_info; |
4099 | struct btrfs_root *extent_root = fs_info->extent_root; | 4098 | struct btrfs_root *extent_root = fs_info->extent_root; |
4100 | int ret; | 4099 | int ret; |
4101 | 4100 | ||
4102 | ret = find_next_chunk(fs_info->chunk_root, | 4101 | chunk_offset = find_next_chunk(fs_info); |
4103 | BTRFS_FIRST_CHUNK_TREE_OBJECTID, &chunk_offset); | ||
4104 | if (ret) | ||
4105 | return ret; | ||
4106 | |||
4107 | alloc_profile = btrfs_get_alloc_profile(extent_root, 0); | 4102 | alloc_profile = btrfs_get_alloc_profile(extent_root, 0); |
4108 | ret = __btrfs_alloc_chunk(trans, extent_root, &map, &chunk_size, | 4103 | ret = __btrfs_alloc_chunk(trans, extent_root, chunk_offset, |
4109 | &stripe_size, chunk_offset, alloc_profile); | 4104 | alloc_profile); |
4110 | if (ret) | 4105 | if (ret) |
4111 | return ret; | 4106 | return ret; |
4112 | 4107 | ||
4113 | sys_chunk_offset = chunk_offset + chunk_size; | 4108 | sys_chunk_offset = find_next_chunk(root->fs_info); |
4114 | |||
4115 | alloc_profile = btrfs_get_alloc_profile(fs_info->chunk_root, 0); | 4109 | alloc_profile = btrfs_get_alloc_profile(fs_info->chunk_root, 0); |
4116 | ret = __btrfs_alloc_chunk(trans, extent_root, &sys_map, | 4110 | ret = __btrfs_alloc_chunk(trans, extent_root, sys_chunk_offset, |
4117 | &sys_chunk_size, &sys_stripe_size, | 4111 | alloc_profile); |
4118 | sys_chunk_offset, alloc_profile); | ||
4119 | if (ret) { | 4112 | if (ret) { |
4120 | btrfs_abort_transaction(trans, root, ret); | 4113 | btrfs_abort_transaction(trans, root, ret); |
4121 | goto out; | 4114 | goto out; |
4122 | } | 4115 | } |
4123 | 4116 | ||
4124 | ret = btrfs_add_device(trans, fs_info->chunk_root, device); | 4117 | ret = btrfs_add_device(trans, fs_info->chunk_root, device); |
4125 | if (ret) { | ||
4126 | btrfs_abort_transaction(trans, root, ret); | ||
4127 | goto out; | ||
4128 | } | ||
4129 | |||
4130 | /* | ||
4131 | * Modifying chunk tree needs allocating new blocks from both | ||
4132 | * system block group and metadata block group. So we only can | ||
4133 | * do operations require modifying the chunk tree after both | ||
4134 | * block groups were created. | ||
4135 | */ | ||
4136 | ret = __finish_chunk_alloc(trans, extent_root, map, chunk_offset, | ||
4137 | chunk_size, stripe_size); | ||
4138 | if (ret) { | ||
4139 | btrfs_abort_transaction(trans, root, ret); | ||
4140 | goto out; | ||
4141 | } | ||
4142 | |||
4143 | ret = __finish_chunk_alloc(trans, extent_root, sys_map, | ||
4144 | sys_chunk_offset, sys_chunk_size, | ||
4145 | sys_stripe_size); | ||
4146 | if (ret) | 4118 | if (ret) |
4147 | btrfs_abort_transaction(trans, root, ret); | 4119 | btrfs_abort_transaction(trans, root, ret); |
4148 | |||
4149 | out: | 4120 | out: |
4150 | |||
4151 | return ret; | 4121 | return ret; |
4152 | } | 4122 | } |
4153 | 4123 | ||
diff --git a/fs/btrfs/volumes.h b/fs/btrfs/volumes.h index 857acd34ccde..86705583480d 100644 --- a/fs/btrfs/volumes.h +++ b/fs/btrfs/volumes.h | |||
@@ -316,7 +316,8 @@ int btrfs_recover_balance(struct btrfs_fs_info *fs_info); | |||
316 | int btrfs_pause_balance(struct btrfs_fs_info *fs_info); | 316 | int btrfs_pause_balance(struct btrfs_fs_info *fs_info); |
317 | int btrfs_cancel_balance(struct btrfs_fs_info *fs_info); | 317 | int btrfs_cancel_balance(struct btrfs_fs_info *fs_info); |
318 | int btrfs_chunk_readonly(struct btrfs_root *root, u64 chunk_offset); | 318 | int btrfs_chunk_readonly(struct btrfs_root *root, u64 chunk_offset); |
319 | int find_free_dev_extent(struct btrfs_device *device, u64 num_bytes, | 319 | int find_free_dev_extent(struct btrfs_trans_handle *trans, |
320 | struct btrfs_device *device, u64 num_bytes, | ||
320 | u64 *start, u64 *max_avail); | 321 | u64 *start, u64 *max_avail); |
321 | void btrfs_dev_stat_inc_and_print(struct btrfs_device *dev, int index); | 322 | void btrfs_dev_stat_inc_and_print(struct btrfs_device *dev, int index); |
322 | int btrfs_get_dev_stats(struct btrfs_root *root, | 323 | int btrfs_get_dev_stats(struct btrfs_root *root, |
@@ -337,6 +338,9 @@ int btrfs_is_parity_mirror(struct btrfs_mapping_tree *map_tree, | |||
337 | unsigned long btrfs_full_stripe_len(struct btrfs_root *root, | 338 | unsigned long btrfs_full_stripe_len(struct btrfs_root *root, |
338 | struct btrfs_mapping_tree *map_tree, | 339 | struct btrfs_mapping_tree *map_tree, |
339 | u64 logical); | 340 | u64 logical); |
341 | int btrfs_finish_chunk_alloc(struct btrfs_trans_handle *trans, | ||
342 | struct btrfs_root *extent_root, | ||
343 | u64 chunk_offset, u64 chunk_size); | ||
340 | static inline void btrfs_dev_stat_inc(struct btrfs_device *dev, | 344 | static inline void btrfs_dev_stat_inc(struct btrfs_device *dev, |
341 | int index) | 345 | int index) |
342 | { | 346 | { |