]> git.ipfire.org Git - thirdparty/kernel/linux.git/blobdiff - fs/fuse/fuse_i.h
fuse: introduce FUSE_PASSTHROUGH capability
[thirdparty/kernel/linux.git] / fs / fuse / fuse_i.h
index 1df83eebda92771d20a42ea2aaefa118effcbc77..19a86acc9dd03b8a68e395e26bf4d5d7a3114cb6 100644 (file)
@@ -76,6 +76,15 @@ struct fuse_submount_lookup {
        struct fuse_forget_link *forget;
 };
 
+/** Container for data related to mapping to backing file */
+struct fuse_backing {
+       struct file *file;
+
+       /** refcount */
+       refcount_t count;
+       struct rcu_head rcu;
+};
+
 /** FUSE inode */
 struct fuse_inode {
        /** Inode data */
@@ -111,7 +120,7 @@ struct fuse_inode {
        u64 attr_version;
 
        union {
-               /* Write related fields (regular file only) */
+               /* read/write io cache (regular file only) */
                struct {
                        /* Files usable in writepage.  Protected by fi->lock */
                        struct list_head write_files;
@@ -123,9 +132,15 @@ struct fuse_inode {
                         * (FUSE_NOWRITE) means more writes are blocked */
                        int writectr;
 
+                       /** Number of files/maps using page cache */
+                       int iocachectr;
+
                        /* Waitq for writepage completion */
                        wait_queue_head_t page_waitq;
 
+                       /* waitq for direct-io completion */
+                       wait_queue_head_t direct_io_waitq;
+
                        /* List of writepage requestst (pending or sent) */
                        struct rb_root writepages;
                };
@@ -173,6 +188,10 @@ struct fuse_inode {
 #endif
        /** Submount specific lookup tracking */
        struct fuse_submount_lookup *submount_lookup;
+#ifdef CONFIG_FUSE_PASSTHROUGH
+       /** Reference to backing file in passthrough mode */
+       struct fuse_backing *fb;
+#endif
 };
 
 /** FUSE inode state bits */
@@ -187,6 +206,8 @@ enum {
        FUSE_I_BAD,
        /* Has btime */
        FUSE_I_BTIME,
+       /* Wants or already has page cache IO */
+       FUSE_I_CACHE_IO_MODE,
 };
 
 struct fuse_conn;
@@ -244,6 +265,9 @@ struct fuse_file {
        /** Wait queue head for poll */
        wait_queue_head_t poll_wait;
 
+       /** Does file hold a fi->iocachectr refcount? */
+       enum { IOM_NONE, IOM_CACHED, IOM_UNCACHED } iomode;
+
        /** Has flock been performed on this file? */
        bool flock:1;
 };
@@ -818,6 +842,12 @@ struct fuse_conn {
        /* Is statx not implemented by fs? */
        unsigned int no_statx:1;
 
+       /** Passthrough support for read/write IO */
+       unsigned int passthrough:1;
+
+       /** Maximum stack depth for passthrough backing files */
+       int max_stack_depth;
+
        /** The number of requests waiting for completion */
        atomic_t num_waiting;
 
@@ -1031,14 +1061,9 @@ void fuse_read_args_fill(struct fuse_io_args *ia, struct file *file, loff_t pos,
                         size_t count, int opcode);
 
 
-/**
- * Send OPEN or OPENDIR request
- */
-int fuse_open_common(struct inode *inode, struct file *file, bool isdir);
-
-struct fuse_file *fuse_file_alloc(struct fuse_mount *fm);
+struct fuse_file *fuse_file_alloc(struct fuse_mount *fm, bool release);
 void fuse_file_free(struct fuse_file *ff);
-void fuse_finish_open(struct inode *inode, struct file *file);
+int fuse_finish_open(struct inode *inode, struct file *file);
 
 void fuse_sync_release(struct fuse_inode *fi, struct fuse_file *ff,
                       unsigned int flags);
@@ -1348,11 +1373,41 @@ int fuse_fileattr_get(struct dentry *dentry, struct fileattr *fa);
 int fuse_fileattr_set(struct mnt_idmap *idmap,
                      struct dentry *dentry, struct fileattr *fa);
 
-/* file.c */
+/* iomode.c */
+int fuse_file_cached_io_start(struct inode *inode, struct fuse_file *ff);
+int fuse_file_uncached_io_start(struct inode *inode, struct fuse_file *ff);
+void fuse_file_uncached_io_end(struct inode *inode, struct fuse_file *ff);
+
+int fuse_file_io_open(struct file *file, struct inode *inode);
+void fuse_file_io_release(struct fuse_file *ff, struct inode *inode);
 
+/* file.c */
 struct fuse_file *fuse_file_open(struct fuse_mount *fm, u64 nodeid,
                                 unsigned int open_flags, bool isdir);
 void fuse_file_release(struct inode *inode, struct fuse_file *ff,
                       unsigned int open_flags, fl_owner_t id, bool isdir);
 
+/* passthrough.c */
+static inline struct fuse_backing *fuse_inode_backing(struct fuse_inode *fi)
+{
+#ifdef CONFIG_FUSE_PASSTHROUGH
+       return READ_ONCE(fi->fb);
+#else
+       return NULL;
+#endif
+}
+
+static inline struct fuse_backing *fuse_inode_backing_set(struct fuse_inode *fi,
+                                                         struct fuse_backing *fb)
+{
+#ifdef CONFIG_FUSE_PASSTHROUGH
+       return xchg(&fi->fb, fb);
+#else
+       return NULL;
+#endif
+}
+
+struct fuse_backing *fuse_backing_get(struct fuse_backing *fb);
+void fuse_backing_put(struct fuse_backing *fb);
+
 #endif /* _FS_FUSE_I_H */