commit 48eacf47fc2f6a6a2bab35579451825282eb4f1f Author: Bernd Schubert Date: Mon Jan 20 00:34:41 2025 +0100 xarray diff --git a/fs/fuse/dev_uring.c b/fs/fuse/dev_uring.c index 40a0c19ab4d7..b8d2cea1f72b 100644 --- a/fs/fuse/dev_uring.c +++ b/fs/fuse/dev_uring.c @@ -7,6 +7,7 @@ #include "fuse_i.h" #include "dev_uring_i.h" #include "fuse_dev_i.h" +#include #include #include @@ -55,7 +56,6 @@ void fuse_uring_destruct(struct fuse_conn *fc) WARN_ON(!list_empty(&queue->ent_commit_queue)); WARN_ON(!list_empty(&queue->ent_in_userspace)); - kfree(queue->fpq.processing); kfree(queue); ring->queues[qid] = NULL; } @@ -135,13 +135,11 @@ static struct fuse_ring_queue *fuse_uring_create_queue(struct fuse_ring *ring, INIT_LIST_HEAD(&queue->ent_in_userspace); INIT_LIST_HEAD(&queue->fuse_req_queue); - queue->fpq.processing = pq; - fuse_pqueue_init(&queue->fpq); + xa_init(&queue->ent_xa); spin_lock(&fc->lock); if (ring->queues[qid]) { spin_unlock(&fc->lock); - kfree(queue->fpq.processing); kfree(queue); return ring->queues[qid]; } @@ -240,7 +238,7 @@ static int fuse_uring_args_to_ring(struct fuse_ring *ring, struct fuse_req *req, struct iov_iter iter; struct fuse_uring_ent_in_out ent_in_out = { .flags = 0, - .commit_id = req->in.h.unique, + .commit_id = ent->id }; err = import_ubuf(ITER_DEST, ent->payload, ring->max_payload_sz, &iter); @@ -373,19 +371,6 @@ static void fuse_uring_ent_avail(struct fuse_ring_ent *ent, ent->state = FRRS_AVAILABLE; } -/* Used to find the request on SQE commit */ -static void fuse_uring_add_to_pq(struct fuse_ring_ent *ent, - struct fuse_req *req) -{ - struct fuse_ring_queue *queue = ent->queue; - struct fuse_pqueue *fpq = &queue->fpq; - unsigned int hash; - - req->ring_entry = ent; - hash = fuse_req_hash(req->in.h.unique); - list_move_tail(&req->list, &fpq->processing[hash]); -} - /* * Assign a fuse queue entry to the given entry */ @@ -410,7 +395,9 @@ static void fuse_uring_add_req_to_ring_ent(struct fuse_ring_ent *ent, ent->fuse_req = req; ent->state = FRRS_FUSE_REQ; list_move(&ent->list, &queue->ent_w_req_queue); - fuse_uring_add_to_pq(ent, req); + + WARN_ON_ONCE(!list_empty(&ent->proc_list)); + list_move_tail(&req->list, &ent->proc_list); } /* @@ -450,6 +437,15 @@ static void fuse_uring_commit(struct fuse_ring_ent *ent, struct fuse_req *req = ent->fuse_req; ssize_t err = 0; + /* + * The request was removed from proc_list - we are not going to further + * process it + */ + if (list_empty(&ent->proc_list)) + return; + + list_del_init(&req->list); + err = copy_from_user(&req->out.h, &ent->headers->in_out, sizeof(req->out.h)); if (err) { @@ -506,6 +502,12 @@ static int fuse_ring_ent_set_commit(struct fuse_ring_ent *ent) return 0; } +static struct fuse_ring_ent * +fuse_uring_find_ring_ent(struct fuse_ring_queue *queue, u32 id) +{ + return xa_load(&queue->ent_xa, id); +} + /* FUSE_URING_CMD_COMMIT_AND_FETCH handler */ static int fuse_uring_commit_fetch(struct io_uring_cmd *cmd, int issue_flags, struct fuse_conn *fc) @@ -517,7 +519,6 @@ static int fuse_uring_commit_fetch(struct io_uring_cmd *cmd, int issue_flags, struct fuse_ring_queue *queue; uint64_t commit_id = READ_ONCE(cmd_req->commit_id); unsigned int qid = READ_ONCE(cmd_req->qid); - struct fuse_pqueue *fpq; struct fuse_req *req; err = -ENOTCONN; @@ -530,28 +531,20 @@ static int fuse_uring_commit_fetch(struct io_uring_cmd *cmd, int issue_flags, queue = ring->queues[qid]; if (!queue) return err; - fpq = &queue->fpq; spin_lock(&queue->lock); - /* Find a request based on the unique ID of the fuse request - * This should get revised, as it needs a hash calculation and list - * search. And full struct fuse_pqueue is needed (memory overhead). - * As well as the link from req to ring_ent. - */ - req = fuse_request_find(fpq, commit_id); + err = -ENOENT; - if (!req) { - pr_info("qid=%d commit_id %llu not found\n", queue->qid, - commit_id); + ent = fuse_uring_find_ring_ent(queue, commit_id); + if (!ent) { spin_unlock(&queue->lock); return err; } - list_del_init(&req->list); - ent = req->ring_entry; - req->ring_entry = NULL; + + req = ent->fuse_req; err = fuse_ring_ent_set_commit(ent); - if (err != 0) { + if (err != 0 && !list_empty(&ent->proc_list)) { pr_info_ratelimited("qid=%d commit_id %llu state %d", queue->qid, commit_id, ent->state); spin_unlock(&queue->lock); @@ -658,11 +651,19 @@ fuse_uring_create_ring_ent(struct io_uring_cmd *cmd, return ERR_PTR(err); INIT_LIST_HEAD(&ent->list); + INIT_LIST_HEAD(&ent->proc_list); ent->queue = queue; ent->headers = iov[0].iov_base; ent->payload = iov[1].iov_base; + // Generate a unique ID and add to XArray + err = xa_alloc(&queue->ent_xa, &ent->id, ent, xa_limit_32b, GFP_KERNEL); + if (err) { + kfree(ent); + return ERR_PTR(err); + } + return ent; } diff --git a/fs/fuse/dev_uring_i.h b/fs/fuse/dev_uring_i.h index 44bf237f0d5a..b77f1a485c8b 100644 --- a/fs/fuse/dev_uring_i.h +++ b/fs/fuse/dev_uring_i.h @@ -44,7 +44,16 @@ struct fuse_ring_ent { enum fuse_ring_req_state state; + /* + * processing queue, as list to comply with remaining fuse code + * that expects the entry on a list and might also remove it + * from the list + */ + struct list_head proc_list; + struct fuse_req *fuse_req; + + u32 id; /* entry ID*/ }; struct fuse_ring_queue { @@ -79,7 +88,8 @@ struct fuse_ring_queue { /* fuse requests waiting for an entry slot */ struct list_head fuse_req_queue; - struct fuse_pqueue fpq; + /* XArray to store and find ring entries */ + struct xarray ent_xa; }; /**