From patchwork Mon Jan 21 10:30:52 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alex Lyakas X-Patchwork-Id: 2010601 Return-Path: X-Original-To: patchwork-linux-btrfs@patchwork.kernel.org Delivered-To: patchwork-process-083081@patchwork1.kernel.org Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by patchwork1.kernel.org (Postfix) with ESMTP id 3C5133FD1A for ; Mon, 21 Jan 2013 10:31:01 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752655Ab3AUKa6 (ORCPT ); Mon, 21 Jan 2013 05:30:58 -0500 Received: from mail-we0-f176.google.com ([74.125.82.176]:39296 "EHLO mail-we0-f176.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752223Ab3AUKa5 (ORCPT ); Mon, 21 Jan 2013 05:30:57 -0500 Received: by mail-we0-f176.google.com with SMTP id s43so169765wey.7 for ; Mon, 21 Jan 2013 02:30:53 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20120113; h=mime-version:x-received:date:message-id:subject:from:to:cc :content-type:x-gm-message-state; bh=UDRg7y90N74Vj2UfhsoL7WUp2bHAvTh0lyAeBzYsLG4=; b=KJlajJaI/b1xAdmgWUAgi4QYoK71FI8n55l1GS/me4MiFHvgZRlMjS3BZBNAp7VEgo 8qKK7VCiKg83cXg7/hlhiy/HiCV/zTGJ8iUjTQh4bQqNP+AI+sWllI+dL8lygblxvfAM hNrvGwtcunbjoxleMF/4uf2U61Fmor5+eK+OY4w+DIyciLsBmhEY5YWcdjrsPNJMpop/ VPQIZfN8anjcZdhqsBcZ+LlTyj0bGVQUcEen8jo6rF/BCpuWZWaApgiucL53G7x09yha 8D+tzuWJHXi9WUZqIrPXCpQK2YXRGQPeVdXk14zmThmEkH2VzaPmmX369qQBSp0iagIE kiiQ== MIME-Version: 1.0 X-Received: by 10.194.236.68 with SMTP id us4mr25572905wjc.11.1358764253018; Mon, 21 Jan 2013 02:30:53 -0800 (PST) Received: by 10.194.23.3 with HTTP; Mon, 21 Jan 2013 02:30:52 -0800 (PST) Date: Mon, 21 Jan 2013 12:30:52 +0200 Message-ID: Subject: [PATCH 2/2] V2 On a diff-send, avoid sending PREALLOC extents From: Alex Lyakas To: linux-btrfs , Josef Bacik , Alexander Block , Jan Schmidt , Chen Yang Cc: Arne Jansen X-Gm-Message-State: ALoCoQlBpD3HCgiAC63zxVnFful8J3Fy5hWqLamf1f2OrjuZ6ZGL7KkzOxjhaJfuHQ7rEzD+3IjP Sender: linux-btrfs-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-btrfs@vger.kernel.org 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 avoid sending PREALLOC extents, because on full-send or on 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 --- fs/btrfs/send.c | 154 +++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 150 insertions(+), 4 deletions(-) -- 1.7.9.5 -- 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 --git a/fs/btrfs/send.c b/fs/btrfs/send.c index bdef966..a162fa6 100644 --- a/fs/btrfs/send.c +++ b/fs/btrfs/send.c @@ -3763,6 +3763,148 @@ 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, struct btrfs_key *ekey) @@ -3786,15 +3928,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 +3967,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;