summaryrefslogtreecommitdiffstats
path: root/fs/iomap/direct-io.c
diff options
context:
space:
mode:
authorGoldwyn Rodrigues <rgoldwyn@suse.com>2020-09-28 17:51:08 +0200
committerDarrick J. Wong <darrick.wong@oracle.com>2020-09-28 17:51:08 +0200
commit1a31182edd0083bb9f26e582ed39f92f898c4d0a (patch)
tree8bbfb19660649ede924df743a4cc1db1ed645b02 /fs/iomap/direct-io.c
parentiomap: Allow filesystem to call iomap_dio_complete without i_rwsem (diff)
downloadlinux-1a31182edd0083bb9f26e582ed39f92f898c4d0a.tar.xz
linux-1a31182edd0083bb9f26e582ed39f92f898c4d0a.zip
iomap: Call inode_dio_end() before generic_write_sync()
iomap complete routine can deadlock with btrfs_fallocate because of the call to generic_write_sync(). P0 P1 inode_lock() fallocate(FALLOC_FL_ZERO_RANGE) __iomap_dio_rw() inode_lock() <block> <submits IO> <completes IO> inode_unlock() <gets inode_lock()> inode_dio_wait() iomap_dio_complete() generic_write_sync() btrfs_file_fsync() inode_lock() <deadlock> inode_dio_end() is used to notify the end of DIO data in order to synchronize with truncate. Call inode_dio_end() before calling generic_write_sync(), so filesystems can lock i_rwsem during a sync. This matches the way it is done in fs/direct-io.c:dio_complete(). Signed-off-by: Goldwyn Rodrigues <rgoldwyn@suse.com> Reviewed-by: Christoph Hellwig <hch@lst.de> Reviewed-by: Josef Bacik <josef@toxicpanda.com> Reviewed-by: Darrick J. Wong <darrick.wong@oracle.com> Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
Diffstat (limited to 'fs/iomap/direct-io.c')
-rw-r--r--fs/iomap/direct-io.c2
1 files changed, 1 insertions, 1 deletions
diff --git a/fs/iomap/direct-io.c b/fs/iomap/direct-io.c
index b005ef5f554e..933f234d5bec 100644
--- a/fs/iomap/direct-io.c
+++ b/fs/iomap/direct-io.c
@@ -118,6 +118,7 @@ ssize_t iomap_dio_complete(struct iomap_dio *dio)
dio_warn_stale_pagecache(iocb->ki_filp);
}
+ inode_dio_end(file_inode(iocb->ki_filp));
/*
* If this is a DSYNC write, make sure we push it to stable storage now
* that we've written data.
@@ -125,7 +126,6 @@ ssize_t iomap_dio_complete(struct iomap_dio *dio)
if (ret > 0 && (dio->flags & IOMAP_DIO_NEED_SYNC))
ret = generic_write_sync(iocb, ret);
- inode_dio_end(file_inode(iocb->ki_filp));
kfree(dio);
return ret;