Merge tag 'selinux-pr-20181115' of git://git.kernel.org/pub/scm/linux/kernel/git...
[sfrench/cifs-2.6.git] / fs / fuse / fuse_i.h
index f78e9614bb5f712d2936bffa2fa886c7027ba7c1..e9f712e81c7d9e188ae174d2bb3f0ba3b853d90f 100644 (file)
 #include <linux/refcount.h>
 #include <linux/user_namespace.h>
 
-/** Max number of pages that can be used in a single read request */
-#define FUSE_MAX_PAGES_PER_REQ 32
+/** Default max number of pages that can be used in a single read request */
+#define FUSE_DEFAULT_MAX_PAGES_PER_REQ 32
+
+/** Maximum of max_pages received in init_out */
+#define FUSE_MAX_MAX_PAGES 256
 
 /** Bias for fi->writectr, meaning new writepages must not be sent */
 #define FUSE_NOWRITE INT_MIN
@@ -77,6 +80,9 @@ struct fuse_inode {
        /** Time in jiffies until the file attributes are valid */
        u64 i_time;
 
+       /* Which attributes are invalid */
+       u32 inval_mask;
+
        /** The sticky bit in inode->i_mode may have been removed, so
            preserve the original mode */
        umode_t orig_i_mode;
@@ -87,21 +93,51 @@ struct fuse_inode {
        /** Version of last attribute change */
        u64 attr_version;
 
-       /** Files usable in writepage.  Protected by fc->lock */
-       struct list_head write_files;
+       union {
+               /* Write related fields (regular file only) */
+               struct {
+                       /* Files usable in writepage.  Protected by fc->lock */
+                       struct list_head write_files;
+
+                       /* Writepages pending on truncate or fsync */
+                       struct list_head queued_writes;
 
-       /** Writepages pending on truncate or fsync */
-       struct list_head queued_writes;
+                       /* Number of sent writes, a negative bias
+                        * (FUSE_NOWRITE) means more writes are blocked */
+                       int writectr;
+
+                       /* Waitq for writepage completion */
+                       wait_queue_head_t page_waitq;
+
+                       /* List of writepage requestst (pending or sent) */
+                       struct list_head writepages;
+               };
+
+               /* readdir cache (directory only) */
+               struct {
+                       /* true if fully cached */
+                       bool cached;
 
-       /** Number of sent writes, a negative bias (FUSE_NOWRITE)
-        * means more writes are blocked */
-       int writectr;
+                       /* size of cache */
+                       loff_t size;
 
-       /** Waitq for writepage completion */
-       wait_queue_head_t page_waitq;
+                       /* position at end of cache (position of next entry) */
+                       loff_t pos;
 
-       /** List of writepage requestst (pending or sent) */
-       struct list_head writepages;
+                       /* version of the cache */
+                       u64 version;
+
+                       /* modification time of directory when cache was
+                        * started */
+                       struct timespec64 mtime;
+
+                       /* iversion of directory when cache was started */
+                       u64 iversion;
+
+                       /* protects above fields */
+                       spinlock_t lock;
+               } rdc;
+       };
 
        /** Miscellaneous bits describing inode state */
        unsigned long state;
@@ -148,6 +184,25 @@ struct fuse_file {
        /** Entry on inode's write_files list */
        struct list_head write_entry;
 
+       /* Readdir related */
+       struct {
+               /*
+                * Protects below fields against (crazy) parallel readdir on
+                * same open file.  Uncontended in the normal case.
+                */
+               struct mutex lock;
+
+               /* Dir stream position */
+               loff_t pos;
+
+               /* Offset in cache */
+               loff_t cache_off;
+
+               /* Version of cache we are reading */
+               u64 version;
+
+       } readdir;
+
        /** RB node to be linked on fuse_conn->polled_files */
        struct rb_node polled_node;
 
@@ -311,9 +366,6 @@ struct fuse_req {
        /** refcount */
        refcount_t count;
 
-       /** Unique ID for the interrupt request */
-       u64 intr_unique;
-
        /* Request flags, updated with test/set/clear_bit() */
        unsigned long flags;
 
@@ -411,6 +463,9 @@ struct fuse_iqueue {
        struct fasync_struct *fasync;
 };
 
+#define FUSE_PQ_HASH_BITS 8
+#define FUSE_PQ_HASH_SIZE (1 << FUSE_PQ_HASH_BITS)
+
 struct fuse_pqueue {
        /** Connection established */
        unsigned connected;
@@ -418,8 +473,8 @@ struct fuse_pqueue {
        /** Lock protecting accessess to  members of this structure */
        spinlock_t lock;
 
-       /** The list of requests being processed */
-       struct list_head processing;
+       /** Hash table of requests being processed */
+       struct list_head *processing;
 
        /** The list of requests under I/O */
        struct list_head io;
@@ -476,6 +531,9 @@ struct fuse_conn {
        /** Maximum write size */
        unsigned max_write;
 
+       /** Maxmum number of pages that can be used in a single request */
+       unsigned int max_pages;
+
        /** Input queue */
        struct fuse_iqueue iq;
 
@@ -500,6 +558,10 @@ struct fuse_conn {
        /** The list of background requests set aside for later queuing */
        struct list_head bg_queue;
 
+       /** Protects: max_background, congestion_threshold, num_background,
+        * active_background, bg_queue, blocked */
+       spinlock_t bg_lock;
+
        /** Flag indicating that INIT reply has been received. Allocating
         * any fuse request will be suspended until the flag is set */
        int initialized;
@@ -551,6 +613,9 @@ struct fuse_conn {
        /** handle fs handles killing suid/sgid/cap on write/chown/trunc */
        unsigned handle_killpriv:1;
 
+       /** cache READLINK responses in page cache */
+       unsigned cache_symlinks:1;
+
        /*
         * The following bitfields are only for optimization purposes
         * and hence races in setting them will not cause malfunction
@@ -637,6 +702,9 @@ struct fuse_conn {
        /** Allow other than the mounter user to access the filesystem ? */
        unsigned allow_other:1;
 
+       /** Does the filesystem support copy_file_range? */
+       unsigned no_copy_file_range:1;
+
        /** The number of requests waiting for completion */
        atomic_t num_waiting;
 
@@ -697,6 +765,11 @@ static inline u64 get_node_id(struct inode *inode)
        return get_fuse_inode(inode)->nodeid;
 }
 
+static inline int invalid_nodeid(u64 nodeid)
+{
+       return !nodeid || nodeid == FUSE_ROOT_ID;
+}
+
 /** Device operations */
 extern const struct file_operations fuse_dev_operations;
 
@@ -812,6 +885,10 @@ struct fuse_req *fuse_request_alloc(unsigned npages);
 
 struct fuse_req *fuse_request_alloc_nofs(unsigned npages);
 
+bool fuse_req_realloc_pages(struct fuse_conn *fc, struct fuse_req *req,
+                           gfp_t flags);
+
+
 /**
  * Free a request
  */
@@ -856,9 +933,7 @@ ssize_t fuse_simple_request(struct fuse_conn *fc, struct fuse_args *args);
  * Send a request in the background
  */
 void fuse_request_send_background(struct fuse_conn *fc, struct fuse_req *req);
-
-void fuse_request_send_background_locked(struct fuse_conn *fc,
-                                        struct fuse_req *req);
+bool fuse_request_queue_background(struct fuse_conn *fc, struct fuse_req *req);
 
 /* Abort all requests */
 void fuse_abort_conn(struct fuse_conn *fc, bool is_abort);
@@ -873,6 +948,9 @@ void fuse_invalidate_entry_cache(struct dentry *entry);
 
 void fuse_invalidate_atime(struct inode *inode);
 
+u64 entry_attr_timeout(struct fuse_entry_out *o);
+void fuse_change_entry_timeout(struct dentry *entry, struct fuse_entry_out *o);
+
 /**
  * Acquire reference to fuse_conn
  */
@@ -992,4 +1070,8 @@ struct posix_acl;
 struct posix_acl *fuse_get_acl(struct inode *inode, int type);
 int fuse_set_acl(struct inode *inode, struct posix_acl *acl, int type);
 
+
+/* readdir.c */
+int fuse_readdir(struct file *file, struct dir_context *ctx);
+
 #endif /* _FS_FUSE_I_H */