From ccd366f0d011e24a441f52fc8573a731e1301ba6 Mon Sep 17 00:00:00 2001 From: yangerkun Date: Mon, 8 Jan 2024 11:21:43 +0800 Subject: [PATCH] pipe: Fix endless sleep problem due to the out-of-order hulk inclusion category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/I8U3TT --------------------------- Thers is a out-of-order access problem which would cause endless sleep when we use pipe with epoll. The story is following, we assume the ring size is 2, the ring head is 1, the ring tail is 0, task0 is write task, task1 is read task, task2 is write task. Task0 Task1 Task2 epoll_ctl(fd, EPOLL_CTL_ADD, ...) pipe_poll() poll_wait() tail = READ_ONCE(pipe->tail); // Re-order and get tail=0 pipe_read tail++ //tail=1 pipe_write head++ //head=2 head = READ_ONCE(pipe->head); // head = 2 check ring is full by head - tail Task0 get head = 2 and tail = 0, so it mistake that the pipe ring is full, then task0 is not add into ready list. If the ring is not full anymore, task0 would not be woken up forever. The reason of this problem is that we got inconsistent head/tail value of the pipe ring, so we fix the problem by getting them protected. Signed-off-by: yangerkun Signed-off-by: Baokun Li --- fs/pipe.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/fs/pipe.c b/fs/pipe.c index 139190165a1c2..34752ba942ab5 100644 --- a/fs/pipe.c +++ b/fs/pipe.c @@ -672,8 +672,10 @@ pipe_poll(struct file *filp, poll_table *wait) * if something changes and you got it wrong, the poll * table entry will wake you up and fix it. */ + spin_lock_irq(&pipe->rd_wait.lock); head = READ_ONCE(pipe->head); tail = READ_ONCE(pipe->tail); + spin_unlock_irq(&pipe->rd_wait.lock); mask = 0; if (filp->f_mode & FMODE_READ) { -- Gitee