256 lines · 5.5 KB · C
RawDownload
/* SPDX-License-Identifier: GPL-2.0 * * FUSE: Filesystem in Userspace * Copyright (c) 2023-2024 DataDirect Networks. */ #ifndef _FS_FUSE_DEV_URING_I_H#define _FS_FUSE_DEV_URING_I_H #include <linux/uio.h> #include "fuse_dev_i.h" #ifdef CONFIG_FUSE_IO_URING #define FUSE_URING_TEARDOWN_TIMEOUT (5 * HZ)#define FUSE_URING_TEARDOWN_INTERVAL (HZ/20) enum fuse_ring_req_state {	FRRS_INVALID = 0, 	/* The ring entry received from userspace and it is being processed */	FRRS_COMMIT, 	/* The ring entry is waiting for new fuse requests */	FRRS_AVAILABLE, 	/* The ring entry got assigned a fuse req */	FRRS_FUSE_REQ, 	/* The ring entry is in or on the way to user space */	FRRS_USERSPACE, 	/* The ring entry is in teardown */	FRRS_TEARDOWN, 	/* The ring entry is released, but not freed yet */	FRRS_RELEASED,}; /* how a queue's payload buffers are provided */enum fuse_queue_payload_mode {	/* not yet committed (a bufpool may still be added) */	FUSE_PAYLOAD_UNSET = 0,	/* each entry registers its own payload buffer */	FUSE_PAYLOAD_PER_ENT,	/* each entry's payload buffer is assigned from a bufpool */	FUSE_PAYLOAD_BUFPOOL,}; struct fuse_bufpool {	bool registered; 	/*	 * io_uring registered buffer table index for this pool, bound at	 * ADD_BUFPOOL time. Only valid if the bufpool is registered	 */	u16 registered_index; 	/* starting uaddr of the bufpool */	uintptr_t base_uaddr; 	/* size of each buffer in the pool */	size_t buf_size; 	/* total number of buffers in the pool */	unsigned int nr_bufs; 	/* bitmap tracking which buffers are free */	unsigned long free_map[];}; /** A fuse ring entry, part of the ring queue */struct fuse_ring_ent {	/* userspace buffer */	struct fuse_uring_req_header __user *headers;	struct iovec payload; 	/* buffer id in the pool, if bufpools are used. ignored otherwise */	unsigned int buf_id; 	/* true if the request's pages are being zero-copied */	bool zero_copied;	unsigned int zero_copy_index; 	/* the ring queue that owns the request */	struct fuse_ring_queue *queue; 	/* fields below are protected by queue->lock */ 	struct io_uring_cmd *cmd; 	struct list_head list; 	enum fuse_ring_req_state state; 	struct fuse_req *fuse_req;}; struct fuse_ring_queue {	/*	 * back pointer to the main fuse uring structure that holds this	 * queue	 */	struct fuse_ring *ring; 	/* queue id, corresponds to the cpu core */	unsigned int qid; 	/*	 * queue lock, taken when any value in the queue changes _and_ also	 * a ring entry state changes.	 */	spinlock_t lock; 	/* available ring entries (struct fuse_ring_ent) */	struct list_head ent_avail_queue; 	/*	 * entries in the process of being committed or in the process	 * to be sent to userspace	 */	struct list_head ent_w_req_queue;	struct list_head ent_commit_queue; 	/* entries in userspace */	struct list_head ent_in_userspace; 	/* entries that are released */	struct list_head ent_released; 	/* fuse requests waiting for an entry slot */	struct list_head fuse_req_queue; 	/* background fuse requests */	struct list_head fuse_req_bg_queue; 	struct fuse_pqueue fpq; 	unsigned int active_background; 	bool stopped; 	/* how this queue's payload buffers are provided */	enum fuse_queue_payload_mode payload_mode; 	/* only allocated when payload_mode == FUSE_PAYLOAD_BUFPOOL */	struct fuse_bufpool *bufpool; 	bool zero_copy;}; /* * Describes if uring is for communication and holds alls the data needed * for uring communication */struct fuse_ring {	/* back pointer */	struct fuse_chan *chan; 	/* number of ring queues */	size_t nr_queues; 	/* maximum payload/arg size */	size_t max_payload_sz; 	struct fuse_ring_queue **queues; 	/*	 * Log ring entry states on stop when entries cannot be released	 */	unsigned int stop_debug_log : 1; 	wait_queue_head_t stop_waitq; 	/* async tear down */	struct delayed_work async_teardown_work; 	/* log */	unsigned long teardown_time; 	atomic_t queue_refs; 	bool ready;}; void fuse_uring_conn_init(struct fuse_chan *fch);void fuse_uring_stop_queues(struct fuse_ring *ring);void fuse_uring_abort_end_requests(struct fuse_ring *ring);int fuse_uring_cmd(struct io_uring_cmd *cmd, unsigned int issue_flags);void fuse_uring_queue_fuse_req(struct fuse_iqueue *fiq, struct fuse_req *req);bool fuse_uring_queue_bq_req(struct fuse_req *req);bool fuse_uring_remove_pending_req(struct fuse_req *req);bool fuse_uring_request_expired(struct fuse_chan *fch); static inline void fuse_uring_abort(struct fuse_chan *fch){	struct fuse_ring *ring = fch->ring; 	if (ring == NULL)		return; 	fuse_uring_abort_end_requests(ring); 	if (atomic_read(&ring->queue_refs) > 0)		fuse_uring_stop_queues(ring);} static inline void fuse_uring_wait_stopped_queues(struct fuse_chan *fch){	struct fuse_ring *ring = fch->ring; 	if (ring)		wait_event(ring->stop_waitq,			   atomic_read(&ring->queue_refs) == 0);} static inline bool fuse_uring_ready(struct fuse_chan *fch){	struct fuse_ring *ring = READ_ONCE(fch->ring); 	return ring && smp_load_acquire(&ring->ready);} #else /* CONFIG_FUSE_IO_URING */ static inline void fuse_uring_conn_init(struct fuse_chan *fch){} static inline void fuse_uring_abort(struct fuse_chan *fch){} static inline void fuse_uring_wait_stopped_queues(struct fuse_chan *fch){} static inline bool fuse_uring_ready(struct fuse_chan *fch){	return false;} static inline bool fuse_uring_remove_pending_req(struct fuse_req *req){	return false;} static inline bool fuse_uring_request_expired(struct fuse_chan *fch){	return false;} #endif /* CONFIG_FUSE_IO_URING */ #endif /* _FS_FUSE_DEV_URING_I_H */