From: robbieko <robbieko@synology.com>
To: fdmanana@gmail.com
Cc: linux-btrfs <linux-btrfs@vger.kernel.org>,
linux-btrfs-owner@vger.kernel.org
Subject: Re: [PATCH] Btrfs: send, improve clone range
Date: Fri, 29 Mar 2019 16:26:51 +0800 [thread overview]
Message-ID: <5d62997fe230f3f9c849d660a3ce16b2@synology.com> (raw)
In-Reply-To: <CAL3q7H7SOQt-9BVU+0YxoHXNkb7qiY4tN13gogayEH_8GNSK5A@mail.gmail.com>
Filipe Manana 於 2019-03-29 06:52 寫到:
> On Thu, Mar 28, 2019 at 9:41 AM robbieko <robbieko@synology.com> wrote:
>>
>> From: Robbie Ko <robbieko@synology.com>
>>
>> Improve clone_range two use scenarios.
>>
>> 1. Remove the limit of clone inode size
>> We can do partial clone range, so there is no need to limit
>> the inode size.
>
> There is.
> Cloning from a source range that goes beyond the source's i_size
> results in an -EINVAL error returned from the clone ioctl.
>
> Try running fstests btrfs/007, with a seed value of 1553175244 and
> 2000 operations instead of 200:
>
> # /home/fdmanana/git/hub/btrfs-progs/btrfs receive
> /home/fdmanana/btrfs-tests/scratch_1
> ERROR: failed to clone extents to p0/df/d10/f2c: Invalid argument
> At snapshot incr
> failed: '/home/fdmanana/git/hub/btrfs-progs/btrfs receive
> /home/fdmanana/btrfs-tests/scratch_1'
>
This is my fault, fallocate keeps size, which can result in file extent
range > inode size.
So we still need to check if the file range offset + len is greater than
the inode size when cloning
Thanks.
I will fix and send Patch v2.
>
>>
>> 2. In the scenarios of rewrite or clone_range, data_offset
>> rarely matches exactly, so the chance of a clone is missed.
>>
>> e.g.
>> 1. Write a 1M file
>> dd if=/dev/zero of=1M bs=1M count=1
>>
>> 2. Clone 1M file
>> cp --reflink 1M clone
>>
>> 3. Rewrite 4k on the clone file
>> dd if=/dev/zero of=clone bs=4k count=1 conv=notrunc
>>
>> The disk layout is as follows:
>> item 16 key (257 EXTENT_DATA 0) itemoff 15353 itemsize 53
>> extent data disk byte 1103101952 nr 1048576
>> extent data offset 0 nr 1048576 ram 1048576
>> extent compression(none)
>> ...
>> item 22 key (258 EXTENT_DATA 0) itemoff 14959 itemsize 53
>> extent data disk byte 1104150528 nr 4096
>> extent data offset 0 nr 4096 ram 4096
>> extent compression(none)
>> item 23 key (258 EXTENT_DATA 4096) itemoff 14906 itemsize 53
>> extent data disk byte 1103101952 nr 1048576
>> extent data offset 4096 nr 1044480 ram 1048576
>> extent compression(none)
>>
>> When send, inode 258 file offset 4096~1048576 (item 23) has a
>> chance to clone_range, but because data_offset does not match
>> inode 257 (item 16), it causes missed clone and can only transfer
>> actual data.
>>
>> Improve the problem by judging whether the current data_offset
>> has overlap with the file extent item, and if so, adjusting
>> offset and extent_len so that we can clone correctly.
>>
>> Signed-off-by: Robbie Ko <robbieko@synology.com>
>> ---
>> fs/btrfs/send.c | 20 ++++++++++++++++----
>> 1 file changed, 16 insertions(+), 4 deletions(-)
>>
>> diff --git a/fs/btrfs/send.c b/fs/btrfs/send.c
>> index 7ea2d6b..7766b12 100644
>> --- a/fs/btrfs/send.c
>> +++ b/fs/btrfs/send.c
>> @@ -1240,9 +1240,6 @@ static int __iterate_backrefs(u64 ino, u64
>> offset, u64 root, void *ctx_)
>> if (ret < 0)
>> return ret;
>>
>> - if (offset + bctx->data_offset + bctx->extent_len > i_size)
>> - return 0;
>
> And this is why the failure above happens.
>
>> -
>> /*
>> * Make sure we don't consider clones from send_root that are
>> * behind the current inode/offset.
>> @@ -5148,6 +5145,7 @@ static int clone_range(struct send_ctx *sctx,
>> u8 type;
>> u64 ext_len;
>> u64 clone_len;
>> + u64 clone_data_offset;
>
> CC [M] fs/btrfs/send.o
> fs/btrfs/send.c: In function 'process_extent':
> fs/btrfs/send.c:5218:60: warning: 'clone_data_offset' may be used
> uninitialized in this function [-Wmaybe-uninitialized]
> if (btrfs_file_extent_disk_bytenr(leaf, ei) == disk_byte &&
> ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~
> clone_data_offset == data_offset)
> ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> fs/btrfs/send.c:5148:7: note: 'clone_data_offset' was declared here
> u64 clone_data_offset;
> ^~~~~~~~~~~~~~~~~
> LD [M] fs/btrfs/btrfs.o
>
I will fix it in v2 version together.
> $ gcc --version
> gcc --version
> gcc (Debian 6.3.0-18+deb9u1) 6.3.0 20170516
> Copyright (C) 2016 Free Software Foundation, Inc.
>
> Harmless but we shouldn't have warnings, initialize it to something
> impossible (u64(-1) / U64_MAX) or re-structure the change below.
>
>>
>> if (slot >= btrfs_header_nritems(leaf)) {
>> ret = btrfs_next_leaf(clone_root->root, path);
>> @@ -5201,10 +5199,24 @@ static int clone_range(struct send_ctx *sctx,
>> if (key.offset >= clone_root->offset + len)
>> break;
>>
>> + if (btrfs_file_extent_disk_bytenr(leaf, ei) ==
>> disk_byte) {
>> + clone_root->offset = key.offset;
>> + clone_data_offset =
>> btrfs_file_extent_offset(leaf, ei);
>> + if (clone_data_offset < data_offset &&
>> + clone_data_offset + ext_len >
>> data_offset) {
>> + u64 extent_offset;
>> +
>> + extent_offset = data_offset -
>> clone_data_offset;
>> + ext_len -= extent_offset;
>> + clone_data_offset += extent_offset;
>> + clone_root->offset += extent_offset;
>> + }
>> + }
>> +
>> clone_len = min_t(u64, ext_len, len);
>>
>> if (btrfs_file_extent_disk_bytenr(leaf, ei) ==
>> disk_byte &&
>> - btrfs_file_extent_offset(leaf, ei) == data_offset)
>> + clone_data_offset == data_offset)
>> ret = send_clone(sctx, offset, clone_len,
>> clone_root);
>> else
>> ret = send_extent_data(sctx, offset,
>> clone_len);
>> --
>> 1.9.1
>>
next prev parent reply other threads:[~2019-03-29 8:27 UTC|newest]
Thread overview: 4+ messages / expand[flat|nested] mbox.gz Atom feed top
2019-03-28 9:40 [PATCH] Btrfs: send, improve clone range robbieko
2019-03-28 22:52 ` Filipe Manana
2019-03-29 8:26 ` robbieko [this message]
2019-03-31 9:36 ` kbuild test robot
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=5d62997fe230f3f9c849d660a3ce16b2@synology.com \
--to=robbieko@synology.com \
--cc=fdmanana@gmail.com \
--cc=linux-btrfs-owner@vger.kernel.org \
--cc=linux-btrfs@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).