From: Matt Robinson <git@nerdoftheherd.com>
To: Chris Mason <clm@fb.com>, Josef Bacik <jbacik@fb.com>,
David Sterba <dsterba@suse.cz>
Cc: Mark Fasheh <mfasheh@suse.de>,
linux-btrfs@vger.kernel.org,
Matt Robinson <git@nerdoftheherd.com>
Subject: [PATCH 1/1] btrfs: Align EOF length to block in extent_same
Date: Mon, 26 Jan 2015 18:05:51 +0000 [thread overview]
Message-ID: <1422295551-25402-1-git-send-email-git@nerdoftheherd.com> (raw)
It is not currently possible to deduplicate the last block of files
whose size is not a multiple of the block size, as the btrfs_extent_same
ioctl returns -EINVAL if offset + size is greater than the file size or
is not aligned to the fs block size. This prevents btrfs from freeing up
the last extent in the file, causing gains from deduplication to be
smaller than expected.
To resolve this, allow unaligned offset + length values to be passed to
btrfs_ioctl_file_extent_same if offset + length = file size for both src
and dest. This is implemented in the same way as in btrfs_ioctl_clone.
Signed-off-by: Matt Robinson <git@nerdoftheherd.com>
---
fs/btrfs/ioctl.c | 21 ++++++++++++++-------
1 file changed, 14 insertions(+), 7 deletions(-)
diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c
index d49fe8a..a407d8a 100644
--- a/fs/btrfs/ioctl.c
+++ b/fs/btrfs/ioctl.c
@@ -2871,14 +2871,16 @@ static int btrfs_cmp_data(struct inode *src, u64 loff, struct inode *dst,
return ret;
}
-static int extent_same_check_offsets(struct inode *inode, u64 off, u64 len)
+static int extent_same_check_offsets(struct inode *inode, u64 off, u64 len,
+ u64 len_aligned)
{
u64 bs = BTRFS_I(inode)->root->fs_info->sb->s_blocksize;
if (off + len > inode->i_size || off + len < off)
return -EINVAL;
+
/* Check that we are block aligned - btrfs_clone() requires this */
- if (!IS_ALIGNED(off, bs) || !IS_ALIGNED(off + len, bs))
+ if (!IS_ALIGNED(off, bs) || !IS_ALIGNED(off + len_aligned, bs))
return -EINVAL;
return 0;
@@ -2888,6 +2890,8 @@ static int btrfs_extent_same(struct inode *src, u64 loff, u64 len,
struct inode *dst, u64 dst_loff)
{
int ret;
+ u64 len_aligned = len;
+ u64 bs = BTRFS_I(src)->root->fs_info->sb->s_blocksize;
/*
* btrfs_clone() can't handle extents in the same file
@@ -2899,11 +2903,15 @@ static int btrfs_extent_same(struct inode *src, u64 loff, u64 len,
btrfs_double_lock(src, loff, dst, dst_loff, len);
- ret = extent_same_check_offsets(src, loff, len);
+ /* if we extend to both eofs, continue to block boundaries */
+ if (loff + len == src->i_size && dst_loff + len == dst->i_size)
+ len_aligned = ALIGN(src->i_size, bs) - loff;
+
+ ret = extent_same_check_offsets(src, loff, len, len_aligned);
if (ret)
goto out_unlock;
- ret = extent_same_check_offsets(dst, dst_loff, len);
+ ret = extent_same_check_offsets(dst, dst_loff, len, len_aligned);
if (ret)
goto out_unlock;
@@ -2916,7 +2924,7 @@ static int btrfs_extent_same(struct inode *src, u64 loff, u64 len,
ret = btrfs_cmp_data(src, loff, dst, dst_loff, len);
if (ret == 0)
- ret = btrfs_clone(src, dst, loff, len, len, dst_loff);
+ ret = btrfs_clone(src, dst, loff, len, len_aligned, dst_loff);
out_unlock:
btrfs_double_unlock(src, loff, dst, dst_loff, len);
@@ -3162,8 +3170,7 @@ static void clone_update_extent_map(struct inode *inode,
* @inode: Inode to clone to
* @off: Offset within source to start clone from
* @olen: Original length, passed by user, of range to clone
- * @olen_aligned: Block-aligned value of olen, extent_same uses
- * identical values here
+ * @olen_aligned: Block-aligned value of olen
* @destoff: Offset within @inode to start clone
*/
static int btrfs_clone(struct inode *src, struct inode *inode,
--
2.1.0
next reply other threads:[~2015-01-26 18:33 UTC|newest]
Thread overview: 6+ messages / expand[flat|nested] mbox.gz Atom feed top
2015-01-26 18:05 Matt Robinson [this message]
2015-01-28 12:55 ` [PATCH 1/1] btrfs: Align EOF length to block in extent_same David Sterba
2015-01-28 19:46 ` Matt Robinson
2015-03-02 20:59 ` Matt Robinson
2015-03-03 0:27 ` Zygo Blaxell
2015-04-11 19:17 ` Matt Robinson
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=1422295551-25402-1-git-send-email-git@nerdoftheherd.com \
--to=git@nerdoftheherd.com \
--cc=clm@fb.com \
--cc=dsterba@suse.cz \
--cc=jbacik@fb.com \
--cc=linux-btrfs@vger.kernel.org \
--cc=mfasheh@suse.de \
/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).