Skip to content

Commit f6174bb

Browse files
fdmananagregkh
authored andcommitted
btrfs: fix race with memory mapped writes when activating swap file
commit 0525064 upstream. When activating the swap file we flush all delalloc and wait for ordered extent completion, so that we don't miss any delalloc and extents before we check that the file's extent layout is usable for a swap file and activate the swap file. We are called with the inode's VFS lock acquired, so we won't race with buffered and direct IO writes, however we can still race with memory mapped writes since they don't acquire the inode's VFS lock. The race window is between flushing all delalloc and locking the whole file's extent range, since memory mapped writes lock an extent range with the length of a page. Fix this by acquiring the inode's mmap lock before we flush delalloc. CC: [email protected] # 5.4+ Reviewed-by: Qu Wenruo <[email protected]> Signed-off-by: Filipe Manana <[email protected]> Signed-off-by: David Sterba <[email protected]> Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent f6279a9 commit f6174bb

File tree

1 file changed

+24
-7
lines changed

1 file changed

+24
-7
lines changed

fs/btrfs/inode.c

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9790,29 +9790,41 @@ static int btrfs_swap_activate(struct swap_info_struct *sis, struct file *file,
97909790
u64 isize;
97919791
u64 start;
97929792

9793+
/*
9794+
* Acquire the inode's mmap lock to prevent races with memory mapped
9795+
* writes, as they could happen after we flush delalloc below and before
9796+
* we lock the extent range further below. The inode was already locked
9797+
* up in the call chain.
9798+
*/
9799+
btrfs_assert_inode_locked(BTRFS_I(inode));
9800+
down_write(&BTRFS_I(inode)->i_mmap_lock);
9801+
97939802
/*
97949803
* If the swap file was just created, make sure delalloc is done. If the
97959804
* file changes again after this, the user is doing something stupid and
97969805
* we don't really care.
97979806
*/
97989807
ret = btrfs_wait_ordered_range(BTRFS_I(inode), 0, (u64)-1);
97999808
if (ret)
9800-
return ret;
9809+
goto out_unlock_mmap;
98019810

98029811
/*
98039812
* The inode is locked, so these flags won't change after we check them.
98049813
*/
98059814
if (BTRFS_I(inode)->flags & BTRFS_INODE_COMPRESS) {
98069815
btrfs_warn(fs_info, "swapfile must not be compressed");
9807-
return -EINVAL;
9816+
ret = -EINVAL;
9817+
goto out_unlock_mmap;
98089818
}
98099819
if (!(BTRFS_I(inode)->flags & BTRFS_INODE_NODATACOW)) {
98109820
btrfs_warn(fs_info, "swapfile must not be copy-on-write");
9811-
return -EINVAL;
9821+
ret = -EINVAL;
9822+
goto out_unlock_mmap;
98129823
}
98139824
if (!(BTRFS_I(inode)->flags & BTRFS_INODE_NODATASUM)) {
98149825
btrfs_warn(fs_info, "swapfile must not be checksummed");
9815-
return -EINVAL;
9826+
ret = -EINVAL;
9827+
goto out_unlock_mmap;
98169828
}
98179829

98189830
/*
@@ -9827,7 +9839,8 @@ static int btrfs_swap_activate(struct swap_info_struct *sis, struct file *file,
98279839
if (!btrfs_exclop_start(fs_info, BTRFS_EXCLOP_SWAP_ACTIVATE)) {
98289840
btrfs_warn(fs_info,
98299841
"cannot activate swapfile while exclusive operation is running");
9830-
return -EBUSY;
9842+
ret = -EBUSY;
9843+
goto out_unlock_mmap;
98319844
}
98329845

98339846
/*
@@ -9841,7 +9854,8 @@ static int btrfs_swap_activate(struct swap_info_struct *sis, struct file *file,
98419854
btrfs_exclop_finish(fs_info);
98429855
btrfs_warn(fs_info,
98439856
"cannot activate swapfile because snapshot creation is in progress");
9844-
return -EINVAL;
9857+
ret = -EINVAL;
9858+
goto out_unlock_mmap;
98459859
}
98469860
/*
98479861
* Snapshots can create extents which require COW even if NODATACOW is
@@ -9862,7 +9876,8 @@ static int btrfs_swap_activate(struct swap_info_struct *sis, struct file *file,
98629876
btrfs_warn(fs_info,
98639877
"cannot activate swapfile because subvolume %llu is being deleted",
98649878
btrfs_root_id(root));
9865-
return -EPERM;
9879+
ret = -EPERM;
9880+
goto out_unlock_mmap;
98669881
}
98679882
atomic_inc(&root->nr_swapfiles);
98689883
spin_unlock(&root->root_item_lock);
@@ -10017,6 +10032,8 @@ static int btrfs_swap_activate(struct swap_info_struct *sis, struct file *file,
1001710032

1001810033
btrfs_exclop_finish(fs_info);
1001910034

10035+
out_unlock_mmap:
10036+
up_write(&BTRFS_I(inode)->i_mmap_lock);
1002010037
if (ret)
1002110038
return ret;
1002210039

0 commit comments

Comments
 (0)