diff options
author | Roland Dreier <roland@topspin.com> | 2005-05-25 15:31:29 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-05-25 18:31:28 -0400 |
commit | e4f50f003dc568f6fc3904d451c562007bd09640 (patch) | |
tree | 6af02e623ba96d367c1c3948b9bb85bc793cc47f /drivers/infiniband | |
parent | 4f60fdf613536402e3313c5019b3ae6060b2ae4a (diff) |
[PATCH] IB: allow NULL sa_query callbacks
Check if a client passes a NULL callback into an SA query, and if so, never
call back. This fixes an oops if someone unloads ib_ipoib and ib_sa in
rapid succession. ib_ipoib does an MCMember delete with a NULL callback
and 0 timeout on unload, which is usually fine since the delete completes
successfully. However, if ib_sa is unloaded immediately afterwards, the
delete will be canceled and ib_sa will try to call the (now already
unloaded) ib_ipoib module back with the cancel completion, which triggers
the oops.
Signed-off-by: Roland Dreier <roland@topspin.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'drivers/infiniband')
-rw-r--r-- | drivers/infiniband/core/sa_query.c | 35 |
1 files changed, 18 insertions, 17 deletions
diff --git a/drivers/infiniband/core/sa_query.c b/drivers/infiniband/core/sa_query.c index d4233ee61c35..276e1a53010d 100644 --- a/drivers/infiniband/core/sa_query.c +++ b/drivers/infiniband/core/sa_query.c | |||
@@ -587,7 +587,7 @@ int ib_sa_path_rec_get(struct ib_device *device, u8 port_num, | |||
587 | 587 | ||
588 | init_mad(query->sa_query.mad, agent); | 588 | init_mad(query->sa_query.mad, agent); |
589 | 589 | ||
590 | query->sa_query.callback = ib_sa_path_rec_callback; | 590 | query->sa_query.callback = callback ? ib_sa_path_rec_callback : NULL; |
591 | query->sa_query.release = ib_sa_path_rec_release; | 591 | query->sa_query.release = ib_sa_path_rec_release; |
592 | query->sa_query.port = port; | 592 | query->sa_query.port = port; |
593 | query->sa_query.mad->mad_hdr.method = IB_MGMT_METHOD_GET; | 593 | query->sa_query.mad->mad_hdr.method = IB_MGMT_METHOD_GET; |
@@ -663,7 +663,7 @@ int ib_sa_mcmember_rec_query(struct ib_device *device, u8 port_num, | |||
663 | 663 | ||
664 | init_mad(query->sa_query.mad, agent); | 664 | init_mad(query->sa_query.mad, agent); |
665 | 665 | ||
666 | query->sa_query.callback = ib_sa_mcmember_rec_callback; | 666 | query->sa_query.callback = callback ? ib_sa_mcmember_rec_callback : NULL; |
667 | query->sa_query.release = ib_sa_mcmember_rec_release; | 667 | query->sa_query.release = ib_sa_mcmember_rec_release; |
668 | query->sa_query.port = port; | 668 | query->sa_query.port = port; |
669 | query->sa_query.mad->mad_hdr.method = method; | 669 | query->sa_query.mad->mad_hdr.method = method; |
@@ -698,20 +698,21 @@ static void send_handler(struct ib_mad_agent *agent, | |||
698 | if (!query) | 698 | if (!query) |
699 | return; | 699 | return; |
700 | 700 | ||
701 | switch (mad_send_wc->status) { | 701 | if (query->callback) |
702 | case IB_WC_SUCCESS: | 702 | switch (mad_send_wc->status) { |
703 | /* No callback -- already got recv */ | 703 | case IB_WC_SUCCESS: |
704 | break; | 704 | /* No callback -- already got recv */ |
705 | case IB_WC_RESP_TIMEOUT_ERR: | 705 | break; |
706 | query->callback(query, -ETIMEDOUT, NULL); | 706 | case IB_WC_RESP_TIMEOUT_ERR: |
707 | break; | 707 | query->callback(query, -ETIMEDOUT, NULL); |
708 | case IB_WC_WR_FLUSH_ERR: | 708 | break; |
709 | query->callback(query, -EINTR, NULL); | 709 | case IB_WC_WR_FLUSH_ERR: |
710 | break; | 710 | query->callback(query, -EINTR, NULL); |
711 | default: | 711 | break; |
712 | query->callback(query, -EIO, NULL); | 712 | default: |
713 | break; | 713 | query->callback(query, -EIO, NULL); |
714 | } | 714 | break; |
715 | } | ||
715 | 716 | ||
716 | dma_unmap_single(agent->device->dma_device, | 717 | dma_unmap_single(agent->device->dma_device, |
717 | pci_unmap_addr(query, mapping), | 718 | pci_unmap_addr(query, mapping), |
@@ -736,7 +737,7 @@ static void recv_handler(struct ib_mad_agent *mad_agent, | |||
736 | query = idr_find(&query_idr, mad_recv_wc->wc->wr_id); | 737 | query = idr_find(&query_idr, mad_recv_wc->wc->wr_id); |
737 | spin_unlock_irqrestore(&idr_lock, flags); | 738 | spin_unlock_irqrestore(&idr_lock, flags); |
738 | 739 | ||
739 | if (query) { | 740 | if (query && query->callback) { |
740 | if (mad_recv_wc->wc->status == IB_WC_SUCCESS) | 741 | if (mad_recv_wc->wc->status == IB_WC_SUCCESS) |
741 | query->callback(query, | 742 | query->callback(query, |
742 | mad_recv_wc->recv_buf.mad->mad_hdr.status ? | 743 | mad_recv_wc->recv_buf.mad->mad_hdr.status ? |