Skip to content

Commit 2ed147f

Browse files
dhowellstorvalds
authored andcommitted
watch_queue: Fix lack of barrier/sync/lock between post and read
There's nothing to synchronise post_one_notification() versus pipe_read(). Whilst posting is done under pipe->rd_wait.lock, the reader only takes pipe->mutex which cannot bar notification posting as that may need to be made from contexts that cannot sleep. Fix this by setting pipe->head with a barrier in post_one_notification() and reading pipe->head with a barrier in pipe_read(). If that's not sufficient, the rd_wait.lock will need to be taken, possibly in a ->confirm() op so that it only applies to notifications. The lock would, however, have to be dropped before copy_page_to_iter() is invoked. Fixes: c73be61 ("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>
1 parent 7ea1a01 commit 2ed147f

2 files changed

Lines changed: 3 additions & 2 deletions

File tree

fs/pipe.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -253,7 +253,8 @@ pipe_read(struct kiocb *iocb, struct iov_iter *to)
253253
*/
254254
was_full = pipe_full(pipe->head, pipe->tail, pipe->max_usage);
255255
for (;;) {
256-
unsigned int head = pipe->head;
256+
/* Read ->head with a barrier vs post_one_notification() */
257+
unsigned int head = smp_load_acquire(&pipe->head);
257258
unsigned int tail = pipe->tail;
258259
unsigned int mask = pipe->ring_size - 1;
259260

kernel/watch_queue.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ static bool post_one_notification(struct watch_queue *wqueue,
113113
buf->offset = offset;
114114
buf->len = len;
115115
buf->flags = PIPE_BUF_FLAG_WHOLE;
116-
pipe->head = head + 1;
116+
smp_store_release(&pipe->head, head + 1); /* vs pipe_read() */
117117

118118
if (!test_and_clear_bit(note, wqueue->notes_bitmap)) {
119119
spin_unlock_irq(&pipe->rd_wait.lock);

0 commit comments

Comments
 (0)