win-pvdrivers

changeset 788:3058ea7a6f59

Make evtchn race-proof
author James Harper <james.harper@bendigoit.com.au>
date Sat Feb 20 16:34:22 2010 +1100 (2010-02-20)
parents e723cc352a15
children 65a687a0933e
files xenpci/evtchn.c xenpci/xenpci.h
line diff
     1.1 --- a/xenpci/evtchn.c	Sat Feb 20 16:31:45 2010 +1100
     1.2 +++ b/xenpci/evtchn.c	Sat Feb 20 16:34:22 2010 +1100
     1.3 @@ -224,14 +224,14 @@ NTSTATUS
     1.4  EvtChn_Bind(PVOID Context, evtchn_port_t Port, PXEN_EVTCHN_SERVICE_ROUTINE ServiceRoutine, PVOID ServiceContext)
     1.5  {
     1.6    PXENPCI_DEVICE_DATA xpdd = Context;
     1.7 +  ev_action_t *action = &xpdd->ev_actions[Port];
     1.8  
     1.9    FUNCTION_ENTER();
    1.10    
    1.11 -  if (xpdd->ev_actions[Port].type != EVT_ACTION_TYPE_EMPTY)
    1.12 +  if (InterlockedCompareExchange((volatile LONG *)&action->type, EVT_ACTION_TYPE_NEW, EVT_ACTION_TYPE_EMPTY) != EVT_ACTION_TYPE_EMPTY)
    1.13    {
    1.14 -    xpdd->ev_actions[Port].type = EVT_ACTION_TYPE_EMPTY;
    1.15 -    KeMemoryBarrier(); // make sure we don't call the old Service Routine with the new data...
    1.16 -    KdPrint((__DRIVER_NAME " Handler for port %d already registered, replacing\n", Port));
    1.17 +    KdPrint((__DRIVER_NAME " Handler for port %d already registered\n", Port));
    1.18 +    return STATUS_UNSUCCESSFUL;
    1.19    }
    1.20  
    1.21    xpdd->ev_actions[Port].ServiceRoutine = ServiceRoutine;
    1.22 @@ -251,22 +251,21 @@ NTSTATUS
    1.23  EvtChn_BindDpc(PVOID Context, evtchn_port_t Port, PXEN_EVTCHN_SERVICE_ROUTINE ServiceRoutine, PVOID ServiceContext)
    1.24  {
    1.25    PXENPCI_DEVICE_DATA xpdd = Context;
    1.26 +  ev_action_t *action = &xpdd->ev_actions[Port];
    1.27  
    1.28    FUNCTION_ENTER();
    1.29 -
    1.30 -  if (xpdd->ev_actions[Port].type != EVT_ACTION_TYPE_EMPTY)
    1.31 +  
    1.32 +  if (InterlockedCompareExchange((volatile LONG *)&action->type, EVT_ACTION_TYPE_NEW, EVT_ACTION_TYPE_EMPTY) != EVT_ACTION_TYPE_EMPTY)
    1.33    {
    1.34 -    xpdd->ev_actions[Port].type = EVT_ACTION_TYPE_EMPTY;
    1.35 -    KeMemoryBarrier(); // make sure we don't call the old Service Routine with the new data...
    1.36 -    KdPrint((__DRIVER_NAME " Handler for port %d already registered, replacing\n", Port));
    1.37 +    KdPrint((__DRIVER_NAME " Handler for port %d already registered\n", Port));
    1.38 +    return STATUS_UNSUCCESSFUL;
    1.39    }
    1.40  
    1.41    xpdd->ev_actions[Port].ServiceRoutine = ServiceRoutine;
    1.42    xpdd->ev_actions[Port].ServiceContext = ServiceContext;
    1.43    xpdd->ev_actions[Port].xpdd = xpdd;
    1.44 -  KeInitializeDpc(&xpdd->ev_actions[Port].Dpc, EvtChn_DpcBounce, &xpdd->ev_actions[Port]);
    1.45    KeMemoryBarrier(); // make sure that the new service routine is only called once the context is set up
    1.46 -  xpdd->ev_actions[Port].type = EVT_ACTION_TYPE_DPC;
    1.47 +  InterlockedExchange((volatile LONG *)&action->type, EVT_ACTION_TYPE_DPC);
    1.48  
    1.49    EvtChn_Unmask(Context, Port);
    1.50  
    1.51 @@ -279,14 +278,14 @@ NTSTATUS
    1.52  EvtChn_BindIrq(PVOID Context, evtchn_port_t Port, ULONG vector, PCHAR description)
    1.53  {
    1.54    PXENPCI_DEVICE_DATA xpdd = Context;
    1.55 +  ev_action_t *action = &xpdd->ev_actions[Port];
    1.56  
    1.57    FUNCTION_ENTER();
    1.58 -
    1.59 -  if (xpdd->ev_actions[Port].type != EVT_ACTION_TYPE_EMPTY)
    1.60 +  
    1.61 +  if (InterlockedCompareExchange((volatile LONG *)&action->type, EVT_ACTION_TYPE_NEW, EVT_ACTION_TYPE_EMPTY) != EVT_ACTION_TYPE_EMPTY)
    1.62    {
    1.63 -    xpdd->ev_actions[Port].type = EVT_ACTION_TYPE_EMPTY;
    1.64 -    KeMemoryBarrier(); // make sure we don't call the old Service Routine with the new data...
    1.65 -    KdPrint((__DRIVER_NAME " Handler for port %d already registered, replacing\n", Port));
    1.66 +    KdPrint((__DRIVER_NAME " Handler for port %d already registered\n", Port));
    1.67 +    return STATUS_UNSUCCESSFUL;
    1.68    }
    1.69  
    1.70    xpdd->ev_actions[Port].vector = vector;
    1.71 @@ -306,21 +305,22 @@ NTSTATUS
    1.72  EvtChn_Unbind(PVOID Context, evtchn_port_t Port)
    1.73  {
    1.74    PXENPCI_DEVICE_DATA xpdd = Context;
    1.75 +  ev_action_t *action = &xpdd->ev_actions[Port];
    1.76    int old_type;
    1.77    
    1.78    EvtChn_Mask(Context, Port);
    1.79 -  old_type = xpdd->ev_actions[Port].type;
    1.80 -  xpdd->ev_actions[Port].type = EVT_ACTION_TYPE_EMPTY;
    1.81 -  KeMemoryBarrier(); // make sure we don't call the old Service Routine with the new data...
    1.82 -  xpdd->ev_actions[Port].ServiceRoutine = NULL;
    1.83 -  xpdd->ev_actions[Port].ServiceContext = NULL;
    1.84 -
    1.85 -  if (old_type == EVT_ACTION_TYPE_DPC)
    1.86 +  old_type = InterlockedExchange((volatile LONG *)&action->type, EVT_ACTION_TYPE_EMPTY);
    1.87 +  
    1.88 +  if (old_type == EVT_ACTION_TYPE_DPC || old_type == EVT_ACTION_TYPE_SUSPEND)
    1.89    {
    1.90      KeRemoveQueueDpc(&xpdd->ev_actions[Port].Dpc);
    1.91      KeFlushQueuedDpcs();
    1.92    }
    1.93    
    1.94 +  KeMemoryBarrier(); // make sure we don't call the old Service Routine with the new data...
    1.95 +  xpdd->ev_actions[Port].ServiceRoutine = NULL;
    1.96 +  xpdd->ev_actions[Port].ServiceContext = NULL;
    1.97 +
    1.98    return STATUS_SUCCESS;
    1.99  }
   1.100  
   1.101 @@ -404,6 +404,7 @@ NTSTATUS
   1.102  EvtChn_Init(PXENPCI_DEVICE_DATA xpdd)
   1.103  {
   1.104    ULONGLONG result;
   1.105 +  ev_action_t *action;
   1.106    int i;
   1.107  
   1.108    FUNCTION_ENTER();
   1.109 @@ -411,8 +412,10 @@ EvtChn_Init(PXENPCI_DEVICE_DATA xpdd)
   1.110    for (i = 0; i < NR_EVENTS; i++)
   1.111    {
   1.112      EvtChn_Mask(xpdd, i);
   1.113 -    xpdd->ev_actions[i].type = EVT_ACTION_TYPE_EMPTY;
   1.114 -    xpdd->ev_actions[i].count = 0;
   1.115 +    action = &xpdd->ev_actions[i];
   1.116 +    action->type = EVT_ACTION_TYPE_EMPTY;
   1.117 +    action->count = 0;
   1.118 +    KeInitializeDpc(&action->Dpc, EvtChn_DpcBounce, action);
   1.119    }
   1.120  
   1.121    for (i = 0; i < 8; i++)
     2.1 --- a/xenpci/xenpci.h	Sat Feb 20 16:31:45 2010 +1100
     2.2 +++ b/xenpci/xenpci.h	Sat Feb 20 16:34:22 2010 +1100
     2.3 @@ -67,6 +67,7 @@ DEFINE_GUID( GUID_XENPCI_DEVCLASS, 0xC82
     2.4  #define EVT_ACTION_TYPE_DPC     2
     2.5  #define EVT_ACTION_TYPE_IRQ     3
     2.6  #define EVT_ACTION_TYPE_SUSPEND 4
     2.7 +#define EVT_ACTION_TYPE_NEW     5 /* setup of event is in progress */
     2.8  
     2.9  #define XEN_PV_PRODUCT_NUMBER   0x0002
    2.10  #define XEN_PV_PRODUCT_BUILD    0x00000001
    2.11 @@ -79,9 +80,11 @@ typedef struct _ev_action_t {
    2.12    CHAR description[128];
    2.13    ULONG type; /* EVT_ACTION_TYPE_* */
    2.14    KDPC Dpc;
    2.15 +  ULONG port;
    2.16    ULONG vector;
    2.17    ULONG count;
    2.18    PVOID xpdd;
    2.19 +  ULONG generation; /* increases each time the event is renewed */
    2.20  } ev_action_t;
    2.21  
    2.22  typedef struct _XENBUS_WATCH_RING