sys: implement FsvrtDeviceExpirationRoutine and supporting infra

This commit is contained in:
Bill Zissimopoulos 2015-12-16 16:11:29 -08:00
parent ec0e8548b5
commit 460c4e0c55
5 changed files with 135 additions and 3 deletions

View File

@ -13,17 +13,23 @@ NTSTATUS FspDeviceCreateSecure(UINT32 Kind, ULONG ExtraSize,
NTSTATUS FspDeviceCreate(UINT32 Kind, ULONG ExtraSize,
DEVICE_TYPE DeviceType,
PDEVICE_OBJECT *PDeviceObject);
VOID FspDeviceInitComplete(PDEVICE_OBJECT DeviceObject);
VOID FspDeviceDelete(PDEVICE_OBJECT DeviceObject);
static NTSTATUS FspFsctlDeviceInit(PDEVICE_OBJECT DeviceObject);
static VOID FspFsctlDeviceInitComplete(PDEVICE_OBJECT DeviceObject);
static VOID FspFsctlDeviceFini(PDEVICE_OBJECT DeviceObject);
static NTSTATUS FspFsvrtDeviceInit(PDEVICE_OBJECT DeviceObject);
static VOID FspFsvrtDeviceInitComplete(PDEVICE_OBJECT DeviceObject);
static VOID FspFsvrtDeviceFini(PDEVICE_OBJECT DeviceObject);
static NTSTATUS FspFsvolDeviceInit(PDEVICE_OBJECT DeviceObject);
static VOID FspFsvolDeviceInitComplete(PDEVICE_OBJECT DeviceObject);
static VOID FspFsvolDeviceFini(PDEVICE_OBJECT DeviceObject);
BOOLEAN FspDeviceRetain(PDEVICE_OBJECT DeviceObject);
VOID FspDeviceRelease(PDEVICE_OBJECT DeviceObject);
VOID FspFsctlDeviceVolumeCreated(PDEVICE_OBJECT DeviceObject);
VOID FspFsctlDeviceVolumeDeleted(PDEVICE_OBJECT DeviceObject);
static IO_TIMER_ROUTINE FspFsvrtDeviceTimerRoutine;
static WORKER_THREAD_ROUTINE FspFsvrtDeviceExpirationRoutine;
PVOID FspFsvolDeviceLookupContext(PDEVICE_OBJECT DeviceObject, UINT64 Identifier);
PVOID FspFsvolDeviceInsertContext(PDEVICE_OBJECT DeviceObject, UINT64 Identifier, PVOID Context,
FSP_DEVICE_GENERIC_TABLE_ELEMENT *ElementStorage, PBOOLEAN PInserted);
@ -41,12 +47,16 @@ VOID FspDeviceDeleteAll(VOID);
#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE, FspDeviceCreateSecure)
#pragma alloc_text(PAGE, FspDeviceCreate)
#pragma alloc_text(PAGE, FspDeviceInitComplete)
#pragma alloc_text(PAGE, FspDeviceDelete)
#pragma alloc_text(PAGE, FspFsctlDeviceInit)
#pragma alloc_text(PAGE, FspFsctlDeviceInitComplete)
#pragma alloc_text(PAGE, FspFsctlDeviceFini)
#pragma alloc_text(PAGE, FspFsvrtDeviceInit)
#pragma alloc_text(PAGE, FspFsvrtDeviceInitComplete)
#pragma alloc_text(PAGE, FspFsvrtDeviceFini)
#pragma alloc_text(PAGE, FspFsvolDeviceInit)
#pragma alloc_text(PAGE, FspFsvolDeviceInitComplete)
#pragma alloc_text(PAGE, FspFsvolDeviceFini)
#pragma alloc_text(PAGE, FspFsctlDeviceVolumeCreated)
#pragma alloc_text(PAGE, FspFsctlDeviceVolumeDeleted)
@ -142,6 +152,31 @@ NTSTATUS FspDeviceCreate(UINT32 Kind, ULONG ExtraSize,
return FspDeviceCreateSecure(Kind, ExtraSize, 0, DeviceType, 0, 0, PDeviceObject);
}
VOID FspDeviceInitComplete(PDEVICE_OBJECT DeviceObject)
{
PAGED_CODE();
FSP_DEVICE_EXTENSION *DeviceExtension = FspDeviceExtension(DeviceObject);
switch (DeviceExtension->Kind)
{
case FspFsvolDeviceExtensionKind:
FspFsvolDeviceInitComplete(DeviceObject);
break;
case FspFsvrtDeviceExtensionKind:
FspFsvrtDeviceInitComplete(DeviceObject);
break;
case FspFsctlDeviceExtensionKind:
FspFsctlDeviceInitComplete(DeviceObject);
break;
default:
ASSERT(0);
return;
}
ClearFlag(DeviceObject->Flags, DO_DEVICE_INITIALIZING);
}
VOID FspDeviceDelete(PDEVICE_OBJECT DeviceObject)
{
PAGED_CODE();
@ -176,6 +211,11 @@ static NTSTATUS FspFsctlDeviceInit(PDEVICE_OBJECT DeviceObject)
return STATUS_SUCCESS;
}
static VOID FspFsctlDeviceInitComplete(PDEVICE_OBJECT DeviceObject)
{
PAGED_CODE();
}
static VOID FspFsctlDeviceFini(PDEVICE_OBJECT DeviceObject)
{
PAGED_CODE();
@ -185,9 +225,18 @@ static NTSTATUS FspFsvrtDeviceInit(PDEVICE_OBJECT DeviceObject)
{
PAGED_CODE();
NTSTATUS Result;
FSP_FSVRT_DEVICE_EXTENSION *FsvrtDeviceExtension = FspFsvrtDeviceExtension(DeviceObject);
/* initialize our timer routine */
Result = IoInitializeTimer(DeviceObject, FspFsvrtDeviceTimerRoutine, 0);
if (!NT_SUCCESS(Result))
return Result;
FspIoqInitialize(&FsvrtDeviceExtension->Ioq);
KeInitializeSpinLock(&FsvrtDeviceExtension->ExpirationLock);
ExInitializeWorkItem(&FsvrtDeviceExtension->ExpirationWorkItem,
FspFsvrtDeviceExpirationRoutine, DeviceObject);
FsvrtDeviceExtension->SwapVpb = FspAllocNonPagedExternal(sizeof *FsvrtDeviceExtension->SwapVpb);
if (0 == FsvrtDeviceExtension->SwapVpb)
@ -197,12 +246,28 @@ static NTSTATUS FspFsvrtDeviceInit(PDEVICE_OBJECT DeviceObject)
return STATUS_SUCCESS;
}
static VOID FspFsvrtDeviceInitComplete(PDEVICE_OBJECT DeviceObject)
{
PAGED_CODE();
IoStartTimer(DeviceObject);
}
static VOID FspFsvrtDeviceFini(PDEVICE_OBJECT DeviceObject)
{
PAGED_CODE();
FSP_FSVRT_DEVICE_EXTENSION *FsvrtDeviceExtension = FspFsvrtDeviceExtension(DeviceObject);
/*
* First things first: stop our timer.
*
* Our IoTimer routine will NOT be called again after IoStopTimer() returns.
* However a work item may be in flight. For this reason our IoTimer routine
* does an ObReferenceObject() on our DeviceObject before queueing work items.
*/
IoStopTimer(DeviceObject);
if (0 != FsvrtDeviceExtension->SwapVpb)
FspFreeExternal(FsvrtDeviceExtension->SwapVpb);
}
@ -219,6 +284,11 @@ static NTSTATUS FspFsvolDeviceInit(PDEVICE_OBJECT DeviceObject)
return STATUS_SUCCESS;
}
static VOID FspFsvolDeviceInitComplete(PDEVICE_OBJECT DeviceObject)
{
PAGED_CODE();
}
static VOID FspFsvolDeviceFini(PDEVICE_OBJECT DeviceObject)
{
PAGED_CODE();
@ -314,6 +384,58 @@ VOID FspFsctlDeviceVolumeDeleted(PDEVICE_OBJECT DeviceObject)
#endif
}
static VOID FspFsvrtDeviceTimerRoutine(PDEVICE_OBJECT DeviceObject, PVOID Context)
{
// !PAGED_CODE();
/*
* This routine runs at DPC level. Reference our DeviceObject and queue a work item
* so that we can do our processing at Passive level. Only do so if the work item
* is not already in flight (otherwise we could requeue the same work item).
*/
ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
FSP_FSVRT_DEVICE_EXTENSION *FsvrtDeviceExtension = FspFsvrtDeviceExtension(DeviceObject);
KeAcquireSpinLockAtDpcLevel(&FsvrtDeviceExtension->ExpirationLock);
if (!FsvrtDeviceExtension->ExpirationInProgress)
{
FsvrtDeviceExtension->ExpirationInProgress = TRUE;
ObReferenceObject(DeviceObject);
ExQueueWorkItem(&FsvrtDeviceExtension->ExpirationWorkItem, DelayedWorkQueue);
}
KeReleaseSpinLockFromDpcLevel(&FsvrtDeviceExtension->ExpirationLock);
}
static VOID FspFsvrtDeviceExpirationRoutine(PVOID Context)
{
// !PAGED_CODE();
PDEVICE_OBJECT DeviceObject = Context;
if (FspDeviceRetain(DeviceObject))
try
{
FSP_FSVRT_DEVICE_EXTENSION *FsvrtDeviceExtension = FspFsvrtDeviceExtension(DeviceObject);
LARGE_INTEGER Timeout;
KIRQL Irql;
Timeout.QuadPart = FsvrtDeviceExtension->VolumeParams.IrpTimeout * 10000;
/* convert millis to nanos */
FspIoqRemoveExpired(&FsvrtDeviceExtension->Ioq, &Timeout);
KeAcquireSpinLock(&FsvrtDeviceExtension->ExpirationLock, &Irql);
FsvrtDeviceExtension->ExpirationInProgress = FALSE;
KeReleaseSpinLock(&FsvrtDeviceExtension->ExpirationLock, Irql);
}
finally
{
FspDeviceRelease(DeviceObject);
}
ObDereferenceObject(DeviceObject);
}
PVOID FspFsvolDeviceLookupContext(PDEVICE_OBJECT DeviceObject, UINT64 Identifier)
{
PAGED_CODE();

View File

@ -39,6 +39,8 @@ NTSTATUS DriverEntry(
&FspFsctlNetDeviceObject);
if (!NT_SUCCESS(Result))
FSP_RETURN(FspDeviceDelete(FspFsctlDiskDeviceObject));
FspDeviceInitComplete(FspFsctlDiskDeviceObject);
FspDeviceInitComplete(FspFsctlNetDeviceObject);
/* setup the driver object */
DriverObject->DriverUnload = FspUnload;

View File

@ -318,6 +318,9 @@ typedef struct
PDEVICE_OBJECT FsvolDeviceObject;
FSP_FSCTL_VOLUME_PARAMS VolumeParams;
FSP_IOQ Ioq;
KSPIN_LOCK ExpirationLock;
WORK_QUEUE_ITEM ExpirationWorkItem;
BOOLEAN ExpirationInProgress;
PVPB SwapVpb;
BOOLEAN Deleted;
FSP_FSCTL_DECLSPEC_ALIGN UINT8 SecurityDescriptorBuf[];
@ -369,6 +372,7 @@ NTSTATUS FspDeviceCreateSecure(UINT32 Kind, ULONG ExtraSize,
NTSTATUS FspDeviceCreate(UINT32 Kind, ULONG ExtraSize,
DEVICE_TYPE DeviceType,
PDEVICE_OBJECT *PDeviceObject);
VOID FspDeviceInitComplete(PDEVICE_OBJECT DeviceObject);
VOID FspDeviceDelete(PDEVICE_OBJECT DeviceObject);
BOOLEAN FspDeviceRetain(PDEVICE_OBJECT DeviceObject);
VOID FspDeviceRelease(PDEVICE_OBJECT DeviceObject);

View File

@ -178,7 +178,7 @@ static NTSTATUS FspFsctlCreateVolume(
FsvrtDeviceExtension->VolumeParams = VolumeParams;
RtlCopyMemory(FsvrtDeviceExtension->SecurityDescriptorBuf,
SecurityDescriptorBuf, SecurityDescriptorSize);
ClearFlag(FsvrtDeviceObject->Flags, DO_DEVICE_INITIALIZING);
FspDeviceInitComplete(FsvrtDeviceObject);
Irp->IoStatus.Information = DeviceName.Length + sizeof(WCHAR);
FspFsctlDeviceVolumeCreated(DeviceObject);
}
@ -255,7 +255,7 @@ static NTSTATUS FspFsctlMountVolume(
FsvolDeviceExtension = FspFsvolDeviceExtension(FsvolDeviceObject);
FsvolDeviceExtension->FsvrtDeviceObject = FsvrtDeviceObject;
FsvrtDeviceExtension->FsvolDeviceObject = FsvolDeviceObject;
ClearFlag(FsvolDeviceObject->Flags, DO_DEVICE_INITIALIZING);
FspDeviceInitComplete(FsvolDeviceObject);
Vpb->DeviceObject = FsvolDeviceObject;
Vpb->SerialNumber = FsvrtDeviceExtension->VolumeParams.SerialNumber;
Irp->IoStatus.Information = 0;

View File

@ -238,7 +238,11 @@ VOID FspIoqRemoveExpired(FSP_IOQ *Ioq, PLARGE_INTEGER Timeout)
{
FSP_IOQ_PEEK_CONTEXT PeekContext;
PeekContext.IrpHint = 0;
PeekContext.ExpirationTime = KeQueryInterruptTime() - Timeout->QuadPart;
PeekContext.ExpirationTime = KeQueryInterruptTime();
if (PeekContext.ExpirationTime >= (ULONGLONG)Timeout->QuadPart)
PeekContext.ExpirationTime -= Timeout->QuadPart;
else
PeekContext.ExpirationTime = 0;
PIRP Irp;
while (0 != (Irp = IoCsqRemoveNextIrp(&Ioq->PendingIoCsq, &PeekContext)))
FspIoqPendingCompleteCanceledIrp(&Ioq->PendingIoCsq, Irp);