124fe962cSBernd Schubert // SPDX-License-Identifier: GPL-2.0 224fe962cSBernd Schubert /* 324fe962cSBernd Schubert * FUSE: Filesystem in Userspace 424fe962cSBernd Schubert * Copyright (c) 2023-2024 DataDirect Networks. 524fe962cSBernd Schubert */ 624fe962cSBernd Schubert 724fe962cSBernd Schubert #include "fuse_i.h" 824fe962cSBernd Schubert #include "dev_uring_i.h" 924fe962cSBernd Schubert #include "fuse_dev_i.h" 1024fe962cSBernd Schubert 1124fe962cSBernd Schubert #include <linux/fs.h> 1224fe962cSBernd Schubert #include <linux/io_uring/cmd.h> 1324fe962cSBernd Schubert 1424fe962cSBernd Schubert static bool __read_mostly enable_uring; 1524fe962cSBernd Schubert module_param(enable_uring, bool, 0644); 1624fe962cSBernd Schubert MODULE_PARM_DESC(enable_uring, 1724fe962cSBernd Schubert "Enable userspace communication through io-uring"); 1824fe962cSBernd Schubert 1924fe962cSBernd Schubert #define FUSE_URING_IOV_SEGS 2 /* header and payload */ 2024fe962cSBernd Schubert 2124fe962cSBernd Schubert 2224fe962cSBernd Schubert bool fuse_uring_enabled(void) 2324fe962cSBernd Schubert { 2424fe962cSBernd Schubert return enable_uring; 2524fe962cSBernd Schubert } 2624fe962cSBernd Schubert 27*c2c9af9aSBernd Schubert struct fuse_uring_pdu { 28*c2c9af9aSBernd Schubert struct fuse_ring_ent *ent; 29*c2c9af9aSBernd Schubert }; 30*c2c9af9aSBernd Schubert 31*c2c9af9aSBernd Schubert static const struct fuse_iqueue_ops fuse_io_uring_ops; 32*c2c9af9aSBernd Schubert 33*c2c9af9aSBernd Schubert static void uring_cmd_set_ring_ent(struct io_uring_cmd *cmd, 34*c2c9af9aSBernd Schubert struct fuse_ring_ent *ring_ent) 35*c2c9af9aSBernd Schubert { 36*c2c9af9aSBernd Schubert struct fuse_uring_pdu *pdu = 37*c2c9af9aSBernd Schubert io_uring_cmd_to_pdu(cmd, struct fuse_uring_pdu); 38*c2c9af9aSBernd Schubert 39*c2c9af9aSBernd Schubert pdu->ent = ring_ent; 40*c2c9af9aSBernd Schubert } 41*c2c9af9aSBernd Schubert 42*c2c9af9aSBernd Schubert static struct fuse_ring_ent *uring_cmd_to_ring_ent(struct io_uring_cmd *cmd) 43*c2c9af9aSBernd Schubert { 44*c2c9af9aSBernd Schubert struct fuse_uring_pdu *pdu = 45*c2c9af9aSBernd Schubert io_uring_cmd_to_pdu(cmd, struct fuse_uring_pdu); 46*c2c9af9aSBernd Schubert 47*c2c9af9aSBernd Schubert return pdu->ent; 48*c2c9af9aSBernd Schubert } 49*c2c9af9aSBernd Schubert 50c090c8abSBernd Schubert static void fuse_uring_req_end(struct fuse_ring_ent *ent, struct fuse_req *req, 51c090c8abSBernd Schubert int error) 52c090c8abSBernd Schubert { 53c090c8abSBernd Schubert ent->fuse_req = NULL; 54c090c8abSBernd Schubert if (error) 55c090c8abSBernd Schubert req->out.h.error = error; 56c090c8abSBernd Schubert 57c090c8abSBernd Schubert clear_bit(FR_SENT, &req->flags); 58c090c8abSBernd Schubert fuse_request_end(req); 59c090c8abSBernd Schubert } 60c090c8abSBernd Schubert 614a9bfb9bSBernd Schubert /* Abort all list queued request on the given ring queue */ 624a9bfb9bSBernd Schubert static void fuse_uring_abort_end_queue_requests(struct fuse_ring_queue *queue) 634a9bfb9bSBernd Schubert { 644a9bfb9bSBernd Schubert struct fuse_req *req; 654a9bfb9bSBernd Schubert LIST_HEAD(req_list); 664a9bfb9bSBernd Schubert 674a9bfb9bSBernd Schubert spin_lock(&queue->lock); 684a9bfb9bSBernd Schubert list_for_each_entry(req, &queue->fuse_req_queue, list) 694a9bfb9bSBernd Schubert clear_bit(FR_PENDING, &req->flags); 704a9bfb9bSBernd Schubert list_splice_init(&queue->fuse_req_queue, &req_list); 714a9bfb9bSBernd Schubert spin_unlock(&queue->lock); 724a9bfb9bSBernd Schubert 734a9bfb9bSBernd Schubert /* must not hold queue lock to avoid order issues with fi->lock */ 744a9bfb9bSBernd Schubert fuse_dev_end_requests(&req_list); 754a9bfb9bSBernd Schubert } 764a9bfb9bSBernd Schubert 774a9bfb9bSBernd Schubert void fuse_uring_abort_end_requests(struct fuse_ring *ring) 784a9bfb9bSBernd Schubert { 794a9bfb9bSBernd Schubert int qid; 804a9bfb9bSBernd Schubert struct fuse_ring_queue *queue; 814a9bfb9bSBernd Schubert 824a9bfb9bSBernd Schubert for (qid = 0; qid < ring->nr_queues; qid++) { 834a9bfb9bSBernd Schubert queue = READ_ONCE(ring->queues[qid]); 844a9bfb9bSBernd Schubert if (!queue) 854a9bfb9bSBernd Schubert continue; 864a9bfb9bSBernd Schubert 874a9bfb9bSBernd Schubert queue->stopped = true; 884a9bfb9bSBernd Schubert fuse_uring_abort_end_queue_requests(queue); 894a9bfb9bSBernd Schubert } 904a9bfb9bSBernd Schubert } 914a9bfb9bSBernd Schubert 9224fe962cSBernd Schubert void fuse_uring_destruct(struct fuse_conn *fc) 9324fe962cSBernd Schubert { 9424fe962cSBernd Schubert struct fuse_ring *ring = fc->ring; 9524fe962cSBernd Schubert int qid; 9624fe962cSBernd Schubert 9724fe962cSBernd Schubert if (!ring) 9824fe962cSBernd Schubert return; 9924fe962cSBernd Schubert 10024fe962cSBernd Schubert for (qid = 0; qid < ring->nr_queues; qid++) { 10124fe962cSBernd Schubert struct fuse_ring_queue *queue = ring->queues[qid]; 10224fe962cSBernd Schubert 10324fe962cSBernd Schubert if (!queue) 10424fe962cSBernd Schubert continue; 10524fe962cSBernd Schubert 10624fe962cSBernd Schubert WARN_ON(!list_empty(&queue->ent_avail_queue)); 107c090c8abSBernd Schubert WARN_ON(!list_empty(&queue->ent_w_req_queue)); 10824fe962cSBernd Schubert WARN_ON(!list_empty(&queue->ent_commit_queue)); 109c090c8abSBernd Schubert WARN_ON(!list_empty(&queue->ent_in_userspace)); 11024fe962cSBernd Schubert 111c090c8abSBernd Schubert kfree(queue->fpq.processing); 11224fe962cSBernd Schubert kfree(queue); 11324fe962cSBernd Schubert ring->queues[qid] = NULL; 11424fe962cSBernd Schubert } 11524fe962cSBernd Schubert 11624fe962cSBernd Schubert kfree(ring->queues); 11724fe962cSBernd Schubert kfree(ring); 11824fe962cSBernd Schubert fc->ring = NULL; 11924fe962cSBernd Schubert } 12024fe962cSBernd Schubert 12124fe962cSBernd Schubert /* 12224fe962cSBernd Schubert * Basic ring setup for this connection based on the provided configuration 12324fe962cSBernd Schubert */ 12424fe962cSBernd Schubert static struct fuse_ring *fuse_uring_create(struct fuse_conn *fc) 12524fe962cSBernd Schubert { 12624fe962cSBernd Schubert struct fuse_ring *ring; 12724fe962cSBernd Schubert size_t nr_queues = num_possible_cpus(); 12824fe962cSBernd Schubert struct fuse_ring *res = NULL; 12924fe962cSBernd Schubert size_t max_payload_size; 13024fe962cSBernd Schubert 13124fe962cSBernd Schubert ring = kzalloc(sizeof(*fc->ring), GFP_KERNEL_ACCOUNT); 13224fe962cSBernd Schubert if (!ring) 13324fe962cSBernd Schubert return NULL; 13424fe962cSBernd Schubert 13524fe962cSBernd Schubert ring->queues = kcalloc(nr_queues, sizeof(struct fuse_ring_queue *), 13624fe962cSBernd Schubert GFP_KERNEL_ACCOUNT); 13724fe962cSBernd Schubert if (!ring->queues) 13824fe962cSBernd Schubert goto out_err; 13924fe962cSBernd Schubert 14024fe962cSBernd Schubert max_payload_size = max(FUSE_MIN_READ_BUFFER, fc->max_write); 14124fe962cSBernd Schubert max_payload_size = max(max_payload_size, fc->max_pages * PAGE_SIZE); 14224fe962cSBernd Schubert 14324fe962cSBernd Schubert spin_lock(&fc->lock); 14424fe962cSBernd Schubert if (fc->ring) { 14524fe962cSBernd Schubert /* race, another thread created the ring in the meantime */ 14624fe962cSBernd Schubert spin_unlock(&fc->lock); 14724fe962cSBernd Schubert res = fc->ring; 14824fe962cSBernd Schubert goto out_err; 14924fe962cSBernd Schubert } 15024fe962cSBernd Schubert 1514a9bfb9bSBernd Schubert init_waitqueue_head(&ring->stop_waitq); 1524a9bfb9bSBernd Schubert 15324fe962cSBernd Schubert fc->ring = ring; 15424fe962cSBernd Schubert ring->nr_queues = nr_queues; 15524fe962cSBernd Schubert ring->fc = fc; 15624fe962cSBernd Schubert ring->max_payload_sz = max_payload_size; 1574a9bfb9bSBernd Schubert atomic_set(&ring->queue_refs, 0); 15824fe962cSBernd Schubert 15924fe962cSBernd Schubert spin_unlock(&fc->lock); 16024fe962cSBernd Schubert return ring; 16124fe962cSBernd Schubert 16224fe962cSBernd Schubert out_err: 16324fe962cSBernd Schubert kfree(ring->queues); 16424fe962cSBernd Schubert kfree(ring); 16524fe962cSBernd Schubert return res; 16624fe962cSBernd Schubert } 16724fe962cSBernd Schubert 16824fe962cSBernd Schubert static struct fuse_ring_queue *fuse_uring_create_queue(struct fuse_ring *ring, 16924fe962cSBernd Schubert int qid) 17024fe962cSBernd Schubert { 17124fe962cSBernd Schubert struct fuse_conn *fc = ring->fc; 17224fe962cSBernd Schubert struct fuse_ring_queue *queue; 173c090c8abSBernd Schubert struct list_head *pq; 17424fe962cSBernd Schubert 17524fe962cSBernd Schubert queue = kzalloc(sizeof(*queue), GFP_KERNEL_ACCOUNT); 17624fe962cSBernd Schubert if (!queue) 17724fe962cSBernd Schubert return NULL; 178c090c8abSBernd Schubert pq = kcalloc(FUSE_PQ_HASH_SIZE, sizeof(struct list_head), GFP_KERNEL); 179c090c8abSBernd Schubert if (!pq) { 180c090c8abSBernd Schubert kfree(queue); 181c090c8abSBernd Schubert return NULL; 182c090c8abSBernd Schubert } 183c090c8abSBernd Schubert 18424fe962cSBernd Schubert queue->qid = qid; 18524fe962cSBernd Schubert queue->ring = ring; 18624fe962cSBernd Schubert spin_lock_init(&queue->lock); 18724fe962cSBernd Schubert 18824fe962cSBernd Schubert INIT_LIST_HEAD(&queue->ent_avail_queue); 18924fe962cSBernd Schubert INIT_LIST_HEAD(&queue->ent_commit_queue); 190c090c8abSBernd Schubert INIT_LIST_HEAD(&queue->ent_w_req_queue); 191c090c8abSBernd Schubert INIT_LIST_HEAD(&queue->ent_in_userspace); 192c090c8abSBernd Schubert INIT_LIST_HEAD(&queue->fuse_req_queue); 193c090c8abSBernd Schubert 194c090c8abSBernd Schubert queue->fpq.processing = pq; 195c090c8abSBernd Schubert fuse_pqueue_init(&queue->fpq); 19624fe962cSBernd Schubert 19724fe962cSBernd Schubert spin_lock(&fc->lock); 19824fe962cSBernd Schubert if (ring->queues[qid]) { 19924fe962cSBernd Schubert spin_unlock(&fc->lock); 200c090c8abSBernd Schubert kfree(queue->fpq.processing); 20124fe962cSBernd Schubert kfree(queue); 20224fe962cSBernd Schubert return ring->queues[qid]; 20324fe962cSBernd Schubert } 20424fe962cSBernd Schubert 20524fe962cSBernd Schubert /* 20624fe962cSBernd Schubert * write_once and lock as the caller mostly doesn't take the lock at all 20724fe962cSBernd Schubert */ 20824fe962cSBernd Schubert WRITE_ONCE(ring->queues[qid], queue); 20924fe962cSBernd Schubert spin_unlock(&fc->lock); 21024fe962cSBernd Schubert 21124fe962cSBernd Schubert return queue; 21224fe962cSBernd Schubert } 21324fe962cSBernd Schubert 2144a9bfb9bSBernd Schubert static void fuse_uring_stop_fuse_req_end(struct fuse_req *req) 2154a9bfb9bSBernd Schubert { 2164a9bfb9bSBernd Schubert clear_bit(FR_SENT, &req->flags); 2174a9bfb9bSBernd Schubert req->out.h.error = -ECONNABORTED; 2184a9bfb9bSBernd Schubert fuse_request_end(req); 2194a9bfb9bSBernd Schubert } 2204a9bfb9bSBernd Schubert 2214a9bfb9bSBernd Schubert /* 2224a9bfb9bSBernd Schubert * Release a request/entry on connection tear down 2234a9bfb9bSBernd Schubert */ 2244a9bfb9bSBernd Schubert static void fuse_uring_entry_teardown(struct fuse_ring_ent *ent) 2254a9bfb9bSBernd Schubert { 2264a9bfb9bSBernd Schubert struct fuse_req *req; 2274a9bfb9bSBernd Schubert struct io_uring_cmd *cmd; 2284a9bfb9bSBernd Schubert 2294a9bfb9bSBernd Schubert struct fuse_ring_queue *queue = ent->queue; 2304a9bfb9bSBernd Schubert 2314a9bfb9bSBernd Schubert spin_lock(&queue->lock); 2324a9bfb9bSBernd Schubert cmd = ent->cmd; 2334a9bfb9bSBernd Schubert ent->cmd = NULL; 2344a9bfb9bSBernd Schubert req = ent->fuse_req; 2354a9bfb9bSBernd Schubert ent->fuse_req = NULL; 2364a9bfb9bSBernd Schubert if (req) { 2374a9bfb9bSBernd Schubert /* remove entry from queue->fpq->processing */ 2384a9bfb9bSBernd Schubert list_del_init(&req->list); 2394a9bfb9bSBernd Schubert } 2404a9bfb9bSBernd Schubert spin_unlock(&queue->lock); 2414a9bfb9bSBernd Schubert 2424a9bfb9bSBernd Schubert if (cmd) 2434a9bfb9bSBernd Schubert io_uring_cmd_done(cmd, -ENOTCONN, 0, IO_URING_F_UNLOCKED); 2444a9bfb9bSBernd Schubert 2454a9bfb9bSBernd Schubert if (req) 2464a9bfb9bSBernd Schubert fuse_uring_stop_fuse_req_end(req); 2474a9bfb9bSBernd Schubert 2484a9bfb9bSBernd Schubert list_del_init(&ent->list); 2494a9bfb9bSBernd Schubert kfree(ent); 2504a9bfb9bSBernd Schubert } 2514a9bfb9bSBernd Schubert 2524a9bfb9bSBernd Schubert static void fuse_uring_stop_list_entries(struct list_head *head, 2534a9bfb9bSBernd Schubert struct fuse_ring_queue *queue, 2544a9bfb9bSBernd Schubert enum fuse_ring_req_state exp_state) 2554a9bfb9bSBernd Schubert { 2564a9bfb9bSBernd Schubert struct fuse_ring *ring = queue->ring; 2574a9bfb9bSBernd Schubert struct fuse_ring_ent *ent, *next; 2584a9bfb9bSBernd Schubert ssize_t queue_refs = SSIZE_MAX; 2594a9bfb9bSBernd Schubert LIST_HEAD(to_teardown); 2604a9bfb9bSBernd Schubert 2614a9bfb9bSBernd Schubert spin_lock(&queue->lock); 2624a9bfb9bSBernd Schubert list_for_each_entry_safe(ent, next, head, list) { 2634a9bfb9bSBernd Schubert if (ent->state != exp_state) { 2644a9bfb9bSBernd Schubert pr_warn("entry teardown qid=%d state=%d expected=%d", 2654a9bfb9bSBernd Schubert queue->qid, ent->state, exp_state); 2664a9bfb9bSBernd Schubert continue; 2674a9bfb9bSBernd Schubert } 2684a9bfb9bSBernd Schubert 2694a9bfb9bSBernd Schubert list_move(&ent->list, &to_teardown); 2704a9bfb9bSBernd Schubert } 2714a9bfb9bSBernd Schubert spin_unlock(&queue->lock); 2724a9bfb9bSBernd Schubert 2734a9bfb9bSBernd Schubert /* no queue lock to avoid lock order issues */ 2744a9bfb9bSBernd Schubert list_for_each_entry_safe(ent, next, &to_teardown, list) { 2754a9bfb9bSBernd Schubert fuse_uring_entry_teardown(ent); 2764a9bfb9bSBernd Schubert queue_refs = atomic_dec_return(&ring->queue_refs); 2774a9bfb9bSBernd Schubert WARN_ON_ONCE(queue_refs < 0); 2784a9bfb9bSBernd Schubert } 2794a9bfb9bSBernd Schubert } 2804a9bfb9bSBernd Schubert 2814a9bfb9bSBernd Schubert static void fuse_uring_teardown_entries(struct fuse_ring_queue *queue) 2824a9bfb9bSBernd Schubert { 2834a9bfb9bSBernd Schubert fuse_uring_stop_list_entries(&queue->ent_in_userspace, queue, 2844a9bfb9bSBernd Schubert FRRS_USERSPACE); 2854a9bfb9bSBernd Schubert fuse_uring_stop_list_entries(&queue->ent_avail_queue, queue, 2864a9bfb9bSBernd Schubert FRRS_AVAILABLE); 2874a9bfb9bSBernd Schubert } 2884a9bfb9bSBernd Schubert 2894a9bfb9bSBernd Schubert /* 2904a9bfb9bSBernd Schubert * Log state debug info 2914a9bfb9bSBernd Schubert */ 2924a9bfb9bSBernd Schubert static void fuse_uring_log_ent_state(struct fuse_ring *ring) 2934a9bfb9bSBernd Schubert { 2944a9bfb9bSBernd Schubert int qid; 2954a9bfb9bSBernd Schubert struct fuse_ring_ent *ent; 2964a9bfb9bSBernd Schubert 2974a9bfb9bSBernd Schubert for (qid = 0; qid < ring->nr_queues; qid++) { 2984a9bfb9bSBernd Schubert struct fuse_ring_queue *queue = ring->queues[qid]; 2994a9bfb9bSBernd Schubert 3004a9bfb9bSBernd Schubert if (!queue) 3014a9bfb9bSBernd Schubert continue; 3024a9bfb9bSBernd Schubert 3034a9bfb9bSBernd Schubert spin_lock(&queue->lock); 3044a9bfb9bSBernd Schubert /* 3054a9bfb9bSBernd Schubert * Log entries from the intermediate queue, the other queues 3064a9bfb9bSBernd Schubert * should be empty 3074a9bfb9bSBernd Schubert */ 3084a9bfb9bSBernd Schubert list_for_each_entry(ent, &queue->ent_w_req_queue, list) { 3094a9bfb9bSBernd Schubert pr_info(" ent-req-queue ring=%p qid=%d ent=%p state=%d\n", 3104a9bfb9bSBernd Schubert ring, qid, ent, ent->state); 3114a9bfb9bSBernd Schubert } 3124a9bfb9bSBernd Schubert list_for_each_entry(ent, &queue->ent_commit_queue, list) { 3134a9bfb9bSBernd Schubert pr_info(" ent-commit-queue ring=%p qid=%d ent=%p state=%d\n", 3144a9bfb9bSBernd Schubert ring, qid, ent, ent->state); 3154a9bfb9bSBernd Schubert } 3164a9bfb9bSBernd Schubert spin_unlock(&queue->lock); 3174a9bfb9bSBernd Schubert } 3184a9bfb9bSBernd Schubert ring->stop_debug_log = 1; 3194a9bfb9bSBernd Schubert } 3204a9bfb9bSBernd Schubert 3214a9bfb9bSBernd Schubert static void fuse_uring_async_stop_queues(struct work_struct *work) 3224a9bfb9bSBernd Schubert { 3234a9bfb9bSBernd Schubert int qid; 3244a9bfb9bSBernd Schubert struct fuse_ring *ring = 3254a9bfb9bSBernd Schubert container_of(work, struct fuse_ring, async_teardown_work.work); 3264a9bfb9bSBernd Schubert 3274a9bfb9bSBernd Schubert /* XXX code dup */ 3284a9bfb9bSBernd Schubert for (qid = 0; qid < ring->nr_queues; qid++) { 3294a9bfb9bSBernd Schubert struct fuse_ring_queue *queue = READ_ONCE(ring->queues[qid]); 3304a9bfb9bSBernd Schubert 3314a9bfb9bSBernd Schubert if (!queue) 3324a9bfb9bSBernd Schubert continue; 3334a9bfb9bSBernd Schubert 3344a9bfb9bSBernd Schubert fuse_uring_teardown_entries(queue); 3354a9bfb9bSBernd Schubert } 3364a9bfb9bSBernd Schubert 3374a9bfb9bSBernd Schubert /* 3384a9bfb9bSBernd Schubert * Some ring entries might be in the middle of IO operations, 3394a9bfb9bSBernd Schubert * i.e. in process to get handled by file_operations::uring_cmd 3404a9bfb9bSBernd Schubert * or on the way to userspace - we could handle that with conditions in 3414a9bfb9bSBernd Schubert * run time code, but easier/cleaner to have an async tear down handler 3424a9bfb9bSBernd Schubert * If there are still queue references left 3434a9bfb9bSBernd Schubert */ 3444a9bfb9bSBernd Schubert if (atomic_read(&ring->queue_refs) > 0) { 3454a9bfb9bSBernd Schubert if (time_after(jiffies, 3464a9bfb9bSBernd Schubert ring->teardown_time + FUSE_URING_TEARDOWN_TIMEOUT)) 3474a9bfb9bSBernd Schubert fuse_uring_log_ent_state(ring); 3484a9bfb9bSBernd Schubert 3494a9bfb9bSBernd Schubert schedule_delayed_work(&ring->async_teardown_work, 3504a9bfb9bSBernd Schubert FUSE_URING_TEARDOWN_INTERVAL); 3514a9bfb9bSBernd Schubert } else { 3524a9bfb9bSBernd Schubert wake_up_all(&ring->stop_waitq); 3534a9bfb9bSBernd Schubert } 3544a9bfb9bSBernd Schubert } 3554a9bfb9bSBernd Schubert 3564a9bfb9bSBernd Schubert /* 3574a9bfb9bSBernd Schubert * Stop the ring queues 3584a9bfb9bSBernd Schubert */ 3594a9bfb9bSBernd Schubert void fuse_uring_stop_queues(struct fuse_ring *ring) 3604a9bfb9bSBernd Schubert { 3614a9bfb9bSBernd Schubert int qid; 3624a9bfb9bSBernd Schubert 3634a9bfb9bSBernd Schubert for (qid = 0; qid < ring->nr_queues; qid++) { 3644a9bfb9bSBernd Schubert struct fuse_ring_queue *queue = READ_ONCE(ring->queues[qid]); 3654a9bfb9bSBernd Schubert 3664a9bfb9bSBernd Schubert if (!queue) 3674a9bfb9bSBernd Schubert continue; 3684a9bfb9bSBernd Schubert 3694a9bfb9bSBernd Schubert fuse_uring_teardown_entries(queue); 3704a9bfb9bSBernd Schubert } 3714a9bfb9bSBernd Schubert 3724a9bfb9bSBernd Schubert if (atomic_read(&ring->queue_refs) > 0) { 3734a9bfb9bSBernd Schubert ring->teardown_time = jiffies; 3744a9bfb9bSBernd Schubert INIT_DELAYED_WORK(&ring->async_teardown_work, 3754a9bfb9bSBernd Schubert fuse_uring_async_stop_queues); 3764a9bfb9bSBernd Schubert schedule_delayed_work(&ring->async_teardown_work, 3774a9bfb9bSBernd Schubert FUSE_URING_TEARDOWN_INTERVAL); 3784a9bfb9bSBernd Schubert } else { 3794a9bfb9bSBernd Schubert wake_up_all(&ring->stop_waitq); 3804a9bfb9bSBernd Schubert } 3814a9bfb9bSBernd Schubert } 3824a9bfb9bSBernd Schubert 38324fe962cSBernd Schubert /* 384c090c8abSBernd Schubert * Checks for errors and stores it into the request 385c090c8abSBernd Schubert */ 386c090c8abSBernd Schubert static int fuse_uring_out_header_has_err(struct fuse_out_header *oh, 387c090c8abSBernd Schubert struct fuse_req *req, 388c090c8abSBernd Schubert struct fuse_conn *fc) 389c090c8abSBernd Schubert { 390c090c8abSBernd Schubert int err; 391c090c8abSBernd Schubert 392c090c8abSBernd Schubert err = -EINVAL; 393c090c8abSBernd Schubert if (oh->unique == 0) { 394c090c8abSBernd Schubert /* Not supported through io-uring yet */ 395c090c8abSBernd Schubert pr_warn_once("notify through fuse-io-uring not supported\n"); 396c090c8abSBernd Schubert goto err; 397c090c8abSBernd Schubert } 398c090c8abSBernd Schubert 399c090c8abSBernd Schubert if (oh->error <= -ERESTARTSYS || oh->error > 0) 400c090c8abSBernd Schubert goto err; 401c090c8abSBernd Schubert 402c090c8abSBernd Schubert if (oh->error) { 403c090c8abSBernd Schubert err = oh->error; 404c090c8abSBernd Schubert goto err; 405c090c8abSBernd Schubert } 406c090c8abSBernd Schubert 407c090c8abSBernd Schubert err = -ENOENT; 408c090c8abSBernd Schubert if ((oh->unique & ~FUSE_INT_REQ_BIT) != req->in.h.unique) { 409c090c8abSBernd Schubert pr_warn_ratelimited("unique mismatch, expected: %llu got %llu\n", 410c090c8abSBernd Schubert req->in.h.unique, 411c090c8abSBernd Schubert oh->unique & ~FUSE_INT_REQ_BIT); 412c090c8abSBernd Schubert goto err; 413c090c8abSBernd Schubert } 414c090c8abSBernd Schubert 415c090c8abSBernd Schubert /* 416c090c8abSBernd Schubert * Is it an interrupt reply ID? 417c090c8abSBernd Schubert * XXX: Not supported through fuse-io-uring yet, it should not even 418c090c8abSBernd Schubert * find the request - should not happen. 419c090c8abSBernd Schubert */ 420c090c8abSBernd Schubert WARN_ON_ONCE(oh->unique & FUSE_INT_REQ_BIT); 421c090c8abSBernd Schubert 422c090c8abSBernd Schubert err = 0; 423c090c8abSBernd Schubert err: 424c090c8abSBernd Schubert return err; 425c090c8abSBernd Schubert } 426c090c8abSBernd Schubert 427c090c8abSBernd Schubert static int fuse_uring_copy_from_ring(struct fuse_ring *ring, 428c090c8abSBernd Schubert struct fuse_req *req, 429c090c8abSBernd Schubert struct fuse_ring_ent *ent) 430c090c8abSBernd Schubert { 431c090c8abSBernd Schubert struct fuse_copy_state cs; 432c090c8abSBernd Schubert struct fuse_args *args = req->args; 433c090c8abSBernd Schubert struct iov_iter iter; 434c090c8abSBernd Schubert int err; 435c090c8abSBernd Schubert struct fuse_uring_ent_in_out ring_in_out; 436c090c8abSBernd Schubert 437c090c8abSBernd Schubert err = copy_from_user(&ring_in_out, &ent->headers->ring_ent_in_out, 438c090c8abSBernd Schubert sizeof(ring_in_out)); 439c090c8abSBernd Schubert if (err) 440c090c8abSBernd Schubert return -EFAULT; 441c090c8abSBernd Schubert 442c090c8abSBernd Schubert err = import_ubuf(ITER_SOURCE, ent->payload, ring->max_payload_sz, 443c090c8abSBernd Schubert &iter); 444c090c8abSBernd Schubert if (err) 445c090c8abSBernd Schubert return err; 446c090c8abSBernd Schubert 447c090c8abSBernd Schubert fuse_copy_init(&cs, 0, &iter); 448c090c8abSBernd Schubert cs.is_uring = 1; 449c090c8abSBernd Schubert cs.req = req; 450c090c8abSBernd Schubert 451c090c8abSBernd Schubert return fuse_copy_out_args(&cs, args, ring_in_out.payload_sz); 452c090c8abSBernd Schubert } 453c090c8abSBernd Schubert 454c090c8abSBernd Schubert /* 455c090c8abSBernd Schubert * Copy data from the req to the ring buffer 456c090c8abSBernd Schubert */ 457c090c8abSBernd Schubert static int fuse_uring_args_to_ring(struct fuse_ring *ring, struct fuse_req *req, 458c090c8abSBernd Schubert struct fuse_ring_ent *ent) 459c090c8abSBernd Schubert { 460c090c8abSBernd Schubert struct fuse_copy_state cs; 461c090c8abSBernd Schubert struct fuse_args *args = req->args; 462c090c8abSBernd Schubert struct fuse_in_arg *in_args = args->in_args; 463c090c8abSBernd Schubert int num_args = args->in_numargs; 464c090c8abSBernd Schubert int err; 465c090c8abSBernd Schubert struct iov_iter iter; 466c090c8abSBernd Schubert struct fuse_uring_ent_in_out ent_in_out = { 467c090c8abSBernd Schubert .flags = 0, 468c090c8abSBernd Schubert .commit_id = req->in.h.unique, 469c090c8abSBernd Schubert }; 470c090c8abSBernd Schubert 471c090c8abSBernd Schubert err = import_ubuf(ITER_DEST, ent->payload, ring->max_payload_sz, &iter); 472c090c8abSBernd Schubert if (err) { 473c090c8abSBernd Schubert pr_info_ratelimited("fuse: Import of user buffer failed\n"); 474c090c8abSBernd Schubert return err; 475c090c8abSBernd Schubert } 476c090c8abSBernd Schubert 477c090c8abSBernd Schubert fuse_copy_init(&cs, 1, &iter); 478c090c8abSBernd Schubert cs.is_uring = 1; 479c090c8abSBernd Schubert cs.req = req; 480c090c8abSBernd Schubert 481c090c8abSBernd Schubert if (num_args > 0) { 482c090c8abSBernd Schubert /* 483c090c8abSBernd Schubert * Expectation is that the first argument is the per op header. 484c090c8abSBernd Schubert * Some op code have that as zero size. 485c090c8abSBernd Schubert */ 486c090c8abSBernd Schubert if (args->in_args[0].size > 0) { 487c090c8abSBernd Schubert err = copy_to_user(&ent->headers->op_in, in_args->value, 488c090c8abSBernd Schubert in_args->size); 489c090c8abSBernd Schubert if (err) { 490c090c8abSBernd Schubert pr_info_ratelimited( 491c090c8abSBernd Schubert "Copying the header failed.\n"); 492c090c8abSBernd Schubert return -EFAULT; 493c090c8abSBernd Schubert } 494c090c8abSBernd Schubert } 495c090c8abSBernd Schubert in_args++; 496c090c8abSBernd Schubert num_args--; 497c090c8abSBernd Schubert } 498c090c8abSBernd Schubert 499c090c8abSBernd Schubert /* copy the payload */ 500c090c8abSBernd Schubert err = fuse_copy_args(&cs, num_args, args->in_pages, 501c090c8abSBernd Schubert (struct fuse_arg *)in_args, 0); 502c090c8abSBernd Schubert if (err) { 503c090c8abSBernd Schubert pr_info_ratelimited("%s fuse_copy_args failed\n", __func__); 504c090c8abSBernd Schubert return err; 505c090c8abSBernd Schubert } 506c090c8abSBernd Schubert 507c090c8abSBernd Schubert ent_in_out.payload_sz = cs.ring.copied_sz; 508c090c8abSBernd Schubert err = copy_to_user(&ent->headers->ring_ent_in_out, &ent_in_out, 509c090c8abSBernd Schubert sizeof(ent_in_out)); 510c090c8abSBernd Schubert return err ? -EFAULT : 0; 511c090c8abSBernd Schubert } 512c090c8abSBernd Schubert 513c090c8abSBernd Schubert static int fuse_uring_copy_to_ring(struct fuse_ring_ent *ent, 514c090c8abSBernd Schubert struct fuse_req *req) 515c090c8abSBernd Schubert { 516c090c8abSBernd Schubert struct fuse_ring_queue *queue = ent->queue; 517c090c8abSBernd Schubert struct fuse_ring *ring = queue->ring; 518c090c8abSBernd Schubert int err; 519c090c8abSBernd Schubert 520c090c8abSBernd Schubert err = -EIO; 521c090c8abSBernd Schubert if (WARN_ON(ent->state != FRRS_FUSE_REQ)) { 522c090c8abSBernd Schubert pr_err("qid=%d ring-req=%p invalid state %d on send\n", 523c090c8abSBernd Schubert queue->qid, ent, ent->state); 524c090c8abSBernd Schubert return err; 525c090c8abSBernd Schubert } 526c090c8abSBernd Schubert 527c090c8abSBernd Schubert err = -EINVAL; 528c090c8abSBernd Schubert if (WARN_ON(req->in.h.unique == 0)) 529c090c8abSBernd Schubert return err; 530c090c8abSBernd Schubert 531c090c8abSBernd Schubert /* copy the request */ 532c090c8abSBernd Schubert err = fuse_uring_args_to_ring(ring, req, ent); 533c090c8abSBernd Schubert if (unlikely(err)) { 534c090c8abSBernd Schubert pr_info_ratelimited("Copy to ring failed: %d\n", err); 535c090c8abSBernd Schubert return err; 536c090c8abSBernd Schubert } 537c090c8abSBernd Schubert 538c090c8abSBernd Schubert /* copy fuse_in_header */ 539c090c8abSBernd Schubert err = copy_to_user(&ent->headers->in_out, &req->in.h, 540c090c8abSBernd Schubert sizeof(req->in.h)); 541c090c8abSBernd Schubert if (err) { 542c090c8abSBernd Schubert err = -EFAULT; 543c090c8abSBernd Schubert return err; 544c090c8abSBernd Schubert } 545c090c8abSBernd Schubert 546c090c8abSBernd Schubert return 0; 547c090c8abSBernd Schubert } 548c090c8abSBernd Schubert 549c090c8abSBernd Schubert static int fuse_uring_prepare_send(struct fuse_ring_ent *ent, 550c090c8abSBernd Schubert struct fuse_req *req) 551c090c8abSBernd Schubert { 552c090c8abSBernd Schubert int err; 553c090c8abSBernd Schubert 554c090c8abSBernd Schubert err = fuse_uring_copy_to_ring(ent, req); 555c090c8abSBernd Schubert if (!err) 556c090c8abSBernd Schubert set_bit(FR_SENT, &req->flags); 557c090c8abSBernd Schubert else 558c090c8abSBernd Schubert fuse_uring_req_end(ent, req, err); 559c090c8abSBernd Schubert 560c090c8abSBernd Schubert return err; 561c090c8abSBernd Schubert } 562c090c8abSBernd Schubert 563c090c8abSBernd Schubert /* 564c090c8abSBernd Schubert * Write data to the ring buffer and send the request to userspace, 565c090c8abSBernd Schubert * userspace will read it 566c090c8abSBernd Schubert * This is comparable with classical read(/dev/fuse) 567c090c8abSBernd Schubert */ 568c090c8abSBernd Schubert static int fuse_uring_send_next_to_ring(struct fuse_ring_ent *ent, 569c090c8abSBernd Schubert struct fuse_req *req, 570c090c8abSBernd Schubert unsigned int issue_flags) 571c090c8abSBernd Schubert { 572c090c8abSBernd Schubert struct fuse_ring_queue *queue = ent->queue; 573c090c8abSBernd Schubert int err; 574c090c8abSBernd Schubert struct io_uring_cmd *cmd; 575c090c8abSBernd Schubert 576c090c8abSBernd Schubert err = fuse_uring_prepare_send(ent, req); 577c090c8abSBernd Schubert if (err) 578c090c8abSBernd Schubert return err; 579c090c8abSBernd Schubert 580c090c8abSBernd Schubert spin_lock(&queue->lock); 581c090c8abSBernd Schubert cmd = ent->cmd; 582c090c8abSBernd Schubert ent->cmd = NULL; 583c090c8abSBernd Schubert ent->state = FRRS_USERSPACE; 584c090c8abSBernd Schubert list_move(&ent->list, &queue->ent_in_userspace); 585c090c8abSBernd Schubert spin_unlock(&queue->lock); 586c090c8abSBernd Schubert 587c090c8abSBernd Schubert io_uring_cmd_done(cmd, 0, 0, issue_flags); 588c090c8abSBernd Schubert return 0; 589c090c8abSBernd Schubert } 590c090c8abSBernd Schubert 591c090c8abSBernd Schubert /* 59224fe962cSBernd Schubert * Make a ring entry available for fuse_req assignment 59324fe962cSBernd Schubert */ 59424fe962cSBernd Schubert static void fuse_uring_ent_avail(struct fuse_ring_ent *ent, 59524fe962cSBernd Schubert struct fuse_ring_queue *queue) 59624fe962cSBernd Schubert { 59724fe962cSBernd Schubert WARN_ON_ONCE(!ent->cmd); 59824fe962cSBernd Schubert list_move(&ent->list, &queue->ent_avail_queue); 59924fe962cSBernd Schubert ent->state = FRRS_AVAILABLE; 60024fe962cSBernd Schubert } 60124fe962cSBernd Schubert 602c090c8abSBernd Schubert /* Used to find the request on SQE commit */ 603c090c8abSBernd Schubert static void fuse_uring_add_to_pq(struct fuse_ring_ent *ent, 604c090c8abSBernd Schubert struct fuse_req *req) 605c090c8abSBernd Schubert { 606c090c8abSBernd Schubert struct fuse_ring_queue *queue = ent->queue; 607c090c8abSBernd Schubert struct fuse_pqueue *fpq = &queue->fpq; 608c090c8abSBernd Schubert unsigned int hash; 609c090c8abSBernd Schubert 610c090c8abSBernd Schubert req->ring_entry = ent; 611c090c8abSBernd Schubert hash = fuse_req_hash(req->in.h.unique); 612c090c8abSBernd Schubert list_move_tail(&req->list, &fpq->processing[hash]); 613c090c8abSBernd Schubert } 614c090c8abSBernd Schubert 615c090c8abSBernd Schubert /* 616c090c8abSBernd Schubert * Assign a fuse queue entry to the given entry 617c090c8abSBernd Schubert */ 618c090c8abSBernd Schubert static void fuse_uring_add_req_to_ring_ent(struct fuse_ring_ent *ent, 619c090c8abSBernd Schubert struct fuse_req *req) 620c090c8abSBernd Schubert { 621c090c8abSBernd Schubert struct fuse_ring_queue *queue = ent->queue; 622c090c8abSBernd Schubert struct fuse_conn *fc = req->fm->fc; 623c090c8abSBernd Schubert struct fuse_iqueue *fiq = &fc->iq; 624c090c8abSBernd Schubert 625c090c8abSBernd Schubert lockdep_assert_held(&queue->lock); 626c090c8abSBernd Schubert 627c090c8abSBernd Schubert if (WARN_ON_ONCE(ent->state != FRRS_AVAILABLE && 628c090c8abSBernd Schubert ent->state != FRRS_COMMIT)) { 629c090c8abSBernd Schubert pr_warn("%s qid=%d state=%d\n", __func__, ent->queue->qid, 630c090c8abSBernd Schubert ent->state); 631c090c8abSBernd Schubert } 632c090c8abSBernd Schubert 633c090c8abSBernd Schubert spin_lock(&fiq->lock); 634c090c8abSBernd Schubert clear_bit(FR_PENDING, &req->flags); 635c090c8abSBernd Schubert spin_unlock(&fiq->lock); 636c090c8abSBernd Schubert ent->fuse_req = req; 637c090c8abSBernd Schubert ent->state = FRRS_FUSE_REQ; 638c090c8abSBernd Schubert list_move(&ent->list, &queue->ent_w_req_queue); 639c090c8abSBernd Schubert fuse_uring_add_to_pq(ent, req); 640c090c8abSBernd Schubert } 641c090c8abSBernd Schubert 642c090c8abSBernd Schubert /* Fetch the next fuse request if available */ 643c090c8abSBernd Schubert static struct fuse_req *fuse_uring_ent_assign_req(struct fuse_ring_ent *ent) 644c090c8abSBernd Schubert __must_hold(&queue->lock) 645c090c8abSBernd Schubert { 646c090c8abSBernd Schubert struct fuse_req *req; 647c090c8abSBernd Schubert struct fuse_ring_queue *queue = ent->queue; 648c090c8abSBernd Schubert struct list_head *req_queue = &queue->fuse_req_queue; 649c090c8abSBernd Schubert 650c090c8abSBernd Schubert lockdep_assert_held(&queue->lock); 651c090c8abSBernd Schubert 652c090c8abSBernd Schubert /* get and assign the next entry while it is still holding the lock */ 653c090c8abSBernd Schubert req = list_first_entry_or_null(req_queue, struct fuse_req, list); 654c090c8abSBernd Schubert if (req) 655c090c8abSBernd Schubert fuse_uring_add_req_to_ring_ent(ent, req); 656c090c8abSBernd Schubert 657c090c8abSBernd Schubert return req; 658c090c8abSBernd Schubert } 659c090c8abSBernd Schubert 660c090c8abSBernd Schubert /* 661c090c8abSBernd Schubert * Read data from the ring buffer, which user space has written to 662c090c8abSBernd Schubert * This is comparible with handling of classical write(/dev/fuse). 663c090c8abSBernd Schubert * Also make the ring request available again for new fuse requests. 664c090c8abSBernd Schubert */ 665c090c8abSBernd Schubert static void fuse_uring_commit(struct fuse_ring_ent *ent, struct fuse_req *req, 666c090c8abSBernd Schubert unsigned int issue_flags) 667c090c8abSBernd Schubert { 668c090c8abSBernd Schubert struct fuse_ring *ring = ent->queue->ring; 669c090c8abSBernd Schubert struct fuse_conn *fc = ring->fc; 670c090c8abSBernd Schubert ssize_t err = 0; 671c090c8abSBernd Schubert 672c090c8abSBernd Schubert err = copy_from_user(&req->out.h, &ent->headers->in_out, 673c090c8abSBernd Schubert sizeof(req->out.h)); 674c090c8abSBernd Schubert if (err) { 675c090c8abSBernd Schubert req->out.h.error = -EFAULT; 676c090c8abSBernd Schubert goto out; 677c090c8abSBernd Schubert } 678c090c8abSBernd Schubert 679c090c8abSBernd Schubert err = fuse_uring_out_header_has_err(&req->out.h, req, fc); 680c090c8abSBernd Schubert if (err) { 681c090c8abSBernd Schubert /* req->out.h.error already set */ 682c090c8abSBernd Schubert goto out; 683c090c8abSBernd Schubert } 684c090c8abSBernd Schubert 685c090c8abSBernd Schubert err = fuse_uring_copy_from_ring(ring, req, ent); 686c090c8abSBernd Schubert out: 687c090c8abSBernd Schubert fuse_uring_req_end(ent, req, err); 688c090c8abSBernd Schubert } 689c090c8abSBernd Schubert 690c090c8abSBernd Schubert /* 691c090c8abSBernd Schubert * Get the next fuse req and send it 692c090c8abSBernd Schubert */ 693c090c8abSBernd Schubert static void fuse_uring_next_fuse_req(struct fuse_ring_ent *ent, 694c090c8abSBernd Schubert struct fuse_ring_queue *queue, 695c090c8abSBernd Schubert unsigned int issue_flags) 696c090c8abSBernd Schubert { 697c090c8abSBernd Schubert int err; 698c090c8abSBernd Schubert struct fuse_req *req; 699c090c8abSBernd Schubert 700c090c8abSBernd Schubert retry: 701c090c8abSBernd Schubert spin_lock(&queue->lock); 702c090c8abSBernd Schubert fuse_uring_ent_avail(ent, queue); 703c090c8abSBernd Schubert req = fuse_uring_ent_assign_req(ent); 704c090c8abSBernd Schubert spin_unlock(&queue->lock); 705c090c8abSBernd Schubert 706c090c8abSBernd Schubert if (req) { 707c090c8abSBernd Schubert err = fuse_uring_send_next_to_ring(ent, req, issue_flags); 708c090c8abSBernd Schubert if (err) 709c090c8abSBernd Schubert goto retry; 710c090c8abSBernd Schubert } 711c090c8abSBernd Schubert } 712c090c8abSBernd Schubert 713c090c8abSBernd Schubert static int fuse_ring_ent_set_commit(struct fuse_ring_ent *ent) 714c090c8abSBernd Schubert { 715c090c8abSBernd Schubert struct fuse_ring_queue *queue = ent->queue; 716c090c8abSBernd Schubert 717c090c8abSBernd Schubert lockdep_assert_held(&queue->lock); 718c090c8abSBernd Schubert 719c090c8abSBernd Schubert if (WARN_ON_ONCE(ent->state != FRRS_USERSPACE)) 720c090c8abSBernd Schubert return -EIO; 721c090c8abSBernd Schubert 722c090c8abSBernd Schubert ent->state = FRRS_COMMIT; 723c090c8abSBernd Schubert list_move(&ent->list, &queue->ent_commit_queue); 724c090c8abSBernd Schubert 725c090c8abSBernd Schubert return 0; 726c090c8abSBernd Schubert } 727c090c8abSBernd Schubert 728c090c8abSBernd Schubert /* FUSE_URING_CMD_COMMIT_AND_FETCH handler */ 729c090c8abSBernd Schubert static int fuse_uring_commit_fetch(struct io_uring_cmd *cmd, int issue_flags, 730c090c8abSBernd Schubert struct fuse_conn *fc) 731c090c8abSBernd Schubert { 732c090c8abSBernd Schubert const struct fuse_uring_cmd_req *cmd_req = io_uring_sqe_cmd(cmd->sqe); 733c090c8abSBernd Schubert struct fuse_ring_ent *ent; 734c090c8abSBernd Schubert int err; 735c090c8abSBernd Schubert struct fuse_ring *ring = fc->ring; 736c090c8abSBernd Schubert struct fuse_ring_queue *queue; 737c090c8abSBernd Schubert uint64_t commit_id = READ_ONCE(cmd_req->commit_id); 738c090c8abSBernd Schubert unsigned int qid = READ_ONCE(cmd_req->qid); 739c090c8abSBernd Schubert struct fuse_pqueue *fpq; 740c090c8abSBernd Schubert struct fuse_req *req; 741c090c8abSBernd Schubert 742c090c8abSBernd Schubert err = -ENOTCONN; 743c090c8abSBernd Schubert if (!ring) 744c090c8abSBernd Schubert return err; 745c090c8abSBernd Schubert 746c090c8abSBernd Schubert if (qid >= ring->nr_queues) 747c090c8abSBernd Schubert return -EINVAL; 748c090c8abSBernd Schubert 749c090c8abSBernd Schubert queue = ring->queues[qid]; 750c090c8abSBernd Schubert if (!queue) 751c090c8abSBernd Schubert return err; 752c090c8abSBernd Schubert fpq = &queue->fpq; 753c090c8abSBernd Schubert 7544a9bfb9bSBernd Schubert if (!READ_ONCE(fc->connected) || READ_ONCE(queue->stopped)) 7554a9bfb9bSBernd Schubert return err; 7564a9bfb9bSBernd Schubert 757c090c8abSBernd Schubert spin_lock(&queue->lock); 758c090c8abSBernd Schubert /* Find a request based on the unique ID of the fuse request 759c090c8abSBernd Schubert * This should get revised, as it needs a hash calculation and list 760c090c8abSBernd Schubert * search. And full struct fuse_pqueue is needed (memory overhead). 761c090c8abSBernd Schubert * As well as the link from req to ring_ent. 762c090c8abSBernd Schubert */ 763c090c8abSBernd Schubert req = fuse_request_find(fpq, commit_id); 764c090c8abSBernd Schubert err = -ENOENT; 765c090c8abSBernd Schubert if (!req) { 766c090c8abSBernd Schubert pr_info("qid=%d commit_id %llu not found\n", queue->qid, 767c090c8abSBernd Schubert commit_id); 768c090c8abSBernd Schubert spin_unlock(&queue->lock); 769c090c8abSBernd Schubert return err; 770c090c8abSBernd Schubert } 771c090c8abSBernd Schubert list_del_init(&req->list); 772c090c8abSBernd Schubert ent = req->ring_entry; 773c090c8abSBernd Schubert req->ring_entry = NULL; 774c090c8abSBernd Schubert 775c090c8abSBernd Schubert err = fuse_ring_ent_set_commit(ent); 776c090c8abSBernd Schubert if (err != 0) { 777c090c8abSBernd Schubert pr_info_ratelimited("qid=%d commit_id %llu state %d", 778c090c8abSBernd Schubert queue->qid, commit_id, ent->state); 779c090c8abSBernd Schubert spin_unlock(&queue->lock); 780c090c8abSBernd Schubert req->out.h.error = err; 781c090c8abSBernd Schubert clear_bit(FR_SENT, &req->flags); 782c090c8abSBernd Schubert fuse_request_end(req); 783c090c8abSBernd Schubert return err; 784c090c8abSBernd Schubert } 785c090c8abSBernd Schubert 786c090c8abSBernd Schubert ent->cmd = cmd; 787c090c8abSBernd Schubert spin_unlock(&queue->lock); 788c090c8abSBernd Schubert 789c090c8abSBernd Schubert /* without the queue lock, as other locks are taken */ 790c090c8abSBernd Schubert fuse_uring_commit(ent, req, issue_flags); 791c090c8abSBernd Schubert 792c090c8abSBernd Schubert /* 793c090c8abSBernd Schubert * Fetching the next request is absolutely required as queued 794c090c8abSBernd Schubert * fuse requests would otherwise not get processed - committing 795c090c8abSBernd Schubert * and fetching is done in one step vs legacy fuse, which has separated 796c090c8abSBernd Schubert * read (fetch request) and write (commit result). 797c090c8abSBernd Schubert */ 798c090c8abSBernd Schubert fuse_uring_next_fuse_req(ent, queue, issue_flags); 799c090c8abSBernd Schubert return 0; 800c090c8abSBernd Schubert } 801c090c8abSBernd Schubert 802*c2c9af9aSBernd Schubert static bool is_ring_ready(struct fuse_ring *ring, int current_qid) 803*c2c9af9aSBernd Schubert { 804*c2c9af9aSBernd Schubert int qid; 805*c2c9af9aSBernd Schubert struct fuse_ring_queue *queue; 806*c2c9af9aSBernd Schubert bool ready = true; 807*c2c9af9aSBernd Schubert 808*c2c9af9aSBernd Schubert for (qid = 0; qid < ring->nr_queues && ready; qid++) { 809*c2c9af9aSBernd Schubert if (current_qid == qid) 810*c2c9af9aSBernd Schubert continue; 811*c2c9af9aSBernd Schubert 812*c2c9af9aSBernd Schubert queue = ring->queues[qid]; 813*c2c9af9aSBernd Schubert if (!queue) { 814*c2c9af9aSBernd Schubert ready = false; 815*c2c9af9aSBernd Schubert break; 816*c2c9af9aSBernd Schubert } 817*c2c9af9aSBernd Schubert 818*c2c9af9aSBernd Schubert spin_lock(&queue->lock); 819*c2c9af9aSBernd Schubert if (list_empty(&queue->ent_avail_queue)) 820*c2c9af9aSBernd Schubert ready = false; 821*c2c9af9aSBernd Schubert spin_unlock(&queue->lock); 822*c2c9af9aSBernd Schubert } 823*c2c9af9aSBernd Schubert 824*c2c9af9aSBernd Schubert return ready; 825*c2c9af9aSBernd Schubert } 826*c2c9af9aSBernd Schubert 82724fe962cSBernd Schubert /* 82824fe962cSBernd Schubert * fuse_uring_req_fetch command handling 82924fe962cSBernd Schubert */ 83024fe962cSBernd Schubert static void fuse_uring_do_register(struct fuse_ring_ent *ent, 83124fe962cSBernd Schubert struct io_uring_cmd *cmd, 83224fe962cSBernd Schubert unsigned int issue_flags) 83324fe962cSBernd Schubert { 83424fe962cSBernd Schubert struct fuse_ring_queue *queue = ent->queue; 835*c2c9af9aSBernd Schubert struct fuse_ring *ring = queue->ring; 836*c2c9af9aSBernd Schubert struct fuse_conn *fc = ring->fc; 837*c2c9af9aSBernd Schubert struct fuse_iqueue *fiq = &fc->iq; 83824fe962cSBernd Schubert 83924fe962cSBernd Schubert spin_lock(&queue->lock); 84024fe962cSBernd Schubert ent->cmd = cmd; 84124fe962cSBernd Schubert fuse_uring_ent_avail(ent, queue); 84224fe962cSBernd Schubert spin_unlock(&queue->lock); 843*c2c9af9aSBernd Schubert 844*c2c9af9aSBernd Schubert if (!ring->ready) { 845*c2c9af9aSBernd Schubert bool ready = is_ring_ready(ring, queue->qid); 846*c2c9af9aSBernd Schubert 847*c2c9af9aSBernd Schubert if (ready) { 848*c2c9af9aSBernd Schubert WRITE_ONCE(fiq->ops, &fuse_io_uring_ops); 849*c2c9af9aSBernd Schubert WRITE_ONCE(ring->ready, true); 850*c2c9af9aSBernd Schubert } 851*c2c9af9aSBernd Schubert } 85224fe962cSBernd Schubert } 85324fe962cSBernd Schubert 85424fe962cSBernd Schubert /* 85524fe962cSBernd Schubert * sqe->addr is a ptr to an iovec array, iov[0] has the headers, iov[1] 85624fe962cSBernd Schubert * the payload 85724fe962cSBernd Schubert */ 85824fe962cSBernd Schubert static int fuse_uring_get_iovec_from_sqe(const struct io_uring_sqe *sqe, 85924fe962cSBernd Schubert struct iovec iov[FUSE_URING_IOV_SEGS]) 86024fe962cSBernd Schubert { 86124fe962cSBernd Schubert struct iovec __user *uiov = u64_to_user_ptr(READ_ONCE(sqe->addr)); 86224fe962cSBernd Schubert struct iov_iter iter; 86324fe962cSBernd Schubert ssize_t ret; 86424fe962cSBernd Schubert 86524fe962cSBernd Schubert if (sqe->len != FUSE_URING_IOV_SEGS) 86624fe962cSBernd Schubert return -EINVAL; 86724fe962cSBernd Schubert 86824fe962cSBernd Schubert /* 86924fe962cSBernd Schubert * Direction for buffer access will actually be READ and WRITE, 87024fe962cSBernd Schubert * using write for the import should include READ access as well. 87124fe962cSBernd Schubert */ 87224fe962cSBernd Schubert ret = import_iovec(WRITE, uiov, FUSE_URING_IOV_SEGS, 87324fe962cSBernd Schubert FUSE_URING_IOV_SEGS, &iov, &iter); 87424fe962cSBernd Schubert if (ret < 0) 87524fe962cSBernd Schubert return ret; 87624fe962cSBernd Schubert 87724fe962cSBernd Schubert return 0; 87824fe962cSBernd Schubert } 87924fe962cSBernd Schubert 88024fe962cSBernd Schubert static struct fuse_ring_ent * 88124fe962cSBernd Schubert fuse_uring_create_ring_ent(struct io_uring_cmd *cmd, 88224fe962cSBernd Schubert struct fuse_ring_queue *queue) 88324fe962cSBernd Schubert { 88424fe962cSBernd Schubert struct fuse_ring *ring = queue->ring; 88524fe962cSBernd Schubert struct fuse_ring_ent *ent; 88624fe962cSBernd Schubert size_t payload_size; 88724fe962cSBernd Schubert struct iovec iov[FUSE_URING_IOV_SEGS]; 88824fe962cSBernd Schubert int err; 88924fe962cSBernd Schubert 89024fe962cSBernd Schubert err = fuse_uring_get_iovec_from_sqe(cmd->sqe, iov); 89124fe962cSBernd Schubert if (err) { 89224fe962cSBernd Schubert pr_info_ratelimited("Failed to get iovec from sqe, err=%d\n", 89324fe962cSBernd Schubert err); 89424fe962cSBernd Schubert return ERR_PTR(err); 89524fe962cSBernd Schubert } 89624fe962cSBernd Schubert 89724fe962cSBernd Schubert err = -EINVAL; 89824fe962cSBernd Schubert if (iov[0].iov_len < sizeof(struct fuse_uring_req_header)) { 89924fe962cSBernd Schubert pr_info_ratelimited("Invalid header len %zu\n", iov[0].iov_len); 90024fe962cSBernd Schubert return ERR_PTR(err); 90124fe962cSBernd Schubert } 90224fe962cSBernd Schubert 90324fe962cSBernd Schubert payload_size = iov[1].iov_len; 90424fe962cSBernd Schubert if (payload_size < ring->max_payload_sz) { 90524fe962cSBernd Schubert pr_info_ratelimited("Invalid req payload len %zu\n", 90624fe962cSBernd Schubert payload_size); 90724fe962cSBernd Schubert return ERR_PTR(err); 90824fe962cSBernd Schubert } 90924fe962cSBernd Schubert 91024fe962cSBernd Schubert err = -ENOMEM; 91124fe962cSBernd Schubert ent = kzalloc(sizeof(*ent), GFP_KERNEL_ACCOUNT); 91224fe962cSBernd Schubert if (!ent) 91324fe962cSBernd Schubert return ERR_PTR(err); 91424fe962cSBernd Schubert 91524fe962cSBernd Schubert INIT_LIST_HEAD(&ent->list); 91624fe962cSBernd Schubert 91724fe962cSBernd Schubert ent->queue = queue; 91824fe962cSBernd Schubert ent->headers = iov[0].iov_base; 91924fe962cSBernd Schubert ent->payload = iov[1].iov_base; 92024fe962cSBernd Schubert 9214a9bfb9bSBernd Schubert atomic_inc(&ring->queue_refs); 92224fe962cSBernd Schubert return ent; 92324fe962cSBernd Schubert } 92424fe962cSBernd Schubert 92524fe962cSBernd Schubert /* 92624fe962cSBernd Schubert * Register header and payload buffer with the kernel and puts the 92724fe962cSBernd Schubert * entry as "ready to get fuse requests" on the queue 92824fe962cSBernd Schubert */ 92924fe962cSBernd Schubert static int fuse_uring_register(struct io_uring_cmd *cmd, 93024fe962cSBernd Schubert unsigned int issue_flags, struct fuse_conn *fc) 93124fe962cSBernd Schubert { 93224fe962cSBernd Schubert const struct fuse_uring_cmd_req *cmd_req = io_uring_sqe_cmd(cmd->sqe); 93324fe962cSBernd Schubert struct fuse_ring *ring = fc->ring; 93424fe962cSBernd Schubert struct fuse_ring_queue *queue; 93524fe962cSBernd Schubert struct fuse_ring_ent *ent; 93624fe962cSBernd Schubert int err; 93724fe962cSBernd Schubert unsigned int qid = READ_ONCE(cmd_req->qid); 93824fe962cSBernd Schubert 93924fe962cSBernd Schubert err = -ENOMEM; 94024fe962cSBernd Schubert if (!ring) { 94124fe962cSBernd Schubert ring = fuse_uring_create(fc); 94224fe962cSBernd Schubert if (!ring) 94324fe962cSBernd Schubert return err; 94424fe962cSBernd Schubert } 94524fe962cSBernd Schubert 94624fe962cSBernd Schubert if (qid >= ring->nr_queues) { 94724fe962cSBernd Schubert pr_info_ratelimited("fuse: Invalid ring qid %u\n", qid); 94824fe962cSBernd Schubert return -EINVAL; 94924fe962cSBernd Schubert } 95024fe962cSBernd Schubert 95124fe962cSBernd Schubert queue = ring->queues[qid]; 95224fe962cSBernd Schubert if (!queue) { 95324fe962cSBernd Schubert queue = fuse_uring_create_queue(ring, qid); 95424fe962cSBernd Schubert if (!queue) 95524fe962cSBernd Schubert return err; 95624fe962cSBernd Schubert } 95724fe962cSBernd Schubert 95824fe962cSBernd Schubert /* 95924fe962cSBernd Schubert * The created queue above does not need to be destructed in 96024fe962cSBernd Schubert * case of entry errors below, will be done at ring destruction time. 96124fe962cSBernd Schubert */ 96224fe962cSBernd Schubert 96324fe962cSBernd Schubert ent = fuse_uring_create_ring_ent(cmd, queue); 96424fe962cSBernd Schubert if (IS_ERR(ent)) 96524fe962cSBernd Schubert return PTR_ERR(ent); 96624fe962cSBernd Schubert 96724fe962cSBernd Schubert fuse_uring_do_register(ent, cmd, issue_flags); 96824fe962cSBernd Schubert 96924fe962cSBernd Schubert return 0; 97024fe962cSBernd Schubert } 97124fe962cSBernd Schubert 97224fe962cSBernd Schubert /* 97324fe962cSBernd Schubert * Entry function from io_uring to handle the given passthrough command 97424fe962cSBernd Schubert * (op code IORING_OP_URING_CMD) 97524fe962cSBernd Schubert */ 97624fe962cSBernd Schubert int __maybe_unused fuse_uring_cmd(struct io_uring_cmd *cmd, 97724fe962cSBernd Schubert unsigned int issue_flags) 97824fe962cSBernd Schubert { 97924fe962cSBernd Schubert struct fuse_dev *fud; 98024fe962cSBernd Schubert struct fuse_conn *fc; 98124fe962cSBernd Schubert u32 cmd_op = cmd->cmd_op; 98224fe962cSBernd Schubert int err; 98324fe962cSBernd Schubert 98424fe962cSBernd Schubert if (!enable_uring) { 98524fe962cSBernd Schubert pr_info_ratelimited("fuse-io-uring is disabled\n"); 98624fe962cSBernd Schubert return -EOPNOTSUPP; 98724fe962cSBernd Schubert } 98824fe962cSBernd Schubert 98924fe962cSBernd Schubert /* This extra SQE size holds struct fuse_uring_cmd_req */ 99024fe962cSBernd Schubert if (!(issue_flags & IO_URING_F_SQE128)) 99124fe962cSBernd Schubert return -EINVAL; 99224fe962cSBernd Schubert 99324fe962cSBernd Schubert fud = fuse_get_dev(cmd->file); 99424fe962cSBernd Schubert if (!fud) { 99524fe962cSBernd Schubert pr_info_ratelimited("No fuse device found\n"); 99624fe962cSBernd Schubert return -ENOTCONN; 99724fe962cSBernd Schubert } 99824fe962cSBernd Schubert fc = fud->fc; 99924fe962cSBernd Schubert 100024fe962cSBernd Schubert if (fc->aborted) 100124fe962cSBernd Schubert return -ECONNABORTED; 100224fe962cSBernd Schubert if (!fc->connected) 100324fe962cSBernd Schubert return -ENOTCONN; 100424fe962cSBernd Schubert 100524fe962cSBernd Schubert /* 100624fe962cSBernd Schubert * fuse_uring_register() needs the ring to be initialized, 100724fe962cSBernd Schubert * we need to know the max payload size 100824fe962cSBernd Schubert */ 100924fe962cSBernd Schubert if (!fc->initialized) 101024fe962cSBernd Schubert return -EAGAIN; 101124fe962cSBernd Schubert 101224fe962cSBernd Schubert switch (cmd_op) { 101324fe962cSBernd Schubert case FUSE_IO_URING_CMD_REGISTER: 101424fe962cSBernd Schubert err = fuse_uring_register(cmd, issue_flags, fc); 101524fe962cSBernd Schubert if (err) { 101624fe962cSBernd Schubert pr_info_once("FUSE_IO_URING_CMD_REGISTER failed err=%d\n", 101724fe962cSBernd Schubert err); 101824fe962cSBernd Schubert return err; 101924fe962cSBernd Schubert } 102024fe962cSBernd Schubert break; 1021c090c8abSBernd Schubert case FUSE_IO_URING_CMD_COMMIT_AND_FETCH: 1022c090c8abSBernd Schubert err = fuse_uring_commit_fetch(cmd, issue_flags, fc); 1023c090c8abSBernd Schubert if (err) { 1024c090c8abSBernd Schubert pr_info_once("FUSE_IO_URING_COMMIT_AND_FETCH failed err=%d\n", 1025c090c8abSBernd Schubert err); 1026c090c8abSBernd Schubert return err; 1027c090c8abSBernd Schubert } 1028c090c8abSBernd Schubert break; 102924fe962cSBernd Schubert default: 103024fe962cSBernd Schubert return -EINVAL; 103124fe962cSBernd Schubert } 103224fe962cSBernd Schubert 103324fe962cSBernd Schubert return -EIOCBQUEUED; 103424fe962cSBernd Schubert } 1035*c2c9af9aSBernd Schubert 1036*c2c9af9aSBernd Schubert static void fuse_uring_send(struct fuse_ring_ent *ent, struct io_uring_cmd *cmd, 1037*c2c9af9aSBernd Schubert ssize_t ret, unsigned int issue_flags) 1038*c2c9af9aSBernd Schubert { 1039*c2c9af9aSBernd Schubert struct fuse_ring_queue *queue = ent->queue; 1040*c2c9af9aSBernd Schubert 1041*c2c9af9aSBernd Schubert spin_lock(&queue->lock); 1042*c2c9af9aSBernd Schubert ent->state = FRRS_USERSPACE; 1043*c2c9af9aSBernd Schubert list_move(&ent->list, &queue->ent_in_userspace); 1044*c2c9af9aSBernd Schubert ent->cmd = NULL; 1045*c2c9af9aSBernd Schubert spin_unlock(&queue->lock); 1046*c2c9af9aSBernd Schubert 1047*c2c9af9aSBernd Schubert io_uring_cmd_done(cmd, ret, 0, issue_flags); 1048*c2c9af9aSBernd Schubert } 1049*c2c9af9aSBernd Schubert 1050*c2c9af9aSBernd Schubert /* 1051*c2c9af9aSBernd Schubert * This prepares and sends the ring request in fuse-uring task context. 1052*c2c9af9aSBernd Schubert * User buffers are not mapped yet - the application does not have permission 1053*c2c9af9aSBernd Schubert * to write to it - this has to be executed in ring task context. 1054*c2c9af9aSBernd Schubert */ 1055*c2c9af9aSBernd Schubert static void fuse_uring_send_in_task(struct io_uring_cmd *cmd, 1056*c2c9af9aSBernd Schubert unsigned int issue_flags) 1057*c2c9af9aSBernd Schubert { 1058*c2c9af9aSBernd Schubert struct fuse_ring_ent *ent = uring_cmd_to_ring_ent(cmd); 1059*c2c9af9aSBernd Schubert struct fuse_ring_queue *queue = ent->queue; 1060*c2c9af9aSBernd Schubert int err; 1061*c2c9af9aSBernd Schubert 1062*c2c9af9aSBernd Schubert if (!(issue_flags & IO_URING_F_TASK_DEAD)) { 1063*c2c9af9aSBernd Schubert err = fuse_uring_prepare_send(ent, ent->fuse_req); 1064*c2c9af9aSBernd Schubert if (err) { 1065*c2c9af9aSBernd Schubert fuse_uring_next_fuse_req(ent, queue, issue_flags); 1066*c2c9af9aSBernd Schubert return; 1067*c2c9af9aSBernd Schubert } 1068*c2c9af9aSBernd Schubert } else { 1069*c2c9af9aSBernd Schubert err = -ECANCELED; 1070*c2c9af9aSBernd Schubert } 1071*c2c9af9aSBernd Schubert 1072*c2c9af9aSBernd Schubert fuse_uring_send(ent, cmd, err, issue_flags); 1073*c2c9af9aSBernd Schubert } 1074*c2c9af9aSBernd Schubert 1075*c2c9af9aSBernd Schubert static struct fuse_ring_queue *fuse_uring_task_to_queue(struct fuse_ring *ring) 1076*c2c9af9aSBernd Schubert { 1077*c2c9af9aSBernd Schubert unsigned int qid; 1078*c2c9af9aSBernd Schubert struct fuse_ring_queue *queue; 1079*c2c9af9aSBernd Schubert 1080*c2c9af9aSBernd Schubert qid = task_cpu(current); 1081*c2c9af9aSBernd Schubert 1082*c2c9af9aSBernd Schubert if (WARN_ONCE(qid >= ring->nr_queues, 1083*c2c9af9aSBernd Schubert "Core number (%u) exceeds nr queues (%zu)\n", qid, 1084*c2c9af9aSBernd Schubert ring->nr_queues)) 1085*c2c9af9aSBernd Schubert qid = 0; 1086*c2c9af9aSBernd Schubert 1087*c2c9af9aSBernd Schubert queue = ring->queues[qid]; 1088*c2c9af9aSBernd Schubert WARN_ONCE(!queue, "Missing queue for qid %d\n", qid); 1089*c2c9af9aSBernd Schubert 1090*c2c9af9aSBernd Schubert return queue; 1091*c2c9af9aSBernd Schubert } 1092*c2c9af9aSBernd Schubert 1093*c2c9af9aSBernd Schubert static void fuse_uring_dispatch_ent(struct fuse_ring_ent *ent) 1094*c2c9af9aSBernd Schubert { 1095*c2c9af9aSBernd Schubert struct io_uring_cmd *cmd = ent->cmd; 1096*c2c9af9aSBernd Schubert 1097*c2c9af9aSBernd Schubert uring_cmd_set_ring_ent(cmd, ent); 1098*c2c9af9aSBernd Schubert io_uring_cmd_complete_in_task(cmd, fuse_uring_send_in_task); 1099*c2c9af9aSBernd Schubert } 1100*c2c9af9aSBernd Schubert 1101*c2c9af9aSBernd Schubert /* queue a fuse request and send it if a ring entry is available */ 1102*c2c9af9aSBernd Schubert void fuse_uring_queue_fuse_req(struct fuse_iqueue *fiq, struct fuse_req *req) 1103*c2c9af9aSBernd Schubert { 1104*c2c9af9aSBernd Schubert struct fuse_conn *fc = req->fm->fc; 1105*c2c9af9aSBernd Schubert struct fuse_ring *ring = fc->ring; 1106*c2c9af9aSBernd Schubert struct fuse_ring_queue *queue; 1107*c2c9af9aSBernd Schubert struct fuse_ring_ent *ent = NULL; 1108*c2c9af9aSBernd Schubert int err; 1109*c2c9af9aSBernd Schubert 1110*c2c9af9aSBernd Schubert err = -EINVAL; 1111*c2c9af9aSBernd Schubert queue = fuse_uring_task_to_queue(ring); 1112*c2c9af9aSBernd Schubert if (!queue) 1113*c2c9af9aSBernd Schubert goto err; 1114*c2c9af9aSBernd Schubert 1115*c2c9af9aSBernd Schubert if (req->in.h.opcode != FUSE_NOTIFY_REPLY) 1116*c2c9af9aSBernd Schubert req->in.h.unique = fuse_get_unique(fiq); 1117*c2c9af9aSBernd Schubert 1118*c2c9af9aSBernd Schubert spin_lock(&queue->lock); 1119*c2c9af9aSBernd Schubert err = -ENOTCONN; 1120*c2c9af9aSBernd Schubert if (unlikely(queue->stopped)) 1121*c2c9af9aSBernd Schubert goto err_unlock; 1122*c2c9af9aSBernd Schubert 1123*c2c9af9aSBernd Schubert ent = list_first_entry_or_null(&queue->ent_avail_queue, 1124*c2c9af9aSBernd Schubert struct fuse_ring_ent, list); 1125*c2c9af9aSBernd Schubert if (ent) 1126*c2c9af9aSBernd Schubert fuse_uring_add_req_to_ring_ent(ent, req); 1127*c2c9af9aSBernd Schubert else 1128*c2c9af9aSBernd Schubert list_add_tail(&req->list, &queue->fuse_req_queue); 1129*c2c9af9aSBernd Schubert spin_unlock(&queue->lock); 1130*c2c9af9aSBernd Schubert 1131*c2c9af9aSBernd Schubert if (ent) 1132*c2c9af9aSBernd Schubert fuse_uring_dispatch_ent(ent); 1133*c2c9af9aSBernd Schubert 1134*c2c9af9aSBernd Schubert return; 1135*c2c9af9aSBernd Schubert 1136*c2c9af9aSBernd Schubert err_unlock: 1137*c2c9af9aSBernd Schubert spin_unlock(&queue->lock); 1138*c2c9af9aSBernd Schubert err: 1139*c2c9af9aSBernd Schubert req->out.h.error = err; 1140*c2c9af9aSBernd Schubert clear_bit(FR_PENDING, &req->flags); 1141*c2c9af9aSBernd Schubert fuse_request_end(req); 1142*c2c9af9aSBernd Schubert } 1143*c2c9af9aSBernd Schubert 1144*c2c9af9aSBernd Schubert static const struct fuse_iqueue_ops fuse_io_uring_ops = { 1145*c2c9af9aSBernd Schubert /* should be send over io-uring as enhancement */ 1146*c2c9af9aSBernd Schubert .send_forget = fuse_dev_queue_forget, 1147*c2c9af9aSBernd Schubert 1148*c2c9af9aSBernd Schubert /* 1149*c2c9af9aSBernd Schubert * could be send over io-uring, but interrupts should be rare, 1150*c2c9af9aSBernd Schubert * no need to make the code complex 1151*c2c9af9aSBernd Schubert */ 1152*c2c9af9aSBernd Schubert .send_interrupt = fuse_dev_queue_interrupt, 1153*c2c9af9aSBernd Schubert .send_req = fuse_uring_queue_fuse_req, 1154*c2c9af9aSBernd Schubert }; 1155