diff options
Diffstat (limited to 'fs/btrfs/relocation.c')
-rw-r--r-- | fs/btrfs/relocation.c | 102 |
1 files changed, 78 insertions, 24 deletions
diff --git a/fs/btrfs/relocation.c b/fs/btrfs/relocation.c index 4febca4fc2de..12096496cc99 100644 --- a/fs/btrfs/relocation.c +++ b/fs/btrfs/relocation.c | |||
@@ -1305,6 +1305,7 @@ static struct btrfs_root *create_reloc_root(struct btrfs_trans_handle *trans, | |||
1305 | struct extent_buffer *eb; | 1305 | struct extent_buffer *eb; |
1306 | struct btrfs_root_item *root_item; | 1306 | struct btrfs_root_item *root_item; |
1307 | struct btrfs_key root_key; | 1307 | struct btrfs_key root_key; |
1308 | u64 last_snap = 0; | ||
1308 | int ret; | 1309 | int ret; |
1309 | 1310 | ||
1310 | root_item = kmalloc(sizeof(*root_item), GFP_NOFS); | 1311 | root_item = kmalloc(sizeof(*root_item), GFP_NOFS); |
@@ -1320,6 +1321,7 @@ static struct btrfs_root *create_reloc_root(struct btrfs_trans_handle *trans, | |||
1320 | BTRFS_TREE_RELOC_OBJECTID); | 1321 | BTRFS_TREE_RELOC_OBJECTID); |
1321 | BUG_ON(ret); | 1322 | BUG_ON(ret); |
1322 | 1323 | ||
1324 | last_snap = btrfs_root_last_snapshot(&root->root_item); | ||
1323 | btrfs_set_root_last_snapshot(&root->root_item, | 1325 | btrfs_set_root_last_snapshot(&root->root_item, |
1324 | trans->transid - 1); | 1326 | trans->transid - 1); |
1325 | } else { | 1327 | } else { |
@@ -1345,6 +1347,12 @@ static struct btrfs_root *create_reloc_root(struct btrfs_trans_handle *trans, | |||
1345 | memset(&root_item->drop_progress, 0, | 1347 | memset(&root_item->drop_progress, 0, |
1346 | sizeof(struct btrfs_disk_key)); | 1348 | sizeof(struct btrfs_disk_key)); |
1347 | root_item->drop_level = 0; | 1349 | root_item->drop_level = 0; |
1350 | /* | ||
1351 | * abuse rtransid, it is safe because it is impossible to | ||
1352 | * receive data into a relocation tree. | ||
1353 | */ | ||
1354 | btrfs_set_root_rtransid(root_item, last_snap); | ||
1355 | btrfs_set_root_otransid(root_item, trans->transid); | ||
1348 | } | 1356 | } |
1349 | 1357 | ||
1350 | btrfs_tree_unlock(eb); | 1358 | btrfs_tree_unlock(eb); |
@@ -1355,8 +1363,7 @@ static struct btrfs_root *create_reloc_root(struct btrfs_trans_handle *trans, | |||
1355 | BUG_ON(ret); | 1363 | BUG_ON(ret); |
1356 | kfree(root_item); | 1364 | kfree(root_item); |
1357 | 1365 | ||
1358 | reloc_root = btrfs_read_fs_root_no_radix(root->fs_info->tree_root, | 1366 | reloc_root = btrfs_read_fs_root(root->fs_info->tree_root, &root_key); |
1359 | &root_key); | ||
1360 | BUG_ON(IS_ERR(reloc_root)); | 1367 | BUG_ON(IS_ERR(reloc_root)); |
1361 | reloc_root->last_trans = trans->transid; | 1368 | reloc_root->last_trans = trans->transid; |
1362 | return reloc_root; | 1369 | return reloc_root; |
@@ -2273,8 +2280,12 @@ void free_reloc_roots(struct list_head *list) | |||
2273 | static noinline_for_stack | 2280 | static noinline_for_stack |
2274 | int merge_reloc_roots(struct reloc_control *rc) | 2281 | int merge_reloc_roots(struct reloc_control *rc) |
2275 | { | 2282 | { |
2283 | struct btrfs_trans_handle *trans; | ||
2276 | struct btrfs_root *root; | 2284 | struct btrfs_root *root; |
2277 | struct btrfs_root *reloc_root; | 2285 | struct btrfs_root *reloc_root; |
2286 | u64 last_snap; | ||
2287 | u64 otransid; | ||
2288 | u64 objectid; | ||
2278 | LIST_HEAD(reloc_roots); | 2289 | LIST_HEAD(reloc_roots); |
2279 | int found = 0; | 2290 | int found = 0; |
2280 | int ret = 0; | 2291 | int ret = 0; |
@@ -2308,12 +2319,44 @@ again: | |||
2308 | } else { | 2319 | } else { |
2309 | list_del_init(&reloc_root->root_list); | 2320 | list_del_init(&reloc_root->root_list); |
2310 | } | 2321 | } |
2322 | |||
2323 | /* | ||
2324 | * we keep the old last snapshod transid in rtranid when we | ||
2325 | * created the relocation tree. | ||
2326 | */ | ||
2327 | last_snap = btrfs_root_rtransid(&reloc_root->root_item); | ||
2328 | otransid = btrfs_root_otransid(&reloc_root->root_item); | ||
2329 | objectid = reloc_root->root_key.offset; | ||
2330 | |||
2311 | ret = btrfs_drop_snapshot(reloc_root, rc->block_rsv, 0, 1); | 2331 | ret = btrfs_drop_snapshot(reloc_root, rc->block_rsv, 0, 1); |
2312 | if (ret < 0) { | 2332 | if (ret < 0) { |
2313 | if (list_empty(&reloc_root->root_list)) | 2333 | if (list_empty(&reloc_root->root_list)) |
2314 | list_add_tail(&reloc_root->root_list, | 2334 | list_add_tail(&reloc_root->root_list, |
2315 | &reloc_roots); | 2335 | &reloc_roots); |
2316 | goto out; | 2336 | goto out; |
2337 | } else if (!ret) { | ||
2338 | /* | ||
2339 | * recover the last snapshot tranid to avoid | ||
2340 | * the space balance break NOCOW. | ||
2341 | */ | ||
2342 | root = read_fs_root(rc->extent_root->fs_info, | ||
2343 | objectid); | ||
2344 | if (IS_ERR(root)) | ||
2345 | continue; | ||
2346 | |||
2347 | if (btrfs_root_refs(&root->root_item) == 0) | ||
2348 | continue; | ||
2349 | |||
2350 | trans = btrfs_join_transaction(root); | ||
2351 | BUG_ON(IS_ERR(trans)); | ||
2352 | |||
2353 | /* Check if the fs/file tree was snapshoted or not. */ | ||
2354 | if (btrfs_root_last_snapshot(&root->root_item) == | ||
2355 | otransid - 1) | ||
2356 | btrfs_set_root_last_snapshot(&root->root_item, | ||
2357 | last_snap); | ||
2358 | |||
2359 | btrfs_end_transaction(trans, root); | ||
2317 | } | 2360 | } |
2318 | } | 2361 | } |
2319 | 2362 | ||
@@ -3266,6 +3309,8 @@ static int __add_tree_block(struct reloc_control *rc, | |||
3266 | struct btrfs_path *path; | 3309 | struct btrfs_path *path; |
3267 | struct btrfs_key key; | 3310 | struct btrfs_key key; |
3268 | int ret; | 3311 | int ret; |
3312 | bool skinny = btrfs_fs_incompat(rc->extent_root->fs_info, | ||
3313 | SKINNY_METADATA); | ||
3269 | 3314 | ||
3270 | if (tree_block_processed(bytenr, blocksize, rc)) | 3315 | if (tree_block_processed(bytenr, blocksize, rc)) |
3271 | return 0; | 3316 | return 0; |
@@ -3276,10 +3321,15 @@ static int __add_tree_block(struct reloc_control *rc, | |||
3276 | path = btrfs_alloc_path(); | 3321 | path = btrfs_alloc_path(); |
3277 | if (!path) | 3322 | if (!path) |
3278 | return -ENOMEM; | 3323 | return -ENOMEM; |
3279 | 3324 | again: | |
3280 | key.objectid = bytenr; | 3325 | key.objectid = bytenr; |
3281 | key.type = BTRFS_EXTENT_ITEM_KEY; | 3326 | if (skinny) { |
3282 | key.offset = blocksize; | 3327 | key.type = BTRFS_METADATA_ITEM_KEY; |
3328 | key.offset = (u64)-1; | ||
3329 | } else { | ||
3330 | key.type = BTRFS_EXTENT_ITEM_KEY; | ||
3331 | key.offset = blocksize; | ||
3332 | } | ||
3283 | 3333 | ||
3284 | path->search_commit_root = 1; | 3334 | path->search_commit_root = 1; |
3285 | path->skip_locking = 1; | 3335 | path->skip_locking = 1; |
@@ -3287,11 +3337,23 @@ static int __add_tree_block(struct reloc_control *rc, | |||
3287 | if (ret < 0) | 3337 | if (ret < 0) |
3288 | goto out; | 3338 | goto out; |
3289 | 3339 | ||
3290 | btrfs_item_key_to_cpu(path->nodes[0], &key, path->slots[0]); | 3340 | if (ret > 0 && skinny) { |
3291 | if (ret > 0) { | 3341 | if (path->slots[0]) { |
3292 | if (key.objectid == bytenr && | 3342 | path->slots[0]--; |
3293 | key.type == BTRFS_METADATA_ITEM_KEY) | 3343 | btrfs_item_key_to_cpu(path->nodes[0], &key, |
3294 | ret = 0; | 3344 | path->slots[0]); |
3345 | if (key.objectid == bytenr && | ||
3346 | (key.type == BTRFS_METADATA_ITEM_KEY || | ||
3347 | (key.type == BTRFS_EXTENT_ITEM_KEY && | ||
3348 | key.offset == blocksize))) | ||
3349 | ret = 0; | ||
3350 | } | ||
3351 | |||
3352 | if (ret) { | ||
3353 | skinny = false; | ||
3354 | btrfs_release_path(path); | ||
3355 | goto again; | ||
3356 | } | ||
3295 | } | 3357 | } |
3296 | BUG_ON(ret); | 3358 | BUG_ON(ret); |
3297 | 3359 | ||
@@ -4160,12 +4222,12 @@ int btrfs_relocate_block_group(struct btrfs_root *extent_root, u64 group_start) | |||
4160 | (unsigned long long)rc->block_group->key.objectid, | 4222 | (unsigned long long)rc->block_group->key.objectid, |
4161 | (unsigned long long)rc->block_group->flags); | 4223 | (unsigned long long)rc->block_group->flags); |
4162 | 4224 | ||
4163 | ret = btrfs_start_delalloc_inodes(fs_info->tree_root, 0); | 4225 | ret = btrfs_start_all_delalloc_inodes(fs_info, 0); |
4164 | if (ret < 0) { | 4226 | if (ret < 0) { |
4165 | err = ret; | 4227 | err = ret; |
4166 | goto out; | 4228 | goto out; |
4167 | } | 4229 | } |
4168 | btrfs_wait_ordered_extents(fs_info->tree_root, 0); | 4230 | btrfs_wait_all_ordered_extents(fs_info, 0); |
4169 | 4231 | ||
4170 | while (1) { | 4232 | while (1) { |
4171 | mutex_lock(&fs_info->cleaner_mutex); | 4233 | mutex_lock(&fs_info->cleaner_mutex); |
@@ -4277,7 +4339,7 @@ int btrfs_recover_relocation(struct btrfs_root *root) | |||
4277 | key.type != BTRFS_ROOT_ITEM_KEY) | 4339 | key.type != BTRFS_ROOT_ITEM_KEY) |
4278 | break; | 4340 | break; |
4279 | 4341 | ||
4280 | reloc_root = btrfs_read_fs_root_no_radix(root, &key); | 4342 | reloc_root = btrfs_read_fs_root(root, &key); |
4281 | if (IS_ERR(reloc_root)) { | 4343 | if (IS_ERR(reloc_root)) { |
4282 | err = PTR_ERR(reloc_root); | 4344 | err = PTR_ERR(reloc_root); |
4283 | goto out; | 4345 | goto out; |
@@ -4396,10 +4458,8 @@ out: | |||
4396 | int btrfs_reloc_clone_csums(struct inode *inode, u64 file_pos, u64 len) | 4458 | int btrfs_reloc_clone_csums(struct inode *inode, u64 file_pos, u64 len) |
4397 | { | 4459 | { |
4398 | struct btrfs_ordered_sum *sums; | 4460 | struct btrfs_ordered_sum *sums; |
4399 | struct btrfs_sector_sum *sector_sum; | ||
4400 | struct btrfs_ordered_extent *ordered; | 4461 | struct btrfs_ordered_extent *ordered; |
4401 | struct btrfs_root *root = BTRFS_I(inode)->root; | 4462 | struct btrfs_root *root = BTRFS_I(inode)->root; |
4402 | size_t offset; | ||
4403 | int ret; | 4463 | int ret; |
4404 | u64 disk_bytenr; | 4464 | u64 disk_bytenr; |
4405 | LIST_HEAD(list); | 4465 | LIST_HEAD(list); |
@@ -4413,19 +4473,13 @@ int btrfs_reloc_clone_csums(struct inode *inode, u64 file_pos, u64 len) | |||
4413 | if (ret) | 4473 | if (ret) |
4414 | goto out; | 4474 | goto out; |
4415 | 4475 | ||
4476 | disk_bytenr = ordered->start; | ||
4416 | while (!list_empty(&list)) { | 4477 | while (!list_empty(&list)) { |
4417 | sums = list_entry(list.next, struct btrfs_ordered_sum, list); | 4478 | sums = list_entry(list.next, struct btrfs_ordered_sum, list); |
4418 | list_del_init(&sums->list); | 4479 | list_del_init(&sums->list); |
4419 | 4480 | ||
4420 | sector_sum = sums->sums; | 4481 | sums->bytenr = disk_bytenr; |
4421 | sums->bytenr = ordered->start; | 4482 | disk_bytenr += sums->len; |
4422 | |||
4423 | offset = 0; | ||
4424 | while (offset < sums->len) { | ||
4425 | sector_sum->bytenr += ordered->start - disk_bytenr; | ||
4426 | sector_sum++; | ||
4427 | offset += root->sectorsize; | ||
4428 | } | ||
4429 | 4483 | ||
4430 | btrfs_add_ordered_sum(inode, ordered, sums); | 4484 | btrfs_add_ordered_sum(inode, ordered, sums); |
4431 | } | 4485 | } |