Revise TransitionLock usage
The exclusive TransitionLock hold is required with all state changes that: - Switch adapter TUN_STATE_RUNNING -> TUN_STATE_PAUSING - Switch media status to MediaConnectStateDisconnected - Switch adapter to low-power state NdisDeviceStateD1-n Because, those transitions require NBL queue to clear and stay empty. The parts of the code that fill the NBL queue get a shared lock before state check and release it after they are done filling the queue. This prevents intermediate state changes while filling, and the queue clearing parts of the code to wait for the filling parts to prevent a race. Starting up adapter (TUN_STATE_RESTARTING -> TUN_STATE_RUNNING, MediaConnectStateDisconnected -> MediaConnectStateConnected, or NdisDeviceStateDx -> NdisDeviceStateD0) does not require emptying NBL queue and it does not need TransitionLock held. This commit also moves TunQueueClear() out of exclusive TransitionLock hold, because it is not necessary. Signed-off-by: Simon Rozman <simon@rozman.si>
This commit is contained in:
parent
486b1c374b
commit
14617f118f
22
wintun.c
22
wintun.c
@ -775,11 +775,9 @@ static NTSTATUS TunDispatch(DEVICE_OBJECT *DeviceObject, IRP *Irp)
|
||||
if (!NT_SUCCESS(status = IoAcquireRemoveLock(&ctx->Device.RemoveLock, stack->FileObject)))
|
||||
goto cleanup_complete_req_and_release_remove_lock;
|
||||
|
||||
irql = ExAcquireSpinLockExclusive(&ctx->TransitionLock);
|
||||
ASSERT(InterlockedGet64(&ctx->Device.RefCount) < MAXLONG64);
|
||||
if (InterlockedIncrement64(&ctx->Device.RefCount) > 0)
|
||||
TunIndicateStatus(ctx->MiniportAdapterHandle, MediaConnectStateConnected);
|
||||
ExReleaseSpinLockExclusive(&ctx->TransitionLock, irql);
|
||||
|
||||
status = STATUS_SUCCESS;
|
||||
goto cleanup_complete_req_and_release_remove_lock;
|
||||
@ -788,11 +786,12 @@ static NTSTATUS TunDispatch(DEVICE_OBJECT *DeviceObject, IRP *Irp)
|
||||
irql = ExAcquireSpinLockExclusive(&ctx->TransitionLock);
|
||||
ASSERT(InterlockedGet64(&ctx->Device.RefCount) > 0);
|
||||
if (InterlockedDecrement64(&ctx->Device.RefCount) <= 0) {
|
||||
ExReleaseSpinLockExclusive(&ctx->TransitionLock, irql);
|
||||
if (ctx->MiniportAdapterHandle)
|
||||
TunIndicateStatus(ctx->MiniportAdapterHandle, MediaConnectStateDisconnected);
|
||||
TunQueueClear(ctx, NDIS_STATUS_SEND_ABORTED);
|
||||
}
|
||||
ExReleaseSpinLockExclusive(&ctx->TransitionLock, irql);
|
||||
} else
|
||||
ExReleaseSpinLockExclusive(&ctx->TransitionLock, irql);
|
||||
IoReleaseRemoveLock(&ctx->Device.RemoveLock, stack->FileObject);
|
||||
|
||||
status = STATUS_SUCCESS;
|
||||
@ -840,11 +839,9 @@ static NDIS_STATUS TunRestart(NDIS_HANDLE MiniportAdapterContext, PNDIS_MINIPORT
|
||||
{
|
||||
TUN_CTX *ctx = (TUN_CTX *)MiniportAdapterContext;
|
||||
|
||||
KIRQL irql = ExAcquireSpinLockExclusive(&ctx->TransitionLock);
|
||||
InterlockedExchange((LONG *)&ctx->State, TUN_STATE_RESTARTING);
|
||||
InterlockedExchange64(&ctx->ActiveTransactionCount, 1);
|
||||
InterlockedExchange((LONG *)&ctx->State, TUN_STATE_RUNNING);
|
||||
ExReleaseSpinLockExclusive(&ctx->TransitionLock, irql);
|
||||
|
||||
return NDIS_STATUS_SUCCESS;
|
||||
}
|
||||
@ -1284,7 +1281,7 @@ static void TunHaltEx(NDIS_HANDLE MiniportAdapterContext, NDIS_HALT_ACTION HaltA
|
||||
|
||||
ASSERT(!InterlockedGet64(&ctx->ActiveTransactionCount)); /* Adapter should not be halted if it wasn't fully paused first. */
|
||||
|
||||
InterlockedExchange((LONG *)&ctx->State, TUN_STATE_HALTING);
|
||||
InterlockedExchange((LONG*)& ctx->State, TUN_STATE_HALTING);
|
||||
|
||||
if (ctx->PnPNotifications.Handle) {
|
||||
PVOID h = ctx->PnPNotifications.Handle;
|
||||
@ -1322,8 +1319,8 @@ static void TunHaltEx(NDIS_HANDLE MiniportAdapterContext, NDIS_HALT_ACTION HaltA
|
||||
/* MiniportAdapterHandle must not be used in TunDispatch(). After TunHaltEx() returns it is invalidated. */
|
||||
ctx->MiniportAdapterHandle = NULL;
|
||||
|
||||
InterlockedExchange((LONG *)&ctx->PowerState, NdisDeviceStateUnspecified);
|
||||
InterlockedExchange((LONG *)&ctx->State, TUN_STATE_HALTED);
|
||||
InterlockedExchange((LONG*)& ctx->PowerState, NdisDeviceStateUnspecified);
|
||||
InterlockedExchange((LONG*)& ctx->State, TUN_STATE_HALTED);
|
||||
|
||||
if (!InterlockedDecrement64(&AdapterCount))
|
||||
TunWaitForReferencesToDropToZero(ctx);
|
||||
@ -1364,11 +1361,12 @@ static NDIS_STATUS TunOidSet(_Inout_ TUN_CTX *ctx, _Inout_ NDIS_OID_REQUEST *Oid
|
||||
}
|
||||
OidRequest->DATA.SET_INFORMATION.BytesRead = sizeof(NDIS_DEVICE_POWER_STATE);
|
||||
|
||||
KIRQL irql = ExAcquireSpinLockExclusive(&ctx->TransitionLock);
|
||||
NDIS_DEVICE_POWER_STATE state = *(NDIS_DEVICE_POWER_STATE *)OidRequest->DATA.SET_INFORMATION.InformationBuffer;
|
||||
if (InterlockedExchange((LONG *)&ctx->PowerState, state) == NdisDeviceStateD0 && state >= NdisDeviceStateD1)
|
||||
TunQueueClear(ctx, STATUS_NDIS_LOW_POWER_STATE);
|
||||
KIRQL irql = ExAcquireSpinLockExclusive(&ctx->TransitionLock);
|
||||
InterlockedExchange((LONG *)&ctx->PowerState, state);
|
||||
ExReleaseSpinLockExclusive(&ctx->TransitionLock, irql);
|
||||
if (state >= NdisDeviceStateD1)
|
||||
TunQueueClear(ctx, STATUS_NDIS_LOW_POWER_STATE);
|
||||
|
||||
return NDIS_STATUS_SUCCESS;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user