win-pvdrivers

changeset 850:182a8e70c562

Fix xennet resume race
author James Harper <james.harper@bendigoit.com.au>
date Mon Feb 14 22:43:42 2011 +1100 (2011-02-14)
parents f5ecdc025c76
children f1deffa0ea6b
files xennet/xennet.c xennet/xennet.h
line diff
     1.1 --- a/xennet/xennet.c	Fri Feb 11 11:14:25 2011 +1100
     1.2 +++ b/xennet/xennet.c	Mon Feb 14 22:43:42 2011 +1100
     1.3 @@ -24,7 +24,7 @@ Foundation, Inc., 51 Franklin Street, Fi
     1.4  
     1.5  /* Not really necessary but keeps PREfast happy */
     1.6  DRIVER_INITIALIZE DriverEntry;
     1.7 -static IO_WORKITEM_ROUTINE XenNet_Resume;
     1.8 +static IO_WORKITEM_ROUTINE XenNet_ResumeWorkItem;
     1.9  #if (NTDDI_VERSION >= NTDDI_WINXP)
    1.10  static KDEFERRED_ROUTINE XenNet_SuspendResume;
    1.11  #endif
    1.12 @@ -235,28 +235,33 @@ XenNet_ConnectBackend(struct xennet_info
    1.13    return NDIS_STATUS_SUCCESS;
    1.14  }
    1.15  
    1.16 -static DDKAPI VOID
    1.17 -XenNet_Resume(PDEVICE_OBJECT device_object, PVOID context)
    1.18 +static VOID
    1.19 +XenNet_ResumeWorkItem(PDEVICE_OBJECT device_object, PVOID context)
    1.20  {
    1.21    struct xennet_info *xi = context;
    1.22 +  KIRQL old_irql;
    1.23    
    1.24    UNREFERENCED_PARAMETER(device_object);
    1.25    
    1.26    FUNCTION_ENTER();
    1.27 -  
    1.28 -  ASSERT(xi->resume_work_item);
    1.29 +
    1.30 +  ASSERT(!xi->resume_work_item);
    1.31 +
    1.32    IoFreeWorkItem(xi->resume_work_item);
    1.33 -  xi->resume_work_item = NULL;
    1.34    
    1.35    XenNet_TxResumeStart(xi);
    1.36    XenNet_RxResumeStart(xi);
    1.37    XenNet_ConnectBackend(xi);
    1.38    XenNet_RxResumeEnd(xi);
    1.39    XenNet_TxResumeEnd(xi);
    1.40 +
    1.41 +  KeAcquireSpinLock(&xi->resume_lock, &old_irql);
    1.42 +  xi->resume_work_item = NULL;
    1.43    KdPrint((__DRIVER_NAME "     *Setting suspend_resume_state_fdo = %d\n", xi->device_state->suspend_resume_state_pdo));
    1.44    xi->device_state->suspend_resume_state_fdo = xi->device_state->suspend_resume_state_pdo;
    1.45    KdPrint((__DRIVER_NAME "     *Notifying event channel %d\n", xi->device_state->pdo_event_channel));
    1.46    xi->vectors.EvtChn_Notify(xi->vectors.context, xi->device_state->pdo_event_channel);
    1.47 +  KeReleaseSpinLock(&xi->resume_lock, old_irql);
    1.48  
    1.49    FUNCTION_EXIT();
    1.50  
    1.51 @@ -267,6 +272,7 @@ XenNet_SuspendResume(PKDPC dpc, PVOID co
    1.52  {
    1.53    struct xennet_info *xi = context;
    1.54    KIRQL old_irql;
    1.55 +  PIO_WORKITEM resume_work_item;
    1.56  
    1.57    UNREFERENCED_PARAMETER(dpc);
    1.58    UNREFERENCED_PARAMETER(arg1);
    1.59 @@ -279,7 +285,7 @@ XenNet_SuspendResume(PKDPC dpc, PVOID co
    1.60    case SR_STATE_SUSPENDING:
    1.61      KdPrint((__DRIVER_NAME "     New state SUSPENDING\n"));
    1.62      KeAcquireSpinLock(&xi->rx_lock, &old_irql);
    1.63 -    if (xi->rx_id_free == NET_TX_RING_SIZE)
    1.64 +    if (xi->rx_id_free == NET_RX_RING_SIZE)
    1.65      {  
    1.66        xi->device_state->suspend_resume_state_fdo = SR_STATE_SUSPENDING;
    1.67        KdPrint((__DRIVER_NAME "     Notifying event channel %d\n", xi->device_state->pdo_event_channel));
    1.68 @@ -289,9 +295,18 @@ XenNet_SuspendResume(PKDPC dpc, PVOID co
    1.69      break;
    1.70    case SR_STATE_RESUMING:
    1.71      KdPrint((__DRIVER_NAME "     New state SR_STATE_RESUMING\n"));
    1.72 -    ASSERT(!xi->resume_work_item);
    1.73 -    xi->resume_work_item = IoAllocateWorkItem(xi->fdo);
    1.74 -    IoQueueWorkItem(xi->resume_work_item, XenNet_Resume, DelayedWorkQueue, xi);
    1.75 +    /* do it like this so we don't race and double-free the work item */
    1.76 +    resume_work_item = IoAllocateWorkItem(xi->fdo);
    1.77 +    KeAcquireSpinLock(&xi->resume_lock, &old_irql);
    1.78 +    if (xi->resume_work_item || xi->device_state->suspend_resume_state_fdo == SR_STATE_RESUMING)
    1.79 +    {
    1.80 +      KeReleaseSpinLock(&xi->resume_lock, old_irql);
    1.81 +      IoFreeWorkItem(resume_work_item);
    1.82 +      return;
    1.83 +    }
    1.84 +    xi->resume_work_item = resume_work_item;
    1.85 +    KeReleaseSpinLock(&xi->resume_lock, old_irql);
    1.86 +    IoQueueWorkItem(xi->resume_work_item, XenNet_ResumeWorkItem, DelayedWorkQueue, xi);
    1.87      break;
    1.88    default:
    1.89      KdPrint((__DRIVER_NAME "     New state %d\n", xi->device_state->suspend_resume_state_fdo));
    1.90 @@ -600,6 +615,7 @@ XenNet_Init(
    1.91    }
    1.92  
    1.93    KeInitializeDpc(&xi->suspend_dpc, XenNet_SuspendResume, xi);
    1.94 +  KeInitializeSpinLock(&xi->resume_lock);
    1.95  
    1.96    NdisMGetDeviceProperty(MiniportAdapterHandle, &xi->pdo, &xi->fdo,
    1.97      &xi->lower_do, NULL, NULL);
     2.1 --- a/xennet/xennet.h	Fri Feb 11 11:14:25 2011 +1100
     2.2 +++ b/xennet/xennet.h	Mon Feb 14 22:43:42 2011 +1100
     2.3 @@ -268,6 +268,7 @@ struct xennet_info
     2.4    ULONG multicast_list_size;
     2.5    KDPC suspend_dpc;
     2.6    PIO_WORKITEM resume_work_item;
     2.7 +  KSPIN_LOCK resume_lock;
     2.8  
     2.9    /* tx related - protected by tx_lock */
    2.10    KSPIN_LOCK tx_lock;