[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>

authored by Roland Dreier and committed by Linus Torvalds e4f50f00 4f60fdf6

+18 -17
+18 -17
drivers/infiniband/core/sa_query.c
··· 587 587 588 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 591 query->sa_query.release = ib_sa_path_rec_release; 592 592 query->sa_query.port = port; 593 593 query->sa_query.mad->mad_hdr.method = IB_MGMT_METHOD_GET; ··· 663 663 664 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 667 query->sa_query.release = ib_sa_mcmember_rec_release; 668 668 query->sa_query.port = port; 669 669 query->sa_query.mad->mad_hdr.method = method; ··· 698 698 if (!query) 699 699 return; 700 700 701 - switch (mad_send_wc->status) { 702 - case IB_WC_SUCCESS: 703 - /* No callback -- already got recv */ 704 - break; 705 - case IB_WC_RESP_TIMEOUT_ERR: 706 - query->callback(query, -ETIMEDOUT, NULL); 707 - break; 708 - case IB_WC_WR_FLUSH_ERR: 709 - query->callback(query, -EINTR, NULL); 710 - break; 711 - default: 712 - query->callback(query, -EIO, NULL); 713 - break; 714 - } 701 + if (query->callback) 702 + switch (mad_send_wc->status) { 703 + case IB_WC_SUCCESS: 704 + /* No callback -- already got recv */ 705 + break; 706 + case IB_WC_RESP_TIMEOUT_ERR: 707 + query->callback(query, -ETIMEDOUT, NULL); 708 + break; 709 + case IB_WC_WR_FLUSH_ERR: 710 + query->callback(query, -EINTR, NULL); 711 + break; 712 + default: 713 + query->callback(query, -EIO, NULL); 714 + break; 715 + } 715 716 716 717 dma_unmap_single(agent->device->dma_device, 717 718 pci_unmap_addr(query, mapping), ··· 737 736 query = idr_find(&query_idr, mad_recv_wc->wc->wr_id); 738 737 spin_unlock_irqrestore(&idr_lock, flags); 739 738 740 - if (query) { 739 + if (query && query->callback) { 741 740 if (mad_recv_wc->wc->status == IB_WC_SUCCESS) 742 741 query->callback(query, 743 742 mad_recv_wc->recv_buf.mad->mad_hdr.status ?