From: David Howells dhowells@redhat.com
stable inclusion from stable-v5.10.106 commit d729d4e99fb85f734805ff37dd79f38e7db21c0f bugzilla: https://gitee.com/openeuler/kernel/issues/I573US
Reference: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id=...
--------------------------------
commit db8facfc9fafacefe8a835416a6b77c838088f8b upstream.
In free_pipe_info(), free the watchqueue state after clearing the pipe ring as each pipe ring descriptor has a release function, and in the case of a notification message, this is watch_queue_pipe_buf_release() which tries to mark the allocation bitmap that was previously released.
Fix this by moving the put of the pipe's ref on the watch queue to after the ring has been cleared. We still need to call watch_queue_clear() before doing that to make sure that the pipe is disconnected from any notification sources first.
Fixes: c73be61cede5 ("pipe: Add general notification queue support") Reported-by: Jann Horn jannh@google.com Signed-off-by: David Howells dhowells@redhat.com Signed-off-by: Linus Torvalds torvalds@linux-foundation.org Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org Signed-off-by: Yu Liao liaoyu15@huawei.com Reviewed-by: Wei Li liwei391@huawei.com Signed-off-by: Zheng Zengkai zhengzengkai@huawei.com --- fs/pipe.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-)
diff --git a/fs/pipe.c b/fs/pipe.c index f5ae4feb512e..a9ee94d990c6 100644 --- a/fs/pipe.c +++ b/fs/pipe.c @@ -832,10 +832,8 @@ void free_pipe_info(struct pipe_inode_info *pipe) int i;
#ifdef CONFIG_WATCH_QUEUE - if (pipe->watch_queue) { + if (pipe->watch_queue) watch_queue_clear(pipe->watch_queue); - put_watch_queue(pipe->watch_queue); - } #endif
(void) account_pipe_buffers(pipe->user, pipe->nr_accounted, 0); @@ -845,6 +843,10 @@ void free_pipe_info(struct pipe_inode_info *pipe) if (buf->ops) pipe_buf_release(pipe, buf); } +#ifdef CONFIG_WATCH_QUEUE + if (pipe->watch_queue) + put_watch_queue(pipe->watch_queue); +#endif if (pipe->tmp_page) __free_page(pipe->tmp_page); kfree(pipe->bufs);