From patchwork Thu Jan 5 08:24:57 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: robbieko X-Patchwork-Id: 9498627 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id C9BFF60235 for ; Thu, 5 Jan 2017 08:27:25 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id BB0E52818E for ; Thu, 5 Jan 2017 08:27:25 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id AFCD72819A; Thu, 5 Jan 2017 08:27:25 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.8 required=2.0 tests=BAYES_00,DKIM_SIGNED, RCVD_IN_DNSWL_HI,T_DKIM_INVALID autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 1CCB128173 for ; Thu, 5 Jan 2017 08:27:25 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1033272AbdAEI1L (ORCPT ); Thu, 5 Jan 2017 03:27:11 -0500 Received: from synology.com ([59.124.61.242]:39661 "EHLO synology.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1033230AbdAEI0d (ORCPT ); Thu, 5 Jan 2017 03:26:33 -0500 Received: from localhost.localdomain (unknown [10.12.12.46]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-SHA256 (128/128 bits)) (No client certificate requested) (Authenticated sender: robbieko@synology.com) by synology.com (Postfix) with ESMTPSA id 537376BA99D; Thu, 5 Jan 2017 16:25:22 +0800 (CST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=synology.com; s=123; t=1483604722; bh=CydX8vLApbwk4NPOODyXwi0asFAPI+nNoHmZPw+p/bU=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=qRq2b1/Jftr6wEPm82e7NSVoN6ianZ1sMZMLiagXLbWexJSSz6v5UTcugs9GAeavs soZNeNSITf/mKtZeZ1rp8hOVkFCby8lMhyxNN2S77o2H2W32sScB1tSEbP3AgUYPj0 vAdIgz6sOzTim+9i6I0+8hE41/jKUihk/QkjV/x4= From: robbieko To: linux-btrfs@vger.kernel.org Cc: Robbie Ko Subject: [PATCH v3 3/6] Btrfs: incremental send, fix not necessary waiting for rmdir operation Date: Thu, 5 Jan 2017 16:24:57 +0800 Message-Id: <1483604700-21017-4-git-send-email-robbieko@synology.com> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1483604700-21017-1-git-send-email-robbieko@synology.com> References: <1483604700-21017-1-git-send-email-robbieko@synology.com> X-MailScanner-ID: 537376BA99D.AB897 X-MailScanner: Found to be clean X-MailScanner-MCPCheck: MCP-Clean, MCP-Checker (score=0, required 80) X-MailScanner-SpamCheck: not spam (whitelisted), SpamAssassin (not cached, score=-0.889, required 4.5, ALL_TRUSTED -1.00, DKIM_SIGNED 0.10, T_DKIM_INVALID 0.01, URIBL_BLOCKED 0.00) X-MailScanner-From: robbieko@synology.com Sender: linux-btrfs-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-btrfs@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP From: Robbie Ko Under certain situations, an incremental send operation can delay rmdir operation when processing inode 258, but it is not necessary, because dir258 is empty. Example scenario: Parent snapshot: |---- dir258/ (ino 258, gen 27) |---- dir257/ (ino 257, gen 27) |---- dir259/ (ino 259, gen 27) Send snapshot: |---- new_dir259/ (ino 259, gen 38) |---- new_dir258/ (ino 258, gen 38) |---- new_dir257/ (ino 257, gen 38) rmdir dir258/dir257 mkdir o257-38-0 mkdir o258-38-0 chown o257-38-0 - uid=0, gid=0 chmod o257-38-0 - mode=0755 rename dir258 -> o258-27-0 -----> dir is empty, but waiting o257-38-0 mkdir o259-38-0 chown o258-38-0 - uid=0, gid=0 chmod o258-38-0 - mode=0755 rmdir dir259 rename o259-38-0 -> new_dir259 utimes chown new_dir259 - uid=0, gid=0 chmod new_dir259 - mode=0755 rename o258-38-0 -> new_dir259/new_dir258 utimes new_dir259/new_dir258 utimes new_dir259 rename o257-38-0 -> new_dir259/new_dir258/new_dir257 rmdir o258-27-0 -----> when o257-38-0 finish, delete utimes new_dir259/new_dir258/new_dir257 utimes new_dir259/new_dir258 utimes new_dir259 While computing the send stream the following steps happen: 1) While processing inode 257 we delete dir258/dir257 immediately. After create o257-38-0, we then delay its rename operation because its new parent in the send snapshot, inode 258, was not yet processed and therefore not yet renamed. 2) On processing inode 258, we need to check if all under files are done before rmdir dir258. However, the waiting o257-38-0 (ino 257) will mislead the check making it think dir257 (ino 257) is still there. dir258 will be orphanized at first but in fact it has become empty. Fix this by adding generation to waiting_dir_move struct, so can_rmdir can use it to correct the result. Signed-off-by: Robbie Ko --- V3: improve the change log fs/btrfs/send.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/fs/btrfs/send.c b/fs/btrfs/send.c index 22eca86..eaf1c92 100644 --- a/fs/btrfs/send.c +++ b/fs/btrfs/send.c @@ -237,6 +237,7 @@ struct pending_dir_move { struct waiting_dir_move { struct rb_node node; u64 ino; + u64 gen; /* * There might be some directory that could not be removed because it * was waiting for this directory inode to be moved first. Therefore @@ -2930,6 +2931,7 @@ static int can_rmdir(struct send_ctx *sctx, u64 dir, u64 dir_gen, struct btrfs_key found_key; struct btrfs_key loc; struct btrfs_dir_item *di; + u64 gen; /* * Don't try to rmdir the top/root subvolume dir. @@ -2969,8 +2971,13 @@ static int can_rmdir(struct send_ctx *sctx, u64 dir, u64 dir_gen, struct btrfs_dir_item); btrfs_dir_item_key_to_cpu(path->nodes[0], di, &loc); + ret = get_inode_info(root, loc.objectid, NULL, &gen, NULL, + NULL, NULL, NULL); + if (ret < 0) + goto out; + dm = get_waiting_dir_move(sctx, loc.objectid); - if (dm) { + if (dm && dm->gen == gen) { struct orphan_dir_info *odi; odi = add_orphan_dir_info(sctx, dir); @@ -3010,7 +3017,8 @@ static int is_waiting_for_move(struct send_ctx *sctx, u64 ino) return entry != NULL; } -static int add_waiting_dir_move(struct send_ctx *sctx, u64 ino, bool orphanized) +static int add_waiting_dir_move(struct send_ctx *sctx, u64 ino, u64 gen, + bool orphanized) { struct rb_node **p = &sctx->waiting_dir_moves.rb_node; struct rb_node *parent = NULL; @@ -3020,6 +3028,7 @@ static int add_waiting_dir_move(struct send_ctx *sctx, u64 ino, bool orphanized) if (!dm) return -ENOMEM; dm->ino = ino; + dm->gen = gen; dm->rmdir_ino = 0; dm->orphanized = orphanized; @@ -3117,7 +3126,7 @@ static int add_pending_dir_move(struct send_ctx *sctx, goto out; } - ret = add_waiting_dir_move(sctx, pm->ino, is_orphan); + ret = add_waiting_dir_move(sctx, pm->ino, pm->gen, is_orphan); if (ret) goto out;