From: Roland Dreier Date: Mon, 7 Nov 2005 18:41:29 +0000 (-0800) Subject: [IB] umad: avoid potential deadlock when unregistering MAD agents X-Git-Url: https://git.karo-electronics.de/?a=commitdiff_plain;h=2f76e82947b977a1008cfd2868351a701c93c69c;p=linux-beck.git [IB] umad: avoid potential deadlock when unregistering MAD agents ib_unregister_mad_agent() completes all pending MAD sends and waits for the agent's send_handler routine to return. umad's send_handler() calls queue_packet(), which does down_read() on the port mutex to look up the agent ID. This means that the port mutex cannot be held for writing while calling ib_unregister_mad_agent(), or else it will deadlock. This patch fixes all the calls to ib_unregister_mad_agent() in the umad module to avoid this deadlock. Signed-off-by: Roland Dreier --- diff --git a/drivers/infiniband/core/user_mad.c b/drivers/infiniband/core/user_mad.c index 6aefeed42ab3..f5ed36c2a06c 100644 --- a/drivers/infiniband/core/user_mad.c +++ b/drivers/infiniband/core/user_mad.c @@ -505,8 +505,6 @@ found: goto out; } - file->agent[agent_id] = agent; - file->mr[agent_id] = ib_get_dma_mr(agent->qp->pd, IB_ACCESS_LOCAL_WRITE); if (IS_ERR(file->mr[agent_id])) { ret = -ENOMEM; @@ -519,14 +517,15 @@ found: goto err_mr; } + file->agent[agent_id] = agent; ret = 0; + goto out; err_mr: ib_dereg_mr(file->mr[agent_id]); err: - file->agent[agent_id] = NULL; ib_unregister_mad_agent(agent); out: @@ -536,27 +535,33 @@ out: static int ib_umad_unreg_agent(struct ib_umad_file *file, unsigned long arg) { + struct ib_mad_agent *agent = NULL; + struct ib_mr *mr = NULL; u32 id; int ret = 0; - down_write(&file->port->mutex); + if (get_user(id, (u32 __user *) arg)) + return -EFAULT; - if (get_user(id, (u32 __user *) arg)) { - ret = -EFAULT; - goto out; - } + down_write(&file->port->mutex); if (id < 0 || id >= IB_UMAD_MAX_AGENTS || !file->agent[id]) { ret = -EINVAL; goto out; } - ib_dereg_mr(file->mr[id]); - ib_unregister_mad_agent(file->agent[id]); + agent = file->agent[id]; + mr = file->mr[id]; file->agent[id] = NULL; out: up_write(&file->port->mutex); + + if (agent) { + ib_unregister_mad_agent(agent); + ib_dereg_mr(mr); + } + return ret; } @@ -623,16 +628,16 @@ static int ib_umad_close(struct inode *inode, struct file *filp) struct ib_umad_packet *packet, *tmp; int i; - down_write(&file->port->mutex); for (i = 0; i < IB_UMAD_MAX_AGENTS; ++i) if (file->agent[i]) { - ib_dereg_mr(file->mr[i]); ib_unregister_mad_agent(file->agent[i]); + ib_dereg_mr(file->mr[i]); } list_for_each_entry_safe(packet, tmp, &file->recv_list, list) kfree(packet); + down_write(&file->port->mutex); list_del(&file->port_list); up_write(&file->port->mutex);