From: Michael S. Tsirkin Date: Thu, 30 Mar 2006 13:52:54 +0000 (+0200) Subject: IB/mad: fix oops in cancel_mads X-Git-Tag: v2.6.17-rc2~79^2~12 X-Git-Url: https://err.no/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=37289efe3ee0c0a00b5d8302df9a2b007e65c187;p=linux-2.6 IB/mad: fix oops in cancel_mads We have seen the following OOPs in cancel_mads, when restarting opensm multiple times: Call Trace: [] show_stack+0x9b/0xb0 [] show_registers+0x11c/0x190 [] die+0xed/0x160 [] do_page_fault+0x3f6/0x5d0 [] error_code+0x4f/0x60 [] cancel_mads+0x128/0x150 [ib_mad] [] unregister_mad_agent+0x11/0x130 [ib_mad] [] ib_unregister_mad_agent+0x12/0x20 [ib_mad] [] ib_umad_close+0xf3/0x130 [ib_umad] [] __fput+0x187/0x1c0 [] fput+0x19/0x20 [] filp_close+0x3a/0x60 [] put_files_struct+0x68/0xa0 [] do_signal+0x47/0x100 [] do_notify_resume+0x3d/0x40 [] work_notifysig+0x13/0x25 We traced this back to local_completions unlocking mad_agent_priv->lock while still keeping a pointer into local_list. A later call to list_del(&local->completion_list) would then corrupt the list. To fix this, remove the entry from local_list after looking it up but before releasing mad_agent_priv->lock, to prevent cancel_mads from finding and freeing it. Signed-off-by: Jack Morgenstein Signed-off-by: Michael S. Tsirkin Signed-off-by: Roland Dreier --- diff --git a/drivers/infiniband/core/mad.c b/drivers/infiniband/core/mad.c index ba54c856b0..3a702da83e 100644 --- a/drivers/infiniband/core/mad.c +++ b/drivers/infiniband/core/mad.c @@ -2311,6 +2311,7 @@ static void local_completions(void *data) local = list_entry(mad_agent_priv->local_list.next, struct ib_mad_local_private, completion_list); + list_del(&local->completion_list); spin_unlock_irqrestore(&mad_agent_priv->lock, flags); if (local->mad_priv) { recv_mad_agent = local->recv_mad_agent; @@ -2362,7 +2363,6 @@ local_send_completion: &mad_send_wc); spin_lock_irqsave(&mad_agent_priv->lock, flags); - list_del(&local->completion_list); atomic_dec(&mad_agent_priv->refcount); if (!recv) kmem_cache_free(ib_mad_cache, local->mad_priv);