fuse: add a new fuse init flag to relax restrictions in no cache mode
authorHao Xu <howeyxu@tencent.com>
Tue, 1 Aug 2023 08:06:46 +0000 (16:06 +0800)
committerMiklos Szeredi <mszeredi@redhat.com>
Wed, 16 Aug 2023 10:39:16 +0000 (12:39 +0200)
FOPEN_DIRECT_IO is usually set by fuse daemon to indicate need of strong
coherency, e.g. network filesystems.  Thus shared mmap is disabled since it
leverages page cache and may write to it, which may cause inconsistence.

But FOPEN_DIRECT_IO can be used not for coherency but to reduce memory
footprint as well, e.g. reduce guest memory usage with virtiofs.
Therefore, add a new fuse init flag FUSE_DIRECT_IO_RELAX to relax
restrictions in that mode, currently, it allows shared mmap.  One thing to
note is to make sure it doesn't break coherency in your use case.

Signed-off-by: Hao Xu <howeyxu@tencent.com>
Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
fs/fuse/file.c
fs/fuse/fuse_i.h
fs/fuse/inode.c
include/uapi/linux/fuse.h

index 1aa7dde..e6034ce 100644 (file)
@@ -2451,14 +2451,17 @@ static const struct vm_operations_struct fuse_file_vm_ops = {
 static int fuse_file_mmap(struct file *file, struct vm_area_struct *vma)
 {
        struct fuse_file *ff = file->private_data;
+       struct fuse_conn *fc = ff->fm->fc;
 
        /* DAX mmap is superior to direct_io mmap */
        if (FUSE_IS_DAX(file_inode(file)))
                return fuse_dax_mmap(file, vma);
 
        if (ff->open_flags & FOPEN_DIRECT_IO) {
-               /* Can't provide the coherency needed for MAP_SHARED */
-               if (vma->vm_flags & VM_MAYSHARE)
+               /* Can't provide the coherency needed for MAP_SHARED
+                * if FUSE_DIRECT_IO_RELAX isn't set.
+                */
+               if ((vma->vm_flags & VM_MAYSHARE) && !fc->direct_io_relax)
                        return -ENODEV;
 
                invalidate_inode_pages2(file->f_mapping);
index 9b7fc7d..d830c23 100644 (file)
@@ -792,6 +792,9 @@ struct fuse_conn {
        /* Is tmpfile not implemented by fs? */
        unsigned int no_tmpfile:1;
 
+       /* relax restrictions in FOPEN_DIRECT_IO mode */
+       unsigned int direct_io_relax:1;
+
        /** The number of requests waiting for completion */
        atomic_t num_waiting;
 
index f19d748..4a16185 100644 (file)
@@ -1212,6 +1212,8 @@ static void process_init_reply(struct fuse_mount *fm, struct fuse_args *args,
                                fc->init_security = 1;
                        if (flags & FUSE_CREATE_SUPP_GROUP)
                                fc->create_supp_group = 1;
+                       if (flags & FUSE_DIRECT_IO_RELAX)
+                               fc->direct_io_relax = 1;
                } else {
                        ra_pages = fc->max_read / PAGE_SIZE;
                        fc->no_lock = 1;
@@ -1258,7 +1260,7 @@ void fuse_send_init(struct fuse_mount *fm)
                FUSE_NO_OPENDIR_SUPPORT | FUSE_EXPLICIT_INVAL_DATA |
                FUSE_HANDLE_KILLPRIV_V2 | FUSE_SETXATTR_EXT | FUSE_INIT_EXT |
                FUSE_SECURITY_CTX | FUSE_CREATE_SUPP_GROUP |
-               FUSE_HAS_EXPIRE_ONLY;
+               FUSE_HAS_EXPIRE_ONLY | FUSE_DIRECT_IO_RELAX;
 #ifdef CONFIG_FUSE_DAX
        if (fm->fc->dax)
                flags |= FUSE_MAP_ALIGNMENT;
index b3fcab1..c2da950 100644 (file)
  *  - add FUSE_EXT_GROUPS
  *  - add FUSE_CREATE_SUPP_GROUP
  *  - add FUSE_HAS_EXPIRE_ONLY
+ *
+ *  7.39
+ *  - add FUSE_DIRECT_IO_RELAX
  */
 
 #ifndef _LINUX_FUSE_H
 #define FUSE_KERNEL_VERSION 7
 
 /** Minor version number of this interface */
-#define FUSE_KERNEL_MINOR_VERSION 38
+#define FUSE_KERNEL_MINOR_VERSION 39
 
 /** The node ID of the root inode */
 #define FUSE_ROOT_ID 1
@@ -371,6 +374,8 @@ struct fuse_file_lock {
  * FUSE_CREATE_SUPP_GROUP: add supplementary group info to create, mkdir,
  *                     symlink and mknod (single group that matches parent)
  * FUSE_HAS_EXPIRE_ONLY: kernel supports expiry-only entry invalidation
+ * FUSE_DIRECT_IO_RELAX: relax restrictions in FOPEN_DIRECT_IO mode, for now
+ *                       allow shared mmap
  */
 #define FUSE_ASYNC_READ                (1 << 0)
 #define FUSE_POSIX_LOCKS       (1 << 1)
@@ -409,6 +414,7 @@ struct fuse_file_lock {
 #define FUSE_HAS_INODE_DAX     (1ULL << 33)
 #define FUSE_CREATE_SUPP_GROUP (1ULL << 34)
 #define FUSE_HAS_EXPIRE_ONLY   (1ULL << 35)
+#define FUSE_DIRECT_IO_RELAX   (1ULL << 36)
 
 /**
  * CUSE INIT request/reply flags