* [PATCH 0/5 v3] fuse direct write consolidation and parallel IO
@ 2023-08-29 16:11 Bernd Schubert
2023-08-29 16:11 ` [PATCH 1/6] fuse: direct IO can use the write-through code path Bernd Schubert
` (5 more replies)
0 siblings, 6 replies; 18+ messages in thread
From: Bernd Schubert @ 2023-08-29 16:11 UTC (permalink / raw)
To: linux-fsdevel
Cc: bernd.schubert, miklos, dsingh, Bernd Schubert, Hao Xu,
Christoph Hellwig
This series consolidates DIO writes into a single code path via
fuse_cache_write_iter/generic_file_direct_write. Before
it was only used for O_DIRECT and when writeback cache was not enabled.
For server/daemon dio enforcement (FOPEN_DIRECT_IO) another code
path was used before, but I _think_ that is not needed and
just IOCB_DIRECT needs to be set/enforced.
When writeback-cache was enabled another code path was used, with
a fallback to write-through - for direct IO that should not be
needed either.
So far O_DIRECT through fuse_cache_write_iter also took an exclusive
lock, this should not be needed either, at least when server side
sets FOPEN_PARALLEL_DIRECT_WRITES.
v3:
Addresses review comments
- Rename fuse_direct_write_extending_i_size to io_past_eof
- Change to single line conditions in fuse_dio_wr_exclusive_lock
(also fixes accidental parenthesis).
- Add another patch to rename fuse_direct_io to fuse_send_dio
- Add detailed information into the commit message of the patch
that consolidates IO paths (5/6, previously 4/5) and also
update the subject.
v2:
The entire v1 approach to route DIO writes through fuse_direct_write_iter
was turned around and fuse_direct_write_iter is removed instead and all
DIO writes are now routed through fuse_cache_write_iter
Cc: Hao Xu <howeyxu@tencent.com>
Cc: Christoph Hellwig <hch@infradead.org>
Cc: Miklos Szeredi <miklos@szeredi.hu>
Cc: Dharmendra Singh <dsingh@ddn.com>
Cc: linux-fsdevel@vger.kernel.org
Bernd Schubert (5):
fuse: direct IO can use the write-through code path
fuse: Create helper function if DIO write needs exclusive lock
fuse: Allow parallel direct writes for O_DIRECT
[RFC] fuse: Set and use IOCB_DIRECT when FOPEN_DIRECT_IO is set
fuse: Remove page flush/invaliation in fuse_direct_io
fs/fuse/file.c | 122 ++++++++++++++++--------------------------------
fs/fuse/xattr.c | 8 ++--
2 files changed, 43 insertions(+), 87 deletions(-)
--
2.39.2
^ permalink raw reply [flat|nested] 18+ messages in thread
* [PATCH 1/6] fuse: direct IO can use the write-through code path
2023-08-29 16:11 [PATCH 0/5 v3] fuse direct write consolidation and parallel IO Bernd Schubert
@ 2023-08-29 16:11 ` Bernd Schubert
2023-08-29 16:11 ` [PATCH 2/6] fuse: Create helper function if DIO write needs exclusive lock Bernd Schubert
` (4 subsequent siblings)
5 siblings, 0 replies; 18+ messages in thread
From: Bernd Schubert @ 2023-08-29 16:11 UTC (permalink / raw)
To: linux-fsdevel
Cc: bernd.schubert, miklos, dsingh, Bernd Schubert, Hao Xu,
Miklos Szeredi
Direct IO does not benefit from write back cache and it
also avoides another direct IO write code path.
Cc: Hao Xu <howeyxu@tencent.com>
Cc: Miklos Szeredi <miklos@szeredi.hu>
Cc: Dharmendra Singh <dsingh@ddn.com>
Signed-off-by: Bernd Schubert <bschubert@ddn.com>
Acked-by: Miklos Szeredi <mszeredi@redhat.com>
---
fs/fuse/file.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/fs/fuse/file.c b/fs/fuse/file.c
index 1cdb6327511e..b1b9f2b9a37d 100644
--- a/fs/fuse/file.c
+++ b/fs/fuse/file.c
@@ -1307,7 +1307,7 @@ static ssize_t fuse_cache_write_iter(struct kiocb *iocb, struct iov_iter *from)
ssize_t err;
struct fuse_conn *fc = get_fuse_conn(inode);
- if (fc->writeback_cache) {
+ if (fc->writeback_cache && !(iocb->ki_flags & IOCB_DIRECT)) {
/* Update size (EOF optimization) and mode (SUID clearing) */
err = fuse_update_attributes(mapping->host, file,
STATX_SIZE | STATX_MODE);
--
2.39.2
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH 2/6] fuse: Create helper function if DIO write needs exclusive lock
2023-08-29 16:11 [PATCH 0/5 v3] fuse direct write consolidation and parallel IO Bernd Schubert
2023-08-29 16:11 ` [PATCH 1/6] fuse: direct IO can use the write-through code path Bernd Schubert
@ 2023-08-29 16:11 ` Bernd Schubert
2023-08-30 10:57 ` Miklos Szeredi
2023-08-29 16:11 ` [PATCH 3/6] fuse: Allow parallel direct writes for O_DIRECT Bernd Schubert
` (3 subsequent siblings)
5 siblings, 1 reply; 18+ messages in thread
From: Bernd Schubert @ 2023-08-29 16:11 UTC (permalink / raw)
To: linux-fsdevel; +Cc: bernd.schubert, miklos, dsingh, Bernd Schubert, Hao Xu
This is just a preparation to avoid code duplication in the next
commit.
Cc: Hao Xu <howeyxu@tencent.com>
Cc: Miklos Szeredi <miklos@szeredi.hu>
Cc: Dharmendra Singh <dsingh@ddn.com>
Signed-off-by: Bernd Schubert <bschubert@ddn.com>
---
fs/fuse/file.c | 48 +++++++++++++++++++++++++++++++++---------------
1 file changed, 33 insertions(+), 15 deletions(-)
diff --git a/fs/fuse/file.c b/fs/fuse/file.c
index b1b9f2b9a37d..6b8b9512c336 100644
--- a/fs/fuse/file.c
+++ b/fs/fuse/file.c
@@ -1298,6 +1298,37 @@ static ssize_t fuse_perform_write(struct kiocb *iocb, struct iov_iter *ii)
return res;
}
+static bool fuse_io_past_eof(struct kiocb *iocb,
+ struct iov_iter *iter)
+{
+ struct inode *inode = file_inode(iocb->ki_filp);
+
+ return iocb->ki_pos + iov_iter_count(iter) > i_size_read(inode);
+}
+
+/*
+ * @return true if an exclusive lock direct IO writes is needed
+ */
+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;
+
+ /* server side has to advise that it supports parallel dio writes */
+ if (!(ff->open_flags & FOPEN_PARALLEL_DIRECT_WRITES))
+ return false;
+
+ /* append will need to know the eventual eof - always needs a lock */
+ if (iocb->ki_flags & IOCB_APPEND)
+ return false;
+
+ /* parallel dio beyond eof is at least for now not supported */
+ if (fuse_io_past_eof(iocb, from))
+ return false;
+
+ return true;
+}
+
static ssize_t fuse_cache_write_iter(struct kiocb *iocb, struct iov_iter *from)
{
struct file *file = iocb->ki_filp;
@@ -1557,25 +1588,12 @@ static ssize_t fuse_direct_read_iter(struct kiocb *iocb, struct iov_iter *to)
return res;
}
-static bool fuse_direct_write_extending_i_size(struct kiocb *iocb,
- struct iov_iter *iter)
-{
- struct inode *inode = file_inode(iocb->ki_filp);
-
- return iocb->ki_pos + iov_iter_count(iter) > i_size_read(inode);
-}
-
static ssize_t fuse_direct_write_iter(struct kiocb *iocb, struct iov_iter *from)
{
struct inode *inode = file_inode(iocb->ki_filp);
- struct file *file = iocb->ki_filp;
- struct fuse_file *ff = file->private_data;
struct fuse_io_priv io = FUSE_IO_PRIV_SYNC(iocb);
ssize_t res;
- bool exclusive_lock =
- !(ff->open_flags & FOPEN_PARALLEL_DIRECT_WRITES) ||
- iocb->ki_flags & IOCB_APPEND ||
- fuse_direct_write_extending_i_size(iocb, from);
+ bool exclusive_lock = fuse_dio_wr_exclusive_lock(iocb, from);
/*
* Take exclusive lock if
@@ -1591,7 +1609,7 @@ static ssize_t fuse_direct_write_iter(struct kiocb *iocb, struct iov_iter *from)
/* A race with truncate might have come up as the decision for
* the lock type was done without holding the lock, check again.
*/
- if (fuse_direct_write_extending_i_size(iocb, from)) {
+ if (fuse_io_past_eof(iocb, from)) {
inode_unlock_shared(inode);
inode_lock(inode);
exclusive_lock = true;
--
2.39.2
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH 3/6] fuse: Allow parallel direct writes for O_DIRECT
2023-08-29 16:11 [PATCH 0/5 v3] fuse direct write consolidation and parallel IO Bernd Schubert
2023-08-29 16:11 ` [PATCH 1/6] fuse: direct IO can use the write-through code path Bernd Schubert
2023-08-29 16:11 ` [PATCH 2/6] fuse: Create helper function if DIO write needs exclusive lock Bernd Schubert
@ 2023-08-29 16:11 ` Bernd Schubert
2023-08-30 13:28 ` Miklos Szeredi
2023-08-31 8:30 ` Hao Xu
2023-08-29 16:11 ` [PATCH 4/6] fuse: Rename fuse_direct_io Bernd Schubert
` (2 subsequent siblings)
5 siblings, 2 replies; 18+ messages in thread
From: Bernd Schubert @ 2023-08-29 16:11 UTC (permalink / raw)
To: linux-fsdevel; +Cc: bernd.schubert, miklos, dsingh, Bernd Schubert, Hao Xu
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.
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 | 18 ++++++++++++++++--
1 file changed, 16 insertions(+), 2 deletions(-)
diff --git a/fs/fuse/file.c b/fs/fuse/file.c
index 6b8b9512c336..a6b99bc80fe7 100644
--- a/fs/fuse/file.c
+++ b/fs/fuse/file.c
@@ -1314,6 +1314,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;
+ /* this function is about direct IO only */
+ if (!(iocb->ki_flags & IOCB_DIRECT))
+ return false;
+
/* server side has to advise that it supports parallel dio writes */
if (!(ff->open_flags & FOPEN_PARALLEL_DIRECT_WRITES))
return false;
@@ -1337,6 +1341,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);
if (fc->writeback_cache && !(iocb->ki_flags & IOCB_DIRECT)) {
/* Update size (EOF optimization) and mode (SUID clearing) */
@@ -1355,7 +1360,10 @@ static ssize_t fuse_cache_write_iter(struct kiocb *iocb, struct iov_iter *from)
}
writethrough:
- inode_lock(inode);
+ if (excl_lock)
+ inode_lock(inode);
+ else
+ inode_lock_shared(inode);
err = generic_write_checks(iocb, from);
if (err <= 0)
@@ -1370,6 +1378,9 @@ static ssize_t fuse_cache_write_iter(struct kiocb *iocb, struct iov_iter *from)
goto out;
if (iocb->ki_flags & IOCB_DIRECT) {
+ /* file extending writes will trigger i_size_write - exclusive
+ * lock is needed
+ */
written = generic_file_direct_write(iocb, from);
if (written < 0 || !iov_iter_count(from))
goto out;
@@ -1379,7 +1390,10 @@ static ssize_t fuse_cache_write_iter(struct kiocb *iocb, struct iov_iter *from)
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);
--
2.39.2
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH 4/6] fuse: Rename fuse_direct_io
2023-08-29 16:11 [PATCH 0/5 v3] fuse direct write consolidation and parallel IO Bernd Schubert
` (2 preceding siblings ...)
2023-08-29 16:11 ` [PATCH 3/6] fuse: Allow parallel direct writes for O_DIRECT Bernd Schubert
@ 2023-08-29 16:11 ` Bernd Schubert
2023-08-29 16:11 ` [PATCH 5/6] fuse: Remove fuse_direct_write_iter code path / use IOCB_DIRECT Bernd Schubert
2023-08-29 16:11 ` [PATCH 6/6] fuse: Remove page flush/invaliation in fuse_direct_io Bernd Schubert
5 siblings, 0 replies; 18+ messages in thread
From: Bernd Schubert @ 2023-08-29 16:11 UTC (permalink / raw)
To: linux-fsdevel; +Cc: bernd.schubert, miklos, dsingh, Bernd Schubert, Hao Xu
Just to avoid confusion with fuse_direct_IO.
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/cuse.c | 5 ++---
fs/fuse/dax.c | 2 +-
fs/fuse/file.c | 14 +++++++-------
fs/fuse/fuse_i.h | 8 ++++----
4 files changed, 14 insertions(+), 15 deletions(-)
diff --git a/fs/fuse/cuse.c b/fs/fuse/cuse.c
index 91e89e68177e..c267ae9dcba6 100644
--- a/fs/fuse/cuse.c
+++ b/fs/fuse/cuse.c
@@ -96,7 +96,7 @@ static ssize_t cuse_read_iter(struct kiocb *kiocb, struct iov_iter *to)
struct fuse_io_priv io = FUSE_IO_PRIV_SYNC(kiocb);
loff_t pos = 0;
- return fuse_direct_io(&io, to, &pos, FUSE_DIO_CUSE);
+ return fuse_send_dio(&io, to, &pos, FUSE_DIO_CUSE);
}
static ssize_t cuse_write_iter(struct kiocb *kiocb, struct iov_iter *from)
@@ -107,8 +107,7 @@ static ssize_t cuse_write_iter(struct kiocb *kiocb, struct iov_iter *from)
* No locking or generic_write_checks(), the server is
* responsible for locking and sanity checks.
*/
- return fuse_direct_io(&io, from, &pos,
- FUSE_DIO_WRITE | FUSE_DIO_CUSE);
+ return fuse_send_dio(&io, from, &pos, FUSE_DIO_WRITE | FUSE_DIO_CUSE);
}
static int cuse_open(struct inode *inode, struct file *file)
diff --git a/fs/fuse/dax.c b/fs/fuse/dax.c
index 8e74f278a3f6..423e40ab3e31 100644
--- a/fs/fuse/dax.c
+++ b/fs/fuse/dax.c
@@ -731,7 +731,7 @@ static ssize_t fuse_dax_direct_write(struct kiocb *iocb, struct iov_iter *from)
struct fuse_io_priv io = FUSE_IO_PRIV_SYNC(iocb);
ssize_t ret;
- ret = fuse_direct_io(&io, from, &iocb->ki_pos, FUSE_DIO_WRITE);
+ ret = fuse_send_dio(&io, from, &iocb->ki_pos, FUSE_DIO_WRITE);
fuse_write_update_attr(inode, iocb->ki_pos, ret);
return ret;
diff --git a/fs/fuse/file.c b/fs/fuse/file.c
index a6b99bc80fe7..f9d21804d313 100644
--- a/fs/fuse/file.c
+++ b/fs/fuse/file.c
@@ -1467,8 +1467,8 @@ static int fuse_get_user_pages(struct fuse_args_pages *ap, struct iov_iter *ii,
return ret < 0 ? ret : 0;
}
-ssize_t fuse_direct_io(struct fuse_io_priv *io, struct iov_iter *iter,
- loff_t *ppos, int flags)
+ssize_t fuse_send_dio(struct fuse_io_priv *io, struct iov_iter *iter,
+ loff_t *ppos, int flags)
{
int write = flags & FUSE_DIO_WRITE;
int cuse = flags & FUSE_DIO_CUSE;
@@ -1569,7 +1569,7 @@ ssize_t fuse_direct_io(struct fuse_io_priv *io, struct iov_iter *iter,
return res > 0 ? res : err;
}
-EXPORT_SYMBOL_GPL(fuse_direct_io);
+EXPORT_SYMBOL_GPL(fuse_send_dio);
static ssize_t __fuse_direct_read(struct fuse_io_priv *io,
struct iov_iter *iter,
@@ -1578,7 +1578,7 @@ static ssize_t __fuse_direct_read(struct fuse_io_priv *io,
ssize_t res;
struct inode *inode = file_inode(io->iocb->ki_filp);
- res = fuse_direct_io(io, iter, ppos, 0);
+ res = fuse_send_dio(io, iter, ppos, 0);
fuse_invalidate_atime(inode);
@@ -1635,8 +1635,8 @@ static ssize_t fuse_direct_write_iter(struct kiocb *iocb, struct iov_iter *from)
if (!is_sync_kiocb(iocb) && iocb->ki_flags & IOCB_DIRECT) {
res = fuse_direct_IO(iocb, from);
} else {
- res = fuse_direct_io(&io, from, &iocb->ki_pos,
- FUSE_DIO_WRITE);
+ res = fuse_send_dio(&io, from, &iocb->ki_pos,
+ FUSE_DIO_WRITE);
fuse_write_update_attr(inode, iocb->ki_pos, res);
}
}
@@ -2972,7 +2972,7 @@ fuse_direct_IO(struct kiocb *iocb, struct iov_iter *iter)
}
if (iov_iter_rw(iter) == WRITE) {
- ret = fuse_direct_io(io, iter, &pos, FUSE_DIO_WRITE);
+ ret = fuse_send_dio(io, iter, &pos, FUSE_DIO_WRITE);
fuse_invalidate_attr_mask(inode, FUSE_STATX_MODSIZE);
} else {
ret = __fuse_direct_read(io, iter, &pos);
diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h
index bf0b85d0b95c..05c5cae59bad 100644
--- a/fs/fuse/fuse_i.h
+++ b/fs/fuse/fuse_i.h
@@ -1247,17 +1247,17 @@ int fuse_do_open(struct fuse_mount *fm, u64 nodeid, struct file *file,
bool isdir);
/**
- * fuse_direct_io() flags
+ * fuse_send_dio() flags
*/
/** If set, it is WRITE; otherwise - READ */
#define FUSE_DIO_WRITE (1 << 0)
-/** CUSE pass fuse_direct_io() a file which f_mapping->host is not from FUSE */
+/** CUSE pass fuse_send_dio() a file which f_mapping->host is not from FUSE */
#define FUSE_DIO_CUSE (1 << 1)
-ssize_t fuse_direct_io(struct fuse_io_priv *io, struct iov_iter *iter,
- loff_t *ppos, int flags);
+ssize_t fuse_send_dio(struct fuse_io_priv *io, struct iov_iter *iter,
+ loff_t *ppos, int flags);
long fuse_do_ioctl(struct file *file, unsigned int cmd, unsigned long arg,
unsigned int flags);
long fuse_ioctl_common(struct file *file, unsigned int cmd,
--
2.39.2
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH 5/6] fuse: Remove fuse_direct_write_iter code path / use IOCB_DIRECT
2023-08-29 16:11 [PATCH 0/5 v3] fuse direct write consolidation and parallel IO Bernd Schubert
` (3 preceding siblings ...)
2023-08-29 16:11 ` [PATCH 4/6] fuse: Rename fuse_direct_io Bernd Schubert
@ 2023-08-29 16:11 ` Bernd Schubert
2023-08-31 9:19 ` Hao Xu
2023-08-29 16:11 ` [PATCH 6/6] fuse: Remove page flush/invaliation in fuse_direct_io Bernd Schubert
5 siblings, 1 reply; 18+ messages in thread
From: Bernd Schubert @ 2023-08-29 16:11 UTC (permalink / raw)
To: linux-fsdevel; +Cc: bernd.schubert, miklos, dsingh, Bernd Schubert, Hao Xu
fuse_direct_write_iter is basically duplicating what is already
in fuse_cache_write_iter/generic_file_direct_write. That can be
avoided by setting IOCB_DIRECT in fuse_file_write_iter, after that
fuse_cache_write_iter can be used for the FOPEN_DIRECT_IO code path
and fuse_direct_write_iter can be removed.
Before it was using for FOPEN_DIRECT_IO
1) async (!is_sync_kiocb(iocb)) && IOCB_DIRECT
fuse_file_write_iter
fuse_direct_write_iter
fuse_direct_IO
fuse_send_dio
2) sync (is_sync_kiocb(iocb)) or IOCB_DIRECT not being set
fuse_file_write_iter
fuse_direct_write_iter
fuse_send_dio
3) FOPEN_DIRECT_IO not set
Same as the consolidates path below
The new consolidated code path is always
fuse_file_write_iter
fuse_cache_write_iter
generic_file_write_iter
__generic_file_write_iter
generic_file_direct_write
mapping->a_ops->direct_IO / fuse_direct_IO
fuse_send_dio
So in general for FOPEN_DIRECT_IO the code path gets longer. Additionally
fuse_direct_IO does an allocation of struct fuse_io_priv - might be a bit
slower in micro benchmarks.
Also, the IOCB_DIRECT information gets lost (as we now set it outselves).
But then IOCB_DIRECT is directly related to O_DIRECT set in
struct file::f_flags.
An additional change is for condition 2 above, which might will now do
async IO on the condition ff->fm->fc->async_dio. Given that async IO for
FOPEN_DIRECT_IO was especially introduced in commit
'commit 23c94e1cdcbf ("fuse: Switch to using async direct IO for
FOPEN_DIRECT_IO")'
it should not matter. Especially as fuse_direct_IO is blocking for
is_sync_kiocb(), at worst it has another slight overhead.
Advantage is the removal of code paths and conditions and it is now also
possible to remove FOPEN_DIRECT_IO conditions in fuse_send_dio
(in a later patch).
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 | 54 ++++----------------------------------------------
1 file changed, 4 insertions(+), 50 deletions(-)
diff --git a/fs/fuse/file.c b/fs/fuse/file.c
index f9d21804d313..0b3363eec435 100644
--- a/fs/fuse/file.c
+++ b/fs/fuse/file.c
@@ -1602,52 +1602,6 @@ static ssize_t fuse_direct_read_iter(struct kiocb *iocb, struct iov_iter *to)
return res;
}
-static ssize_t fuse_direct_write_iter(struct kiocb *iocb, struct iov_iter *from)
-{
- struct inode *inode = file_inode(iocb->ki_filp);
- struct fuse_io_priv io = FUSE_IO_PRIV_SYNC(iocb);
- ssize_t res;
- bool exclusive_lock = fuse_dio_wr_exclusive_lock(iocb, from);
-
- /*
- * Take exclusive lock if
- * - Parallel direct writes are disabled - a user space decision
- * - Parallel direct writes are enabled and i_size is being extended.
- * This might not be needed at all, but needs further investigation.
- */
- if (exclusive_lock)
- inode_lock(inode);
- else {
- inode_lock_shared(inode);
-
- /* A race with truncate might have come up as the decision for
- * the lock type was done without holding the lock, check again.
- */
- if (fuse_io_past_eof(iocb, from)) {
- inode_unlock_shared(inode);
- inode_lock(inode);
- exclusive_lock = true;
- }
- }
-
- res = generic_write_checks(iocb, from);
- if (res > 0) {
- if (!is_sync_kiocb(iocb) && iocb->ki_flags & IOCB_DIRECT) {
- res = fuse_direct_IO(iocb, from);
- } else {
- res = fuse_send_dio(&io, from, &iocb->ki_pos,
- FUSE_DIO_WRITE);
- fuse_write_update_attr(inode, iocb->ki_pos, res);
- }
- }
- if (exclusive_lock)
- inode_unlock(inode);
- else
- inode_unlock_shared(inode);
-
- return res;
-}
-
static ssize_t fuse_file_read_iter(struct kiocb *iocb, struct iov_iter *to)
{
struct file *file = iocb->ki_filp;
@@ -1678,10 +1632,10 @@ static ssize_t fuse_file_write_iter(struct kiocb *iocb, struct iov_iter *from)
if (FUSE_IS_DAX(inode))
return fuse_dax_write_iter(iocb, from);
- if (!(ff->open_flags & FOPEN_DIRECT_IO))
- return fuse_cache_write_iter(iocb, from);
- else
- return fuse_direct_write_iter(iocb, from);
+ if (ff->open_flags & FOPEN_DIRECT_IO)
+ iocb->ki_flags |= IOCB_DIRECT;
+
+ return fuse_cache_write_iter(iocb, from);
}
static void fuse_writepage_free(struct fuse_writepage_args *wpa)
--
2.39.2
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH 6/6] fuse: Remove page flush/invaliation in fuse_direct_io
2023-08-29 16:11 [PATCH 0/5 v3] fuse direct write consolidation and parallel IO Bernd Schubert
` (4 preceding siblings ...)
2023-08-29 16:11 ` [PATCH 5/6] fuse: Remove fuse_direct_write_iter code path / use IOCB_DIRECT Bernd Schubert
@ 2023-08-29 16:11 ` Bernd Schubert
5 siblings, 0 replies; 18+ messages in thread
From: Bernd Schubert @ 2023-08-29 16:11 UTC (permalink / raw)
To: linux-fsdevel
Cc: bernd.schubert, miklos, dsingh, Bernd Schubert, Hao Xu,
Miklos Szeredi
Page flush and invalidation in fuse_direct_io can when FOPEN_DIRECT_IO
is set can be removed, as the code path is now always via
generic_file_direct_write, which already does it.
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>
Acked-by: Miklos Szeredi <mszeredi@redhat.com>
---
fs/fuse/file.c | 17 -----------------
1 file changed, 17 deletions(-)
diff --git a/fs/fuse/file.c b/fs/fuse/file.c
index 0b3363eec435..eaafa3fb0e0c 100644
--- a/fs/fuse/file.c
+++ b/fs/fuse/file.c
@@ -1486,20 +1486,11 @@ ssize_t fuse_send_dio(struct fuse_io_priv *io, struct iov_iter *iter,
int err = 0;
struct fuse_io_args *ia;
unsigned int max_pages;
- bool fopen_direct_io = ff->open_flags & FOPEN_DIRECT_IO;
-
max_pages = iov_iter_npages(iter, fc->max_pages);
ia = fuse_io_alloc(io, max_pages);
if (!ia)
return -ENOMEM;
- if (fopen_direct_io && fc->direct_io_relax) {
- res = filemap_write_and_wait_range(mapping, pos, pos + count - 1);
- if (res) {
- fuse_io_free(ia);
- return res;
- }
- }
if (!cuse && fuse_range_is_writeback(inode, idx_from, idx_to)) {
if (!write)
inode_lock(inode);
@@ -1508,14 +1499,6 @@ ssize_t fuse_send_dio(struct fuse_io_priv *io, struct iov_iter *iter,
inode_unlock(inode);
}
- if (fopen_direct_io && write) {
- res = invalidate_inode_pages2_range(mapping, idx_from, idx_to);
- if (res) {
- fuse_io_free(ia);
- return res;
- }
- }
-
io->should_dirty = !write && user_backed_iter(iter);
while (count) {
ssize_t nres;
--
2.39.2
^ permalink raw reply related [flat|nested] 18+ messages in thread
* Re: [PATCH 2/6] fuse: Create helper function if DIO write needs exclusive lock
2023-08-29 16:11 ` [PATCH 2/6] fuse: Create helper function if DIO write needs exclusive lock Bernd Schubert
@ 2023-08-30 10:57 ` Miklos Szeredi
2023-08-30 12:13 ` Bernd Schubert
0 siblings, 1 reply; 18+ messages in thread
From: Miklos Szeredi @ 2023-08-30 10:57 UTC (permalink / raw)
To: Bernd Schubert; +Cc: linux-fsdevel, bernd.schubert, dsingh, Hao Xu
On Tue, 29 Aug 2023 at 18:11, Bernd Schubert <bschubert@ddn.com> wrote:
>
> This is just a preparation to avoid code duplication in the next
> commit.
>
> Cc: Hao Xu <howeyxu@tencent.com>
> Cc: Miklos Szeredi <miklos@szeredi.hu>
> Cc: Dharmendra Singh <dsingh@ddn.com>
> Signed-off-by: Bernd Schubert <bschubert@ddn.com>
> ---
> fs/fuse/file.c | 48 +++++++++++++++++++++++++++++++++---------------
> 1 file changed, 33 insertions(+), 15 deletions(-)
>
> diff --git a/fs/fuse/file.c b/fs/fuse/file.c
> index b1b9f2b9a37d..6b8b9512c336 100644
> --- a/fs/fuse/file.c
> +++ b/fs/fuse/file.c
> @@ -1298,6 +1298,37 @@ static ssize_t fuse_perform_write(struct kiocb *iocb, struct iov_iter *ii)
> return res;
> }
>
> +static bool fuse_io_past_eof(struct kiocb *iocb,
> + struct iov_iter *iter)
> +{
> + struct inode *inode = file_inode(iocb->ki_filp);
> +
> + return iocb->ki_pos + iov_iter_count(iter) > i_size_read(inode);
> +}
> +
> +/*
> + * @return true if an exclusive lock direct IO writes is needed
> + */
> +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;
> +
> + /* server side has to advise that it supports parallel dio writes */
> + if (!(ff->open_flags & FOPEN_PARALLEL_DIRECT_WRITES))
> + return false;
You got the return values the wrong way around. I can fix this, no
need to resend.
Thanks,
Miklos
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH 2/6] fuse: Create helper function if DIO write needs exclusive lock
2023-08-30 10:57 ` Miklos Szeredi
@ 2023-08-30 12:13 ` Bernd Schubert
2023-08-30 12:14 ` Miklos Szeredi
0 siblings, 1 reply; 18+ messages in thread
From: Bernd Schubert @ 2023-08-30 12:13 UTC (permalink / raw)
To: Miklos Szeredi, Bernd Schubert
Cc: linux-fsdevel, bernd.schubert, dsingh, Hao Xu
On 8/30/23 12:57, Miklos Szeredi wrote:
> On Tue, 29 Aug 2023 at 18:11, Bernd Schubert <bschubert@ddn.com> wrote:
>>
>> This is just a preparation to avoid code duplication in the next
>> commit.
>>
>> Cc: Hao Xu <howeyxu@tencent.com>
>> Cc: Miklos Szeredi <miklos@szeredi.hu>
>> Cc: Dharmendra Singh <dsingh@ddn.com>
>> Signed-off-by: Bernd Schubert <bschubert@ddn.com>
>> ---
>> fs/fuse/file.c | 48 +++++++++++++++++++++++++++++++++---------------
>> 1 file changed, 33 insertions(+), 15 deletions(-)
>>
>> diff --git a/fs/fuse/file.c b/fs/fuse/file.c
>> index b1b9f2b9a37d..6b8b9512c336 100644
>> --- a/fs/fuse/file.c
>> +++ b/fs/fuse/file.c
>> @@ -1298,6 +1298,37 @@ static ssize_t fuse_perform_write(struct kiocb *iocb, struct iov_iter *ii)
>> return res;
>> }
>>
>> +static bool fuse_io_past_eof(struct kiocb *iocb,
>> + struct iov_iter *iter)
>> +{
>> + struct inode *inode = file_inode(iocb->ki_filp);
>> +
>> + return iocb->ki_pos + iov_iter_count(iter) > i_size_read(inode);
>> +}
>> +
>> +/*
>> + * @return true if an exclusive lock direct IO writes is needed
>> + */
>> +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;
>> +
>> + /* server side has to advise that it supports parallel dio writes */
>> + if (!(ff->open_flags & FOPEN_PARALLEL_DIRECT_WRITES))
>> + return false;
>
> You got the return values the wrong way around. I can fix this, no
> need to resend.
Ooops, sorry! Do you mind to take this series for next merge round? I
obviously didn't test the latest series yet and I would like to first
test performance and do several rounds of xfs tests. That should be done
by Monday, but might be a bit late for 6.6
Thanks,
Bernd
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH 2/6] fuse: Create helper function if DIO write needs exclusive lock
2023-08-30 12:13 ` Bernd Schubert
@ 2023-08-30 12:14 ` Miklos Szeredi
0 siblings, 0 replies; 18+ messages in thread
From: Miklos Szeredi @ 2023-08-30 12:14 UTC (permalink / raw)
To: Bernd Schubert
Cc: Bernd Schubert, linux-fsdevel, bernd.schubert, dsingh, Hao Xu
On Wed, 30 Aug 2023 at 14:13, Bernd Schubert <aakef@fastmail.fm> wrote:
>
>
>
> On 8/30/23 12:57, Miklos Szeredi wrote:
> > On Tue, 29 Aug 2023 at 18:11, Bernd Schubert <bschubert@ddn.com> wrote:
> >>
> >> This is just a preparation to avoid code duplication in the next
> >> commit.
> >>
> >> Cc: Hao Xu <howeyxu@tencent.com>
> >> Cc: Miklos Szeredi <miklos@szeredi.hu>
> >> Cc: Dharmendra Singh <dsingh@ddn.com>
> >> Signed-off-by: Bernd Schubert <bschubert@ddn.com>
> >> ---
> >> fs/fuse/file.c | 48 +++++++++++++++++++++++++++++++++---------------
> >> 1 file changed, 33 insertions(+), 15 deletions(-)
> >>
> >> diff --git a/fs/fuse/file.c b/fs/fuse/file.c
> >> index b1b9f2b9a37d..6b8b9512c336 100644
> >> --- a/fs/fuse/file.c
> >> +++ b/fs/fuse/file.c
> >> @@ -1298,6 +1298,37 @@ static ssize_t fuse_perform_write(struct kiocb *iocb, struct iov_iter *ii)
> >> return res;
> >> }
> >>
> >> +static bool fuse_io_past_eof(struct kiocb *iocb,
> >> + struct iov_iter *iter)
> >> +{
> >> + struct inode *inode = file_inode(iocb->ki_filp);
> >> +
> >> + return iocb->ki_pos + iov_iter_count(iter) > i_size_read(inode);
> >> +}
> >> +
> >> +/*
> >> + * @return true if an exclusive lock direct IO writes is needed
> >> + */
> >> +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;
> >> +
> >> + /* server side has to advise that it supports parallel dio writes */
> >> + if (!(ff->open_flags & FOPEN_PARALLEL_DIRECT_WRITES))
> >> + return false;
> >
> > You got the return values the wrong way around. I can fix this, no
> > need to resend.
>
> Ooops, sorry! Do you mind to take this series for next merge round? I
> obviously didn't test the latest series yet and I would like to first
> test performance and do several rounds of xfs tests. That should be done
> by Monday, but might be a bit late for 6.6
Right, this should aim for 6.7.
Thanks,
Miklos
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH 3/6] fuse: Allow parallel direct writes for O_DIRECT
2023-08-29 16:11 ` [PATCH 3/6] fuse: Allow parallel direct writes for O_DIRECT Bernd Schubert
@ 2023-08-30 13:28 ` Miklos Szeredi
2023-08-30 14:38 ` Bernd Schubert
2023-08-31 8:30 ` Hao Xu
1 sibling, 1 reply; 18+ messages in thread
From: Miklos Szeredi @ 2023-08-30 13:28 UTC (permalink / raw)
To: Bernd Schubert; +Cc: linux-fsdevel, bernd.schubert, dsingh, Hao Xu
On Tue, 29 Aug 2023 at 18:11, Bernd Schubert <bschubert@ddn.com> wrote:
>
> 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.
Hmm, I think file_remove_privs() needs exclusive lock (due to calling
notify_change()). And the fallback case also.
Need to be careful with such locking changes...
Thanks,
Miklos
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH 3/6] fuse: Allow parallel direct writes for O_DIRECT
2023-08-30 13:28 ` Miklos Szeredi
@ 2023-08-30 14:38 ` Bernd Schubert
2023-08-30 14:50 ` Miklos Szeredi
0 siblings, 1 reply; 18+ messages in thread
From: Bernd Schubert @ 2023-08-30 14:38 UTC (permalink / raw)
To: Miklos Szeredi, Bernd Schubert
Cc: linux-fsdevel, bernd.schubert, dsingh, Hao Xu
On 8/30/23 15:28, Miklos Szeredi wrote:
> On Tue, 29 Aug 2023 at 18:11, Bernd Schubert <bschubert@ddn.com> wrote:
>>
>> 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.
>
> Hmm, I think file_remove_privs() needs exclusive lock (due to calling
> notify_change()). And the fallback case also.
>
> Need to be careful with such locking changes...
Hrmm, yeah, I missed that :( Really sorry and thanks!
I guess I can fix it if by exporting dentry_needs_remove_privs. I hope
that is acceptable. Interesting is that btrfs_direct_write seems to have
the same issue.
btrfs_direct_write
if (iocb->ki_pos + iov_iter_count(from) <= i_size_read(inode))
ilock_flags |= BTRFS_ILOCK_SHARED;
...
err = btrfs_inode_lock(BTRFS_I(inode), ilock_flags);
...
err = btrfs_write_check(iocb, from, err);
...
ret = file_remove_privs(file);
I think that can be fixed as well after exporting
dentry_needs_remove_privs().
Btw, why is fuse_direct_write_iter not dropping privileges? That is
another change I need to document...
Another issue I just see is that it needs to check file size again after
taking the lock.
Thanks a lot for your review,
Bernd
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH 3/6] fuse: Allow parallel direct writes for O_DIRECT
2023-08-30 14:38 ` Bernd Schubert
@ 2023-08-30 14:50 ` Miklos Szeredi
0 siblings, 0 replies; 18+ messages in thread
From: Miklos Szeredi @ 2023-08-30 14:50 UTC (permalink / raw)
To: Bernd Schubert
Cc: Bernd Schubert, linux-fsdevel, bernd.schubert, dsingh, Hao Xu
On Wed, 30 Aug 2023 at 16:38, Bernd Schubert <aakef@fastmail.fm> wrote:
>
>
>
> On 8/30/23 15:28, Miklos Szeredi wrote:
> > On Tue, 29 Aug 2023 at 18:11, Bernd Schubert <bschubert@ddn.com> wrote:
> >>
> >> 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.
> >
> > Hmm, I think file_remove_privs() needs exclusive lock (due to calling
> > notify_change()). And the fallback case also.
> >
> > Need to be careful with such locking changes...
>
> Hrmm, yeah, I missed that :( Really sorry and thanks!
>
> I guess I can fix it if by exporting dentry_needs_remove_privs. I hope
> that is acceptable. Interesting is that btrfs_direct_write seems to have
> the same issue.
>
> btrfs_direct_write
> if (iocb->ki_pos + iov_iter_count(from) <= i_size_read(inode))
> ilock_flags |= BTRFS_ILOCK_SHARED;
> ...
> err = btrfs_inode_lock(BTRFS_I(inode), ilock_flags);
> ...
> err = btrfs_write_check(iocb, from, err);
> ...
> ret = file_remove_privs(file);
>
>
> I think that can be fixed as well after exporting
> dentry_needs_remove_privs().
Interesting. Would be worth asking the btrfs devs what they think of this.
>
>
> Btw, why is fuse_direct_write_iter not dropping privileges? That is
> another change I need to document...
Generally read and write can't fail due to lack of privileges, so that
should be okay. But it would be more consistent to drop privs during
I/O as well. But this is something that needs some thought as well,
because there could be non-obvious consequences.
> Another issue I just see is that it needs to check file size again after
> taking the lock.
Yes.
> Thanks a lot for your review,
Thanks for doing the actual work, that's the harder one.
Thanks,
Miklos
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH 3/6] fuse: Allow parallel direct writes for O_DIRECT
2023-08-29 16:11 ` [PATCH 3/6] fuse: Allow parallel direct writes for O_DIRECT Bernd Schubert
2023-08-30 13:28 ` Miklos Szeredi
@ 2023-08-31 8:30 ` Hao Xu
2023-08-31 8:33 ` Bernd Schubert
1 sibling, 1 reply; 18+ messages in thread
From: Hao Xu @ 2023-08-31 8:30 UTC (permalink / raw)
To: Bernd Schubert, linux-fsdevel; +Cc: bernd.schubert, miklos, dsingh, Hao Xu
On 8/30/23 00:11, Bernd Schubert wrote:
> 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.
>
> 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 | 18 ++++++++++++++++--
> 1 file changed, 16 insertions(+), 2 deletions(-)
>
> diff --git a/fs/fuse/file.c b/fs/fuse/file.c
> index 6b8b9512c336..a6b99bc80fe7 100644
> --- a/fs/fuse/file.c
> +++ b/fs/fuse/file.c
> @@ -1314,6 +1314,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;
>
> + /* this function is about direct IO only */
> + if (!(iocb->ki_flags & IOCB_DIRECT))
> + return false;
This means for buffered write in fuse_cache_write_iter(), we grab shared
lock, looks not right.
> +
> /* server side has to advise that it supports parallel dio writes */
> if (!(ff->open_flags & FOPEN_PARALLEL_DIRECT_WRITES))
> return false;
> @@ -1337,6 +1341,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);
>
> if (fc->writeback_cache && !(iocb->ki_flags & IOCB_DIRECT)) {
> /* Update size (EOF optimization) and mode (SUID clearing) */
> @@ -1355,7 +1360,10 @@ static ssize_t fuse_cache_write_iter(struct kiocb *iocb, struct iov_iter *from)
> }
>
> writethrough:
> - inode_lock(inode);
> + if (excl_lock)
> + inode_lock(inode);
> + else
> + inode_lock_shared(inode);
>
> err = generic_write_checks(iocb, from);
> if (err <= 0)
> @@ -1370,6 +1378,9 @@ static ssize_t fuse_cache_write_iter(struct kiocb *iocb, struct iov_iter *from)
> goto out;
>
> if (iocb->ki_flags & IOCB_DIRECT) {
> + /* file extending writes will trigger i_size_write - exclusive
> + * lock is needed
> + */
> written = generic_file_direct_write(iocb, from);
> if (written < 0 || !iov_iter_count(from))
> goto out;
> @@ -1379,7 +1390,10 @@ static ssize_t fuse_cache_write_iter(struct kiocb *iocb, struct iov_iter *from)
> 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);
>
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH 3/6] fuse: Allow parallel direct writes for O_DIRECT
2023-08-31 8:30 ` Hao Xu
@ 2023-08-31 8:33 ` Bernd Schubert
0 siblings, 0 replies; 18+ messages in thread
From: Bernd Schubert @ 2023-08-31 8:33 UTC (permalink / raw)
To: Hao Xu, Bernd Schubert, linux-fsdevel; +Cc: miklos, dsingh, Hao Xu
On 8/31/23 10:30, Hao Xu wrote:
> On 8/30/23 00:11, Bernd Schubert wrote:
>> 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.
>>
>> 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 | 18 ++++++++++++++++--
>> 1 file changed, 16 insertions(+), 2 deletions(-)
>>
>> diff --git a/fs/fuse/file.c b/fs/fuse/file.c
>> index 6b8b9512c336..a6b99bc80fe7 100644
>> --- a/fs/fuse/file.c
>> +++ b/fs/fuse/file.c
>> @@ -1314,6 +1314,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;
>> + /* this function is about direct IO only */
>> + if (!(iocb->ki_flags & IOCB_DIRECT))
>> + return false;
>
> This means for buffered write in fuse_cache_write_iter(), we grab shared
> lock, looks not right.
>
Yeah, sorry, I made all values the other way around, consistently.
Miklos had already noticed.
Thanks,
Bernd
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH 5/6] fuse: Remove fuse_direct_write_iter code path / use IOCB_DIRECT
2023-08-29 16:11 ` [PATCH 5/6] fuse: Remove fuse_direct_write_iter code path / use IOCB_DIRECT Bernd Schubert
@ 2023-08-31 9:19 ` Hao Xu
2023-08-31 9:34 ` Bernd Schubert
0 siblings, 1 reply; 18+ messages in thread
From: Hao Xu @ 2023-08-31 9:19 UTC (permalink / raw)
To: Bernd Schubert, linux-fsdevel; +Cc: bernd.schubert, miklos, dsingh, Hao Xu
On 8/30/23 00:11, Bernd Schubert wrote:
> fuse_direct_write_iter is basically duplicating what is already
> in fuse_cache_write_iter/generic_file_direct_write. That can be
> avoided by setting IOCB_DIRECT in fuse_file_write_iter, after that
> fuse_cache_write_iter can be used for the FOPEN_DIRECT_IO code path
> and fuse_direct_write_iter can be removed.
>
> Before it was using for FOPEN_DIRECT_IO
>
> 1) async (!is_sync_kiocb(iocb)) && IOCB_DIRECT
>
> fuse_file_write_iter
> fuse_direct_write_iter
> fuse_direct_IO
> fuse_send_dio
>
> 2) sync (is_sync_kiocb(iocb)) or IOCB_DIRECT not being set
>
> fuse_file_write_iter
> fuse_direct_write_iter
> fuse_send_dio
>
> 3) FOPEN_DIRECT_IO not set
>
> Same as the consolidates path below
>
> The new consolidated code path is always
>
> fuse_file_write_iter
> fuse_cache_write_iter
> generic_file_write_iter
> __generic_file_write_iter
> generic_file_direct_write
> mapping->a_ops->direct_IO / fuse_direct_IO
> fuse_send_dio
>
> So in general for FOPEN_DIRECT_IO the code path gets longer. Additionally
> fuse_direct_IO does an allocation of struct fuse_io_priv - might be a bit
> slower in micro benchmarks.
> Also, the IOCB_DIRECT information gets lost (as we now set it outselves).
> But then IOCB_DIRECT is directly related to O_DIRECT set in
> struct file::f_flags.
>
> An additional change is for condition 2 above, which might will now do
> async IO on the condition ff->fm->fc->async_dio. Given that async IO for
> FOPEN_DIRECT_IO was especially introduced in commit
> 'commit 23c94e1cdcbf ("fuse: Switch to using async direct IO for
> FOPEN_DIRECT_IO")'
> it should not matter. Especially as fuse_direct_IO is blocking for
> is_sync_kiocb(), at worst it has another slight overhead.
>
> Advantage is the removal of code paths and conditions and it is now also
> possible to remove FOPEN_DIRECT_IO conditions in fuse_send_dio
> (in a later patch).
>
> 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 | 54 ++++----------------------------------------------
> 1 file changed, 4 insertions(+), 50 deletions(-)
>
> diff --git a/fs/fuse/file.c b/fs/fuse/file.c
> index f9d21804d313..0b3363eec435 100644
> --- a/fs/fuse/file.c
> +++ b/fs/fuse/file.c
> @@ -1602,52 +1602,6 @@ static ssize_t fuse_direct_read_iter(struct kiocb *iocb, struct iov_iter *to)
> return res;
> }
>
> -static ssize_t fuse_direct_write_iter(struct kiocb *iocb, struct iov_iter *from)
> -{
> - struct inode *inode = file_inode(iocb->ki_filp);
> - struct fuse_io_priv io = FUSE_IO_PRIV_SYNC(iocb);
> - ssize_t res;
> - bool exclusive_lock = fuse_dio_wr_exclusive_lock(iocb, from);
> -
> - /*
> - * Take exclusive lock if
> - * - Parallel direct writes are disabled - a user space decision
> - * - Parallel direct writes are enabled and i_size is being extended.
> - * This might not be needed at all, but needs further investigation.
> - */
> - if (exclusive_lock)
> - inode_lock(inode);
> - else {
> - inode_lock_shared(inode);
> -
> - /* A race with truncate might have come up as the decision for
> - * the lock type was done without holding the lock, check again.
> - */
> - if (fuse_io_past_eof(iocb, from)) {
> - inode_unlock_shared(inode);
> - inode_lock(inode);
> - exclusive_lock = true;
> - }
> - }
> -
> - res = generic_write_checks(iocb, from);
> - if (res > 0) {
> - if (!is_sync_kiocb(iocb) && iocb->ki_flags & IOCB_DIRECT) {
> - res = fuse_direct_IO(iocb, from);
> - } else {
> - res = fuse_send_dio(&io, from, &iocb->ki_pos,
> - FUSE_DIO_WRITE);
> - fuse_write_update_attr(inode, iocb->ki_pos, res);
> - }
> - }
> - if (exclusive_lock)
> - inode_unlock(inode);
> - else
> - inode_unlock_shared(inode);
> -
> - return res;
> -}
> -
> static ssize_t fuse_file_read_iter(struct kiocb *iocb, struct iov_iter *to)
> {
> struct file *file = iocb->ki_filp;
> @@ -1678,10 +1632,10 @@ static ssize_t fuse_file_write_iter(struct kiocb *iocb, struct iov_iter *from)
> if (FUSE_IS_DAX(inode))
> return fuse_dax_write_iter(iocb, from);
>
> - if (!(ff->open_flags & FOPEN_DIRECT_IO))
> - return fuse_cache_write_iter(iocb, from);
> - else
> - return fuse_direct_write_iter(iocb, from);
> + if (ff->open_flags & FOPEN_DIRECT_IO)
> + iocb->ki_flags |= IOCB_DIRECT;
I think this affect the back-end behavior, changes a buffered IO to
direct io. FOPEN_DIRECT_IO means no cache in front-end, but we should
respect the back-end semantics. We may need another way to indicate
"we need go the direct io code path while IOCB_DIRECT is not set though".
> +
> + return fuse_cache_write_iter(iocb, from);
> }
>
> static void fuse_writepage_free(struct fuse_writepage_args *wpa)
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH 5/6] fuse: Remove fuse_direct_write_iter code path / use IOCB_DIRECT
2023-08-31 9:19 ` Hao Xu
@ 2023-08-31 9:34 ` Bernd Schubert
2023-09-01 2:54 ` Hao Xu
0 siblings, 1 reply; 18+ messages in thread
From: Bernd Schubert @ 2023-08-31 9:34 UTC (permalink / raw)
To: Hao Xu, Bernd Schubert, linux-fsdevel; +Cc: miklos, dsingh, Hao Xu
On 8/31/23 11:19, Hao Xu wrote:
> On 8/30/23 00:11, Bernd Schubert wrote:
>> fuse_direct_write_iter is basically duplicating what is already
>> in fuse_cache_write_iter/generic_file_direct_write. That can be
>> avoided by setting IOCB_DIRECT in fuse_file_write_iter, after that
>> fuse_cache_write_iter can be used for the FOPEN_DIRECT_IO code path
>> and fuse_direct_write_iter can be removed.
>>
>> Before it was using for FOPEN_DIRECT_IO
>>
>> 1) async (!is_sync_kiocb(iocb)) && IOCB_DIRECT
>>
>> fuse_file_write_iter
>> fuse_direct_write_iter
>> fuse_direct_IO
>> fuse_send_dio
>>
>> 2) sync (is_sync_kiocb(iocb)) or IOCB_DIRECT not being set
>>
>> fuse_file_write_iter
>> fuse_direct_write_iter
>> fuse_send_dio
>>
>> 3) FOPEN_DIRECT_IO not set
>>
>> Same as the consolidates path below
>>
>> The new consolidated code path is always
>>
>> fuse_file_write_iter
>> fuse_cache_write_iter
>> generic_file_write_iter
>> __generic_file_write_iter
>> generic_file_direct_write
>> mapping->a_ops->direct_IO / fuse_direct_IO
>> fuse_send_dio
>>
>> So in general for FOPEN_DIRECT_IO the code path gets longer. Additionally
>> fuse_direct_IO does an allocation of struct fuse_io_priv - might be a bit
>> slower in micro benchmarks.
>> Also, the IOCB_DIRECT information gets lost (as we now set it outselves).
>> But then IOCB_DIRECT is directly related to O_DIRECT set in
>> struct file::f_flags.
>>
>> An additional change is for condition 2 above, which might will now do
>> async IO on the condition ff->fm->fc->async_dio. Given that async IO for
>> FOPEN_DIRECT_IO was especially introduced in commit
>> 'commit 23c94e1cdcbf ("fuse: Switch to using async direct IO for
>> FOPEN_DIRECT_IO")'
>> it should not matter. Especially as fuse_direct_IO is blocking for
>> is_sync_kiocb(), at worst it has another slight overhead.
>>
>> Advantage is the removal of code paths and conditions and it is now also
>> possible to remove FOPEN_DIRECT_IO conditions in fuse_send_dio
>> (in a later patch).
>>
>> 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 | 54 ++++----------------------------------------------
>> 1 file changed, 4 insertions(+), 50 deletions(-)
>>
>> diff --git a/fs/fuse/file.c b/fs/fuse/file.c
>> index f9d21804d313..0b3363eec435 100644
>> --- a/fs/fuse/file.c
>> +++ b/fs/fuse/file.c
>> @@ -1602,52 +1602,6 @@ static ssize_t fuse_direct_read_iter(struct
>> kiocb *iocb, struct iov_iter *to)
>> return res;
>> }
>> -static ssize_t fuse_direct_write_iter(struct kiocb *iocb, struct
>> iov_iter *from)
>> -{
>> - struct inode *inode = file_inode(iocb->ki_filp);
>> - struct fuse_io_priv io = FUSE_IO_PRIV_SYNC(iocb);
>> - ssize_t res;
>> - bool exclusive_lock = fuse_dio_wr_exclusive_lock(iocb, from);
>> -
>> - /*
>> - * Take exclusive lock if
>> - * - Parallel direct writes are disabled - a user space decision
>> - * - Parallel direct writes are enabled and i_size is being
>> extended.
>> - * This might not be needed at all, but needs further
>> investigation.
>> - */
>> - if (exclusive_lock)
>> - inode_lock(inode);
>> - else {
>> - inode_lock_shared(inode);
>> -
>> - /* A race with truncate might have come up as the decision for
>> - * the lock type was done without holding the lock, check again.
>> - */
>> - if (fuse_io_past_eof(iocb, from)) {
>> - inode_unlock_shared(inode);
>> - inode_lock(inode);
>> - exclusive_lock = true;
>> - }
>> - }
>> -
>> - res = generic_write_checks(iocb, from);
>> - if (res > 0) {
>> - if (!is_sync_kiocb(iocb) && iocb->ki_flags & IOCB_DIRECT) {
>> - res = fuse_direct_IO(iocb, from);
>> - } else {
>> - res = fuse_send_dio(&io, from, &iocb->ki_pos,
>> - FUSE_DIO_WRITE);
>> - fuse_write_update_attr(inode, iocb->ki_pos, res);
>> - }
>> - }
>> - if (exclusive_lock)
>> - inode_unlock(inode);
>> - else
>> - inode_unlock_shared(inode);
>> -
>> - return res;
>> -}
>> -
>> static ssize_t fuse_file_read_iter(struct kiocb *iocb, struct
>> iov_iter *to)
>> {
>> struct file *file = iocb->ki_filp;
>> @@ -1678,10 +1632,10 @@ static ssize_t fuse_file_write_iter(struct
>> kiocb *iocb, struct iov_iter *from)
>> if (FUSE_IS_DAX(inode))
>> return fuse_dax_write_iter(iocb, from);
>> - if (!(ff->open_flags & FOPEN_DIRECT_IO))
>> - return fuse_cache_write_iter(iocb, from);
>> - else
>> - return fuse_direct_write_iter(iocb, from);
>> + if (ff->open_flags & FOPEN_DIRECT_IO)
>> + iocb->ki_flags |= IOCB_DIRECT;
>
> I think this affect the back-end behavior, changes a buffered IO to
> direct io. FOPEN_DIRECT_IO means no cache in front-end, but we should
> respect the back-end semantics. We may need another way to indicate
> "we need go the direct io code path while IOCB_DIRECT is not set though".
I'm confused here, I guess with frontend you mean fuse kernel and with
backend fuse userspace (daemon/server). IOCB_DIRECT is not passed to
server/daemon, so there is no change? Although maybe I should document
in fuse_write_flags() to be careful with returned flags and that
IOCB_DIRECT cannot be trusted - if this should ever passed, one needs to
use struct file::flags & O_DIRECT.
Thanks,
Bernd
Thanks,
Bernd
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH 5/6] fuse: Remove fuse_direct_write_iter code path / use IOCB_DIRECT
2023-08-31 9:34 ` Bernd Schubert
@ 2023-09-01 2:54 ` Hao Xu
0 siblings, 0 replies; 18+ messages in thread
From: Hao Xu @ 2023-09-01 2:54 UTC (permalink / raw)
To: Bernd Schubert, Bernd Schubert, linux-fsdevel; +Cc: miklos, dsingh
On 8/31/23 17:34, Bernd Schubert wrote:
>
>
> On 8/31/23 11:19, Hao Xu wrote:
>> On 8/30/23 00:11, Bernd Schubert wrote:
>>> fuse_direct_write_iter is basically duplicating what is already
>>> in fuse_cache_write_iter/generic_file_direct_write. That can be
>>> avoided by setting IOCB_DIRECT in fuse_file_write_iter, after that
>>> fuse_cache_write_iter can be used for the FOPEN_DIRECT_IO code path
>>> and fuse_direct_write_iter can be removed.
>>>
>>> Before it was using for FOPEN_DIRECT_IO
>>>
>>> 1) async (!is_sync_kiocb(iocb)) && IOCB_DIRECT
>>>
>>> fuse_file_write_iter
>>> fuse_direct_write_iter
>>> fuse_direct_IO
>>> fuse_send_dio
>>>
>>> 2) sync (is_sync_kiocb(iocb)) or IOCB_DIRECT not being set
>>>
>>> fuse_file_write_iter
>>> fuse_direct_write_iter
>>> fuse_send_dio
>>>
>>> 3) FOPEN_DIRECT_IO not set
>>>
>>> Same as the consolidates path below
>>>
>>> The new consolidated code path is always
>>>
>>> fuse_file_write_iter
>>> fuse_cache_write_iter
>>> generic_file_write_iter
>>> __generic_file_write_iter
>>> generic_file_direct_write
>>> mapping->a_ops->direct_IO / fuse_direct_IO
>>> fuse_send_dio
>>>
>>> So in general for FOPEN_DIRECT_IO the code path gets longer.
>>> Additionally
>>> fuse_direct_IO does an allocation of struct fuse_io_priv - might be
>>> a bit
>>> slower in micro benchmarks.
>>> Also, the IOCB_DIRECT information gets lost (as we now set it
>>> outselves).
>>> But then IOCB_DIRECT is directly related to O_DIRECT set in
>>> struct file::f_flags.
>>>
>>> An additional change is for condition 2 above, which might will now do
>>> async IO on the condition ff->fm->fc->async_dio. Given that async IO
>>> for
>>> FOPEN_DIRECT_IO was especially introduced in commit
>>> 'commit 23c94e1cdcbf ("fuse: Switch to using async direct IO for
>>> FOPEN_DIRECT_IO")'
>>> it should not matter. Especially as fuse_direct_IO is blocking for
>>> is_sync_kiocb(), at worst it has another slight overhead.
>>>
>>> Advantage is the removal of code paths and conditions and it is now
>>> also
>>> possible to remove FOPEN_DIRECT_IO conditions in fuse_send_dio
>>> (in a later patch).
>>>
>>> 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 | 54
>>> ++++----------------------------------------------
>>> 1 file changed, 4 insertions(+), 50 deletions(-)
>>>
>>> diff --git a/fs/fuse/file.c b/fs/fuse/file.c
>>> index f9d21804d313..0b3363eec435 100644
>>> --- a/fs/fuse/file.c
>>> +++ b/fs/fuse/file.c
>>> @@ -1602,52 +1602,6 @@ static ssize_t fuse_direct_read_iter(struct
>>> kiocb *iocb, struct iov_iter *to)
>>> return res;
>>> }
>>> -static ssize_t fuse_direct_write_iter(struct kiocb *iocb, struct
>>> iov_iter *from)
>>> -{
>>> - struct inode *inode = file_inode(iocb->ki_filp);
>>> - struct fuse_io_priv io = FUSE_IO_PRIV_SYNC(iocb);
>>> - ssize_t res;
>>> - bool exclusive_lock = fuse_dio_wr_exclusive_lock(iocb, from);
>>> -
>>> - /*
>>> - * Take exclusive lock if
>>> - * - Parallel direct writes are disabled - a user space decision
>>> - * - Parallel direct writes are enabled and i_size is being
>>> extended.
>>> - * This might not be needed at all, but needs further
>>> investigation.
>>> - */
>>> - if (exclusive_lock)
>>> - inode_lock(inode);
>>> - else {
>>> - inode_lock_shared(inode);
>>> -
>>> - /* A race with truncate might have come up as the decision for
>>> - * the lock type was done without holding the lock, check
>>> again.
>>> - */
>>> - if (fuse_io_past_eof(iocb, from)) {
>>> - inode_unlock_shared(inode);
>>> - inode_lock(inode);
>>> - exclusive_lock = true;
>>> - }
>>> - }
>>> -
>>> - res = generic_write_checks(iocb, from);
>>> - if (res > 0) {
>>> - if (!is_sync_kiocb(iocb) && iocb->ki_flags & IOCB_DIRECT) {
>>> - res = fuse_direct_IO(iocb, from);
>>> - } else {
>>> - res = fuse_send_dio(&io, from, &iocb->ki_pos,
>>> - FUSE_DIO_WRITE);
>>> - fuse_write_update_attr(inode, iocb->ki_pos, res);
>>> - }
>>> - }
>>> - if (exclusive_lock)
>>> - inode_unlock(inode);
>>> - else
>>> - inode_unlock_shared(inode);
>>> -
>>> - return res;
>>> -}
>>> -
>>> static ssize_t fuse_file_read_iter(struct kiocb *iocb, struct
>>> iov_iter *to)
>>> {
>>> struct file *file = iocb->ki_filp;
>>> @@ -1678,10 +1632,10 @@ static ssize_t fuse_file_write_iter(struct
>>> kiocb *iocb, struct iov_iter *from)
>>> if (FUSE_IS_DAX(inode))
>>> return fuse_dax_write_iter(iocb, from);
>>> - if (!(ff->open_flags & FOPEN_DIRECT_IO))
>>> - return fuse_cache_write_iter(iocb, from);
>>> - else
>>> - return fuse_direct_write_iter(iocb, from);
>>> + if (ff->open_flags & FOPEN_DIRECT_IO)
>>> + iocb->ki_flags |= IOCB_DIRECT;
>>
>> I think this affect the back-end behavior, changes a buffered IO to
>> direct io. FOPEN_DIRECT_IO means no cache in front-end, but we should
>> respect the back-end semantics. We may need another way to indicate
>> "we need go the direct io code path while IOCB_DIRECT is not set
>> though".
>
> I'm confused here, I guess with frontend you mean fuse kernel and with
> backend fuse userspace (daemon/server). IOCB_DIRECT is not passed to
> server/daemon, so there is no change? Although maybe I should document
> in fuse_write_flags() to be careful with returned flags and that
> IOCB_DIRECT cannot be trusted - if this should ever passed, one needs
> to use struct file::flags & O_DIRECT.
>
I see, I misunderstood the code, `iocb->ki_filp->f_flags` not
`iocb->ki_flags`...
Thanks,
Hao
>
> Thanks,
> Bernd
>
>
> Thanks,
> Bernd
^ permalink raw reply [flat|nested] 18+ messages in thread
end of thread, other threads:[~2023-09-01 2:54 UTC | newest]
Thread overview: 18+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2023-08-29 16:11 [PATCH 0/5 v3] fuse direct write consolidation and parallel IO Bernd Schubert
2023-08-29 16:11 ` [PATCH 1/6] fuse: direct IO can use the write-through code path Bernd Schubert
2023-08-29 16:11 ` [PATCH 2/6] fuse: Create helper function if DIO write needs exclusive lock Bernd Schubert
2023-08-30 10:57 ` Miklos Szeredi
2023-08-30 12:13 ` Bernd Schubert
2023-08-30 12:14 ` Miklos Szeredi
2023-08-29 16:11 ` [PATCH 3/6] fuse: Allow parallel direct writes for O_DIRECT Bernd Schubert
2023-08-30 13:28 ` Miklos Szeredi
2023-08-30 14:38 ` Bernd Schubert
2023-08-30 14:50 ` Miklos Szeredi
2023-08-31 8:30 ` Hao Xu
2023-08-31 8:33 ` Bernd Schubert
2023-08-29 16:11 ` [PATCH 4/6] fuse: Rename fuse_direct_io Bernd Schubert
2023-08-29 16:11 ` [PATCH 5/6] fuse: Remove fuse_direct_write_iter code path / use IOCB_DIRECT Bernd Schubert
2023-08-31 9:19 ` Hao Xu
2023-08-31 9:34 ` Bernd Schubert
2023-09-01 2:54 ` Hao Xu
2023-08-29 16:11 ` [PATCH 6/6] fuse: Remove page flush/invaliation in fuse_direct_io Bernd Schubert
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).