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.