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 | } |
