Btrfs: fix race between fsync and lockless direct IO writes
authorFilipe Manana <fdmanana@suse.com>
Thu, 21 Jan 2016 10:17:54 +0000 (10:17 +0000)
committerChris Mason <clm@fb.com>
Tue, 26 Jan 2016 00:50:26 +0000 (16:50 -0800)
commitde0ee0edb21fbab4c7afa3e94573ecfebfb0244e
tree52b0a9db694a7810bed41f04fa5be2b843352484
parent6b5aa88c861cf0e4156e490009e2018d4fc81109
Btrfs: fix race between fsync and lockless direct IO writes

An fsync, using the fast path, can race with a concurrent lockless direct
IO write and end up logging a file extent item that points to an extent
that wasn't written to yet. This is because the fast fsync path collects
ordered extents into a local list and then collects all the new extent
maps to log file extent items based on them, while the direct IO write
path creates the new extent map before it creates the corresponding
ordered extent (and submitting the respective bio(s)).

So fix this by making the direct IO write path create ordered extents
before the extent maps and make the fast fsync path collect any new
ordered extents after it collects the extent maps.
Note that making the fsync handler call inode_dio_wait() (after acquiring
the inode's i_mutex) would not work and lead to a deadlock when doing
AIO, as through AIO we end up in a path where the fsync handler is called
(through dio_aio_complete_work() -> dio_complete() -> vfs_fsync_range())
before the inode's dio counter is decremented (inode_dio_wait() waits
for this counter to have a value of zero).

Signed-off-by: Filipe Manana <fdmanana@suse.com>
Signed-off-by: Chris Mason <clm@fb.com>
fs/btrfs/inode.c
fs/btrfs/tree-log.c