diff mbox series

[v4,03/10] fuse: prepare support for shared lock for DIO writes

Message ID 20230918150313.3845114-4-bschubert@ddn.com (mailing list archive)
State New, archived
Headers show
Series fuse direct write consolidation and parallel IO | expand

Commit Message

Bernd Schubert Sept. 18, 2023, 3:03 p.m. UTC
Take a shared lock in fuse_cache_write_iter. This was already
done for FOPEN_DIRECT_IO in

commit 153524053bbb ("fuse: allow non-extending parallel direct
writes on the same file")

but so far missing for plain O_DIRECT. Server side needs
to set FOPEN_PARALLEL_DIRECT_WRITES in order to signal that
it supports parallel dio writes.

From style point of view another goto target is introduced,
although the existing writethrough target would be sufficient.
This is just done to make the code easier to read.

In this commit the exclusive lock still enforced by an
'|| 1'. For readability this will be solved in a follow up commit.

Cc: Hao Xu <howeyxu@tencent.com>
Cc: Miklos Szeredi <miklos@szeredi.hu>
Cc: Dharmendra Singh <dsingh@ddn.com>
Cc: linux-fsdevel@vger.kernel.org
Signed-off-by: Bernd Schubert <bschubert@ddn.com>
---
 fs/fuse/file.c | 33 +++++++++++++++++++++++++++++++--
 1 file changed, 31 insertions(+), 2 deletions(-)
diff mbox series

Patch

diff --git a/fs/fuse/file.c b/fs/fuse/file.c
index 7606cf376ec3..76922a6a0962 100644
--- a/fs/fuse/file.c
+++ b/fs/fuse/file.c
@@ -1313,6 +1313,10 @@  static bool fuse_dio_wr_exclusive_lock(struct kiocb *iocb, struct iov_iter *from
 	struct file *file = iocb->ki_filp;
 	struct fuse_file *ff = file->private_data;
 
+	/* the shared lock is about direct IO only */
+	if (!(iocb->ki_flags & IOCB_DIRECT))
+		return true;
+
 	/* server side has to advise that it supports parallel dio writes */
 	if (!(ff->open_flags & FOPEN_PARALLEL_DIRECT_WRITES))
 		return true;
@@ -1338,6 +1342,7 @@  static ssize_t fuse_cache_write_iter(struct kiocb *iocb, struct iov_iter *from)
 	struct inode *inode = mapping->host;
 	ssize_t err;
 	struct fuse_conn *fc = get_fuse_conn(inode);
+	bool excl_lock = fuse_dio_wr_exclusive_lock(iocb, from) || 1;
 
 	if (fc->writeback_cache && !(iocb->ki_flags & IOCB_DIRECT)) {
 		/* Update size (EOF optimization) and mode (SUID clearing) */
@@ -1356,7 +1361,20 @@  static ssize_t fuse_cache_write_iter(struct kiocb *iocb, struct iov_iter *from)
 	}
 
 writethrough:
-	inode_lock(inode);
+relock:
+	if (excl_lock)
+		inode_lock(inode);
+	else {
+		inode_lock_shared(inode);
+		if (fuse_io_past_eof(iocb, from)) {
+			/* file extending writes will trigger i_size_write,
+			 *  exclusive lock is needed
+			 */
+			inode_unlock_shared(inode);
+			excl_lock = true;
+			goto relock;
+		}
+	}
 
 	err = generic_write_checks(iocb, from);
 	if (err <= 0)
@@ -1374,13 +1392,24 @@  static ssize_t fuse_cache_write_iter(struct kiocb *iocb, struct iov_iter *from)
 		written = generic_file_direct_write(iocb, from);
 		if (written < 0 || !iov_iter_count(from))
 			goto out;
+
+		if (!excl_lock) {
+			/* fallback to page IO needs the exclusive lock */
+			inode_unlock_shared(inode);
+			excl_lock = true;
+			goto relock;
+		}
+
 		written = direct_write_fallback(iocb, from, written,
 				fuse_perform_write(iocb, from));
 	} else {
 		written = fuse_perform_write(iocb, from);
 	}
 out:
-	inode_unlock(inode);
+	if (excl_lock)
+		inode_unlock(inode);
+	else
+		inode_unlock_shared(inode);
 	if (written > 0)
 		written = generic_write_sync(iocb, written);