427 lines · 10.7 KB · C
RawDownload
/* SPDX-License-Identifier: GPL-2.0 * * FUSE: Filesystem in Userspace * Copyright (C) 2001-2008  Miklos Szeredi <miklos@szeredi.hu> */#ifndef _FS_FUSE_DEV_I_H#define _FS_FUSE_DEV_I_H #include <linux/fuse.h>#include <linux/types.h>#include <linux/refcount.h>#include <linux/wait.h>#include <linux/workqueue.h>#include <linux/fs.h> /* 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 * @FR_SYNC_WAKEUP:	use synchronous wakeup when queueing this request to *			give the scheduler a hint about the waker task */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,	FR_SYNC_WAKEUP,}; /** * 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;	/* set when the payload is zero-copied. folios are filled in place */	bool skip_folio_copy: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