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 <kkartik@nvidia.com>
Tested-by: Tonny Liang <tonnyl@nvidia.com>
Signed-off-by: Laxman Dewangan <ldewangan@nvidia.com>
Acked-by: Jacob Martin <jacob.martin@canonical.com>
Acked-by: Noah Wager <noah.wager@canonical.com>
Signed-off-by: Noah Wager <noah.wager@canonical.com>
This commit is contained in:
Kartik
2023-07-07 06:23:34 +00:00
committed by Noah Wager
parent 4d4e68d3fa
commit 6edbaf71ba
+10 -1
View File
@@ -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);
}
}