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:
+10
-1
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user