]> git.hungrycats.org Git - linux/commit
btrfs: fix race between dedupe and mmap
authorJosef Bacik <josef@toxicpanda.com>
Fri, 11 Dec 2020 22:12:52 +0000 (17:12 -0500)
committerZygo Blaxell <ce3g8jdj@umail.furryterror.org>
Sat, 6 Mar 2021 14:44:29 +0000 (09:44 -0500)
commitee771a068b2ddde65a3d581879bf1ae75ecde86a
treefa3bd0b3875c561efe9cae5ce2aec24aabd6fa5b
parentc60e665ec1404380bbfb6da209c57b314b669d42
btrfs: fix race between dedupe and mmap

Darrick asked how btrfs currently protects against mmap modifying a page
during dedupe, and when I checked I realized it doesn't.  Previously we
did the following dance

lock page ranges in both files
  lock extent
    flush ordered
      validate pages are the same
        dedupe

However Filipe moved us to use the generic checks, which instead does
this dance

lock inode
  flush everything, check for ordered extents
  lock page in both corresponding inodes
    validate pages are the same
  unlock pages
  lock extent
  dedupe

The problem here is we're not doing our normal page lock -> extent lock
-> validate check.  The generic checks assume we've blocked everybody
from modifying the file, which we have with the exception of mmap.

There are two ways we can fix this, and I've chosen the simplest.

The more complicated way is to add a flag to the generic checks to tell
it that we'll do the page verification ourselves.  Then we add back the
checks to btrfs_extent_same() to do the proper lock ordering in order to
validate the pages.

The simpler way to do this is to simply add a mechanism to block mmap
from happening while we're doing dedupe.  I've opted for this strategy,
because it's more straightforward and allows us to continue using the
generic infrastructure.

Ext4 and xfs do not have this problem because they have an inode lock
that they use to block mmap from happening, the i_mmap_sem in ext4's
case and the ilock for xfs.

Signed-off-by: Josef Bacik <josef@toxicpanda.com>
fs/btrfs/btrfs_inode.h
fs/btrfs/inode.c
fs/btrfs/reflink.c