summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Howells <dhowells@redhat.com>2022-03-11 13:23:38 +0000
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2022-03-16 14:26:50 +0100
commiteef9afda9a16328beb562e09ba2d19f8ec0713eb (patch)
treea1f02b660d15ed8a553254637ab4b0615bc79802
parentb36588ebbcef74583824c08352e75838d6fb4ff2 (diff)
downloadlinux-stable-eef9afda9a16328beb562e09ba2d19f8ec0713eb.tar.gz
linux-stable-eef9afda9a16328beb562e09ba2d19f8ec0713eb.tar.bz2
linux-stable-eef9afda9a16328beb562e09ba2d19f8ec0713eb.zip
watch_queue, pipe: Free watchqueue state after clearing pipe ring
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>
-rw-r--r--fs/pipe.c8
1 files changed, 5 insertions, 3 deletions
diff --git a/fs/pipe.c b/fs/pipe.c
index 6d4342bad9f1..8b0f6979fb49 100644
--- a/fs/pipe.c
+++ b/fs/pipe.c
@@ -830,10 +830,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);
@@ -843,6 +841,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);