From: Shay Drory <sh...@nvidia.com>

[ Upstream commit def4cd43f522253645b72c97181399c241b54536 ]

Currently, polling a umad device will always works, even if the device was
disassociated. A disassociated device should immediately return EPOLLERR
from poll(). Otherwise userspace is endlessly hung on poll() with no idea
that the device has been removed from the system.

Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
Link: https://lore.kernel.org/r/20210125121339.837518-3-l...@kernel.org
Signed-off-by: Shay Drory <sh...@nvidia.com>
Signed-off-by: Leon Romanovsky <leo...@nvidia.com>
Signed-off-by: Jason Gunthorpe <j...@nvidia.com>
Signed-off-by: Sasha Levin <sas...@kernel.org>
---
 drivers/infiniband/core/user_mad.c | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/drivers/infiniband/core/user_mad.c 
b/drivers/infiniband/core/user_mad.c
index 7ec1918431f70..dd7f3b437c6be 100644
--- a/drivers/infiniband/core/user_mad.c
+++ b/drivers/infiniband/core/user_mad.c
@@ -397,6 +397,11 @@ static ssize_t ib_umad_read(struct file *filp, char __user 
*buf,
                mutex_lock(&file->mutex);
        }
 
+       if (file->agents_dead) {
+               mutex_unlock(&file->mutex);
+               return -EIO;
+       }
+
        packet = list_entry(file->recv_list.next, struct ib_umad_packet, list);
        list_del(&packet->list);
 
@@ -658,10 +663,14 @@ static __poll_t ib_umad_poll(struct file *filp, struct 
poll_table_struct *wait)
        /* we will always be able to post a MAD send */
        __poll_t mask = EPOLLOUT | EPOLLWRNORM;
 
+       mutex_lock(&file->mutex);
        poll_wait(filp, &file->recv_wait, wait);
 
        if (!list_empty(&file->recv_list))
                mask |= EPOLLIN | EPOLLRDNORM;
+       if (file->agents_dead)
+               mask = EPOLLERR;
+       mutex_unlock(&file->mutex);
 
        return mask;
 }
@@ -1341,6 +1350,7 @@ static void ib_umad_kill_port(struct ib_umad_port *port)
        list_for_each_entry(file, &port->file_list, port_list) {
                mutex_lock(&file->mutex);
                file->agents_dead = 1;
+               wake_up_interruptible(&file->recv_wait);
                mutex_unlock(&file->mutex);
 
                for (id = 0; id < IB_UMAD_MAX_AGENTS; ++id)
-- 
2.27.0



Reply via email to