Received: by 2002:a05:6a10:8c0a:0:0:0:0 with SMTP id go10csp1710188pxb; Mon, 8 Mar 2021 04:37:53 -0800 (PST) X-Google-Smtp-Source: ABdhPJw7BGrdAv83zsqgDWsQj1+y1mhUGzGGvdedTEaXRwjXsAG9wxZmW+Coo6qgeSwEmt4BhKT2 X-Received: by 2002:a17:906:d790:: with SMTP id pj16mr14520776ejb.255.1615207073702; Mon, 08 Mar 2021 04:37:53 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1615207073; cv=none; d=google.com; s=arc-20160816; b=FXNLeG/mroAdOjlhB/SfBTp+XDvoICYaugFs3sIX6hlbSrpvMtDc6dHtvZiXQid0IC pAMxPG4YnmSGeaHSKX0MNzMqojSsve57xlADpU2eE13GxFl3hIYmzXguThHmKsgpTfxy W1Zu9dSPtUfvFr62RuW1uGz1UDLDZs7qug0zoDtKK8P8t2cl0yApRG7qhxUKHoLXrI2S 8XGd8OEvKQ64StrDBRhxTwRnCWb7DXqcEeVI4EtYSvME0MTnPmhen/oZEw4we8shXVR2 qMEnZQ2MB7oChyHT7FEYkdYaF63H6E+DmLwCO1qSWaRFKXRJTdIweuOfdNl060q2exqN oipg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :user-agent:references:in-reply-to:message-id:date:subject:cc:to :from:dkim-signature; bh=V9UgTcS9Z55daSqgHZJr7r6aXqSu1zU9Qh9H40uzOOE=; b=VLSusDWqViujdUAdF5XSIQ7/Xn7SYS5el1effpgyzPYx+I/v9yetddkaQDe6ucQP0b ND1DqKhsgVu3NkM1EZJUWPB8ujJzGq/QZl0v049figNizl0TqJgEHSxXmGBTsD490Esf Roz+KVg9WdjSNlu5fdtRs98jAmEzyr8XRr3Nhb5V7zRDpdsiNg/WNRN3doDAiewCcfLg Le6FGh/+1CUl8AfPuG9mJWzPOzwcUpw2+Kb8L1XhcJ0IbeN9EgRcewYUUvh7gqUOcr67 uiJ0l7SvNv9P36GYjHorfrS2P2wtcCNxLQfwRQNkys/ORBSUHqZp1n2E2fpaMHK3GoEB XwQA== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linuxfoundation.org header.s=korg header.b=Q0M5+ylE; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linuxfoundation.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [23.128.96.18]) by mx.google.com with ESMTP id u25si6578325edo.148.2021.03.08.04.37.31; Mon, 08 Mar 2021 04:37:53 -0800 (PST) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) client-ip=23.128.96.18; Authentication-Results: mx.google.com; dkim=pass header.i=@linuxfoundation.org header.s=korg header.b=Q0M5+ylE; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linuxfoundation.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231556AbhCHMe3 (ORCPT + 99 others); Mon, 8 Mar 2021 07:34:29 -0500 Received: from mail.kernel.org ([198.145.29.99]:42672 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231201AbhCHMdw (ORCPT ); Mon, 8 Mar 2021 07:33:52 -0500 Received: by mail.kernel.org (Postfix) with ESMTPSA id 5AF6F651C9; Mon, 8 Mar 2021 12:33:51 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=linuxfoundation.org; s=korg; t=1615206832; bh=WVR5SFIiijpd+K2DkWSwe0Lamd/GkLDhrCWBA0qE8tE=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=Q0M5+ylE5kKp4r2Wa9sLgoeSxMZcfs6kWSgDTOcNx4ICcIDcn+C5nNyxOtIDhmgnY /kYIqlOfc6Fti2lkQEeuUBuTrP75cPBpRxJnEUcDG76yaVegSzbN4nP/BOJ2Ypoo/c EMbwSF/yQUNNbhW7sKTszhEZgFYsCyQz4lpng6gI= From: Greg Kroah-Hartman To: linux-kernel@vger.kernel.org Cc: Greg Kroah-Hartman , stable@vger.kernel.org, Anand Jain , Josef Bacik , Filipe Manana , David Sterba Subject: [PATCH 5.10 09/42] btrfs: fix race between swap file activation and snapshot creation Date: Mon, 8 Mar 2021 13:30:35 +0100 Message-Id: <20210308122718.589190577@linuxfoundation.org> X-Mailer: git-send-email 2.30.1 In-Reply-To: <20210308122718.120213856@linuxfoundation.org> References: <20210308122718.120213856@linuxfoundation.org> User-Agent: quilt/0.66 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org From: Filipe Manana commit dd0734f2a866f9d619d4abf97c3d71bcdee40ea9 upstream. When creating a snapshot we check if the current number of swap files, in the root, is non-zero, and if it is, we error out and warn that we can not create the snapshot because there are active swap files. However this is racy because when a task started activation of a swap file, another task might have started already snapshot creation and might have seen the counter for the number of swap files as zero. This means that after the swap file is activated we may end up with a snapshot of the same root successfully created, and therefore when the first write to the swap file happens it has to fall back into COW mode, which should never happen for active swap files. Basically what can happen is: 1) Task A starts snapshot creation and enters ioctl.c:create_snapshot(). There it sees that root->nr_swapfiles has a value of 0 so it continues; 2) Task B enters btrfs_swap_activate(). It is not aware that another task started snapshot creation but it did not finish yet. It increments root->nr_swapfiles from 0 to 1; 3) Task B checks that the file meets all requirements to be an active swap file - it has NOCOW set, there are no snapshots for the inode's root at the moment, no file holes, no reflinked extents, etc; 4) Task B returns success and now the file is an active swap file; 5) Task A commits the transaction to create the snapshot and finishes. The swap file's extents are now shared between the original root and the snapshot; 6) A write into an extent of the swap file is attempted - there is a snapshot of the file's root, so we fall back to COW mode and therefore the physical location of the extent changes on disk. So fix this by taking the snapshot lock during swap file activation before locking the extent range, as that is the order in which we lock these during buffered writes. Fixes: ed46ff3d42378 ("Btrfs: support swap files") CC: stable@vger.kernel.org # 5.4+ Reviewed-by: Anand Jain Reviewed-by: Josef Bacik Signed-off-by: Filipe Manana Signed-off-by: David Sterba Signed-off-by: Greg Kroah-Hartman --- fs/btrfs/inode.c | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -10099,7 +10099,8 @@ static int btrfs_swap_activate(struct sw sector_t *span) { struct inode *inode = file_inode(file); - struct btrfs_fs_info *fs_info = BTRFS_I(inode)->root->fs_info; + struct btrfs_root *root = BTRFS_I(inode)->root; + struct btrfs_fs_info *fs_info = root->fs_info; struct extent_io_tree *io_tree = &BTRFS_I(inode)->io_tree; struct extent_state *cached_state = NULL; struct extent_map *em = NULL; @@ -10150,13 +10151,27 @@ static int btrfs_swap_activate(struct sw "cannot activate swapfile while exclusive operation is running"); return -EBUSY; } + + /* + * Prevent snapshot creation while we are activating the swap file. + * We do not want to race with snapshot creation. If snapshot creation + * already started before we bumped nr_swapfiles from 0 to 1 and + * completes before the first write into the swap file after it is + * activated, than that write would fallback to COW. + */ + if (!btrfs_drew_try_write_lock(&root->snapshot_lock)) { + btrfs_exclop_finish(fs_info); + btrfs_warn(fs_info, + "cannot activate swapfile because snapshot creation is in progress"); + return -EINVAL; + } /* * Snapshots can create extents which require COW even if NODATACOW is * set. We use this counter to prevent snapshots. We must increment it * before walking the extents because we don't want a concurrent * snapshot to run after we've already checked the extents. */ - atomic_inc(&BTRFS_I(inode)->root->nr_swapfiles); + atomic_inc(&root->nr_swapfiles); isize = ALIGN_DOWN(inode->i_size, fs_info->sectorsize); @@ -10302,6 +10317,8 @@ out: if (ret) btrfs_swap_deactivate(file); + btrfs_drew_write_unlock(&root->snapshot_lock); + btrfs_exclop_finish(fs_info); if (ret)