diff options
author | Chris Mason <clm@fb.com> | 2015-10-21 21:23:59 -0400 |
---|---|---|
committer | Chris Mason <clm@fb.com> | 2015-10-21 21:23:59 -0400 |
commit | a408365c62762c30419018587cffd2b89836434e (patch) | |
tree | 4b2ddabcf60970141fa9758153493b2b1d95acfe | |
parent | a0d58e48db58801a0e764e9b9c87e1782d390fcb (diff) | |
parent | 0305cd5f7fca85dae392b9ba85b116896eb7c1c7 (diff) |
Merge branch 'integration-4.4' of git://git.kernel.org/pub/scm/linux/kernel/git/fdmanana/linux into for-linus-4.4
-rw-r--r-- | fs/btrfs/extent_io.c | 8 | ||||
-rw-r--r-- | fs/btrfs/inode.c | 82 | ||||
-rw-r--r-- | fs/btrfs/ioctl.c | 195 | ||||
-rw-r--r-- | fs/btrfs/send.c | 210 |
4 files changed, 407 insertions, 88 deletions
diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c index ecb1204468c3..6e6df34d74f0 100644 --- a/fs/btrfs/extent_io.c +++ b/fs/btrfs/extent_io.c | |||
@@ -3070,8 +3070,12 @@ static int __do_readpage(struct extent_io_tree *tree, | |||
3070 | 3070 | ||
3071 | set_extent_uptodate(tree, cur, cur + iosize - 1, | 3071 | set_extent_uptodate(tree, cur, cur + iosize - 1, |
3072 | &cached, GFP_NOFS); | 3072 | &cached, GFP_NOFS); |
3073 | unlock_extent_cached(tree, cur, cur + iosize - 1, | 3073 | if (parent_locked) |
3074 | &cached, GFP_NOFS); | 3074 | free_extent_state(cached); |
3075 | else | ||
3076 | unlock_extent_cached(tree, cur, | ||
3077 | cur + iosize - 1, | ||
3078 | &cached, GFP_NOFS); | ||
3075 | cur = cur + iosize; | 3079 | cur = cur + iosize; |
3076 | pg_offset += iosize; | 3080 | pg_offset += iosize; |
3077 | continue; | 3081 | continue; |
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 8161afc32fa0..5ce55f6eefce 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c | |||
@@ -4216,6 +4216,47 @@ static int truncate_space_check(struct btrfs_trans_handle *trans, | |||
4216 | 4216 | ||
4217 | } | 4217 | } |
4218 | 4218 | ||
4219 | static int truncate_inline_extent(struct inode *inode, | ||
4220 | struct btrfs_path *path, | ||
4221 | struct btrfs_key *found_key, | ||
4222 | const u64 item_end, | ||
4223 | const u64 new_size) | ||
4224 | { | ||
4225 | struct extent_buffer *leaf = path->nodes[0]; | ||
4226 | int slot = path->slots[0]; | ||
4227 | struct btrfs_file_extent_item *fi; | ||
4228 | u32 size = (u32)(new_size - found_key->offset); | ||
4229 | struct btrfs_root *root = BTRFS_I(inode)->root; | ||
4230 | |||
4231 | fi = btrfs_item_ptr(leaf, slot, struct btrfs_file_extent_item); | ||
4232 | |||
4233 | if (btrfs_file_extent_compression(leaf, fi) != BTRFS_COMPRESS_NONE) { | ||
4234 | loff_t offset = new_size; | ||
4235 | loff_t page_end = ALIGN(offset, PAGE_CACHE_SIZE); | ||
4236 | |||
4237 | /* | ||
4238 | * Zero out the remaining of the last page of our inline extent, | ||
4239 | * instead of directly truncating our inline extent here - that | ||
4240 | * would be much more complex (decompressing all the data, then | ||
4241 | * compressing the truncated data, which might be bigger than | ||
4242 | * the size of the inline extent, resize the extent, etc). | ||
4243 | * We release the path because to get the page we might need to | ||
4244 | * read the extent item from disk (data not in the page cache). | ||
4245 | */ | ||
4246 | btrfs_release_path(path); | ||
4247 | return btrfs_truncate_page(inode, offset, page_end - offset, 0); | ||
4248 | } | ||
4249 | |||
4250 | btrfs_set_file_extent_ram_bytes(leaf, fi, size); | ||
4251 | size = btrfs_file_extent_calc_inline_size(size); | ||
4252 | btrfs_truncate_item(root, path, size, 1); | ||
4253 | |||
4254 | if (test_bit(BTRFS_ROOT_REF_COWS, &root->state)) | ||
4255 | inode_sub_bytes(inode, item_end + 1 - new_size); | ||
4256 | |||
4257 | return 0; | ||
4258 | } | ||
4259 | |||
4219 | /* | 4260 | /* |
4220 | * this can truncate away extent items, csum items and directory items. | 4261 | * this can truncate away extent items, csum items and directory items. |
4221 | * It starts at a high offset and removes keys until it can't find | 4262 | * It starts at a high offset and removes keys until it can't find |
@@ -4410,27 +4451,40 @@ search_again: | |||
4410 | * special encodings | 4451 | * special encodings |
4411 | */ | 4452 | */ |
4412 | if (!del_item && | 4453 | if (!del_item && |
4413 | btrfs_file_extent_compression(leaf, fi) == 0 && | ||
4414 | btrfs_file_extent_encryption(leaf, fi) == 0 && | 4454 | btrfs_file_extent_encryption(leaf, fi) == 0 && |
4415 | btrfs_file_extent_other_encoding(leaf, fi) == 0) { | 4455 | btrfs_file_extent_other_encoding(leaf, fi) == 0) { |
4416 | u32 size = new_size - found_key.offset; | ||
4417 | |||
4418 | if (test_bit(BTRFS_ROOT_REF_COWS, &root->state)) | ||
4419 | inode_sub_bytes(inode, item_end + 1 - | ||
4420 | new_size); | ||
4421 | 4456 | ||
4422 | /* | 4457 | /* |
4423 | * update the ram bytes to properly reflect | 4458 | * Need to release path in order to truncate a |
4424 | * the new size of our item | 4459 | * compressed extent. So delete any accumulated |
4460 | * extent items so far. | ||
4425 | */ | 4461 | */ |
4426 | btrfs_set_file_extent_ram_bytes(leaf, fi, size); | 4462 | if (btrfs_file_extent_compression(leaf, fi) != |
4427 | size = | 4463 | BTRFS_COMPRESS_NONE && pending_del_nr) { |
4428 | btrfs_file_extent_calc_inline_size(size); | 4464 | err = btrfs_del_items(trans, root, path, |
4429 | btrfs_truncate_item(root, path, size, 1); | 4465 | pending_del_slot, |
4466 | pending_del_nr); | ||
4467 | if (err) { | ||
4468 | btrfs_abort_transaction(trans, | ||
4469 | root, | ||
4470 | err); | ||
4471 | goto error; | ||
4472 | } | ||
4473 | pending_del_nr = 0; | ||
4474 | } | ||
4475 | |||
4476 | err = truncate_inline_extent(inode, path, | ||
4477 | &found_key, | ||
4478 | item_end, | ||
4479 | new_size); | ||
4480 | if (err) { | ||
4481 | btrfs_abort_transaction(trans, | ||
4482 | root, err); | ||
4483 | goto error; | ||
4484 | } | ||
4430 | } else if (test_bit(BTRFS_ROOT_REF_COWS, | 4485 | } else if (test_bit(BTRFS_ROOT_REF_COWS, |
4431 | &root->state)) { | 4486 | &root->state)) { |
4432 | inode_sub_bytes(inode, item_end + 1 - | 4487 | inode_sub_bytes(inode, item_end + 1 - new_size); |
4433 | found_key.offset); | ||
4434 | } | 4488 | } |
4435 | } | 4489 | } |
4436 | delete: | 4490 | delete: |
diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c index a30d32b901da..685df7e1b24e 100644 --- a/fs/btrfs/ioctl.c +++ b/fs/btrfs/ioctl.c | |||
@@ -3327,6 +3327,150 @@ static void clone_update_extent_map(struct inode *inode, | |||
3327 | &BTRFS_I(inode)->runtime_flags); | 3327 | &BTRFS_I(inode)->runtime_flags); |
3328 | } | 3328 | } |
3329 | 3329 | ||
3330 | /* | ||
3331 | * Make sure we do not end up inserting an inline extent into a file that has | ||
3332 | * already other (non-inline) extents. If a file has an inline extent it can | ||
3333 | * not have any other extents and the (single) inline extent must start at the | ||
3334 | * file offset 0. Failing to respect these rules will lead to file corruption, | ||
3335 | * resulting in EIO errors on read/write operations, hitting BUG_ON's in mm, etc | ||
3336 | * | ||
3337 | * We can have extents that have been already written to disk or we can have | ||
3338 | * dirty ranges still in delalloc, in which case the extent maps and items are | ||
3339 | * created only when we run delalloc, and the delalloc ranges might fall outside | ||
3340 | * the range we are currently locking in the inode's io tree. So we check the | ||
3341 | * inode's i_size because of that (i_size updates are done while holding the | ||
3342 | * i_mutex, which we are holding here). | ||
3343 | * We also check to see if the inode has a size not greater than "datal" but has | ||
3344 | * extents beyond it, due to an fallocate with FALLOC_FL_KEEP_SIZE (and we are | ||
3345 | * protected against such concurrent fallocate calls by the i_mutex). | ||
3346 | * | ||
3347 | * If the file has no extents but a size greater than datal, do not allow the | ||
3348 | * copy because we would need turn the inline extent into a non-inline one (even | ||
3349 | * with NO_HOLES enabled). If we find our destination inode only has one inline | ||
3350 | * extent, just overwrite it with the source inline extent if its size is less | ||
3351 | * than the source extent's size, or we could copy the source inline extent's | ||
3352 | * data into the destination inode's inline extent if the later is greater then | ||
3353 | * the former. | ||
3354 | */ | ||
3355 | static int clone_copy_inline_extent(struct inode *src, | ||
3356 | struct inode *dst, | ||
3357 | struct btrfs_trans_handle *trans, | ||
3358 | struct btrfs_path *path, | ||
3359 | struct btrfs_key *new_key, | ||
3360 | const u64 drop_start, | ||
3361 | const u64 datal, | ||
3362 | const u64 skip, | ||
3363 | const u64 size, | ||
3364 | char *inline_data) | ||
3365 | { | ||
3366 | struct btrfs_root *root = BTRFS_I(dst)->root; | ||
3367 | const u64 aligned_end = ALIGN(new_key->offset + datal, | ||
3368 | root->sectorsize); | ||
3369 | int ret; | ||
3370 | struct btrfs_key key; | ||
3371 | |||
3372 | if (new_key->offset > 0) | ||
3373 | return -EOPNOTSUPP; | ||
3374 | |||
3375 | key.objectid = btrfs_ino(dst); | ||
3376 | key.type = BTRFS_EXTENT_DATA_KEY; | ||
3377 | key.offset = 0; | ||
3378 | ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); | ||
3379 | if (ret < 0) { | ||
3380 | return ret; | ||
3381 | } else if (ret > 0) { | ||
3382 | if (path->slots[0] >= btrfs_header_nritems(path->nodes[0])) { | ||
3383 | ret = btrfs_next_leaf(root, path); | ||
3384 | if (ret < 0) | ||
3385 | return ret; | ||
3386 | else if (ret > 0) | ||
3387 | goto copy_inline_extent; | ||
3388 | } | ||
3389 | btrfs_item_key_to_cpu(path->nodes[0], &key, path->slots[0]); | ||
3390 | if (key.objectid == btrfs_ino(dst) && | ||
3391 | key.type == BTRFS_EXTENT_DATA_KEY) { | ||
3392 | ASSERT(key.offset > 0); | ||
3393 | return -EOPNOTSUPP; | ||
3394 | } | ||
3395 | } else if (i_size_read(dst) <= datal) { | ||
3396 | struct btrfs_file_extent_item *ei; | ||
3397 | u64 ext_len; | ||
3398 | |||
3399 | /* | ||
3400 | * If the file size is <= datal, make sure there are no other | ||
3401 | * extents following (can happen do to an fallocate call with | ||
3402 | * the flag FALLOC_FL_KEEP_SIZE). | ||
3403 | */ | ||
3404 | ei = btrfs_item_ptr(path->nodes[0], path->slots[0], | ||
3405 | struct btrfs_file_extent_item); | ||
3406 | /* | ||
3407 | * If it's an inline extent, it can not have other extents | ||
3408 | * following it. | ||
3409 | */ | ||
3410 | if (btrfs_file_extent_type(path->nodes[0], ei) == | ||
3411 | BTRFS_FILE_EXTENT_INLINE) | ||
3412 | goto copy_inline_extent; | ||
3413 | |||
3414 | ext_len = btrfs_file_extent_num_bytes(path->nodes[0], ei); | ||
3415 | if (ext_len > aligned_end) | ||
3416 | return -EOPNOTSUPP; | ||
3417 | |||
3418 | ret = btrfs_next_item(root, path); | ||
3419 | if (ret < 0) { | ||
3420 | return ret; | ||
3421 | } else if (ret == 0) { | ||
3422 | btrfs_item_key_to_cpu(path->nodes[0], &key, | ||
3423 | path->slots[0]); | ||
3424 | if (key.objectid == btrfs_ino(dst) && | ||
3425 | key.type == BTRFS_EXTENT_DATA_KEY) | ||
3426 | return -EOPNOTSUPP; | ||
3427 | } | ||
3428 | } | ||
3429 | |||
3430 | copy_inline_extent: | ||
3431 | /* | ||
3432 | * We have no extent items, or we have an extent at offset 0 which may | ||
3433 | * or may not be inlined. All these cases are dealt the same way. | ||
3434 | */ | ||
3435 | if (i_size_read(dst) > datal) { | ||
3436 | /* | ||
3437 | * If the destination inode has an inline extent... | ||
3438 | * This would require copying the data from the source inline | ||
3439 | * extent into the beginning of the destination's inline extent. | ||
3440 | * But this is really complex, both extents can be compressed | ||
3441 | * or just one of them, which would require decompressing and | ||
3442 | * re-compressing data (which could increase the new compressed | ||
3443 | * size, not allowing the compressed data to fit anymore in an | ||
3444 | * inline extent). | ||
3445 | * So just don't support this case for now (it should be rare, | ||
3446 | * we are not really saving space when cloning inline extents). | ||
3447 | */ | ||
3448 | return -EOPNOTSUPP; | ||
3449 | } | ||
3450 | |||
3451 | btrfs_release_path(path); | ||
3452 | ret = btrfs_drop_extents(trans, root, dst, drop_start, aligned_end, 1); | ||
3453 | if (ret) | ||
3454 | return ret; | ||
3455 | ret = btrfs_insert_empty_item(trans, root, path, new_key, size); | ||
3456 | if (ret) | ||
3457 | return ret; | ||
3458 | |||
3459 | if (skip) { | ||
3460 | const u32 start = btrfs_file_extent_calc_inline_size(0); | ||
3461 | |||
3462 | memmove(inline_data + start, inline_data + start + skip, datal); | ||
3463 | } | ||
3464 | |||
3465 | write_extent_buffer(path->nodes[0], inline_data, | ||
3466 | btrfs_item_ptr_offset(path->nodes[0], | ||
3467 | path->slots[0]), | ||
3468 | size); | ||
3469 | inode_add_bytes(dst, datal); | ||
3470 | |||
3471 | return 0; | ||
3472 | } | ||
3473 | |||
3330 | /** | 3474 | /** |
3331 | * btrfs_clone() - clone a range from inode file to another | 3475 | * btrfs_clone() - clone a range from inode file to another |
3332 | * | 3476 | * |
@@ -3593,21 +3737,6 @@ process_slot: | |||
3593 | } else if (type == BTRFS_FILE_EXTENT_INLINE) { | 3737 | } else if (type == BTRFS_FILE_EXTENT_INLINE) { |
3594 | u64 skip = 0; | 3738 | u64 skip = 0; |
3595 | u64 trim = 0; | 3739 | u64 trim = 0; |
3596 | u64 aligned_end = 0; | ||
3597 | |||
3598 | /* | ||
3599 | * Don't copy an inline extent into an offset | ||
3600 | * greater than zero. Having an inline extent | ||
3601 | * at such an offset results in chaos as btrfs | ||
3602 | * isn't prepared for such cases. Just skip | ||
3603 | * this case for the same reasons as commented | ||
3604 | * at btrfs_ioctl_clone(). | ||
3605 | */ | ||
3606 | if (last_dest_end > 0) { | ||
3607 | ret = -EOPNOTSUPP; | ||
3608 | btrfs_end_transaction(trans, root); | ||
3609 | goto out; | ||
3610 | } | ||
3611 | 3740 | ||
3612 | if (off > key.offset) { | 3741 | if (off > key.offset) { |
3613 | skip = off - key.offset; | 3742 | skip = off - key.offset; |
@@ -3625,42 +3754,22 @@ process_slot: | |||
3625 | size -= skip + trim; | 3754 | size -= skip + trim; |
3626 | datal -= skip + trim; | 3755 | datal -= skip + trim; |
3627 | 3756 | ||
3628 | aligned_end = ALIGN(new_key.offset + datal, | 3757 | ret = clone_copy_inline_extent(src, inode, |
3629 | root->sectorsize); | 3758 | trans, path, |
3630 | ret = btrfs_drop_extents(trans, root, inode, | 3759 | &new_key, |
3631 | drop_start, | 3760 | drop_start, |
3632 | aligned_end, | 3761 | datal, |
3633 | 1); | 3762 | skip, size, buf); |
3634 | if (ret) { | 3763 | if (ret) { |
3635 | if (ret != -EOPNOTSUPP) | 3764 | if (ret != -EOPNOTSUPP) |
3636 | btrfs_abort_transaction(trans, | 3765 | btrfs_abort_transaction(trans, |
3637 | root, ret); | 3766 | root, |
3638 | btrfs_end_transaction(trans, root); | 3767 | ret); |
3639 | goto out; | ||
3640 | } | ||
3641 | |||
3642 | ret = btrfs_insert_empty_item(trans, root, path, | ||
3643 | &new_key, size); | ||
3644 | if (ret) { | ||
3645 | btrfs_abort_transaction(trans, root, | ||
3646 | ret); | ||
3647 | btrfs_end_transaction(trans, root); | 3768 | btrfs_end_transaction(trans, root); |
3648 | goto out; | 3769 | goto out; |
3649 | } | 3770 | } |
3650 | |||
3651 | if (skip) { | ||
3652 | u32 start = | ||
3653 | btrfs_file_extent_calc_inline_size(0); | ||
3654 | memmove(buf+start, buf+start+skip, | ||
3655 | datal); | ||
3656 | } | ||
3657 | |||
3658 | leaf = path->nodes[0]; | 3771 | leaf = path->nodes[0]; |
3659 | slot = path->slots[0]; | 3772 | slot = path->slots[0]; |
3660 | write_extent_buffer(leaf, buf, | ||
3661 | btrfs_item_ptr_offset(leaf, slot), | ||
3662 | size); | ||
3663 | inode_add_bytes(inode, datal); | ||
3664 | } | 3773 | } |
3665 | 3774 | ||
3666 | /* If we have an implicit hole (NO_HOLES feature). */ | 3775 | /* If we have an implicit hole (NO_HOLES feature). */ |
diff --git a/fs/btrfs/send.c b/fs/btrfs/send.c index b5d47b9400ba..355a458cba1a 100644 --- a/fs/btrfs/send.c +++ b/fs/btrfs/send.c | |||
@@ -1434,16 +1434,6 @@ verbose_printk(KERN_DEBUG "btrfs: find_extent_clone: data_offset=%llu, " | |||
1434 | } | 1434 | } |
1435 | 1435 | ||
1436 | if (cur_clone_root) { | 1436 | if (cur_clone_root) { |
1437 | if (compressed != BTRFS_COMPRESS_NONE) { | ||
1438 | /* | ||
1439 | * Offsets given by iterate_extent_inodes() are relative | ||
1440 | * to the start of the extent, we need to add logical | ||
1441 | * offset from the file extent item. | ||
1442 | * (See why at backref.c:check_extent_in_eb()) | ||
1443 | */ | ||
1444 | cur_clone_root->offset += btrfs_file_extent_offset(eb, | ||
1445 | fi); | ||
1446 | } | ||
1447 | *found = cur_clone_root; | 1437 | *found = cur_clone_root; |
1448 | ret = 0; | 1438 | ret = 0; |
1449 | } else { | 1439 | } else { |
@@ -2353,8 +2343,14 @@ static int send_subvol_begin(struct send_ctx *sctx) | |||
2353 | } | 2343 | } |
2354 | 2344 | ||
2355 | TLV_PUT_STRING(sctx, BTRFS_SEND_A_PATH, name, namelen); | 2345 | TLV_PUT_STRING(sctx, BTRFS_SEND_A_PATH, name, namelen); |
2356 | TLV_PUT_UUID(sctx, BTRFS_SEND_A_UUID, | 2346 | |
2357 | sctx->send_root->root_item.uuid); | 2347 | if (!btrfs_is_empty_uuid(sctx->send_root->root_item.received_uuid)) |
2348 | TLV_PUT_UUID(sctx, BTRFS_SEND_A_UUID, | ||
2349 | sctx->send_root->root_item.received_uuid); | ||
2350 | else | ||
2351 | TLV_PUT_UUID(sctx, BTRFS_SEND_A_UUID, | ||
2352 | sctx->send_root->root_item.uuid); | ||
2353 | |||
2358 | TLV_PUT_U64(sctx, BTRFS_SEND_A_CTRANSID, | 2354 | TLV_PUT_U64(sctx, BTRFS_SEND_A_CTRANSID, |
2359 | le64_to_cpu(sctx->send_root->root_item.ctransid)); | 2355 | le64_to_cpu(sctx->send_root->root_item.ctransid)); |
2360 | if (parent_root) { | 2356 | if (parent_root) { |
@@ -4687,6 +4683,171 @@ tlv_put_failure: | |||
4687 | return ret; | 4683 | return ret; |
4688 | } | 4684 | } |
4689 | 4685 | ||
4686 | static int send_extent_data(struct send_ctx *sctx, | ||
4687 | const u64 offset, | ||
4688 | const u64 len) | ||
4689 | { | ||
4690 | u64 sent = 0; | ||
4691 | |||
4692 | if (sctx->flags & BTRFS_SEND_FLAG_NO_FILE_DATA) | ||
4693 | return send_update_extent(sctx, offset, len); | ||
4694 | |||
4695 | while (sent < len) { | ||
4696 | u64 size = len - sent; | ||
4697 | int ret; | ||
4698 | |||
4699 | if (size > BTRFS_SEND_READ_SIZE) | ||
4700 | size = BTRFS_SEND_READ_SIZE; | ||
4701 | ret = send_write(sctx, offset + sent, size); | ||
4702 | if (ret < 0) | ||
4703 | return ret; | ||
4704 | if (!ret) | ||
4705 | break; | ||
4706 | sent += ret; | ||
4707 | } | ||
4708 | return 0; | ||
4709 | } | ||
4710 | |||
4711 | static int clone_range(struct send_ctx *sctx, | ||
4712 | struct clone_root *clone_root, | ||
4713 | const u64 disk_byte, | ||
4714 | u64 data_offset, | ||
4715 | u64 offset, | ||
4716 | u64 len) | ||
4717 | { | ||
4718 | struct btrfs_path *path; | ||
4719 | struct btrfs_key key; | ||
4720 | int ret; | ||
4721 | |||
4722 | path = alloc_path_for_send(); | ||
4723 | if (!path) | ||
4724 | return -ENOMEM; | ||
4725 | |||
4726 | /* | ||
4727 | * We can't send a clone operation for the entire range if we find | ||
4728 | * extent items in the respective range in the source file that | ||
4729 | * refer to different extents or if we find holes. | ||
4730 | * So check for that and do a mix of clone and regular write/copy | ||
4731 | * operations if needed. | ||
4732 | * | ||
4733 | * Example: | ||
4734 | * | ||
4735 | * mkfs.btrfs -f /dev/sda | ||
4736 | * mount /dev/sda /mnt | ||
4737 | * xfs_io -f -c "pwrite -S 0xaa 0K 100K" /mnt/foo | ||
4738 | * cp --reflink=always /mnt/foo /mnt/bar | ||
4739 | * xfs_io -c "pwrite -S 0xbb 50K 50K" /mnt/foo | ||
4740 | * btrfs subvolume snapshot -r /mnt /mnt/snap | ||
4741 | * | ||
4742 | * If when we send the snapshot and we are processing file bar (which | ||
4743 | * has a higher inode number than foo) we blindly send a clone operation | ||
4744 | * for the [0, 100K[ range from foo to bar, the receiver ends up getting | ||
4745 | * a file bar that matches the content of file foo - iow, doesn't match | ||
4746 | * the content from bar in the original filesystem. | ||
4747 | */ | ||
4748 | key.objectid = clone_root->ino; | ||
4749 | key.type = BTRFS_EXTENT_DATA_KEY; | ||
4750 | key.offset = clone_root->offset; | ||
4751 | ret = btrfs_search_slot(NULL, clone_root->root, &key, path, 0, 0); | ||
4752 | if (ret < 0) | ||
4753 | goto out; | ||
4754 | if (ret > 0 && path->slots[0] > 0) { | ||
4755 | btrfs_item_key_to_cpu(path->nodes[0], &key, path->slots[0] - 1); | ||
4756 | if (key.objectid == clone_root->ino && | ||
4757 | key.type == BTRFS_EXTENT_DATA_KEY) | ||
4758 | path->slots[0]--; | ||
4759 | } | ||
4760 | |||
4761 | while (true) { | ||
4762 | struct extent_buffer *leaf = path->nodes[0]; | ||
4763 | int slot = path->slots[0]; | ||
4764 | struct btrfs_file_extent_item *ei; | ||
4765 | u8 type; | ||
4766 | u64 ext_len; | ||
4767 | u64 clone_len; | ||
4768 | |||
4769 | if (slot >= btrfs_header_nritems(leaf)) { | ||
4770 | ret = btrfs_next_leaf(clone_root->root, path); | ||
4771 | if (ret < 0) | ||
4772 | goto out; | ||
4773 | else if (ret > 0) | ||
4774 | break; | ||
4775 | continue; | ||
4776 | } | ||
4777 | |||
4778 | btrfs_item_key_to_cpu(leaf, &key, slot); | ||
4779 | |||
4780 | /* | ||
4781 | * We might have an implicit trailing hole (NO_HOLES feature | ||
4782 | * enabled). We deal with it after leaving this loop. | ||
4783 | */ | ||
4784 | if (key.objectid != clone_root->ino || | ||
4785 | key.type != BTRFS_EXTENT_DATA_KEY) | ||
4786 | break; | ||
4787 | |||
4788 | ei = btrfs_item_ptr(leaf, slot, struct btrfs_file_extent_item); | ||
4789 | type = btrfs_file_extent_type(leaf, ei); | ||
4790 | if (type == BTRFS_FILE_EXTENT_INLINE) { | ||
4791 | ext_len = btrfs_file_extent_inline_len(leaf, slot, ei); | ||
4792 | ext_len = PAGE_CACHE_ALIGN(ext_len); | ||
4793 | } else { | ||
4794 | ext_len = btrfs_file_extent_num_bytes(leaf, ei); | ||
4795 | } | ||
4796 | |||
4797 | if (key.offset + ext_len <= clone_root->offset) | ||
4798 | goto next; | ||
4799 | |||
4800 | if (key.offset > clone_root->offset) { | ||
4801 | /* Implicit hole, NO_HOLES feature enabled. */ | ||
4802 | u64 hole_len = key.offset - clone_root->offset; | ||
4803 | |||
4804 | if (hole_len > len) | ||
4805 | hole_len = len; | ||
4806 | ret = send_extent_data(sctx, offset, hole_len); | ||
4807 | if (ret < 0) | ||
4808 | goto out; | ||
4809 | |||
4810 | len -= hole_len; | ||
4811 | if (len == 0) | ||
4812 | break; | ||
4813 | offset += hole_len; | ||
4814 | clone_root->offset += hole_len; | ||
4815 | data_offset += hole_len; | ||
4816 | } | ||
4817 | |||
4818 | if (key.offset >= clone_root->offset + len) | ||
4819 | break; | ||
4820 | |||
4821 | clone_len = min_t(u64, ext_len, len); | ||
4822 | |||
4823 | if (btrfs_file_extent_disk_bytenr(leaf, ei) == disk_byte && | ||
4824 | btrfs_file_extent_offset(leaf, ei) == data_offset) | ||
4825 | ret = send_clone(sctx, offset, clone_len, clone_root); | ||
4826 | else | ||
4827 | ret = send_extent_data(sctx, offset, clone_len); | ||
4828 | |||
4829 | if (ret < 0) | ||
4830 | goto out; | ||
4831 | |||
4832 | len -= clone_len; | ||
4833 | if (len == 0) | ||
4834 | break; | ||
4835 | offset += clone_len; | ||
4836 | clone_root->offset += clone_len; | ||
4837 | data_offset += clone_len; | ||
4838 | next: | ||
4839 | path->slots[0]++; | ||
4840 | } | ||
4841 | |||
4842 | if (len > 0) | ||
4843 | ret = send_extent_data(sctx, offset, len); | ||
4844 | else | ||
4845 | ret = 0; | ||
4846 | out: | ||
4847 | btrfs_free_path(path); | ||
4848 | return ret; | ||
4849 | } | ||
4850 | |||
4690 | static int send_write_or_clone(struct send_ctx *sctx, | 4851 | static int send_write_or_clone(struct send_ctx *sctx, |
4691 | struct btrfs_path *path, | 4852 | struct btrfs_path *path, |
4692 | struct btrfs_key *key, | 4853 | struct btrfs_key *key, |
@@ -4695,9 +4856,7 @@ static int send_write_or_clone(struct send_ctx *sctx, | |||
4695 | int ret = 0; | 4856 | int ret = 0; |
4696 | struct btrfs_file_extent_item *ei; | 4857 | struct btrfs_file_extent_item *ei; |
4697 | u64 offset = key->offset; | 4858 | u64 offset = key->offset; |
4698 | u64 pos = 0; | ||
4699 | u64 len; | 4859 | u64 len; |
4700 | u32 l; | ||
4701 | u8 type; | 4860 | u8 type; |
4702 | u64 bs = sctx->send_root->fs_info->sb->s_blocksize; | 4861 | u64 bs = sctx->send_root->fs_info->sb->s_blocksize; |
4703 | 4862 | ||
@@ -4725,22 +4884,15 @@ static int send_write_or_clone(struct send_ctx *sctx, | |||
4725 | } | 4884 | } |
4726 | 4885 | ||
4727 | if (clone_root && IS_ALIGNED(offset + len, bs)) { | 4886 | if (clone_root && IS_ALIGNED(offset + len, bs)) { |
4728 | ret = send_clone(sctx, offset, len, clone_root); | 4887 | u64 disk_byte; |
4729 | } else if (sctx->flags & BTRFS_SEND_FLAG_NO_FILE_DATA) { | 4888 | u64 data_offset; |
4730 | ret = send_update_extent(sctx, offset, len); | 4889 | |
4890 | disk_byte = btrfs_file_extent_disk_bytenr(path->nodes[0], ei); | ||
4891 | data_offset = btrfs_file_extent_offset(path->nodes[0], ei); | ||
4892 | ret = clone_range(sctx, clone_root, disk_byte, data_offset, | ||
4893 | offset, len); | ||
4731 | } else { | 4894 | } else { |
4732 | while (pos < len) { | 4895 | ret = send_extent_data(sctx, offset, len); |
4733 | l = len - pos; | ||
4734 | if (l > BTRFS_SEND_READ_SIZE) | ||
4735 | l = BTRFS_SEND_READ_SIZE; | ||
4736 | ret = send_write(sctx, pos + offset, l); | ||
4737 | if (ret < 0) | ||
4738 | goto out; | ||
4739 | if (!ret) | ||
4740 | break; | ||
4741 | pos += ret; | ||
4742 | } | ||
4743 | ret = 0; | ||
4744 | } | 4896 | } |
4745 | out: | 4897 | out: |
4746 | return ret; | 4898 | return ret; |