diff options
| -rw-r--r-- | fs/btrfs/ctree.c | 133 | ||||
| -rw-r--r-- | fs/btrfs/ctree.h | 3 | ||||
| -rw-r--r-- | fs/btrfs/extent_map.c | 20 | ||||
| -rw-r--r-- | fs/btrfs/file.c | 2 | ||||
| -rw-r--r-- | fs/btrfs/inode.c | 85 | ||||
| -rw-r--r-- | fs/btrfs/tree-log.c | 338 | ||||
| -rw-r--r-- | fs/btrfs/volumes.c | 1 |
7 files changed, 372 insertions, 210 deletions
diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c index 0c5c28ff794f..e8b32641ea90 100644 --- a/fs/btrfs/ctree.c +++ b/fs/btrfs/ctree.c | |||
| @@ -5490,6 +5490,139 @@ int btrfs_next_leaf(struct btrfs_root *root, struct btrfs_path *path) | |||
| 5490 | return btrfs_next_old_leaf(root, path, 0); | 5490 | return btrfs_next_old_leaf(root, path, 0); |
| 5491 | } | 5491 | } |
| 5492 | 5492 | ||
| 5493 | /* Release the path up to but not including the given level */ | ||
| 5494 | static void btrfs_release_level(struct btrfs_path *path, int level) | ||
| 5495 | { | ||
| 5496 | int i; | ||
| 5497 | |||
| 5498 | for (i = 0; i < level; i++) { | ||
| 5499 | path->slots[i] = 0; | ||
| 5500 | if (!path->nodes[i]) | ||
| 5501 | continue; | ||
| 5502 | if (path->locks[i]) { | ||
| 5503 | btrfs_tree_unlock_rw(path->nodes[i], path->locks[i]); | ||
| 5504 | path->locks[i] = 0; | ||
| 5505 | } | ||
| 5506 | free_extent_buffer(path->nodes[i]); | ||
| 5507 | path->nodes[i] = NULL; | ||
| 5508 | } | ||
| 5509 | } | ||
| 5510 | |||
| 5511 | /* | ||
| 5512 | * This function assumes 2 things | ||
| 5513 | * | ||
| 5514 | * 1) You are using path->keep_locks | ||
| 5515 | * 2) You are not inserting items. | ||
| 5516 | * | ||
| 5517 | * If either of these are not true do not use this function. If you need a next | ||
| 5518 | * leaf with either of these not being true then this function can be easily | ||
| 5519 | * adapted to do that, but at the moment these are the limitations. | ||
| 5520 | */ | ||
| 5521 | int btrfs_next_leaf_write(struct btrfs_trans_handle *trans, | ||
| 5522 | struct btrfs_root *root, struct btrfs_path *path, | ||
| 5523 | int del) | ||
| 5524 | { | ||
| 5525 | struct extent_buffer *b; | ||
| 5526 | struct btrfs_key key; | ||
| 5527 | u32 nritems; | ||
| 5528 | int level = 1; | ||
| 5529 | int slot; | ||
| 5530 | int ret = 1; | ||
| 5531 | int write_lock_level = BTRFS_MAX_LEVEL; | ||
| 5532 | int ins_len = del ? -1 : 0; | ||
| 5533 | |||
| 5534 | WARN_ON(!(path->keep_locks || path->really_keep_locks)); | ||
| 5535 | |||
| 5536 | nritems = btrfs_header_nritems(path->nodes[0]); | ||
| 5537 | btrfs_item_key_to_cpu(path->nodes[0], &key, nritems - 1); | ||
| 5538 | |||
| 5539 | while (path->nodes[level]) { | ||
| 5540 | nritems = btrfs_header_nritems(path->nodes[level]); | ||
| 5541 | if (!(path->locks[level] & BTRFS_WRITE_LOCK)) { | ||
| 5542 | search: | ||
| 5543 | btrfs_release_path(path); | ||
| 5544 | ret = btrfs_search_slot(trans, root, &key, path, | ||
| 5545 | ins_len, 1); | ||
| 5546 | if (ret < 0) | ||
| 5547 | goto out; | ||
| 5548 | level = 1; | ||
| 5549 | continue; | ||
| 5550 | } | ||
| 5551 | |||
| 5552 | if (path->slots[level] >= nritems - 1) { | ||
| 5553 | level++; | ||
| 5554 | continue; | ||
| 5555 | } | ||
| 5556 | |||
| 5557 | btrfs_release_level(path, level); | ||
| 5558 | break; | ||
| 5559 | } | ||
| 5560 | |||
| 5561 | if (!path->nodes[level]) { | ||
| 5562 | ret = 1; | ||
| 5563 | goto out; | ||
| 5564 | } | ||
| 5565 | |||
| 5566 | path->slots[level]++; | ||
| 5567 | b = path->nodes[level]; | ||
| 5568 | |||
| 5569 | while (b) { | ||
| 5570 | level = btrfs_header_level(b); | ||
| 5571 | |||
| 5572 | if (!should_cow_block(trans, root, b)) | ||
| 5573 | goto cow_done; | ||
| 5574 | |||
| 5575 | btrfs_set_path_blocking(path); | ||
| 5576 | ret = btrfs_cow_block(trans, root, b, | ||
| 5577 | path->nodes[level + 1], | ||
| 5578 | path->slots[level + 1], &b); | ||
| 5579 | if (ret) | ||
| 5580 | goto out; | ||
| 5581 | cow_done: | ||
| 5582 | path->nodes[level] = b; | ||
| 5583 | btrfs_clear_path_blocking(path, NULL, 0); | ||
| 5584 | if (level != 0) { | ||
| 5585 | ret = setup_nodes_for_search(trans, root, path, b, | ||
| 5586 | level, ins_len, | ||
| 5587 | &write_lock_level); | ||
| 5588 | if (ret == -EAGAIN) | ||
| 5589 | goto search; | ||
| 5590 | if (ret) | ||
| 5591 | goto out; | ||
| 5592 | |||
| 5593 | b = path->nodes[level]; | ||
| 5594 | slot = path->slots[level]; | ||
| 5595 | |||
| 5596 | ret = read_block_for_search(trans, root, path, | ||
| 5597 | &b, level, slot, &key, 0); | ||
| 5598 | if (ret == -EAGAIN) | ||
| 5599 | goto search; | ||
| 5600 | if (ret) | ||
| 5601 | goto out; | ||
| 5602 | level = btrfs_header_level(b); | ||
| 5603 | if (!btrfs_try_tree_write_lock(b)) { | ||
| 5604 | btrfs_set_path_blocking(path); | ||
| 5605 | btrfs_tree_lock(b); | ||
| 5606 | btrfs_clear_path_blocking(path, b, | ||
| 5607 | BTRFS_WRITE_LOCK); | ||
| 5608 | } | ||
| 5609 | path->locks[level] = BTRFS_WRITE_LOCK; | ||
| 5610 | path->nodes[level] = b; | ||
| 5611 | path->slots[level] = 0; | ||
| 5612 | } else { | ||
| 5613 | path->slots[level] = 0; | ||
| 5614 | ret = 0; | ||
| 5615 | break; | ||
| 5616 | } | ||
| 5617 | } | ||
| 5618 | |||
| 5619 | out: | ||
| 5620 | if (ret) | ||
| 5621 | btrfs_release_path(path); | ||
| 5622 | |||
| 5623 | return ret; | ||
| 5624 | } | ||
| 5625 | |||
| 5493 | int btrfs_next_old_leaf(struct btrfs_root *root, struct btrfs_path *path, | 5626 | int btrfs_next_old_leaf(struct btrfs_root *root, struct btrfs_path *path, |
| 5494 | u64 time_seq) | 5627 | u64 time_seq) |
| 5495 | { | 5628 | { |
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index 9ed452f5d062..55aff6764bb9 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h | |||
| @@ -3187,6 +3187,9 @@ static inline int btrfs_insert_empty_item(struct btrfs_trans_handle *trans, | |||
| 3187 | } | 3187 | } |
| 3188 | 3188 | ||
| 3189 | int btrfs_next_leaf(struct btrfs_root *root, struct btrfs_path *path); | 3189 | int btrfs_next_leaf(struct btrfs_root *root, struct btrfs_path *path); |
| 3190 | int btrfs_next_leaf_write(struct btrfs_trans_handle *trans, | ||
| 3191 | struct btrfs_root *root, struct btrfs_path *path, | ||
| 3192 | int del); | ||
| 3190 | int btrfs_next_old_leaf(struct btrfs_root *root, struct btrfs_path *path, | 3193 | int btrfs_next_old_leaf(struct btrfs_root *root, struct btrfs_path *path, |
| 3191 | u64 time_seq); | 3194 | u64 time_seq); |
| 3192 | static inline int btrfs_next_old_item(struct btrfs_root *root, | 3195 | static inline int btrfs_next_old_item(struct btrfs_root *root, |
diff --git a/fs/btrfs/extent_map.c b/fs/btrfs/extent_map.c index 85ae2b6fe03b..fff2c28497b6 100644 --- a/fs/btrfs/extent_map.c +++ b/fs/btrfs/extent_map.c | |||
| @@ -49,7 +49,7 @@ void extent_map_tree_init(struct extent_map_tree *tree) | |||
| 49 | struct extent_map *alloc_extent_map(void) | 49 | struct extent_map *alloc_extent_map(void) |
| 50 | { | 50 | { |
| 51 | struct extent_map *em; | 51 | struct extent_map *em; |
| 52 | em = kmem_cache_alloc(extent_map_cache, GFP_NOFS); | 52 | em = kmem_cache_zalloc(extent_map_cache, GFP_NOFS); |
| 53 | if (!em) | 53 | if (!em) |
| 54 | return NULL; | 54 | return NULL; |
| 55 | em->in_tree = 0; | 55 | em->in_tree = 0; |
| @@ -198,16 +198,15 @@ static void try_merge_map(struct extent_map_tree *tree, struct extent_map *em) | |||
| 198 | merge = rb_entry(rb, struct extent_map, rb_node); | 198 | merge = rb_entry(rb, struct extent_map, rb_node); |
| 199 | if (rb && mergable_maps(merge, em)) { | 199 | if (rb && mergable_maps(merge, em)) { |
| 200 | em->start = merge->start; | 200 | em->start = merge->start; |
| 201 | em->orig_start = merge->orig_start; | ||
| 201 | em->len += merge->len; | 202 | em->len += merge->len; |
| 202 | em->block_len += merge->block_len; | 203 | em->block_len += merge->block_len; |
| 203 | em->block_start = merge->block_start; | 204 | em->block_start = merge->block_start; |
| 204 | merge->in_tree = 0; | 205 | merge->in_tree = 0; |
| 205 | if (merge->generation > em->generation) { | 206 | em->mod_len = (em->mod_len + em->mod_start) - merge->mod_start; |
| 206 | em->mod_start = em->start; | 207 | em->mod_start = merge->mod_start; |
| 207 | em->mod_len = em->len; | 208 | em->generation = max(em->generation, merge->generation); |
| 208 | em->generation = merge->generation; | 209 | list_move(&em->list, &tree->modified_extents); |
| 209 | list_move(&em->list, &tree->modified_extents); | ||
| 210 | } | ||
| 211 | 210 | ||
| 212 | list_del_init(&merge->list); | 211 | list_del_init(&merge->list); |
| 213 | rb_erase(&merge->rb_node, &tree->map); | 212 | rb_erase(&merge->rb_node, &tree->map); |
| @@ -223,11 +222,8 @@ static void try_merge_map(struct extent_map_tree *tree, struct extent_map *em) | |||
| 223 | em->block_len += merge->len; | 222 | em->block_len += merge->len; |
| 224 | rb_erase(&merge->rb_node, &tree->map); | 223 | rb_erase(&merge->rb_node, &tree->map); |
| 225 | merge->in_tree = 0; | 224 | merge->in_tree = 0; |
| 226 | if (merge->generation > em->generation) { | 225 | em->mod_len = (merge->mod_start + merge->mod_len) - em->mod_start; |
| 227 | em->mod_len = em->len; | 226 | em->generation = max(em->generation, merge->generation); |
| 228 | em->generation = merge->generation; | ||
| 229 | list_move(&em->list, &tree->modified_extents); | ||
| 230 | } | ||
| 231 | list_del_init(&merge->list); | 227 | list_del_init(&merge->list); |
| 232 | free_extent_map(merge); | 228 | free_extent_map(merge); |
| 233 | } | 229 | } |
diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c index 6810145f4e97..c56088ece500 100644 --- a/fs/btrfs/file.c +++ b/fs/btrfs/file.c | |||
| @@ -621,7 +621,7 @@ void btrfs_drop_extent_cache(struct inode *inode, u64 start, u64 end, | |||
| 621 | } else { | 621 | } else { |
| 622 | split->block_len = split->len; | 622 | split->block_len = split->len; |
| 623 | split->block_start = em->block_start + diff; | 623 | split->block_start = em->block_start + diff; |
| 624 | split->orig_start = split->start; | 624 | split->orig_start = em->orig_start; |
| 625 | } | 625 | } |
| 626 | 626 | ||
| 627 | ret = add_extent_mapping(em_tree, split); | 627 | ret = add_extent_mapping(em_tree, split); |
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 73e6833dcc21..355a297e7988 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c | |||
| @@ -95,6 +95,10 @@ static noinline int cow_file_range(struct inode *inode, | |||
| 95 | struct page *locked_page, | 95 | struct page *locked_page, |
| 96 | u64 start, u64 end, int *page_started, | 96 | u64 start, u64 end, int *page_started, |
| 97 | unsigned long *nr_written, int unlock); | 97 | unsigned long *nr_written, int unlock); |
| 98 | static struct extent_map *create_pinned_em(struct inode *inode, u64 start, | ||
| 99 | u64 len, u64 orig_start, | ||
| 100 | u64 block_start, u64 block_len, | ||
| 101 | u64 orig_block_len, int type); | ||
| 98 | 102 | ||
| 99 | static int btrfs_init_inode_security(struct btrfs_trans_handle *trans, | 103 | static int btrfs_init_inode_security(struct btrfs_trans_handle *trans, |
| 100 | struct inode *inode, struct inode *dir, | 104 | struct inode *inode, struct inode *dir, |
| @@ -704,10 +708,14 @@ retry: | |||
| 704 | em->compress_type = async_extent->compress_type; | 708 | em->compress_type = async_extent->compress_type; |
| 705 | set_bit(EXTENT_FLAG_PINNED, &em->flags); | 709 | set_bit(EXTENT_FLAG_PINNED, &em->flags); |
| 706 | set_bit(EXTENT_FLAG_COMPRESSED, &em->flags); | 710 | set_bit(EXTENT_FLAG_COMPRESSED, &em->flags); |
| 711 | em->generation = -1; | ||
| 707 | 712 | ||
| 708 | while (1) { | 713 | while (1) { |
| 709 | write_lock(&em_tree->lock); | 714 | write_lock(&em_tree->lock); |
| 710 | ret = add_extent_mapping(em_tree, em); | 715 | ret = add_extent_mapping(em_tree, em); |
| 716 | if (!ret) | ||
| 717 | list_move(&em->list, | ||
| 718 | &em_tree->modified_extents); | ||
| 711 | write_unlock(&em_tree->lock); | 719 | write_unlock(&em_tree->lock); |
| 712 | if (ret != -EEXIST) { | 720 | if (ret != -EEXIST) { |
| 713 | free_extent_map(em); | 721 | free_extent_map(em); |
| @@ -890,10 +898,14 @@ static noinline int __cow_file_range(struct btrfs_trans_handle *trans, | |||
| 890 | em->orig_block_len = ins.offset; | 898 | em->orig_block_len = ins.offset; |
| 891 | em->bdev = root->fs_info->fs_devices->latest_bdev; | 899 | em->bdev = root->fs_info->fs_devices->latest_bdev; |
| 892 | set_bit(EXTENT_FLAG_PINNED, &em->flags); | 900 | set_bit(EXTENT_FLAG_PINNED, &em->flags); |
| 901 | em->generation = -1; | ||
| 893 | 902 | ||
| 894 | while (1) { | 903 | while (1) { |
| 895 | write_lock(&em_tree->lock); | 904 | write_lock(&em_tree->lock); |
| 896 | ret = add_extent_mapping(em_tree, em); | 905 | ret = add_extent_mapping(em_tree, em); |
| 906 | if (!ret) | ||
| 907 | list_move(&em->list, | ||
| 908 | &em_tree->modified_extents); | ||
| 897 | write_unlock(&em_tree->lock); | 909 | write_unlock(&em_tree->lock); |
| 898 | if (ret != -EEXIST) { | 910 | if (ret != -EEXIST) { |
| 899 | free_extent_map(em); | 911 | free_extent_map(em); |
| @@ -1320,7 +1332,7 @@ out_check: | |||
| 1320 | em = alloc_extent_map(); | 1332 | em = alloc_extent_map(); |
| 1321 | BUG_ON(!em); /* -ENOMEM */ | 1333 | BUG_ON(!em); /* -ENOMEM */ |
| 1322 | em->start = cur_offset; | 1334 | em->start = cur_offset; |
| 1323 | em->orig_start = em->start; | 1335 | em->orig_start = found_key.offset - extent_offset; |
| 1324 | em->len = num_bytes; | 1336 | em->len = num_bytes; |
| 1325 | em->block_len = num_bytes; | 1337 | em->block_len = num_bytes; |
| 1326 | em->block_start = disk_bytenr; | 1338 | em->block_start = disk_bytenr; |
| @@ -1328,9 +1340,13 @@ out_check: | |||
| 1328 | em->bdev = root->fs_info->fs_devices->latest_bdev; | 1340 | em->bdev = root->fs_info->fs_devices->latest_bdev; |
| 1329 | set_bit(EXTENT_FLAG_PINNED, &em->flags); | 1341 | set_bit(EXTENT_FLAG_PINNED, &em->flags); |
| 1330 | set_bit(EXTENT_FLAG_FILLING, &em->flags); | 1342 | set_bit(EXTENT_FLAG_FILLING, &em->flags); |
| 1343 | em->generation = -1; | ||
| 1331 | while (1) { | 1344 | while (1) { |
| 1332 | write_lock(&em_tree->lock); | 1345 | write_lock(&em_tree->lock); |
| 1333 | ret = add_extent_mapping(em_tree, em); | 1346 | ret = add_extent_mapping(em_tree, em); |
| 1347 | if (!ret) | ||
| 1348 | list_move(&em->list, | ||
| 1349 | &em_tree->modified_extents); | ||
| 1334 | write_unlock(&em_tree->lock); | 1350 | write_unlock(&em_tree->lock); |
| 1335 | if (ret != -EEXIST) { | 1351 | if (ret != -EEXIST) { |
| 1336 | free_extent_map(em); | 1352 | free_extent_map(em); |
| @@ -5371,6 +5387,7 @@ again: | |||
| 5371 | if (start + len <= found_key.offset) | 5387 | if (start + len <= found_key.offset) |
| 5372 | goto not_found; | 5388 | goto not_found; |
| 5373 | em->start = start; | 5389 | em->start = start; |
| 5390 | em->orig_start = start; | ||
| 5374 | em->len = found_key.offset - start; | 5391 | em->len = found_key.offset - start; |
| 5375 | goto not_found_em; | 5392 | goto not_found_em; |
| 5376 | } | 5393 | } |
| @@ -5423,7 +5440,7 @@ again: | |||
| 5423 | em->len = (copy_size + root->sectorsize - 1) & | 5440 | em->len = (copy_size + root->sectorsize - 1) & |
| 5424 | ~((u64)root->sectorsize - 1); | 5441 | ~((u64)root->sectorsize - 1); |
| 5425 | em->orig_block_len = em->len; | 5442 | em->orig_block_len = em->len; |
| 5426 | em->orig_start = EXTENT_MAP_INLINE; | 5443 | em->orig_start = em->start; |
| 5427 | if (compress_type) { | 5444 | if (compress_type) { |
| 5428 | set_bit(EXTENT_FLAG_COMPRESSED, &em->flags); | 5445 | set_bit(EXTENT_FLAG_COMPRESSED, &em->flags); |
| 5429 | em->compress_type = compress_type; | 5446 | em->compress_type = compress_type; |
| @@ -5476,6 +5493,7 @@ again: | |||
| 5476 | } | 5493 | } |
| 5477 | not_found: | 5494 | not_found: |
| 5478 | em->start = start; | 5495 | em->start = start; |
| 5496 | em->orig_start = start; | ||
| 5479 | em->len = len; | 5497 | em->len = len; |
| 5480 | not_found_em: | 5498 | not_found_em: |
| 5481 | em->block_start = EXTENT_MAP_HOLE; | 5499 | em->block_start = EXTENT_MAP_HOLE; |
| @@ -5677,30 +5695,14 @@ out: | |||
| 5677 | } | 5695 | } |
| 5678 | 5696 | ||
| 5679 | static struct extent_map *btrfs_new_extent_direct(struct inode *inode, | 5697 | static struct extent_map *btrfs_new_extent_direct(struct inode *inode, |
| 5680 | struct extent_map *em, | ||
| 5681 | u64 start, u64 len) | 5698 | u64 start, u64 len) |
| 5682 | { | 5699 | { |
| 5683 | struct btrfs_root *root = BTRFS_I(inode)->root; | 5700 | struct btrfs_root *root = BTRFS_I(inode)->root; |
| 5684 | struct btrfs_trans_handle *trans; | 5701 | struct btrfs_trans_handle *trans; |
| 5685 | struct extent_map_tree *em_tree = &BTRFS_I(inode)->extent_tree; | 5702 | struct extent_map *em; |
| 5686 | struct btrfs_key ins; | 5703 | struct btrfs_key ins; |
| 5687 | u64 alloc_hint; | 5704 | u64 alloc_hint; |
| 5688 | int ret; | 5705 | int ret; |
| 5689 | bool insert = false; | ||
| 5690 | |||
| 5691 | /* | ||
| 5692 | * Ok if the extent map we looked up is a hole and is for the exact | ||
| 5693 | * range we want, there is no reason to allocate a new one, however if | ||
| 5694 | * it is not right then we need to free this one and drop the cache for | ||
| 5695 | * our range. | ||
| 5696 | */ | ||
| 5697 | if (em->block_start != EXTENT_MAP_HOLE || em->start != start || | ||
| 5698 | em->len != len) { | ||
| 5699 | free_extent_map(em); | ||
| 5700 | em = NULL; | ||
| 5701 | insert = true; | ||
| 5702 | btrfs_drop_extent_cache(inode, start, start + len - 1, 0); | ||
| 5703 | } | ||
| 5704 | 5706 | ||
| 5705 | trans = btrfs_join_transaction(root); | 5707 | trans = btrfs_join_transaction(root); |
| 5706 | if (IS_ERR(trans)) | 5708 | if (IS_ERR(trans)) |
| @@ -5716,38 +5718,10 @@ static struct extent_map *btrfs_new_extent_direct(struct inode *inode, | |||
| 5716 | goto out; | 5718 | goto out; |
| 5717 | } | 5719 | } |
| 5718 | 5720 | ||
| 5719 | if (!em) { | 5721 | em = create_pinned_em(inode, start, ins.offset, start, ins.objectid, |
| 5720 | em = alloc_extent_map(); | 5722 | ins.offset, ins.offset, 0); |
| 5721 | if (!em) { | 5723 | if (IS_ERR(em)) |
| 5722 | em = ERR_PTR(-ENOMEM); | 5724 | goto out; |
| 5723 | goto out; | ||
| 5724 | } | ||
| 5725 | } | ||
| 5726 | |||
| 5727 | em->start = start; | ||
| 5728 | em->orig_start = em->start; | ||
| 5729 | em->len = ins.offset; | ||
| 5730 | |||
| 5731 | em->block_start = ins.objectid; | ||
| 5732 | em->block_len = ins.offset; | ||
| 5733 | em->orig_block_len = ins.offset; | ||
| 5734 | em->bdev = root->fs_info->fs_devices->latest_bdev; | ||
| 5735 | |||
| 5736 | /* | ||
| 5737 | * We need to do this because if we're using the original em we searched | ||
| 5738 | * for, we could have EXTENT_FLAG_VACANCY set, and we don't want that. | ||
| 5739 | */ | ||
| 5740 | em->flags = 0; | ||
| 5741 | set_bit(EXTENT_FLAG_PINNED, &em->flags); | ||
| 5742 | |||
| 5743 | while (insert) { | ||
| 5744 | write_lock(&em_tree->lock); | ||
| 5745 | ret = add_extent_mapping(em_tree, em); | ||
| 5746 | write_unlock(&em_tree->lock); | ||
| 5747 | if (ret != -EEXIST) | ||
| 5748 | break; | ||
| 5749 | btrfs_drop_extent_cache(inode, start, start + em->len - 1, 0); | ||
| 5750 | } | ||
| 5751 | 5725 | ||
| 5752 | ret = btrfs_add_ordered_extent_dio(inode, start, ins.objectid, | 5726 | ret = btrfs_add_ordered_extent_dio(inode, start, ins.objectid, |
| 5753 | ins.offset, ins.offset, 0); | 5727 | ins.offset, ins.offset, 0); |
| @@ -5943,6 +5917,7 @@ static struct extent_map *create_pinned_em(struct inode *inode, u64 start, | |||
| 5943 | em->block_start = block_start; | 5917 | em->block_start = block_start; |
| 5944 | em->bdev = root->fs_info->fs_devices->latest_bdev; | 5918 | em->bdev = root->fs_info->fs_devices->latest_bdev; |
| 5945 | em->orig_block_len = orig_block_len; | 5919 | em->orig_block_len = orig_block_len; |
| 5920 | em->generation = -1; | ||
| 5946 | set_bit(EXTENT_FLAG_PINNED, &em->flags); | 5921 | set_bit(EXTENT_FLAG_PINNED, &em->flags); |
| 5947 | if (type == BTRFS_ORDERED_PREALLOC) | 5922 | if (type == BTRFS_ORDERED_PREALLOC) |
| 5948 | set_bit(EXTENT_FLAG_FILLING, &em->flags); | 5923 | set_bit(EXTENT_FLAG_FILLING, &em->flags); |
| @@ -5952,6 +5927,9 @@ static struct extent_map *create_pinned_em(struct inode *inode, u64 start, | |||
| 5952 | em->start + em->len - 1, 0); | 5927 | em->start + em->len - 1, 0); |
| 5953 | write_lock(&em_tree->lock); | 5928 | write_lock(&em_tree->lock); |
| 5954 | ret = add_extent_mapping(em_tree, em); | 5929 | ret = add_extent_mapping(em_tree, em); |
| 5930 | if (!ret) | ||
| 5931 | list_move(&em->list, | ||
| 5932 | &em_tree->modified_extents); | ||
| 5955 | write_unlock(&em_tree->lock); | 5933 | write_unlock(&em_tree->lock); |
| 5956 | } while (ret == -EEXIST); | 5934 | } while (ret == -EEXIST); |
| 5957 | 5935 | ||
| @@ -6078,7 +6056,7 @@ static int btrfs_get_blocks_direct(struct inode *inode, sector_t iblock, | |||
| 6078 | goto must_cow; | 6056 | goto must_cow; |
| 6079 | 6057 | ||
| 6080 | if (can_nocow_odirect(trans, inode, start, len) == 1) { | 6058 | if (can_nocow_odirect(trans, inode, start, len) == 1) { |
| 6081 | u64 orig_start = em->start; | 6059 | u64 orig_start = em->orig_start; |
| 6082 | u64 orig_block_len = em->orig_block_len; | 6060 | u64 orig_block_len = em->orig_block_len; |
| 6083 | 6061 | ||
| 6084 | if (type == BTRFS_ORDERED_PREALLOC) { | 6062 | if (type == BTRFS_ORDERED_PREALLOC) { |
| @@ -6110,7 +6088,8 @@ must_cow: | |||
| 6110 | * it above | 6088 | * it above |
| 6111 | */ | 6089 | */ |
| 6112 | len = bh_result->b_size; | 6090 | len = bh_result->b_size; |
| 6113 | em = btrfs_new_extent_direct(inode, em, start, len); | 6091 | free_extent_map(em); |
| 6092 | em = btrfs_new_extent_direct(inode, start, len); | ||
| 6114 | if (IS_ERR(em)) { | 6093 | if (IS_ERR(em)) { |
| 6115 | ret = PTR_ERR(em); | 6094 | ret = PTR_ERR(em); |
| 6116 | goto unlock_err; | 6095 | goto unlock_err; |
diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c index ab7168ee618f..72444811d275 100644 --- a/fs/btrfs/tree-log.c +++ b/fs/btrfs/tree-log.c | |||
| @@ -3150,145 +3150,220 @@ static int extent_cmp(void *priv, struct list_head *a, struct list_head *b) | |||
| 3150 | return 0; | 3150 | return 0; |
| 3151 | } | 3151 | } |
| 3152 | 3152 | ||
| 3153 | struct log_args { | 3153 | static int drop_adjacent_extents(struct btrfs_trans_handle *trans, |
| 3154 | struct extent_buffer *src; | 3154 | struct btrfs_root *root, struct inode *inode, |
| 3155 | u64 next_offset; | 3155 | struct extent_map *em, |
| 3156 | int start_slot; | 3156 | struct btrfs_path *path) |
| 3157 | int nr; | 3157 | { |
| 3158 | }; | 3158 | struct btrfs_file_extent_item *fi; |
| 3159 | struct extent_buffer *leaf; | ||
| 3160 | struct btrfs_key key, new_key; | ||
| 3161 | struct btrfs_map_token token; | ||
| 3162 | u64 extent_end; | ||
| 3163 | u64 extent_offset = 0; | ||
| 3164 | int extent_type; | ||
| 3165 | int del_slot = 0; | ||
| 3166 | int del_nr = 0; | ||
| 3167 | int ret = 0; | ||
| 3168 | |||
| 3169 | while (1) { | ||
| 3170 | btrfs_init_map_token(&token); | ||
| 3171 | leaf = path->nodes[0]; | ||
| 3172 | path->slots[0]++; | ||
| 3173 | if (path->slots[0] >= btrfs_header_nritems(leaf)) { | ||
| 3174 | if (del_nr) { | ||
| 3175 | ret = btrfs_del_items(trans, root, path, | ||
| 3176 | del_slot, del_nr); | ||
| 3177 | if (ret) | ||
| 3178 | return ret; | ||
| 3179 | del_nr = 0; | ||
| 3180 | } | ||
| 3181 | |||
| 3182 | ret = btrfs_next_leaf_write(trans, root, path, 1); | ||
| 3183 | if (ret < 0) | ||
| 3184 | return ret; | ||
| 3185 | if (ret > 0) | ||
| 3186 | return 0; | ||
| 3187 | leaf = path->nodes[0]; | ||
| 3188 | } | ||
| 3189 | |||
| 3190 | btrfs_item_key_to_cpu(leaf, &key, path->slots[0]); | ||
| 3191 | if (key.objectid != btrfs_ino(inode) || | ||
| 3192 | key.type != BTRFS_EXTENT_DATA_KEY || | ||
| 3193 | key.offset >= em->start + em->len) | ||
| 3194 | break; | ||
| 3195 | |||
| 3196 | fi = btrfs_item_ptr(leaf, path->slots[0], | ||
| 3197 | struct btrfs_file_extent_item); | ||
| 3198 | extent_type = btrfs_token_file_extent_type(leaf, fi, &token); | ||
| 3199 | if (extent_type == BTRFS_FILE_EXTENT_REG || | ||
| 3200 | extent_type == BTRFS_FILE_EXTENT_PREALLOC) { | ||
| 3201 | extent_offset = btrfs_token_file_extent_offset(leaf, | ||
| 3202 | fi, &token); | ||
| 3203 | extent_end = key.offset + | ||
| 3204 | btrfs_token_file_extent_num_bytes(leaf, fi, | ||
| 3205 | &token); | ||
| 3206 | } else if (extent_type == BTRFS_FILE_EXTENT_INLINE) { | ||
| 3207 | extent_end = key.offset + | ||
| 3208 | btrfs_file_extent_inline_len(leaf, fi); | ||
| 3209 | } else { | ||
| 3210 | BUG(); | ||
| 3211 | } | ||
| 3212 | |||
| 3213 | if (extent_end <= em->len + em->start) { | ||
| 3214 | if (!del_nr) { | ||
| 3215 | del_slot = path->slots[0]; | ||
| 3216 | } | ||
| 3217 | del_nr++; | ||
| 3218 | continue; | ||
| 3219 | } | ||
| 3220 | |||
| 3221 | /* | ||
| 3222 | * Ok so we'll ignore previous items if we log a new extent, | ||
| 3223 | * which can lead to overlapping extents, so if we have an | ||
| 3224 | * existing extent we want to adjust we _have_ to check the next | ||
| 3225 | * guy to make sure we even need this extent anymore, this keeps | ||
| 3226 | * us from panicing in set_item_key_safe. | ||
| 3227 | */ | ||
| 3228 | if (path->slots[0] < btrfs_header_nritems(leaf) - 1) { | ||
| 3229 | struct btrfs_key tmp_key; | ||
| 3230 | |||
| 3231 | btrfs_item_key_to_cpu(leaf, &tmp_key, | ||
| 3232 | path->slots[0] + 1); | ||
| 3233 | if (tmp_key.objectid == btrfs_ino(inode) && | ||
| 3234 | tmp_key.type == BTRFS_EXTENT_DATA_KEY && | ||
| 3235 | tmp_key.offset <= em->start + em->len) { | ||
| 3236 | if (!del_nr) | ||
| 3237 | del_slot = path->slots[0]; | ||
| 3238 | del_nr++; | ||
| 3239 | continue; | ||
| 3240 | } | ||
| 3241 | } | ||
| 3242 | |||
| 3243 | BUG_ON(extent_type == BTRFS_FILE_EXTENT_INLINE); | ||
| 3244 | memcpy(&new_key, &key, sizeof(new_key)); | ||
| 3245 | new_key.offset = em->start + em->len; | ||
| 3246 | btrfs_set_item_key_safe(trans, root, path, &new_key); | ||
| 3247 | extent_offset += em->start + em->len - key.offset; | ||
| 3248 | btrfs_set_token_file_extent_offset(leaf, fi, extent_offset, | ||
| 3249 | &token); | ||
| 3250 | btrfs_set_token_file_extent_num_bytes(leaf, fi, extent_end - | ||
| 3251 | (em->start + em->len), | ||
| 3252 | &token); | ||
| 3253 | btrfs_mark_buffer_dirty(leaf); | ||
| 3254 | } | ||
| 3255 | |||
| 3256 | if (del_nr) | ||
| 3257 | ret = btrfs_del_items(trans, root, path, del_slot, del_nr); | ||
| 3258 | |||
| 3259 | return ret; | ||
| 3260 | } | ||
| 3159 | 3261 | ||
| 3160 | static int log_one_extent(struct btrfs_trans_handle *trans, | 3262 | static int log_one_extent(struct btrfs_trans_handle *trans, |
| 3161 | struct inode *inode, struct btrfs_root *root, | 3263 | struct inode *inode, struct btrfs_root *root, |
| 3162 | struct extent_map *em, struct btrfs_path *path, | 3264 | struct extent_map *em, struct btrfs_path *path) |
| 3163 | struct btrfs_path *dst_path, struct log_args *args) | ||
| 3164 | { | 3265 | { |
| 3165 | struct btrfs_root *log = root->log_root; | 3266 | struct btrfs_root *log = root->log_root; |
| 3267 | struct btrfs_file_extent_item *fi; | ||
| 3268 | struct extent_buffer *leaf; | ||
| 3269 | struct list_head ordered_sums; | ||
| 3166 | struct btrfs_key key; | 3270 | struct btrfs_key key; |
| 3167 | u64 start = em->mod_start; | 3271 | u64 csum_offset = em->mod_start - em->start; |
| 3168 | u64 search_start = start; | 3272 | u64 csum_len = em->mod_len; |
| 3169 | u64 len = em->mod_len; | 3273 | u64 extent_offset = em->start - em->orig_start; |
| 3170 | u64 num_bytes; | 3274 | u64 block_len; |
| 3171 | int nritems; | ||
| 3172 | int ret; | 3275 | int ret; |
| 3276 | bool skip_csum = BTRFS_I(inode)->flags & BTRFS_INODE_NODATASUM; | ||
| 3173 | 3277 | ||
| 3174 | if (BTRFS_I(inode)->logged_trans == trans->transid) { | 3278 | INIT_LIST_HEAD(&ordered_sums); |
| 3175 | ret = __btrfs_drop_extents(trans, log, inode, dst_path, start, | 3279 | key.objectid = btrfs_ino(inode); |
| 3176 | start + len, NULL, 0); | 3280 | key.type = BTRFS_EXTENT_DATA_KEY; |
| 3177 | if (ret) | 3281 | key.offset = em->start; |
| 3178 | return ret; | 3282 | path->really_keep_locks = 1; |
| 3283 | |||
| 3284 | ret = btrfs_insert_empty_item(trans, log, path, &key, sizeof(*fi)); | ||
| 3285 | if (ret && ret != -EEXIST) { | ||
| 3286 | path->really_keep_locks = 0; | ||
| 3287 | return ret; | ||
| 3288 | } | ||
| 3289 | leaf = path->nodes[0]; | ||
| 3290 | fi = btrfs_item_ptr(leaf, path->slots[0], | ||
| 3291 | struct btrfs_file_extent_item); | ||
| 3292 | btrfs_set_file_extent_generation(leaf, fi, em->generation); | ||
| 3293 | if (test_bit(EXTENT_FLAG_PREALLOC, &em->flags)) { | ||
| 3294 | skip_csum = true; | ||
| 3295 | btrfs_set_file_extent_type(leaf, fi, | ||
| 3296 | BTRFS_FILE_EXTENT_PREALLOC); | ||
| 3297 | } else { | ||
| 3298 | btrfs_set_file_extent_type(leaf, fi, BTRFS_FILE_EXTENT_REG); | ||
| 3299 | if (em->block_start == 0) | ||
| 3300 | skip_csum = true; | ||
| 3301 | } | ||
| 3302 | |||
| 3303 | block_len = max(em->block_len, em->orig_block_len); | ||
| 3304 | if (em->compress_type != BTRFS_COMPRESS_NONE) { | ||
| 3305 | btrfs_set_file_extent_disk_bytenr(leaf, fi, em->block_start); | ||
| 3306 | btrfs_set_file_extent_disk_num_bytes(leaf, fi, block_len); | ||
| 3307 | } else if (em->block_start < EXTENT_MAP_LAST_BYTE) { | ||
| 3308 | btrfs_set_file_extent_disk_bytenr(leaf, fi, | ||
| 3309 | em->block_start - | ||
| 3310 | extent_offset); | ||
| 3311 | btrfs_set_file_extent_disk_num_bytes(leaf, fi, block_len); | ||
| 3312 | } else { | ||
| 3313 | btrfs_set_file_extent_disk_bytenr(leaf, fi, 0); | ||
| 3314 | btrfs_set_file_extent_disk_num_bytes(leaf, fi, 0); | ||
| 3179 | } | 3315 | } |
| 3180 | 3316 | ||
| 3181 | while (len) { | 3317 | btrfs_set_file_extent_offset(leaf, fi, em->start - em->orig_start); |
| 3182 | if (args->nr) | 3318 | btrfs_set_file_extent_num_bytes(leaf, fi, em->len); |
| 3183 | goto next_slot; | 3319 | btrfs_set_file_extent_ram_bytes(leaf, fi, em->len); |
| 3184 | again: | 3320 | btrfs_set_file_extent_compression(leaf, fi, em->compress_type); |
| 3185 | key.objectid = btrfs_ino(inode); | 3321 | btrfs_set_file_extent_encryption(leaf, fi, 0); |
| 3186 | key.type = BTRFS_EXTENT_DATA_KEY; | 3322 | btrfs_set_file_extent_other_encoding(leaf, fi, 0); |
| 3187 | key.offset = search_start; | 3323 | btrfs_mark_buffer_dirty(leaf); |
| 3188 | |||
| 3189 | ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); | ||
| 3190 | if (ret < 0) | ||
| 3191 | return ret; | ||
| 3192 | |||
| 3193 | if (ret) { | ||
| 3194 | /* | ||
| 3195 | * A rare case were we can have an em for a section of a | ||
| 3196 | * larger extent so we need to make sure that this em | ||
| 3197 | * falls within the extent we've found. If not we just | ||
| 3198 | * bail and go back to ye-olde way of doing things but | ||
| 3199 | * it happens often enough in testing that we need to do | ||
| 3200 | * this dance to make sure. | ||
| 3201 | */ | ||
| 3202 | do { | ||
| 3203 | if (path->slots[0] == 0) { | ||
| 3204 | btrfs_release_path(path); | ||
| 3205 | if (search_start == 0) | ||
| 3206 | return -ENOENT; | ||
| 3207 | search_start--; | ||
| 3208 | goto again; | ||
| 3209 | } | ||
| 3210 | 3324 | ||
| 3211 | path->slots[0]--; | 3325 | /* |
| 3212 | btrfs_item_key_to_cpu(path->nodes[0], &key, | 3326 | * Have to check the extent to the right of us to make sure it doesn't |
| 3213 | path->slots[0]); | 3327 | * fall in our current range. We're ok if the previous extent is in our |
| 3214 | if (key.objectid != btrfs_ino(inode) || | 3328 | * range since the recovery stuff will run us in key order and thus just |
| 3215 | key.type != BTRFS_EXTENT_DATA_KEY) { | 3329 | * drop the part we overwrote. |
| 3216 | btrfs_release_path(path); | 3330 | */ |
| 3217 | return -ENOENT; | 3331 | ret = drop_adjacent_extents(trans, log, inode, em, path); |
| 3218 | } | 3332 | btrfs_release_path(path); |
| 3219 | } while (key.offset > start); | 3333 | path->really_keep_locks = 0; |
| 3334 | if (ret) { | ||
| 3335 | return ret; | ||
| 3336 | } | ||
| 3220 | 3337 | ||
| 3221 | num_bytes = btrfs_file_extent_length(path); | 3338 | if (skip_csum) |
| 3222 | if (key.offset + num_bytes <= start) { | 3339 | return 0; |
| 3223 | btrfs_release_path(path); | ||
| 3224 | return -ENOENT; | ||
| 3225 | } | ||
| 3226 | } | ||
| 3227 | args->src = path->nodes[0]; | ||
| 3228 | next_slot: | ||
| 3229 | btrfs_item_key_to_cpu(path->nodes[0], &key, path->slots[0]); | ||
| 3230 | num_bytes = btrfs_file_extent_length(path); | ||
| 3231 | if (args->nr && | ||
| 3232 | args->start_slot + args->nr == path->slots[0]) { | ||
| 3233 | args->nr++; | ||
| 3234 | } else if (args->nr) { | ||
| 3235 | ret = copy_items(trans, inode, dst_path, args->src, | ||
| 3236 | args->start_slot, args->nr, | ||
| 3237 | LOG_INODE_ALL); | ||
| 3238 | if (ret) | ||
| 3239 | return ret; | ||
| 3240 | args->nr = 1; | ||
| 3241 | args->start_slot = path->slots[0]; | ||
| 3242 | } else if (!args->nr) { | ||
| 3243 | args->nr = 1; | ||
| 3244 | args->start_slot = path->slots[0]; | ||
| 3245 | } | ||
| 3246 | nritems = btrfs_header_nritems(path->nodes[0]); | ||
| 3247 | path->slots[0]++; | ||
| 3248 | if (len < num_bytes) { | ||
| 3249 | /* I _think_ this is ok, envision we write to a | ||
| 3250 | * preallocated space that is adjacent to a previously | ||
| 3251 | * written preallocated space that gets merged when we | ||
| 3252 | * mark this preallocated space written. If we do not | ||
| 3253 | * have the adjacent extent in cache then when we copy | ||
| 3254 | * this extent it could end up being larger than our EM | ||
| 3255 | * thinks it is, which is a-ok, so just set len to 0. | ||
| 3256 | */ | ||
| 3257 | len = 0; | ||
| 3258 | } else { | ||
| 3259 | len -= num_bytes; | ||
| 3260 | } | ||
| 3261 | start = key.offset + num_bytes; | ||
| 3262 | args->next_offset = start; | ||
| 3263 | search_start = start; | ||
| 3264 | 3340 | ||
| 3265 | if (path->slots[0] < nritems) { | 3341 | /* block start is already adjusted for the file extent offset. */ |
| 3266 | if (len) | 3342 | ret = btrfs_lookup_csums_range(log->fs_info->csum_root, |
| 3267 | goto next_slot; | 3343 | em->block_start + csum_offset, |
| 3268 | break; | 3344 | em->block_start + csum_offset + |
| 3269 | } | 3345 | csum_len - 1, &ordered_sums, 0); |
| 3346 | if (ret) | ||
| 3347 | return ret; | ||
| 3270 | 3348 | ||
| 3271 | if (args->nr) { | 3349 | while (!list_empty(&ordered_sums)) { |
| 3272 | ret = copy_items(trans, inode, dst_path, args->src, | 3350 | struct btrfs_ordered_sum *sums = list_entry(ordered_sums.next, |
| 3273 | args->start_slot, args->nr, | 3351 | struct btrfs_ordered_sum, |
| 3274 | LOG_INODE_ALL); | 3352 | list); |
| 3275 | if (ret) | 3353 | if (!ret) |
| 3276 | return ret; | 3354 | ret = btrfs_csum_file_blocks(trans, log, sums); |
| 3277 | args->nr = 0; | 3355 | list_del(&sums->list); |
| 3278 | btrfs_release_path(path); | 3356 | kfree(sums); |
| 3279 | } | ||
| 3280 | } | 3357 | } |
| 3281 | 3358 | ||
| 3282 | return 0; | 3359 | return ret; |
| 3283 | } | 3360 | } |
| 3284 | 3361 | ||
| 3285 | static int btrfs_log_changed_extents(struct btrfs_trans_handle *trans, | 3362 | static int btrfs_log_changed_extents(struct btrfs_trans_handle *trans, |
| 3286 | struct btrfs_root *root, | 3363 | struct btrfs_root *root, |
| 3287 | struct inode *inode, | 3364 | struct inode *inode, |
| 3288 | struct btrfs_path *path, | 3365 | struct btrfs_path *path) |
| 3289 | struct btrfs_path *dst_path) | ||
| 3290 | { | 3366 | { |
| 3291 | struct log_args args; | ||
| 3292 | struct extent_map *em, *n; | 3367 | struct extent_map *em, *n; |
| 3293 | struct list_head extents; | 3368 | struct list_head extents; |
| 3294 | struct extent_map_tree *tree = &BTRFS_I(inode)->extent_tree; | 3369 | struct extent_map_tree *tree = &BTRFS_I(inode)->extent_tree; |
| @@ -3297,8 +3372,6 @@ static int btrfs_log_changed_extents(struct btrfs_trans_handle *trans, | |||
| 3297 | 3372 | ||
| 3298 | INIT_LIST_HEAD(&extents); | 3373 | INIT_LIST_HEAD(&extents); |
| 3299 | 3374 | ||
| 3300 | memset(&args, 0, sizeof(args)); | ||
| 3301 | |||
| 3302 | write_lock(&tree->lock); | 3375 | write_lock(&tree->lock); |
| 3303 | test_gen = root->fs_info->last_trans_committed; | 3376 | test_gen = root->fs_info->last_trans_committed; |
| 3304 | 3377 | ||
| @@ -3331,34 +3404,13 @@ static int btrfs_log_changed_extents(struct btrfs_trans_handle *trans, | |||
| 3331 | 3404 | ||
| 3332 | write_unlock(&tree->lock); | 3405 | write_unlock(&tree->lock); |
| 3333 | 3406 | ||
| 3334 | /* | 3407 | ret = log_one_extent(trans, inode, root, em, path); |
| 3335 | * If the previous EM and the last extent we left off on aren't | ||
| 3336 | * sequential then we need to copy the items we have and redo | ||
| 3337 | * our search | ||
| 3338 | */ | ||
| 3339 | if (args.nr && em->mod_start != args.next_offset) { | ||
| 3340 | ret = copy_items(trans, inode, dst_path, args.src, | ||
| 3341 | args.start_slot, args.nr, | ||
| 3342 | LOG_INODE_ALL); | ||
| 3343 | if (ret) { | ||
| 3344 | free_extent_map(em); | ||
| 3345 | write_lock(&tree->lock); | ||
| 3346 | continue; | ||
| 3347 | } | ||
| 3348 | btrfs_release_path(path); | ||
| 3349 | args.nr = 0; | ||
| 3350 | } | ||
| 3351 | |||
| 3352 | ret = log_one_extent(trans, inode, root, em, path, dst_path, &args); | ||
| 3353 | free_extent_map(em); | 3408 | free_extent_map(em); |
| 3354 | write_lock(&tree->lock); | 3409 | write_lock(&tree->lock); |
| 3355 | } | 3410 | } |
| 3356 | WARN_ON(!list_empty(&extents)); | 3411 | WARN_ON(!list_empty(&extents)); |
| 3357 | write_unlock(&tree->lock); | 3412 | write_unlock(&tree->lock); |
| 3358 | 3413 | ||
| 3359 | if (!ret && args.nr) | ||
| 3360 | ret = copy_items(trans, inode, dst_path, args.src, | ||
| 3361 | args.start_slot, args.nr, LOG_INODE_ALL); | ||
| 3362 | btrfs_release_path(path); | 3414 | btrfs_release_path(path); |
| 3363 | return ret; | 3415 | return ret; |
| 3364 | } | 3416 | } |
| @@ -3551,10 +3603,8 @@ next_slot: | |||
| 3551 | 3603 | ||
| 3552 | log_extents: | 3604 | log_extents: |
| 3553 | if (fast_search) { | 3605 | if (fast_search) { |
| 3554 | btrfs_release_path(path); | ||
| 3555 | btrfs_release_path(dst_path); | 3606 | btrfs_release_path(dst_path); |
| 3556 | ret = btrfs_log_changed_extents(trans, root, inode, path, | 3607 | ret = btrfs_log_changed_extents(trans, root, inode, dst_path); |
| 3557 | dst_path); | ||
| 3558 | if (ret) { | 3608 | if (ret) { |
| 3559 | err = ret; | 3609 | err = ret; |
| 3560 | goto out_unlock; | 3610 | goto out_unlock; |
diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index 886f4ba0f71d..d79b5b620e94 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c | |||
| @@ -4983,6 +4983,7 @@ static int read_one_chunk(struct btrfs_root *root, struct btrfs_key *key, | |||
| 4983 | em->bdev = (struct block_device *)map; | 4983 | em->bdev = (struct block_device *)map; |
| 4984 | em->start = logical; | 4984 | em->start = logical; |
| 4985 | em->len = length; | 4985 | em->len = length; |
| 4986 | em->orig_start = 0; | ||
| 4986 | em->block_start = 0; | 4987 | em->block_start = 0; |
| 4987 | em->block_len = em->len; | 4988 | em->block_len = em->len; |
| 4988 | 4989 | ||
