From 6edbaf71ba8a004577e347d5de1f7094d2f95ab4 Mon Sep 17 00:00:00 2001 From: Kartik Date: Fri, 7 Jul 2023 06:23:34 +0000 Subject: [PATCH] NVIDIA: SAUCE: fs: eventpoll: Add smp_mb() before waitqueue_active BugLink: https://bugs.launchpad.net/bugs/2072591 Following crash is seen in eventpoll library with real-time kernel: [ 7175.116415] Call trace: [ 7175.116591] __wake_up_common+0xe4/0x150 [ 7175.116881] __wake_up_common_lock+0x7c/0xc0 [ 7175.117198] __wake_up+0x44/0x60 [ 7175.117435] ep_poll_callback+0xa4/0x260 [ 7175.117742] __wake_up_common+0x90/0x150 [ 7175.118034] __wake_up_common_lock+0x7c/0xc0 [ 7175.118356] __wake_up_sync_key+0x44/0x60 Eventpoll callback is unable to identify empty waitqueues when the system is stressed which later results in crash. Add smp_mb() before waitqueue_active() as waitqueue_active() should be preceeded with a smp_mb() when used for wakeups otherwise it should be called with wait_queue_head::lock() held. http://nvbugs/4055544 Signed-off-by: Kartik Tested-by: Tonny Liang Signed-off-by: Laxman Dewangan Acked-by: Jacob Martin Acked-by: Noah Wager Signed-off-by: Noah Wager --- fs/eventpoll.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/fs/eventpoll.c b/fs/eventpoll.c index 1a7e322f4f87..9eea3f0272f4 100644 --- a/fs/eventpoll.c +++ b/fs/eventpoll.c @@ -671,6 +671,7 @@ static void ep_done_scan(struct eventpoll *ep, __pm_relax(ep->ws); if (!list_empty(&ep->rdllist)) { + smp_mb(); if (waitqueue_active(&ep->wq)) wake_up(&ep->wq); } @@ -1250,6 +1251,7 @@ static int ep_poll_callback(wait_queue_entry_t *wait, unsigned mode, int sync, v * Wake up ( if active ) both the eventpoll wait list and the ->poll() * wait list. */ + smp_mb(); if (waitqueue_active(&ep->wq)) { if ((epi->event.events & EPOLLEXCLUSIVE) && !(pollflags & POLLFREE)) { @@ -1622,6 +1624,7 @@ static int ep_insert(struct eventpoll *ep, const struct epoll_event *event, ep_pm_stay_awake(epi); /* Notify waiting tasks that events are available */ + smp_mb(); if (waitqueue_active(&ep->wq)) wake_up(&ep->wq); if (waitqueue_active(&ep->poll_wait)) @@ -1698,6 +1701,7 @@ static int ep_modify(struct eventpoll *ep, struct epitem *epi, ep_pm_stay_awake(epi); /* Notify waiting tasks that events are available */ + smp_mb(); if (waitqueue_active(&ep->wq)) wake_up(&ep->wq); if (waitqueue_active(&ep->poll_wait)) @@ -1952,8 +1956,11 @@ static int ep_poll(struct eventpoll *ep, struct epoll_event __user *events, * important. */ eavail = ep_events_available(ep); - if (!eavail) + if (!eavail) { + spin_lock(&ep->wq.lock); __add_wait_queue_exclusive(&ep->wq, &wait); + spin_unlock(&ep->wq.lock); + } write_unlock_irq(&ep->lock); @@ -1980,7 +1987,9 @@ static int ep_poll(struct eventpoll *ep, struct epoll_event __user *events, */ if (timed_out) eavail = list_empty(&wait.entry); + spin_lock(&ep->wq.lock); __remove_wait_queue(&ep->wq, &wait); + spin_unlock(&ep->wq.lock); write_unlock_irq(&ep->lock); } }