Something went wrong. Try again.
Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203/* 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 "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,};
/** A fuse ring entry, part of the ring queue */struct fuse_ring_ent { /* userspace buffer */ struct fuse_uring_req_header __user *headers; void __user *payload;
/* 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;};
/* * 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_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_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 */