/* SPDX-License-Identifier: GPL-2.0 * * FUSE: Filesystem in Userspace * Copyright (C) 2001-2008 Miklos Szeredi */ #ifndef _FS_FUSE_DEV_I_H #define _FS_FUSE_DEV_I_H #include #include #include #include #include #include /* Ordinary requests have even IDs, while interrupts IDs are odd */ #define FUSE_INT_REQ_BIT (1ULL << 0) #define FUSE_REQ_ID_STEP (1ULL << 1) struct fuse_arg; struct fuse_args; struct fuse_pqueue; struct fuse_iqueue; /** * enum fuse_req_flag - Request flags * * @FR_ISREPLY: set if the request has reply * @FR_FORCE: force sending of the request even if interrupted * @FR_BACKGROUND: request is sent in the background * @FR_WAITING: request is counted as "waiting" * @FR_ABORTED: the request was aborted * @FR_INTERRUPTED: the request has been interrupted * @FR_LOCKED: data is being copied to/from the request * @FR_PENDING: request is not yet in userspace * @FR_SENT: request is in userspace, waiting for an answer * @FR_FINISHED: request is finished * @FR_PRIVATE: request is on private list * @FR_ASYNC: request is asynchronous * @FR_URING: request is handled through fuse-io-uring */ enum fuse_req_flag { FR_ISREPLY, FR_FORCE, FR_BACKGROUND, FR_WAITING, FR_ABORTED, FR_INTERRUPTED, FR_LOCKED, FR_PENDING, FR_SENT, FR_FINISHED, FR_PRIVATE, FR_ASYNC, FR_URING, }; /** * struct fuse_req - A request to the client * * .waitq.lock protects the following fields: * - FR_ABORTED * - FR_LOCKED (may also be modified under fpq->lock, tested under both) */ struct fuse_req { /** * @list: This can be on either pending processing or io lists in * fuse_conn */ struct list_head list; /** @intr_entry: Entry on the interrupts list */ struct list_head intr_entry; /** @args: Input/output arguments */ struct fuse_args *args; /** @count: refcount */ refcount_t count; /** @flags: Request flags, updated with test/set/clear_bit() */ unsigned long flags; /** @in: The request input header */ struct { /** @in.h: The request input header */ struct fuse_in_header h; } in; /** @out: The request output header */ struct { /** @out.h: The request output header */ struct fuse_out_header h; } out; /** @waitq: Used to wake up the task waiting for completion of request */ wait_queue_head_t waitq; #if IS_ENABLED(CONFIG_VIRTIO_FS) /** * @argbuf: virtio-fs's physically contiguous buffer for in and out * args */ void *argbuf; #endif /** @chan: fuse_chan this request belongs to */ struct fuse_chan *chan; #ifdef CONFIG_FUSE_IO_URING void *ring_entry; void *ring_queue; #endif /** @create_time: When (in jiffies) the request was created */ unsigned long create_time; }; /* One forget request */ struct fuse_forget_link { struct fuse_forget_one forget_one; struct fuse_forget_link *next; }; /** * struct fuse_iqueue_ops - Input queue callbacks * * Input queue signalling is device-specific. For example, the /dev/fuse file * uses fiq->waitq and fasync to wake processes that are waiting on queue * readiness. These callbacks allow other device types to respond to input * queue activity. */ struct fuse_iqueue_ops { /** * @send_forget: Send one forget */ void (*send_forget)(struct fuse_iqueue *fiq, struct fuse_forget_link *link); /** * @send_interrupt: Send interrupt for request */ void (*send_interrupt)(struct fuse_iqueue *fiq, struct fuse_req *req); /** * @send_req: Send one request */ void (*send_req)(struct fuse_iqueue *fiq, struct fuse_req *req); /** * @release: Clean up when fuse_iqueue is destroyed */ void (*release)(struct fuse_iqueue *fiq); }; struct fuse_iqueue { /** Connection established */ unsigned connected; /** Lock protecting accesses to members of this structure */ spinlock_t lock; /** Readers of the connection are waiting on this */ wait_queue_head_t waitq; /** The next unique request id */ u64 reqctr; /** The list of pending requests */ struct list_head pending; /** Pending interrupts */ struct list_head interrupts; /** Queue of pending forgets */ struct fuse_forget_link forget_list_head; struct fuse_forget_link *forget_list_tail; /** Batching of FORGET requests (positive indicates FORGET batch) */ int forget_batch; /** O_ASYNC requests */ struct fasync_struct *fasync; /** Device-specific callbacks */ const struct fuse_iqueue_ops *ops; /** Device-specific state */ void *priv; }; struct fuse_chan { /** Lock protecting: - devices - connected - ring - ring->queues[qid] */ spinlock_t lock; /* back pointer: fc->chan->conn == fc */ struct fuse_conn *conn; /** Input queue */ struct fuse_iqueue iq; /** List of device instances belonging to this connection */ struct list_head devices; /** Maximum number of outstanding background requests */ unsigned max_background; /** Number of requests currently in the background */ unsigned num_background; /** Number of background requests currently queued for userspace */ unsigned active_background; /** The list of background requests set aside for later queuing */ struct list_head bg_queue; /** Protects: max_background, 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; /** Flag indicating if connection is blocked. This will be the case before the INIT reply is received, and if there are too many outstading backgrounds requests */ int blocked; /** waitq for blocked connection */ wait_queue_head_t blocked_waitq; /** Connection established, cleared on umount, connection abort and device release */ unsigned connected; /** The number of requests waiting for completion */ atomic_t num_waiting; /** Is interrupt not implemented by fs? */ bool no_interrupt; /* Use io_uring for communication */ unsigned int io_uring; /* Negotiated minor version */ unsigned int minor; /* Maximum write size */ unsigned int max_write; /* Maximum number of pages that can be used in a single request */ unsigned int max_pages; /* Before being installed into fud, contains the preallocated pq array*/ struct list_head *pq_prealloc; /** Connection aborted via sysfs, respond with ECONNABORTED on device I/O */ bool abort_with_err; #ifdef CONFIG_FUSE_IO_URING /** uring connection information*/ struct fuse_ring *ring; #endif /** Only used if the connection opts into request timeouts */ struct { /* Worker for checking if any requests have timed out */ struct delayed_work work; /* Request timeout (in jiffies). 0 = no timeout */ unsigned int req_timeout; } timeout; }; #define FUSE_PQ_HASH_BITS 8 #define FUSE_PQ_HASH_SIZE (1 << FUSE_PQ_HASH_BITS) struct fuse_pqueue { /** Connection established */ unsigned connected; /** Lock protecting accessess to members of this structure */ spinlock_t lock; /** Hash table of requests being processed */ struct list_head *processing; /** The list of requests under I/O */ struct list_head io; }; /** * struct fuse_dev - Fuse device instance */ struct fuse_dev { /** @ref: Reference count of this object */ refcount_t ref; /** @sync_init: Issue FUSE_INIT synchronously */ bool sync_init; /** @chan: Fuse channel for this device */ struct fuse_chan *chan; /** @pq: Processing queue */ struct fuse_pqueue pq; /** @entry: list entry on fch->devices */ struct list_head entry; }; struct fuse_copy_state { struct fuse_req *req; struct iov_iter *iter; struct pipe_buffer *pipebufs; struct pipe_buffer *currbuf; struct pipe_inode_info *pipe; unsigned long nr_segs; struct page *pg; unsigned int len; unsigned int offset; bool write:1; bool move_folios:1; bool is_uring:1; struct { unsigned int copied_sz; /* copied size into the user buffer */ } ring; }; /* fud->chan gets assigned to this value when /dev/fuse is closed */ #define FUSE_DEV_CHAN_DISCONNECTED ((struct fuse_chan *) 1) /* * Lockless access is OK, because fud->chan is set once during mount and is valid * until the file is released. * * fud->chan is set to FUSE_DEV_CHAN_DISCONNECTED only after the containing file is * released, so result is safe to dereference in most cases. Exceptions are: * fuse_dev_put() and fuse_fill_super_common(). */ static inline struct fuse_chan *fuse_dev_chan_get(struct fuse_dev *fud) { /* Pairs with xchg() in fuse_dev_install() */ return smp_load_acquire(&fud->chan); } static inline struct fuse_dev *fuse_file_to_fud(struct file *file) { return file->private_data; } static inline struct fuse_dev *__fuse_get_dev(struct file *file) { struct fuse_dev *fud = fuse_file_to_fud(file); if (!fuse_dev_chan_get(fud)) return NULL; return fud; } void fuse_iqueue_init(struct fuse_iqueue *fiq, const struct fuse_iqueue_ops *ops, void *priv); struct fuse_dev *fuse_get_dev(struct file *file); unsigned int fuse_req_hash(u64 unique); struct fuse_req *fuse_request_find(struct fuse_pqueue *fpq, u64 unique); void fuse_dev_end_requests(struct list_head *head); void fuse_request_bg_finish(struct fuse_chan *fch, struct fuse_req *req); void fuse_copy_init(struct fuse_copy_state *cs, bool write, struct iov_iter *iter); /* * Return the number of bytes in an arguments list */ unsigned int fuse_len_args(unsigned int numargs, struct fuse_arg *args); int fuse_copy_args(struct fuse_copy_state *cs, unsigned int numargs, unsigned int argpages, struct fuse_arg *args, int zeroing); int fuse_copy_out_args(struct fuse_copy_state *cs, struct fuse_args *args, unsigned int nbytes); void fuse_dev_queue_forget(struct fuse_iqueue *fiq, struct fuse_forget_link *forget); void fuse_dev_queue_interrupt(struct fuse_iqueue *fiq, struct fuse_req *req); bool fuse_remove_pending_req(struct fuse_req *req, spinlock_t *lock); bool fuse_request_expired(struct fuse_chan *fch, struct list_head *list); /* * Assign a unique id to a fuse request */ void fuse_request_assign_unique(struct fuse_iqueue *fiq, struct fuse_req *req); /* * Get the next unique ID for a request */ u64 fuse_get_unique(struct fuse_iqueue *fiq); struct fuse_dev *fuse_dev_alloc_install(struct fuse_chan *fch); struct fuse_dev *fuse_dev_alloc(void); int fuse_dev_release(struct inode *inode, struct file *file); struct list_head *fuse_pqueue_alloc(void); /* * Initialize the fuse processing queue */ void fuse_pqueue_init(struct fuse_pqueue *fpq); /* * End a finished request */ void fuse_request_end(struct fuse_req *req); #endif