diff options
author | Roland Dreier <rolandd@cisco.com> | 2005-11-07 13:41:29 -0500 |
---|---|---|
committer | Roland Dreier <rolandd@cisco.com> | 2005-11-10 13:22:50 -0500 |
commit | 2f76e82947b977a1008cfd2868351a701c93c69c (patch) | |
tree | e6df3542a0a9dd36a8fa9939cdaeedf90f4884a5 /drivers/infiniband/core/user_mad.c | |
parent | 1732b0ef3b3a02e3df328086fb3018741c5476da (diff) |
[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 <rolandd@cisco.com>
Diffstat (limited to 'drivers/infiniband/core/user_mad.c')
-rw-r--r-- | drivers/infiniband/core/user_mad.c | 29 |
1 files changed, 17 insertions, 12 deletions
diff --git a/drivers/infiniband/core/user_mad.c b/drivers/infiniband/core/user_mad.c index 6aefeed42ab..f5ed36c2a06 100644 --- a/drivers/infiniband/core/user_mad.c +++ b/drivers/infiniband/core/user_mad.c | |||
@@ -505,8 +505,6 @@ found: | |||
505 | goto out; | 505 | goto out; |
506 | } | 506 | } |
507 | 507 | ||
508 | file->agent[agent_id] = agent; | ||
509 | |||
510 | file->mr[agent_id] = ib_get_dma_mr(agent->qp->pd, IB_ACCESS_LOCAL_WRITE); | 508 | file->mr[agent_id] = ib_get_dma_mr(agent->qp->pd, IB_ACCESS_LOCAL_WRITE); |
511 | if (IS_ERR(file->mr[agent_id])) { | 509 | if (IS_ERR(file->mr[agent_id])) { |
512 | ret = -ENOMEM; | 510 | ret = -ENOMEM; |
@@ -519,14 +517,15 @@ found: | |||
519 | goto err_mr; | 517 | goto err_mr; |
520 | } | 518 | } |
521 | 519 | ||
520 | file->agent[agent_id] = agent; | ||
522 | ret = 0; | 521 | ret = 0; |
522 | |||
523 | goto out; | 523 | goto out; |
524 | 524 | ||
525 | err_mr: | 525 | err_mr: |
526 | ib_dereg_mr(file->mr[agent_id]); | 526 | ib_dereg_mr(file->mr[agent_id]); |
527 | 527 | ||
528 | err: | 528 | err: |
529 | file->agent[agent_id] = NULL; | ||
530 | ib_unregister_mad_agent(agent); | 529 | ib_unregister_mad_agent(agent); |
531 | 530 | ||
532 | out: | 531 | out: |
@@ -536,27 +535,33 @@ out: | |||
536 | 535 | ||
537 | static int ib_umad_unreg_agent(struct ib_umad_file *file, unsigned long arg) | 536 | static int ib_umad_unreg_agent(struct ib_umad_file *file, unsigned long arg) |
538 | { | 537 | { |
538 | struct ib_mad_agent *agent = NULL; | ||
539 | struct ib_mr *mr = NULL; | ||
539 | u32 id; | 540 | u32 id; |
540 | int ret = 0; | 541 | int ret = 0; |
541 | 542 | ||
542 | down_write(&file->port->mutex); | 543 | if (get_user(id, (u32 __user *) arg)) |
544 | return -EFAULT; | ||
543 | 545 | ||
544 | if (get_user(id, (u32 __user *) arg)) { | 546 | down_write(&file->port->mutex); |
545 | ret = -EFAULT; | ||
546 | goto out; | ||
547 | } | ||
548 | 547 | ||
549 | if (id < 0 || id >= IB_UMAD_MAX_AGENTS || !file->agent[id]) { | 548 | if (id < 0 || id >= IB_UMAD_MAX_AGENTS || !file->agent[id]) { |
550 | ret = -EINVAL; | 549 | ret = -EINVAL; |
551 | goto out; | 550 | goto out; |
552 | } | 551 | } |
553 | 552 | ||
554 | ib_dereg_mr(file->mr[id]); | 553 | agent = file->agent[id]; |
555 | ib_unregister_mad_agent(file->agent[id]); | 554 | mr = file->mr[id]; |
556 | file->agent[id] = NULL; | 555 | file->agent[id] = NULL; |
557 | 556 | ||
558 | out: | 557 | out: |
559 | up_write(&file->port->mutex); | 558 | up_write(&file->port->mutex); |
559 | |||
560 | if (agent) { | ||
561 | ib_unregister_mad_agent(agent); | ||
562 | ib_dereg_mr(mr); | ||
563 | } | ||
564 | |||
560 | return ret; | 565 | return ret; |
561 | } | 566 | } |
562 | 567 | ||
@@ -623,16 +628,16 @@ static int ib_umad_close(struct inode *inode, struct file *filp) | |||
623 | struct ib_umad_packet *packet, *tmp; | 628 | struct ib_umad_packet *packet, *tmp; |
624 | int i; | 629 | int i; |
625 | 630 | ||
626 | down_write(&file->port->mutex); | ||
627 | for (i = 0; i < IB_UMAD_MAX_AGENTS; ++i) | 631 | for (i = 0; i < IB_UMAD_MAX_AGENTS; ++i) |
628 | if (file->agent[i]) { | 632 | if (file->agent[i]) { |
629 | ib_dereg_mr(file->mr[i]); | ||
630 | ib_unregister_mad_agent(file->agent[i]); | 633 | ib_unregister_mad_agent(file->agent[i]); |
634 | ib_dereg_mr(file->mr[i]); | ||
631 | } | 635 | } |
632 | 636 | ||
633 | list_for_each_entry_safe(packet, tmp, &file->recv_list, list) | 637 | list_for_each_entry_safe(packet, tmp, &file->recv_list, list) |
634 | kfree(packet); | 638 | kfree(packet); |
635 | 639 | ||
640 | down_write(&file->port->mutex); | ||
636 | list_del(&file->port_list); | 641 | list_del(&file->port_list); |
637 | up_write(&file->port->mutex); | 642 | up_write(&file->port->mutex); |
638 | 643 | ||