diff mbox

[2/2] On a diff-send, avoid sending PREALLOC extent

Message ID CAOcd+r1ZioBQEykibvDdfx-1gmLfUPFfodNK5Dhnv8OB0EFApw@mail.gmail.com (mailing list archive)
State New, archived
Headers show

Commit Message

Alex Lyakas Jan. 9, 2013, 5:41 p.m. UTC
Subject: [PATCH 2/2] On a diff-send, avoid sending PREALLOC extents, if the
 parent root has only PREALLOC extents on an appropriate
 file range.

This does not fully avoids sending PREALLOC extents, because on full-send or
new inode we need a new send command to do that. But this patch improves
the situation by handling diff-sends.

Signed-off-by: Alex Lyakas <alex.btrfs@zadarastorage.com>
---
 fs/btrfs/send.c |  150 +++++++++++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 146 insertions(+), 4 deletions(-)

 			       struct btrfs_key *ekey)
@@ -3786,15 +3924,15 @@ static int is_extent_unchanged(struct send_ctx *sctx,
 	u8 left_type;
 	u8 right_type;

-	path = alloc_path_for_send();
-	if (!path)
-		return -ENOMEM;
-
 	eb = left_path->nodes[0];
 	slot = left_path->slots[0];
 	ei = btrfs_item_ptr(eb, slot, struct btrfs_file_extent_item);
 	left_type = btrfs_file_extent_type(eb, ei);

+	if (left_type == BTRFS_FILE_EXTENT_PREALLOC) {
+		ret = is_prealloc_extent_unchanged(sctx, left_path, ekey);
+		goto out;
+	}
 	if (left_type != BTRFS_FILE_EXTENT_REG) {
 		ret = 0;
 		goto out;
@@ -3825,6 +3963,10 @@ static int is_extent_unchanged(struct send_ctx *sctx,
 	 * Nothing follows after 8.
 	 */

+	path = alloc_path_for_send();
+	if (!path)
+		return -ENOMEM;
+
 	key.objectid = ekey->objectid;
 	key.type = BTRFS_EXTENT_DATA_KEY;
 	key.offset = ekey->offset;

Comments

Josef Bacik Jan. 14, 2013, 6:45 p.m. UTC | #1
On Wed, Jan 09, 2013 at 10:41:10AM -0700, Alex Lyakas wrote:
> Subject: [PATCH 2/2] On a diff-send, avoid sending PREALLOC extents, if the
>  parent root has only PREALLOC extents on an appropriate
>  file range.
> 
> This does not fully avoids sending PREALLOC extents, because on full-send or
> new inode we need a new send command to do that. But this patch improves
> the situation by handling diff-sends.
> 
> Signed-off-by: Alex Lyakas <alex.btrfs@zadarastorage.com>
> ---

Malformed patch and it confused patchwork, please resend.  Thanks,

Josef
--
To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Alex Lyakas Jan. 21, 2013, 10:33 a.m. UTC | #2
Hi Josef,
I have resent the patches. There are still some "please, no space
before tabs" warnings, which I am not sure how to correct, because I
don't see space before tab in that place. If there is still a problem,
can you please advise what is wrong.

Thanks,
Alex.


On Mon, Jan 14, 2013 at 8:45 PM, Josef Bacik <jbacik@fusionio.com> wrote:
> On Wed, Jan 09, 2013 at 10:41:10AM -0700, Alex Lyakas wrote:
>> Subject: [PATCH 2/2] On a diff-send, avoid sending PREALLOC extents, if the
>>  parent root has only PREALLOC extents on an appropriate
>>  file range.
>>
>> This does not fully avoids sending PREALLOC extents, because on full-send or
>> new inode we need a new send command to do that. But this patch improves
>> the situation by handling diff-sends.
>>
>> Signed-off-by: Alex Lyakas <alex.btrfs@zadarastorage.com>
>> ---
>
> Malformed patch and it confused patchwork, please resend.  Thanks,
>
> Josef
--
To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/fs/btrfs/send.c b/fs/btrfs/send.c
index 5ab584f..456bc3e 100644
--- a/fs/btrfs/send.c
+++ b/fs/btrfs/send.c
@@ -3763,6 +3763,144 @@  out:
 	return ret;
 }

+static int is_prealloc_extent_unchanged(struct send_ctx *sctx,
+			       struct btrfs_path *left_path,
+			       struct btrfs_key *ekey)
+{
+	int ret = 0;
+	struct btrfs_key key;
+	struct btrfs_path *path = NULL;
+	struct extent_buffer *eb;
+	int slot;
+	struct btrfs_key found_key;
+	struct btrfs_file_extent_item *ei;
+	u64 left_len;
+	u64 right_len;
+	u8 right_type;
+
+	eb = left_path->nodes[0];
+	slot = left_path->slots[0];
+	ei = btrfs_item_ptr(eb, slot, struct btrfs_file_extent_item);
+	left_len = btrfs_file_extent_num_bytes(eb, ei);
+
+	/*
+	 * The logic is similar, but much simpler than in is_extent_unchanged().
+	 * We need to check extents on the parent root, and make sure that only
+	 * PREALLOC extents are on the same file range as our current extent.
+	 *
+	 * Following comments will refer to these graphics. L is the left
+	 * extents which we are checking at the moment. 1-8 are the right
+	 * extents that we iterate.
+	 *
+	 * 	  |-----L-----|
+	 * |-1-|-2a-|-3-|-4-|-5-|-6-|
+	 *
+	 * 	  |-----L-----|
+	 * |--1--|-2b-|...(same as above)
+	 *
+	 * Alternative situation. Happens on files where extents got split.
+	 * 	  |-----L-----|
+	 * |-----------7-----------|-6-|
+	 *
+	 * Alternative situation. Happens on files which got larger.
+	 * 	  |-----L-----|
+	 * |-8-|
+	 * Nothing follows after 8.
+	 */
+
+	path = alloc_path_for_send();
+	if (!path)
+		return -ENOMEM;
+
+	key.objectid = ekey->objectid;
+	key.type = BTRFS_EXTENT_DATA_KEY;
+	key.offset = ekey->offset;
+	ret = btrfs_search_slot_for_read(sctx->parent_root, &key, path, 0, 0);
+	if (ret < 0)
+		goto out;
+	if (ret) {
+		ret = 0;
+		goto out;
+	}
+
+	/*
+	 * Handle special case where the right side has no extents at all.
+	 */
+	eb = path->nodes[0];
+	slot = path->slots[0];
+	btrfs_item_key_to_cpu(eb, &found_key, slot);
+	if (found_key.objectid != key.objectid ||
+		found_key.type != key.type) {
+		/*
+		 * We need to send a "prealloc" command, which we don't have yet,
+		 * just send this extent fully.
+		 */
+		ret = 0;
+		goto out;
+	}
+
+	key = found_key;
+	while (key.offset < ekey->offset + left_len) {
+		ei = btrfs_item_ptr(eb, slot, struct btrfs_file_extent_item);
+		right_type = btrfs_file_extent_type(eb, ei);
+		right_len = btrfs_file_extent_num_bytes(eb, ei);
+
+		if (right_type != BTRFS_FILE_EXTENT_PREALLOC) {
+			ret = 0;
+			goto out;
+		}
+
+		/*
+		 * Are we at extent 8? If yes, we know the extent is changed.
+		 * This may only happen on the first iteration.
+		 */
+		if (found_key.offset + right_len <= ekey->offset) {
+			/*
+			 * We need to send a "prealloc" command, which we don't have yet,
+			 * just send this extent fully.
+			 */
+			ret = 0;
+			goto out;
+		}
+
+		/* The right extent is also PREALLOC, so up to here we are ok,
continue checking */
+
+		ret = btrfs_next_item(sctx->parent_root, path);
+		if (ret < 0)
+			goto out;
+		if (!ret) {
+			eb = path->nodes[0];
+			slot = path->slots[0];
+			btrfs_item_key_to_cpu(eb, &found_key, slot);
+		}
+		if (ret || found_key.objectid != key.objectid ||
+		    found_key.type != key.type) {
+			key.offset += right_len;
+			break;
+		} else {
+			if (found_key.offset != key.offset + right_len) {
+				/* Should really not happen */
+				ret = -EIO;
+				goto out;
+			}
+		}
+		key = found_key;
+	}
+
+	/*
+	 * We're now behind the left extent (treat as unchanged) or at the end
+	 * of the right side (treat as changed).
+	 */
+	if (key.offset >= ekey->offset + left_len)
+		ret = 1;
+	else
+		ret = 0;
+
+out:
+	btrfs_free_path(path);
+	return ret;
+}
+
 static int is_extent_unchanged(struct send_ctx *sctx,
 			       struct btrfs_path *left_path,