Received: by 2002:a25:c593:0:0:0:0:0 with SMTP id v141csp4122060ybe; Mon, 9 Sep 2019 04:41:41 -0700 (PDT) X-Google-Smtp-Source: APXvYqz+1xcpysMP3kEnTbyUy7pGGuKb9Wh8hCU2PDhP2lo5xHiHRnS+1BqzSQkZTn0tZMpE/qba X-Received: by 2002:a17:906:3715:: with SMTP id d21mr18748234ejc.24.1568029301069; Mon, 09 Sep 2019 04:41:41 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1568029301; cv=none; d=google.com; s=arc-20160816; b=gVtPk5i0NYhHaT2Oo3j3WCfbbR0X1fxpWs+WaF6Ti/ex4PS4X9wO52z5LQVo+2vytp Lu6hK/1r/3ukX32FrR6xW1c4e8PVX3MmO8ZXyVkriSr7/L7mxt5Ihk+isUHc9evZo5gJ 79yVOJRMhd4vXzzc/OXNr0M4M8oQ4PMIolQNOYGZVybrG8norIHgyV/rT1mVP4Ju08ql z+BeqkOs8kIB03+2eJ9baROVsxEXGOhQ/lAoDkMfEtWPUsfu1d5BemDh2mGanLrbJJOP lz6Vw+grLsMjO1p4FQKGsrB9qfn3y6z3bhZDZ45hHjsXquQJKWfgXkObBiMPDJQU1WsM PDew== 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=OL6gaiI8PQM+t9BrYBAqb8vRIFIv3+H+fyDfHKHFyeE=; b=IwjaXgKmdCmhpRySxBVT11w/ZWWVSScoZw01gqubQmSR6t45/mk4JbCMeGQOc/FY1Z ufyWS8e9n9Ekpgz4MCvZOoiSIaU8ZH18/82sPeT/ioRxwwc/56E36pCkh1u7e3AxnLEK 3P7BXz1CPjaKkQj4006+JYYaOsZFlTA0ALoQevwwBWShaWdurSzPzFxvmQbTY4gYmWI0 NBGXVi44FJMPDf7Pnv6BYv0idZJu5r7QDU5+kXxd+tOLfgzZUcqLwpmoJSNu8YfnDpY7 LXj1WmdU0WEeNpn0cNx/Gqlsow6tg/TaSACdVfTxsKYoL3jtSs+NPlyYBObRHU1tYYGD 9mHA== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@kernel.org header.s=default header.b=YPoaQr8V; 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 d27si9470737ede.381.2019.09.09.04.41.15; Mon, 09 Sep 2019 04:41:41 -0700 (PDT) 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=YPoaQr8V; 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 S1730842AbfIHMr6 (ORCPT + 99 others); Sun, 8 Sep 2019 08:47:58 -0400 Received: from mail.kernel.org ([198.145.29.99]:36614 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728551AbfIHMry (ORCPT ); Sun, 8 Sep 2019 08:47:54 -0400 Received: from localhost (unknown [62.28.240.114]) (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 EDA02218AF; Sun, 8 Sep 2019 12:47:52 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=default; t=1567946873; bh=BE1PsLywpsazAx69c7rAKAN5MCKzJisnv2Hf7MFQlnY=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=YPoaQr8VCc/JymH+l545ZCl0YJMhe9RWn0hnFZhCKNNKLLyJBjPwsZC5NeC0HVP3E peGs5HQw79YAGtGmeO7SSPCi6luPmz4C6x5zlqlqqWH1Z0s3CV5X5TQtiG8lvJ8CAC lR/W1cVFg+onUUdQu3z+5dcfzQMN7PIRcfP9igRw= From: Greg Kroah-Hartman To: linux-kernel@vger.kernel.org Cc: Greg Kroah-Hartman , stable@vger.kernel.org, "Darrick J. Wong" , Bill ODonnell , "Matthew Wilcox (Oracle)" , Sasha Levin Subject: [PATCH 4.19 31/57] vfs: fix page locking deadlocks when deduping files Date: Sun, 8 Sep 2019 13:41:55 +0100 Message-Id: <20190908121137.427908611@linuxfoundation.org> X-Mailer: git-send-email 2.23.0 In-Reply-To: <20190908121125.608195329@linuxfoundation.org> References: <20190908121125.608195329@linuxfoundation.org> User-Agent: quilt/0.66 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 [ Upstream commit edc58dd0123b552453a74369bd0c8d890b497b4b ] When dedupe wants to use the page cache to compare parts of two files for dedupe, we must be very careful to handle locking correctly. The current code doesn't do this. It must lock and unlock the page only once if the two pages are the same, since the overlapping range check doesn't catch this when blocksize < pagesize. If the pages are distinct but from the same file, we must observe page locking order and lock them in order of increasing offset to avoid clashing with writeback locking. Fixes: 876bec6f9bbfcb3 ("vfs: refactor clone/dedupe_file_range common functions") Signed-off-by: Darrick J. Wong Reviewed-by: Bill O'Donnell Reviewed-by: Matthew Wilcox (Oracle) Signed-off-by: Sasha Levin --- fs/read_write.c | 49 +++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 41 insertions(+), 8 deletions(-) diff --git a/fs/read_write.c b/fs/read_write.c index 85fd7a8ee29eb..5fb5ee5b8cd70 100644 --- a/fs/read_write.c +++ b/fs/read_write.c @@ -1888,10 +1888,7 @@ int vfs_clone_file_range(struct file *file_in, loff_t pos_in, } EXPORT_SYMBOL(vfs_clone_file_range); -/* - * Read a page's worth of file data into the page cache. Return the page - * locked. - */ +/* Read a page's worth of file data into the page cache. */ static struct page *vfs_dedupe_get_page(struct inode *inode, loff_t offset) { struct address_space *mapping; @@ -1907,10 +1904,32 @@ static struct page *vfs_dedupe_get_page(struct inode *inode, loff_t offset) put_page(page); return ERR_PTR(-EIO); } - lock_page(page); return page; } +/* + * Lock two pages, ensuring that we lock in offset order if the pages are from + * the same file. + */ +static void vfs_lock_two_pages(struct page *page1, struct page *page2) +{ + /* Always lock in order of increasing index. */ + if (page1->index > page2->index) + swap(page1, page2); + + lock_page(page1); + if (page1 != page2) + lock_page(page2); +} + +/* Unlock two pages, being careful not to unlock the same page twice. */ +static void vfs_unlock_two_pages(struct page *page1, struct page *page2) +{ + unlock_page(page1); + if (page1 != page2) + unlock_page(page2); +} + /* * Compare extents of two files to see if they are the same. * Caller must have locked both inodes to prevent write races. @@ -1948,10 +1967,24 @@ int vfs_dedupe_file_range_compare(struct inode *src, loff_t srcoff, dest_page = vfs_dedupe_get_page(dest, destoff); if (IS_ERR(dest_page)) { error = PTR_ERR(dest_page); - unlock_page(src_page); put_page(src_page); goto out_error; } + + vfs_lock_two_pages(src_page, dest_page); + + /* + * Now that we've locked both pages, make sure they're still + * mapped to the file data we're interested in. If not, + * someone is invalidating pages on us and we lose. + */ + if (!PageUptodate(src_page) || !PageUptodate(dest_page) || + src_page->mapping != src->i_mapping || + dest_page->mapping != dest->i_mapping) { + same = false; + goto unlock; + } + src_addr = kmap_atomic(src_page); dest_addr = kmap_atomic(dest_page); @@ -1963,8 +1996,8 @@ int vfs_dedupe_file_range_compare(struct inode *src, loff_t srcoff, kunmap_atomic(dest_addr); kunmap_atomic(src_addr); - unlock_page(dest_page); - unlock_page(src_page); +unlock: + vfs_unlock_two_pages(src_page, dest_page); put_page(dest_page); put_page(src_page); -- 2.20.1