[ofw] [PATCH] checked ipoib_ndis6_cm shutdown race

Alex Naslednikov xalex at mellanox.co.il
Sun Sep 26 04:12:48 PDT 2010


Hello Stan,
I liked the idea, but I suppose that one should use take here spinlock on p_port->obj to ensure that there's no race right after "if". The code should be like:
} else {
		   cl_obj_lock( &p_port->obj );
               if ( h_cq && p_port->state == IB_QPS_RTS ) {
                      // increment reference to ensure no one release the object while
                      work item is queued ipoib_port_ref( p_port, ref_recv_cb );
                      IoQueueWorkItem( p_port->pPoWorkItem, __iopoib_WorkItem,
                      DelayedWorkQueue, p_port); WorkToDo = FALSE;
              } else {
                       WorkToDo = TRUE;
              }
		  cl_obj_unlock( &p_port->obj );
       }
In addition, I found another potentially unsafe place:
Index: B:/users/xalex/MLNX_WinOF-2_1_2/ulp/ipoib_NDIS6_CM/kernel/ipoib_port.cpp
===================================================================
--- B:/users/xalex/MLNX_WinOF/ulp/ipoib_NDIS6_CM/kernel/ipoib_port.cpp	(revision 6513)
+++ B:/users/xalex/MLNX_WinOF/ulp/ipoib_NDIS6_CM/kernel/ipoib_port.cpp	(working copy)
@@ -7002,8 +7002,10 @@
 			ipoib_set_inactive( p_port->p_adapter );
 			__endpt_mgr_reset_all( p_port );
 		}
+		cl_obj_unlock( &p_port->obj );
 		ASSERT(p_port->state == IB_QPS_INIT || p_port->state == IB_QPS_ERROR);
 		p_port->state = IB_QPS_ERROR;
+		cl_obj_unlock( &p_port->obj );
 		KeSetEvent( &p_port->sa_event, EVENT_INCREMENT, FALSE );
 	}

-----Original Message-----
From: Smith, Stan [mailto:stan.smith at intel.com] 
Sent: Wednesday, September 22, 2010 6:22 PM
To: Alex Naslednikov
Cc: ofw at lists.openfabrics.org; Uri Habusha
Subject: RE: [PATCH] checked ipoib_ndis6_cm shutdown race

Hello,
  Any thoughts on this patch?

Smith, Stan wrote:
> Hello,
>   During system shutdown I have witnessed a checked ipoib_ndis6_cm IO
> work thread fail:
>
> 1) IO work thread is blocked from running due to scheduling
> priorities beyond the point in time at which port_destroy() wants to
> delete the port object [cl_obj_destroy( &p_port->obj 0)]. The port
> object delete fails (ASSERT obj_ref > 0 fires) due to the outstanding
> port references incurred by remaining posted recv buffers. The 1st
> 128 WorkRequests have been pulled from the CQ by
> __recv_cb_internal(), which then posts an IO work request to process
> the remaining 384 recv work requests. The IO work request does not
> run prior to port_detroy() being called.
>
> 2) The IO thread attempts to run but blows up (BSOD invalid memory
> reference) as port structures required by the IO work thread have
> been free()'ed.
>
> The fix is to recognize the port is not in the IB_QPS_RTS state, do
> not schedule an IO work thread request and continue to pull recv work
> requests from the CQ until empty.
>
> Code snippets:
>       } else {
>               if ( h_cq && p_port->state == IB_QPS_RTS ) {
>                       // increment reference to ensure no one release the object while
>                       work iteam is queued ipoib_port_ref( p_port, ref_recv_cb );
>                       IoQueueWorkItem( p_port->pPoWorkItem, __iopoib_WorkItem,
>                       DelayedWorkQueue, p_port); WorkToDo = FALSE;
>               } else {
>                       WorkToDo = TRUE;
>               }
>       }
>
> __recv_cb(
>       IN              const   ib_cq_handle_t                          h_cq,
>       IN                              void                                            *cq_context )
> {
>       uint32_t        recv_cnt;
>       boolean_t       WorkToDo;
>
>       do
>       {
>               WorkToDo = __recv_cb_internal(h_cq, cq_context, &recv_cnt);
>       } while( WorkToDo );
> }
>
>
> --- A/ulp/ipoib_ndis6_cm/kernel/ipoib_port.cpp        Mon Sep 13 15:58:08
> 2010 +++ B/ulp/ipoib_NDIS6_CM/kernel/ipoib_port.cpp   Mon Sep 20
> 08:47:08 2010 @@ -2222,7 +2222,7 @@
>               CL_ASSERT( status == IB_SUCCESS );
>
>       } else {
> -             if (h_cq) {
> +             if ( h_cq && p_port->state == IB_QPS_RTS ) {
>                       // increment reference to ensure no one release the object while
>                       work iteam is queued ipoib_port_ref( p_port, ref_recv_cb );
>                       IoQueueWorkItem( p_port->pPoWorkItem, __iopoib_WorkItem,
> DelayedWorkQueue, p_port); @@ -2244,9 +2244,13 @@
>       IN              const   ib_cq_handle_t                          h_cq,
>       IN                              void                                            *cq_context )
>  {
> -     uint32_t recv_cnt;
> +     uint32_t        recv_cnt;
> +     boolean_t       WorkToDo;
>
> -     __recv_cb_internal(h_cq, cq_context, &recv_cnt);
> +     do
> +     {
> +             WorkToDo = __recv_cb_internal(h_cq, cq_context, &recv_cnt);
> +     } while( WorkToDo );
>  }




More information about the ofw mailing list