From: Goldwyn Rodrigues <rgoldwyn@xxxxxxxx>
This is to parallelize direct writes within EOF or with direct I/O
reads. This covers the race with truncate() accidentally increasing the
filesize.
Signed-off-by: Goldwyn Rodrigues <rgoldwyn@xxxxxxxx>
---
fs/btrfs/file.c | 25 +++++++------------------
1 file changed, 7 insertions(+), 18 deletions(-)
diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c
index aa6be931620b..c446a4aeb867 100644
--- a/fs/btrfs/file.c
+++ b/fs/btrfs/file.c
@@ -1957,12 +1957,18 @@ static ssize_t btrfs_direct_write(struct kiocb *iocb, struct iov_iter *from)
loff_t endbyte;
int err;
size_t count = 0;
- bool relock = false;
int flags = IOMAP_DIOF_PGINVALID_FAIL;
int ilock_flags = 0;
if (iocb->ki_flags & IOCB_NOWAIT)
ilock_flags |= BTRFS_ILOCK_TRY;
+ /*
+ * If the write DIO within EOF, use a shared lock
+ */
+ if (pos + count <= i_size_read(inode))
+ ilock_flags |= BTRFS_ILOCK_SHARED;
+ else if (iocb->ki_flags & IOCB_NOWAIT)
+ return -EAGAIN;
err = btrfs_inode_lock(inode, ilock_flags);
if (err < 0)
@@ -1975,20 +1981,6 @@ static ssize_t btrfs_direct_write(struct kiocb *iocb, struct iov_iter *from)
if (check_direct_IO(fs_info, from, pos))
goto buffered;
- count = iov_iter_count(from);
- /*
- * If the write DIO is beyond the EOF, we need update the isize, but it
- * is protected by i_mutex. So we can not unlock the i_mutex at this
- * case.
- */
- if (pos + count <= inode->i_size) {
- inode_unlock(inode);
- relock = true;
- } else if (iocb->ki_flags & IOCB_NOWAIT) {
- err = -EAGAIN;
- goto out;
- }
-
if (is_sync_kiocb(iocb))
flags |= IOMAP_DIOF_WAIT_FOR_COMPLETION;
@@ -1997,9 +1989,6 @@ static ssize_t btrfs_direct_write(struct kiocb *iocb, struct iov_iter *from)
flags);
up_read(&BTRFS_I(inode)->dio_sem);
- if (relock)
- inode_lock(inode);
-
if (written < 0 || !iov_iter_count(from)) {
err = written;
goto error;
--
2.25.0