Received: by 2002:a25:c593:0:0:0:0:0 with SMTP id v141csp4103489ybe; Mon, 9 Sep 2019 04:21:49 -0700 (PDT) X-Google-Smtp-Source: APXvYqwhQ4TeUxhRz2yvPH/WyM5m+ofFKFsoZHeWUSYxi4FYZ369hurqq5weNmHxuNbJC02DwI7Q X-Received: by 2002:a50:d718:: with SMTP id t24mr21299523edi.168.1568028109806; Mon, 09 Sep 2019 04:21:49 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1568028109; cv=none; d=google.com; s=arc-20160816; b=PwEnNJ2YcENAp1zhxFR9rxX2hwOJ6U4vlASiP68SO2L32/HWob/9d8Y5TwyePeYOEc nyFppGLE7oo9DqykctSHWjAjyw6FyNDur6w0gRUBDGqVKTCeXUh4theubDiqNZnGM8ms EgPfXwzuNaQzYII3PuI5RR1i0929tWI3jOVGzwKjPRZt4m9MEiepjak5aUEasIFwQ6hd GHBLdjwUIyr+BQrwseYyaqqovCdbgYaK0RQSPCXZMe1VdYrEB0hu4VBcgjBoxWk1MHZN BfxwsrebuQ4THl6bPPwUI2U7SymIArcF02faufIw0yTUFv74ohmrVXWZNmn1MGbZWWlB FJ2A== 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=tVP7+F0wyI1RrZPtcfsJ6bFqWFKVgt1wQlm9EmUcni4=; b=BA/Iblj49R40fjliNJYuvnGSRqnt0HOVeYY0RMy1hJAn3TVAlE8vgqc3AdjvxcWdlr GxG1r+O1JhwSNgip4Sf1sXKVlLAy1TT5f75YIWZ/wmNB73g6LVW1nwoMPaFcqVnsXeN+ dn/woDiczldEsf/E50IyKEzDCUFQe7uzYeu4pX7OK9m6XQEkZPbafpvcKrBkS/tZuJj6 SACDeBJsCdY6zMmFpC0ZNVW0QCxahMdDqBXtQf6a5jXkK+bFHUKeqObYS2xUfQq0bkcZ VOkKGc394eKyfM/JpjN9NHfO6FvsB6cpgNV5b3l2I/8jigdB9LwHhsj0ExElMlG4nYUj 1bbQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@kernel.org header.s=default header.b=pJXSrVlm; 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 qo10si7150036ejb.358.2019.09.09.04.21.26; Mon, 09 Sep 2019 04:21:49 -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=pJXSrVlm; 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 S1730080AbfIHMpW (ORCPT + 99 others); Sun, 8 Sep 2019 08:45:22 -0400 Received: from mail.kernel.org ([198.145.29.99]:60522 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1730054AbfIHMpR (ORCPT ); Sun, 8 Sep 2019 08:45:17 -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 520BD21927; Sun, 8 Sep 2019 12:45:16 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=default; t=1567946716; bh=KbH5ChOBjcIWqsXWjjoaJyYcDXLRXH80frt6AgaOd78=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=pJXSrVlmvOOb8rUOX/xr62YNZpCAPoYBB3bBOiFPcdBec1WiwHEWI8wMY5bo6A8dI I8exPFPAT5XX6DwzlHlpdKjhriDtMC4CMsYcxwwhrpSRU/p4zyHLNLuEVtsKmXlS9n +hVY2ceU1zvj0ISe5ELOqKrWgr2LYwj/7q8jrWSo= 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.14 14/40] vfs: fix page locking deadlocks when deduping files Date: Sun, 8 Sep 2019 13:41:47 +0100 Message-Id: <20190908121121.267771539@linuxfoundation.org> X-Mailer: git-send-email 2.23.0 In-Reply-To: <20190908121114.260662089@linuxfoundation.org> References: <20190908121114.260662089@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 d6f8bfb0f7942..38a8bcccf0dd0 100644 --- a/fs/read_write.c +++ b/fs/read_write.c @@ -1882,10 +1882,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; @@ -1901,10 +1898,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. @@ -1942,10 +1961,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); @@ -1957,8 +1990,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