Received: by 2002:ad5:474a:0:0:0:0:0 with SMTP id i10csp1992497imu; Fri, 14 Dec 2018 04:11:38 -0800 (PST) X-Google-Smtp-Source: AFSGD/We1NmjQfwIrYN0ZrQ5uYPYBiwgI/EiUbPQ3nDYzosnmxP9S03Yp9aBp2hW5hFAR26AZo9e X-Received: by 2002:a17:902:b20e:: with SMTP id t14mr2674348plr.128.1544789498562; Fri, 14 Dec 2018 04:11:38 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1544789498; cv=none; d=google.com; s=arc-20160816; b=E0uglyQiwu9xz51paXQX5ka4OwIhjDPcVKaoU++LDVJiIPmTjEioF0zIVXCwpiU/9a YFLc2FUfZclSZ+yB01yIvXJeqR/dqUTXAwZq5QJPln1Ze9xeFRnbIWXqyEemR43/5sHD mJOZ94KDuxTCc3f5stB5IqIdAdIHeIFaFaN64kWqpBZb/HSpdAzDz5EKg9otMNg8moMD XoOndKbI9iL3h/IBIXzNDbhSvlptMCeTV+QfUMeko0KBpWKMAoZX2lPqwzaIIKCklIgL GI6dVXuJY5HvbhSs1gH21rGTqKkyCUKEemz5fye3BfijVra70U0iLxsDapwN5/FyJiJq NNUg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:content-transfer-encoding:mime-version :user-agent:references:in-reply-to:message-id:date:subject:cc:to :from:dkim-signature; bh=PK8n+HdKQWfV5aC9Uxa4gjhCcnL3y9K3IaJUltvCLD8=; b=k4Lr4iGg/1lTiGyIm3n/yRLBHZG8jbo85M+x/62nlDn/r1dDaqaM9SRV768MXSwff2 MQa8uddMe9aEEnk5fOWQ3KeWFx6i13UCICOOk8akG6ZtovfXzDeU9AZXt80cFYpU3wZ8 XL/vdgg5/3ueCpTmhSJMQq07qONG8QDpr37K6Zn+JzIYPZ4lWy3vYnzfe6MCHFt7Xb3X w8RhSuengMW+6b/oYVpAFac+vmVKR3G6N1I/1g9VqRcbDOI4Yw31NbHQxDCnW+WOaM+h TwVIqUx8pK57pyLHcZIo7L3Co0jsC73EwkaA5kcC0ZSY9WX3iFk/Jevp/savM+/GXcEt q4mg== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@kernel.org header.s=default header.b=iC3R3QVp; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id r29si2129161pga.477.2018.12.14.04.11.10; Fri, 14 Dec 2018 04:11:38 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=pass header.i=@kernel.org header.s=default header.b=iC3R3QVp; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1731342AbeLNMIs (ORCPT + 99 others); Fri, 14 Dec 2018 07:08:48 -0500 Received: from mail.kernel.org ([198.145.29.99]:54322 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1731003AbeLNMIq (ORCPT ); Fri, 14 Dec 2018 07:08:46 -0500 Received: from localhost (5356596B.cm-6-7b.dynamic.ziggo.nl [83.86.89.107]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPSA id 746CD2147D; Fri, 14 Dec 2018 12:08:45 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=default; t=1544789326; bh=iolrAKp8VOkZWkowjz10hT2MEpX/tEhh9F/RWYmVhac=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=iC3R3QVptwWInORIonjwoSPu2A49GZEWq9+b0O7fYLG5sk5ZoGzfvl1vgafIc7ZxD ecqBS94y07/nM0UAac9Omv4K9Xy/X+B/Cnz2n9selbmMxpOFqyoHJaNY6KXLKuppkH aWRadItC85lzYViTVv3VKVfUaLmUave/9uYunuhk= From: Greg Kroah-Hartman To: linux-kernel@vger.kernel.org Cc: Greg Kroah-Hartman , stable@vger.kernel.org, Robbie Ko , Filipe Manana , David Sterba , Sasha Levin Subject: [PATCH 4.14 38/89] Btrfs: send, fix infinite loop due to directory rename dependencies Date: Fri, 14 Dec 2018 12:59:51 +0100 Message-Id: <20181214115731.570426300@linuxfoundation.org> X-Mailer: git-send-email 2.20.0 In-Reply-To: <20181214115729.658859279@linuxfoundation.org> References: <20181214115729.658859279@linuxfoundation.org> User-Agent: quilt/0.65 X-stable: review X-Patchwork-Hint: ignore MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org 4.14-stable review patch. If anyone has any objections, please let me know. ------------------ [ Upstream commit a4390aee72713d9e73f1132bcdeb17d72fbbf974 ] When doing an incremental send, due to the need of delaying directory move (rename) operations we can end up in infinite loop at apply_children_dir_moves(). An example scenario that triggers this problem is described below, where directory names correspond to the numbers of their respective inodes. Parent snapshot: . |--- 261/ |--- 271/ |--- 266/ |--- 259/ |--- 260/ | |--- 267 | |--- 264/ | |--- 258/ | |--- 257/ | |--- 265/ |--- 268/ |--- 269/ | |--- 262/ | |--- 270/ |--- 272/ | |--- 263/ | |--- 275/ | |--- 274/ |--- 273/ Send snapshot: . |-- 275/ |-- 274/ |-- 273/ |-- 262/ |-- 269/ |-- 258/ |-- 271/ |-- 268/ |-- 267/ |-- 270/ |-- 259/ | |-- 265/ | |-- 272/ |-- 257/ |-- 260/ |-- 264/ |-- 263/ |-- 261/ |-- 266/ When processing inode 257 we delay its move (rename) operation because its new parent in the send snapshot, inode 272, was not yet processed. Then when processing inode 272, we delay the move operation for that inode because inode 274 is its ancestor in the send snapshot. Finally we delay the move operation for inode 274 when processing it because inode 275 is its new parent in the send snapshot and was not yet moved. When finishing processing inode 275, we start to do the move operations that were previously delayed (at apply_children_dir_moves()), resulting in the following iterations: 1) We issue the move operation for inode 274; 2) Because inode 262 depended on the move operation of inode 274 (it was delayed because 274 is its ancestor in the send snapshot), we issue the move operation for inode 262; 3) We issue the move operation for inode 272, because it was delayed by inode 274 too (ancestor of 272 in the send snapshot); 4) We issue the move operation for inode 269 (it was delayed by 262); 5) We issue the move operation for inode 257 (it was delayed by 272); 6) We issue the move operation for inode 260 (it was delayed by 272); 7) We issue the move operation for inode 258 (it was delayed by 269); 8) We issue the move operation for inode 264 (it was delayed by 257); 9) We issue the move operation for inode 271 (it was delayed by 258); 10) We issue the move operation for inode 263 (it was delayed by 264); 11) We issue the move operation for inode 268 (it was delayed by 271); 12) We verify if we can issue the move operation for inode 270 (it was delayed by 271). We detect a path loop in the current state, because inode 267 needs to be moved first before we can issue the move operation for inode 270. So we delay again the move operation for inode 270, this time we will attempt to do it after inode 267 is moved; 13) We issue the move operation for inode 261 (it was delayed by 263); 14) We verify if we can issue the move operation for inode 266 (it was delayed by 263). We detect a path loop in the current state, because inode 270 needs to be moved first before we can issue the move operation for inode 266. So we delay again the move operation for inode 266, this time we will attempt to do it after inode 270 is moved (its move operation was delayed in step 12); 15) We issue the move operation for inode 267 (it was delayed by 268); 16) We verify if we can issue the move operation for inode 266 (it was delayed by 270). We detect a path loop in the current state, because inode 270 needs to be moved first before we can issue the move operation for inode 266. So we delay again the move operation for inode 266, this time we will attempt to do it after inode 270 is moved (its move operation was delayed in step 12). So here we added again the same delayed move operation that we added in step 14; 17) We attempt again to see if we can issue the move operation for inode 266, and as in step 16, we realize we can not due to a path loop in the current state due to a dependency on inode 270. Again we delay inode's 266 rename to happen after inode's 270 move operation, adding the same dependency to the empty stack that we did in steps 14 and 16. The next iteration will pick the same move dependency on the stack (the only entry) and realize again there is still a path loop and then again the same dependency to the stack, over and over, resulting in an infinite loop. So fix this by preventing adding the same move dependency entries to the stack by removing each pending move record from the red black tree of pending moves. This way the next call to get_pending_dir_moves() will not return anything for the current parent inode. A test case for fstests, with this reproducer, follows soon. Signed-off-by: Robbie Ko Reviewed-by: Filipe Manana [Wrote changelog with example and more clear explanation] Signed-off-by: Filipe Manana Signed-off-by: David Sterba Signed-off-by: Sasha Levin --- fs/btrfs/send.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/fs/btrfs/send.c b/fs/btrfs/send.c index baf5a4cd7ffc..3f22af96d63b 100644 --- a/fs/btrfs/send.c +++ b/fs/btrfs/send.c @@ -3354,7 +3354,8 @@ static void free_pending_move(struct send_ctx *sctx, struct pending_dir_move *m) kfree(m); } -static void tail_append_pending_moves(struct pending_dir_move *moves, +static void tail_append_pending_moves(struct send_ctx *sctx, + struct pending_dir_move *moves, struct list_head *stack) { if (list_empty(&moves->list)) { @@ -3365,6 +3366,10 @@ static void tail_append_pending_moves(struct pending_dir_move *moves, list_add_tail(&moves->list, stack); list_splice_tail(&list, stack); } + if (!RB_EMPTY_NODE(&moves->node)) { + rb_erase(&moves->node, &sctx->pending_dir_moves); + RB_CLEAR_NODE(&moves->node); + } } static int apply_children_dir_moves(struct send_ctx *sctx) @@ -3379,7 +3384,7 @@ static int apply_children_dir_moves(struct send_ctx *sctx) return 0; INIT_LIST_HEAD(&stack); - tail_append_pending_moves(pm, &stack); + tail_append_pending_moves(sctx, pm, &stack); while (!list_empty(&stack)) { pm = list_first_entry(&stack, struct pending_dir_move, list); @@ -3390,7 +3395,7 @@ static int apply_children_dir_moves(struct send_ctx *sctx) goto out; pm = get_pending_dir_moves(sctx, parent_ino); if (pm) - tail_append_pending_moves(pm, &stack); + tail_append_pending_moves(sctx, pm, &stack); } return 0; -- 2.19.1