public inbox for linux-btrfs@vger.kernel.org
 help / color / mirror / Atom feed
From: Mark Fasheh <mfasheh@suse.de>
To: Chris Mason <clm@fb.com>
Cc: Josef Bacik <jbacik@fb.com>, David Sterba <dsterba@suse.cz>,
	linux-btrfs@vger.kernel.org, Mark Fasheh <mfasheh@suse.de>
Subject: [PATCH 4/5] btrfs: allow dedupe of same inode
Date: Fri, 26 Jun 2015 14:01:00 -0700	[thread overview]
Message-ID: <1435352461-17689-5-git-send-email-mfasheh@suse.de> (raw)
In-Reply-To: <1435352461-17689-1-git-send-email-mfasheh@suse.de>

clone() supports cloning within an inode so extent-same can do
the same now. This patch fixes up the locking in extent-same to
know about the single-inode case. In addition to that, we add a
check for overlapping ranges, which clone does not allow.

Signed-off-by: Mark Fasheh <mfasheh@suse.de>
Reviewed-by: David Sterba <dsterba@suse.cz>
---
 fs/btrfs/ioctl.c | 76 ++++++++++++++++++++++++++++++++++++++++++++------------
 1 file changed, 60 insertions(+), 16 deletions(-)

diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c
index 8d6887d..83f4679 100644
--- a/fs/btrfs/ioctl.c
+++ b/fs/btrfs/ioctl.c
@@ -2979,27 +2979,61 @@ static int btrfs_extent_same(struct inode *src, u64 loff, u64 olen,
 	int ret;
 	u64 len = olen;
 	struct cmp_pages cmp;
+	int same_inode = 0;
+	u64 same_lock_start = 0;
+	u64 same_lock_len = 0;
 
-	/*
-	 * btrfs_clone() can't handle extents in the same file
-	 * yet. Once that works, we can drop this check and replace it
-	 * with a check for the same inode, but overlapping extents.
-	 */
 	if (src == dst)
-		return -EINVAL;
+		same_inode = 1;
 
 	if (len == 0)
 		return 0;
 
-	btrfs_double_inode_lock(src, dst);
+	if (same_inode) {
+		mutex_lock(&src->i_mutex);
 
-	ret = extent_same_check_offsets(src, loff, &len, olen);
-	if (ret)
-		goto out_unlock;
+		ret = extent_same_check_offsets(src, loff, &len, olen);
+		if (ret)
+			goto out_unlock;
 
-	ret = extent_same_check_offsets(dst, dst_loff, &len, olen);
-	if (ret)
-		goto out_unlock;
+		/*
+		 * Single inode case wants the same checks, except we
+		 * don't want our length pushed out past i_size as
+		 * comparing that data range makes no sense.
+		 *
+		 * extent_same_check_offsets() will do this for an
+		 * unaligned length at i_size, so catch it here and
+		 * reject the request.
+		 *
+		 * This effectively means we require aligned extents
+		 * for the single-inode case, whereas the other cases
+		 * allow an unaligned length so long as it ends at
+		 * i_size.
+		 */
+		if (len != olen) {
+			ret = -EINVAL;
+			goto out_unlock;
+		}
+
+		/* Check for overlapping ranges */
+		if (dst_loff + len > loff && dst_loff < loff + len) {
+			ret = -EINVAL;
+			goto out_unlock;
+		}
+
+		same_lock_start = min_t(u64, loff, dst_loff);
+		same_lock_len = max_t(u64, loff, dst_loff) + len - same_lock_start;
+	} else {
+		btrfs_double_inode_lock(src, dst);
+
+		ret = extent_same_check_offsets(src, loff, &len, olen);
+		if (ret)
+			goto out_unlock;
+
+		ret = extent_same_check_offsets(dst, dst_loff, &len, olen);
+		if (ret)
+			goto out_unlock;
+	}
 
 	/* don't make the dst file partly checksummed */
 	if ((BTRFS_I(src)->flags & BTRFS_INODE_NODATASUM) !=
@@ -3012,18 +3046,28 @@ static int btrfs_extent_same(struct inode *src, u64 loff, u64 olen,
 	if (ret)
 		goto out_unlock;
 
-	btrfs_double_extent_lock(src, loff, dst, dst_loff, len);
+	if (same_inode)
+		lock_extent_range(src, same_lock_start, same_lock_len);
+	else
+		btrfs_double_extent_lock(src, loff, dst, dst_loff, len);
 
 	/* pass original length for comparison so we stay within i_size */
 	ret = btrfs_cmp_data(src, loff, dst, dst_loff, olen, &cmp);
 	if (ret == 0)
 		ret = btrfs_clone(src, dst, loff, olen, len, dst_loff);
 
-	btrfs_double_extent_unlock(src, loff, dst, dst_loff, len);
+	if (same_inode)
+		unlock_extent(&BTRFS_I(src)->io_tree, same_lock_start,
+			      same_lock_start + same_lock_len - 1);
+	else
+		btrfs_double_extent_unlock(src, loff, dst, dst_loff, len);
 
 	btrfs_cmp_data_free(&cmp);
 out_unlock:
-	btrfs_double_inode_unlock(src, dst);
+	if (same_inode)
+		mutex_unlock(&src->i_mutex);
+	else
+		btrfs_double_inode_unlock(src, dst);
 
 	return ret;
 }
-- 
2.1.2


  parent reply	other threads:[~2015-06-26 21:01 UTC|newest]

Thread overview: 14+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2015-06-26 21:00 [PATCH 0/5] btrfs: dedupe fixes, features V4 Mark Fasheh
2015-06-26 21:00 ` [PATCH 1/5] btrfs: pass unaligned length to btrfs_cmp_data() Mark Fasheh
2015-06-26 21:00 ` [PATCH 2/5] btrfs: fix deadlock with extent-same and readpage Mark Fasheh
2015-06-26 21:00 ` [PATCH 3/5] btrfs: fix clone / extent-same deadlocks Mark Fasheh
2015-06-26 21:01 ` Mark Fasheh [this message]
2015-06-26 21:01 ` [PATCH 5/5] btrfs: don't update mtime on deduped inodes Mark Fasheh
2015-06-27 21:44   ` Zygo Blaxell
2015-06-29 17:52     ` Mark Fasheh
2015-06-29 19:35       ` Zygo Blaxell
2015-06-29 20:29         ` Mark Fasheh
  -- strict thread matches above, loose matches on Subject: below --
2015-06-30 21:42 [PATCH 0/5] btrfs: dedupe fixes, features V5 Mark Fasheh
2015-06-30 21:42 ` [PATCH 4/5] btrfs: allow dedupe of same inode Mark Fasheh
2015-06-23 21:28 [PATCH 0/5] btrfs: dedupe fixes, features V3 Mark Fasheh
2015-06-23 21:28 ` [PATCH 4/5] btrfs: allow dedupe of same inode Mark Fasheh
2015-06-22 22:47 [PATCH 0/5] btrfs: dedupe fixes, features V2 Mark Fasheh
2015-06-22 22:47 ` [PATCH 4/5] btrfs: allow dedupe of same inode Mark Fasheh
2015-06-23 14:59   ` David Sterba

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=1435352461-17689-5-git-send-email-mfasheh@suse.de \
    --to=mfasheh@suse.de \
    --cc=clm@fb.com \
    --cc=dsterba@suse.cz \
    --cc=jbacik@fb.com \
    --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