[PATCH] fs/fuse: fix potential memory leak from fuse_uring_cancel

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



fuse: fix potential memory leak from fuse_uring_cancel

If umount or fuse daemon quits at early stage, could happen all ring queues
have already stopped and later some FUSE_IO_URING_CMD_REGISTER commands get
canceled, that leaves ring entities in ent_in_userspace list and will not
be freed by fuse_uring_destruct.
Move such ring entities to ent_canceled list and ensure fuse_uring_destruct
frees these ring entities.

Fixes: b6236c8407cb ("fuse: {io-uring} Prevent mount point hang on fuse-server termination")
Signed-off-by: Jian Huang Li <ali@xxxxxxx>
---
 fs/fuse/dev_uring.c   | 13 +++++++++++--
 fs/fuse/dev_uring_i.h |  6 ++++++
 2 files changed, 17 insertions(+), 2 deletions(-)

diff --git a/fs/fuse/dev_uring.c b/fs/fuse/dev_uring.c
index 249b210becb1..db35797853c1 100644
--- a/fs/fuse/dev_uring.c
+++ b/fs/fuse/dev_uring.c
@@ -203,6 +203,12 @@ void fuse_uring_destruct(struct fuse_conn *fc)
 		WARN_ON(!list_empty(&queue->ent_commit_queue));
 		WARN_ON(!list_empty(&queue->ent_in_userspace));

+		list_for_each_entry_safe(ent, next, &queue->ent_canceled,
+					 list) {
+			list_del_init(&ent->list);
+			kfree(ent);
+		}
+
 		list_for_each_entry_safe(ent, next, &queue->ent_released,
 					 list) {
 			list_del_init(&ent->list);
@@ -291,6 +297,7 @@ 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);
 	INIT_LIST_HEAD(&queue->fuse_req_bg_queue);
+	INIT_LIST_HEAD(&queue->ent_canceled);
 	INIT_LIST_HEAD(&queue->ent_released);

 	queue->fpq.processing = pq;
@@ -391,6 +398,8 @@ static void fuse_uring_teardown_entries(struct fuse_ring_queue *queue)
 {
 	fuse_uring_stop_list_entries(&queue->ent_in_userspace, queue,
 				     FRRS_USERSPACE);
+	fuse_uring_stop_list_entries(&queue->ent_canceled, queue,
+				     FRRS_CANCELED);
 	fuse_uring_stop_list_entries(&queue->ent_avail_queue, queue,
 				     FRRS_AVAILABLE);
 }
@@ -509,8 +518,8 @@ static void fuse_uring_cancel(struct io_uring_cmd *cmd,
 	queue = ent->queue;
 	spin_lock(&queue->lock);
 	if (ent->state == FRRS_AVAILABLE) {
-		ent->state = FRRS_USERSPACE;
-		list_move_tail(&ent->list, &queue->ent_in_userspace);
+		ent->state = FRRS_CANCELED;
+		list_move_tail(&ent->list, &queue->ent_canceled);
 		need_cmd_done = true;
 		ent->cmd = NULL;
 	}
diff --git a/fs/fuse/dev_uring_i.h b/fs/fuse/dev_uring_i.h
index 51a563922ce1..e62bd705e4f5 100644
--- a/fs/fuse/dev_uring_i.h
+++ b/fs/fuse/dev_uring_i.h
@@ -32,6 +32,9 @@ enum fuse_ring_req_state {
 	/* The ring entry is in teardown */
 	FRRS_TEARDOWN,

+	/* The ring entry is canceled */
+	FRRS_CANCELED,
+
 	/* The ring entry is released, but not freed yet */
 	FRRS_RELEASED,
 };
@@ -85,6 +88,9 @@ struct fuse_ring_queue {
 	/* entries in userspace */
 	struct list_head ent_in_userspace;

+	/* entries that are canceled */
+	struct list_head ent_canceled;
+
 	/* entries that are released */
 	struct list_head ent_released;





[Index of Archives]     [Linux Ext4 Filesystem]     [Union Filesystem]     [Filesystem Testing]     [Ceph Users]     [Ecryptfs]     [NTFS 3]     [AutoFS]     [Kernel Newbies]     [Share Photos]     [Security]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux Cachefs]     [Reiser Filesystem]     [Linux RAID]     [NTFS 3]     [Samba]     [Device Mapper]     [CEPH Development]

  Powered by Linux