You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
761 lines
19 KiB
761 lines
19 KiB
/*++
|
|
|
|
Copyright (c) 2000 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
vfirplog.c
|
|
|
|
Abstract:
|
|
|
|
This module manages IRP logs for the verifier.
|
|
|
|
Author:
|
|
|
|
Adrian J. Oney (adriao) 09-May-1998
|
|
|
|
Environment:
|
|
|
|
Kernel mode
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
//
|
|
// Disable W4 level warnings generated by public headers.
|
|
//
|
|
#include "vfpragma.h"
|
|
|
|
#include "..\io\iop.h" // Includes vfdef.h
|
|
#include "viirplog.h"
|
|
|
|
#ifdef ALLOC_PRAGMA
|
|
#pragma alloc_text(PAGEVRFY, VfIrpLogInit)
|
|
#pragma alloc_text(PAGEVRFY, ViIrpLogDatabaseFindPointer)
|
|
#pragma alloc_text(PAGEVRFY, ViIrpLogExposeWmiCallback)
|
|
#pragma alloc_text(PAGEVRFY, VfIrpLogRecordEvent)
|
|
#pragma alloc_text(PAGEVRFY, VfIrpLogGetIrpDatabaseSiloCount)
|
|
#pragma alloc_text(PAGEVRFY, VfIrpLogLockDatabase)
|
|
#pragma alloc_text(PAGEVRFY, VfIrpLogRetrieveWmiData)
|
|
#pragma alloc_text(PAGEVRFY, VfIrpLogUnlockDatabase)
|
|
#pragma alloc_text(PAGEVRFY, VfIrpLogDeleteDeviceLogs)
|
|
#endif
|
|
|
|
PIRPLOG_HEAD ViIrpLogDatabase;
|
|
KSPIN_LOCK ViIrpLogDatabaseLock;
|
|
LONG ViIrpLogDdiLock = DDILOCK_UNREGISTERED;
|
|
|
|
#define POOLTAG_IRPLOG_DATABASE 'dIfV'
|
|
#define POOLTAG_IRPLOG_DATA 'eIfV'
|
|
#define POOLTAG_IRPLOG_TEMP 'tIfV'
|
|
#define POOLTAG_IRPLOG_WORKITEM 'wIfV'
|
|
|
|
#define INSTANCE_NAME_PROLOG L"VERIFIER"
|
|
|
|
VOID
|
|
VfIrpLogInit(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Description:
|
|
|
|
This routine initializes all the important structures we use to log IRPs.
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
ULONG i;
|
|
|
|
PAGED_CODE();
|
|
|
|
KeInitializeSpinLock(&ViIrpLogDatabaseLock);
|
|
|
|
//
|
|
// As this is system startup code, it is one of the very few places
|
|
// where it's ok to use MustSucceed.
|
|
//
|
|
ViIrpLogDatabase = (PIRPLOG_HEAD) ExAllocatePoolWithTag(
|
|
NonPagedPoolMustSucceed,
|
|
VI_IRPLOG_DATABASE_HASH_SIZE * sizeof(IRPLOG_HEAD),
|
|
POOLTAG_IRPLOG_DATABASE
|
|
);
|
|
|
|
for(i=0; i < VI_IRPLOG_DATABASE_HASH_SIZE; i++) {
|
|
|
|
ViIrpLogDatabase[i].Locked = FALSE;
|
|
InitializeListHead(&ViIrpLogDatabase[i].ListHead);
|
|
}
|
|
}
|
|
|
|
|
|
PIRPLOG_DATA
|
|
FASTCALL
|
|
ViIrpLogDatabaseFindPointer(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
OUT PIRPLOG_HEAD *HashHead
|
|
)
|
|
/*++
|
|
|
|
Description:
|
|
|
|
This routine returns a pointer to a pointer to the per-device object.
|
|
data. This function is meant to be called by other routines in this file.
|
|
|
|
N.B. The verifier devobj database lock is assumed to be held by the caller.
|
|
|
|
Arguments:
|
|
|
|
DeviceObject - Device object to locate in the tracking table.
|
|
|
|
HashHead - If return is non-null, points to the hash head that should
|
|
be used to insert the tracking data.
|
|
|
|
Return Value:
|
|
|
|
IrpLogData iff found, NULL otherwise.
|
|
|
|
--*/
|
|
{
|
|
PIRPLOG_DATA irpLogData;
|
|
PLIST_ENTRY listEntry, listHead;
|
|
UINT_PTR hashIndex;
|
|
|
|
hashIndex = VI_IRPLOG_CALCULATE_DATABASE_HASH(DeviceObject);
|
|
|
|
ASSERT_SPINLOCK_HELD(&ViIrpLogDatabaseLock);
|
|
|
|
*HashHead = &ViIrpLogDatabase[hashIndex];
|
|
|
|
listHead = &ViIrpLogDatabase[hashIndex].ListHead;
|
|
|
|
for(listEntry = listHead;
|
|
listEntry->Flink != listHead;
|
|
listEntry = listEntry->Flink) {
|
|
|
|
irpLogData = CONTAINING_RECORD(listEntry->Flink, IRPLOG_DATA, HashLink);
|
|
|
|
if (irpLogData->DeviceObject == DeviceObject) {
|
|
|
|
return irpLogData;
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
|
|
VOID
|
|
ViIrpLogExposeWmiCallback(
|
|
IN PVOID Context
|
|
)
|
|
{
|
|
PWORK_QUEUE_ITEM workQueueItem;
|
|
|
|
PAGED_CODE();
|
|
|
|
workQueueItem = (PWORK_QUEUE_ITEM) Context;
|
|
|
|
VfDdiExposeWmiObjects();
|
|
|
|
ViIrpLogDdiLock = DDILOCK_REGISTERED;
|
|
ExFreePool(workQueueItem);
|
|
}
|
|
|
|
|
|
VOID
|
|
VfIrpLogRecordEvent(
|
|
IN PVERIFIER_SETTINGS_SNAPSHOT VerifierSettingsSnapshot,
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
)
|
|
{
|
|
PIRPLOG_HEAD hashHead;
|
|
PIRPLOG_DATA irpLogData;
|
|
IRPLOG_SNAPSHOT irpLogSnapshot;
|
|
PWORK_QUEUE_ITEM workQueueItem;
|
|
KIRQL oldIrql;
|
|
LONG oldVal;
|
|
ULONG maxElementCount;
|
|
ULONG elementCount;
|
|
LOGICAL logEntry;
|
|
|
|
if (!VfSettingsIsOptionEnabled(VerifierSettingsSnapshot,
|
|
VERIFIER_OPTION_EXPOSE_IRP_HISTORY)) {
|
|
|
|
return;
|
|
}
|
|
|
|
if (ViIrpLogDdiLock != DDILOCK_REGISTERED) {
|
|
|
|
oldVal = InterlockedCompareExchange( &ViIrpLogDdiLock,
|
|
DDILOCK_REGISTERING,
|
|
DDILOCK_UNREGISTERED );
|
|
|
|
if (oldVal == DDILOCK_UNREGISTERED) {
|
|
|
|
workQueueItem = (PWORK_QUEUE_ITEM) ExAllocatePoolWithTag(
|
|
NonPagedPool,
|
|
sizeof(WORK_QUEUE_ITEM),
|
|
POOLTAG_IRPLOG_WORKITEM
|
|
);
|
|
|
|
if (workQueueItem) {
|
|
|
|
ExInitializeWorkItem(
|
|
workQueueItem,
|
|
ViIrpLogExposeWmiCallback,
|
|
workQueueItem
|
|
);
|
|
|
|
ExQueueWorkItem(
|
|
workQueueItem,
|
|
DelayedWorkQueue
|
|
);
|
|
|
|
} else {
|
|
|
|
ViIrpLogDdiLock = DDILOCK_UNREGISTERED;
|
|
}
|
|
}
|
|
}
|
|
|
|
ExAcquireSpinLock(&ViIrpLogDatabaseLock, &oldIrql);
|
|
|
|
irpLogData = ViIrpLogDatabaseFindPointer(DeviceObject, &hashHead);
|
|
|
|
if (hashHead->Locked) {
|
|
|
|
//
|
|
// The current logs are being drained. Since logs are lossy anyway,
|
|
// dump this one on the floor.
|
|
//
|
|
ExReleaseSpinLock(&ViIrpLogDatabaseLock, oldIrql);
|
|
return;
|
|
}
|
|
|
|
if (irpLogData == NULL) {
|
|
|
|
VfSettingsGetValue(
|
|
VerifierSettingsSnapshot,
|
|
VERIFIER_VALUE_IRPLOG_COUNT,
|
|
&maxElementCount
|
|
);
|
|
|
|
irpLogData = ExAllocatePoolWithTag(
|
|
NonPagedPool,
|
|
sizeof(IRPLOG_DATA)+(maxElementCount-1)*sizeof(IRPLOG_SNAPSHOT),
|
|
POOLTAG_IRPLOG_DATA
|
|
);
|
|
|
|
if (irpLogData != NULL) {
|
|
|
|
ObReferenceObject(DeviceObject);
|
|
irpLogData->DeviceObject = DeviceObject;
|
|
irpLogData->Flags = 0;
|
|
irpLogData->DeviceType = DeviceObject->DeviceType;
|
|
irpLogData->Head = 0;
|
|
irpLogData->MaximumElementCount = maxElementCount;
|
|
InsertHeadList(&hashHead->ListHead, &irpLogData->HashLink);
|
|
}
|
|
}
|
|
|
|
if (irpLogData != NULL) {
|
|
|
|
if (!(irpLogData->Flags & (IRPLOG_FLAG_DELETED | IRPLOG_FLAG_NAMELESS))) {
|
|
|
|
if (irpLogData->Flags == IRPLOG_FLAG_FULL) {
|
|
|
|
elementCount = irpLogData->MaximumElementCount;
|
|
|
|
} else {
|
|
|
|
elementCount = irpLogData->Head;
|
|
}
|
|
|
|
logEntry = VfMajorBuildIrpLogEntry(
|
|
Irp,
|
|
elementCount,
|
|
&irpLogData->SnapshotArray[irpLogData->Head],
|
|
&irpLogSnapshot
|
|
);
|
|
|
|
if (logEntry) {
|
|
|
|
irpLogData->SnapshotArray[irpLogData->Head] = irpLogSnapshot;
|
|
|
|
irpLogData->Head++;
|
|
|
|
if (irpLogData->Head == irpLogData->MaximumElementCount) {
|
|
|
|
irpLogData->Flags |= IRPLOG_FLAG_FULL;
|
|
irpLogData->Head = 0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
ExReleaseSpinLock(&ViIrpLogDatabaseLock, oldIrql);
|
|
}
|
|
|
|
|
|
ULONG
|
|
VfIrpLogGetIrpDatabaseSiloCount(
|
|
VOID
|
|
)
|
|
{
|
|
return VI_IRPLOG_DATABASE_HASH_SIZE;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
VfIrpLogLockDatabase(
|
|
IN ULONG SiloNumber
|
|
)
|
|
{
|
|
NTSTATUS status;
|
|
KIRQL oldIrql;
|
|
|
|
ASSERT(SiloNumber < VI_IRPLOG_DATABASE_HASH_SIZE);
|
|
|
|
//
|
|
// Take the database offline. From this point on, changes can still be made
|
|
// but new entries cannot be added, nor can old ones be removed from the
|
|
// tree. We do this under a lock to ensure all current inserts/removals
|
|
// have drained with respect to the state change.
|
|
//
|
|
ExAcquireSpinLock(&ViIrpLogDatabaseLock, &oldIrql);
|
|
|
|
if (ViIrpLogDatabase[SiloNumber].Locked) {
|
|
|
|
//
|
|
// Reentrancy attempt - we don't try to do anything clever.
|
|
//
|
|
status = STATUS_RETRY;
|
|
|
|
} else {
|
|
|
|
ViIrpLogDatabase[SiloNumber].Locked = TRUE;
|
|
status = STATUS_SUCCESS;
|
|
}
|
|
|
|
ExReleaseSpinLock(&ViIrpLogDatabaseLock, oldIrql);
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
VfIrpLogRetrieveWmiData(
|
|
IN ULONG SiloNumber,
|
|
OUT PUCHAR OutputBuffer OPTIONAL,
|
|
OUT ULONG *OffsetInstanceNameOffsets,
|
|
OUT ULONG *InstanceCount,
|
|
OUT ULONG *DataBlockOffset,
|
|
OUT ULONG *TotalRequiredSize
|
|
)
|
|
{
|
|
PIRPLOG_DATA irpLogData;
|
|
PLIST_ENTRY listEntry, listHead;
|
|
ULONG instances;
|
|
POBJECT_NAME_INFORMATION objectName;
|
|
ULONG currentNameSize, neededNameSize;
|
|
ULONG totalDataSize;
|
|
ULONG nameOffsetArrayOffset;
|
|
ULONG instanceLengthArrayOffset;
|
|
ULONG nameStringBufferOffset;
|
|
ULONG instanceDataOffset;
|
|
ULONG individualStringLengthInBytes;
|
|
ULONG individualStringLengthInChars;
|
|
ULONG elementCount;
|
|
PULONG nameOffsetBuffer;
|
|
POFFSETINSTANCEDATAANDLENGTH instanceLengthBuffer;
|
|
PUSHORT nameStringBuffer;
|
|
PUCHAR instanceDataBuffer;
|
|
NTSTATUS status;
|
|
|
|
//
|
|
// The irp log database must be locked for this query.
|
|
//
|
|
ASSERT(SiloNumber < VI_IRPLOG_DATABASE_HASH_SIZE);
|
|
ASSERT(ViIrpLogDatabase[SiloNumber].Locked);
|
|
|
|
//
|
|
// Preinit for error.
|
|
//
|
|
*OffsetInstanceNameOffsets = 0;
|
|
*InstanceCount = 0;
|
|
*DataBlockOffset = 0;
|
|
*TotalRequiredSize = 0;
|
|
|
|
//
|
|
// Allocate an initial buffer.
|
|
//
|
|
currentNameSize = sizeof(OBJECT_NAME_INFORMATION);
|
|
|
|
objectName = ExAllocatePoolWithTag(
|
|
PagedPool,
|
|
currentNameSize,
|
|
POOLTAG_IRPLOG_TEMP
|
|
);
|
|
|
|
if (objectName == NULL) {
|
|
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
//
|
|
// Walk through the database and start retrieving information. First count
|
|
// the instances.
|
|
//
|
|
instances = 0;
|
|
listHead = &ViIrpLogDatabase[SiloNumber].ListHead;
|
|
|
|
for(listEntry = listHead;
|
|
listEntry->Flink != listHead;
|
|
listEntry = listEntry->Flink) {
|
|
|
|
irpLogData = CONTAINING_RECORD(listEntry->Flink, IRPLOG_DATA, HashLink);
|
|
|
|
#ifdef MAX_INSTANCE_COUNT
|
|
if (instances == MAX_INSTANCE_COUNT) {
|
|
|
|
break;
|
|
}
|
|
#endif
|
|
|
|
instances++;
|
|
}
|
|
|
|
//
|
|
// First, since we have dynamic named, we need to allocate space for the
|
|
// ULONG-sized array of offset pointers to each string.
|
|
//
|
|
|
|
//
|
|
// The buffer will look like this:
|
|
//
|
|
// [WNODE_ALL_DATA]
|
|
// [Array of per-instance DataOffset+DataLength entries)
|
|
// [Array of per-instance NameOffset entries]
|
|
// [names]
|
|
// [data]
|
|
//
|
|
instanceLengthArrayOffset = FIELD_OFFSET(WNODE_ALL_DATA, OffsetInstanceDataAndLength);
|
|
nameOffsetArrayOffset = instanceLengthArrayOffset + instances*sizeof(OFFSETINSTANCEDATAANDLENGTH);
|
|
nameStringBufferOffset = nameOffsetArrayOffset + instances*sizeof(ULONG);
|
|
|
|
nameOffsetBuffer = (PULONG) (OutputBuffer + nameOffsetArrayOffset);
|
|
instanceLengthBuffer = (POFFSETINSTANCEDATAANDLENGTH) (OutputBuffer + instanceLengthArrayOffset);
|
|
nameStringBuffer = (PUSHORT) (OutputBuffer + nameStringBufferOffset);
|
|
|
|
//
|
|
// So far the required size only accounts for the array of offsets to names
|
|
//
|
|
totalDataSize = nameStringBufferOffset;
|
|
|
|
//
|
|
// Now start collecting the names.
|
|
//
|
|
status = STATUS_SUCCESS;
|
|
instances = 0;
|
|
listHead = &ViIrpLogDatabase[SiloNumber].ListHead;
|
|
|
|
for(listEntry = listHead;
|
|
listEntry->Flink != listHead;
|
|
listEntry = listEntry->Flink) {
|
|
|
|
irpLogData = CONTAINING_RECORD(listEntry->Flink, IRPLOG_DATA, HashLink);
|
|
|
|
//
|
|
// Retrieve the name
|
|
//
|
|
status = ObQueryNameString(
|
|
irpLogData->DeviceObject,
|
|
objectName,
|
|
currentNameSize,
|
|
&neededNameSize
|
|
);
|
|
|
|
if (status == STATUS_INFO_LENGTH_MISMATCH) {
|
|
|
|
ExFreePool(objectName);
|
|
|
|
objectName = ExAllocatePoolWithTag(
|
|
PagedPool,
|
|
neededNameSize,
|
|
POOLTAG_IRPLOG_TEMP
|
|
);
|
|
|
|
if (objectName == NULL) {
|
|
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
} else {
|
|
|
|
currentNameSize = neededNameSize;
|
|
|
|
status = ObQueryNameString(
|
|
irpLogData->DeviceObject,
|
|
objectName,
|
|
currentNameSize,
|
|
&neededNameSize
|
|
);
|
|
}
|
|
}
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
|
|
break;
|
|
}
|
|
|
|
if (objectName->Name.Length == 0) {
|
|
|
|
irpLogData->Flags |= IRPLOG_FLAG_NAMELESS;
|
|
continue;
|
|
}
|
|
|
|
#ifdef MAX_INSTANCE_COUNT
|
|
if (instances == MAX_INSTANCE_COUNT) {
|
|
|
|
break;
|
|
}
|
|
#endif
|
|
|
|
instances++;
|
|
|
|
//
|
|
// Write the appropriate offset into the name offset array
|
|
//
|
|
if (ARGUMENT_PRESENT(OutputBuffer)) {
|
|
|
|
*nameOffsetBuffer = totalDataSize;
|
|
}
|
|
|
|
nameOffsetBuffer++;
|
|
|
|
//
|
|
// Add in memory for each "counted" string. WMI counted strings are
|
|
// of the form [USHORT LenInBytesIncludingTerminator]
|
|
// [WCHAR Array w/NULL terminator]
|
|
//
|
|
// The string is of the form VERIFIER\Device\Foo (The terminating NULL
|
|
// is accounted for by sizeof().
|
|
//
|
|
individualStringLengthInBytes = objectName->Name.Length + sizeof(INSTANCE_NAME_PROLOG);
|
|
individualStringLengthInChars = individualStringLengthInBytes/sizeof(WCHAR);
|
|
|
|
//
|
|
// Write out the counted string, starting with the length
|
|
//
|
|
ASSERT(OutputBuffer + totalDataSize == (PUCHAR) nameStringBuffer);
|
|
|
|
if (ARGUMENT_PRESENT(OutputBuffer)) {
|
|
|
|
*nameStringBuffer = (USHORT) individualStringLengthInBytes;
|
|
}
|
|
|
|
nameStringBuffer++;
|
|
totalDataSize += sizeof(USHORT);
|
|
|
|
if (ARGUMENT_PRESENT(OutputBuffer)) {
|
|
|
|
RtlCopyMemory(
|
|
nameStringBuffer,
|
|
INSTANCE_NAME_PROLOG,
|
|
sizeof(INSTANCE_NAME_PROLOG)-sizeof(UNICODE_NULL)
|
|
);
|
|
|
|
RtlCopyMemory(
|
|
nameStringBuffer + ((sizeof(INSTANCE_NAME_PROLOG) - sizeof(UNICODE_NULL))/sizeof(WCHAR)),
|
|
objectName->Name.Buffer,
|
|
objectName->Name.Length
|
|
);
|
|
|
|
nameStringBuffer[individualStringLengthInChars-1] = UNICODE_NULL;
|
|
}
|
|
|
|
nameStringBuffer += individualStringLengthInChars;
|
|
totalDataSize += individualStringLengthInBytes;
|
|
}
|
|
|
|
if (objectName) {
|
|
|
|
ExFreePool(objectName);
|
|
}
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
|
|
return status;
|
|
}
|
|
|
|
//
|
|
// Now collect the instance data
|
|
//
|
|
totalDataSize = ALIGN_UP_ULONG(totalDataSize, 8);
|
|
instanceDataOffset = totalDataSize;
|
|
instanceDataBuffer = (OutputBuffer + instanceDataOffset);
|
|
|
|
instances = 0;
|
|
listHead = &ViIrpLogDatabase[SiloNumber].ListHead;
|
|
|
|
for(listEntry = listHead;
|
|
listEntry->Flink != listHead;
|
|
listEntry = listEntry->Flink) {
|
|
|
|
irpLogData = CONTAINING_RECORD(listEntry->Flink, IRPLOG_DATA, HashLink);
|
|
|
|
if (irpLogData->Flags & IRPLOG_FLAG_NAMELESS) {
|
|
|
|
continue;
|
|
}
|
|
|
|
#ifdef MAX_INSTANCE_COUNT
|
|
if (instances == MAX_INSTANCE_COUNT) {
|
|
|
|
break;
|
|
}
|
|
#endif
|
|
|
|
instances++;
|
|
|
|
if (irpLogData->Flags & IRPLOG_FLAG_FULL) {
|
|
|
|
elementCount = irpLogData->MaximumElementCount;
|
|
|
|
} else {
|
|
|
|
elementCount = irpLogData->Head;
|
|
}
|
|
|
|
if (ARGUMENT_PRESENT(OutputBuffer)) {
|
|
|
|
//
|
|
// Update the array of per-instance Offset/Length information
|
|
//
|
|
instanceLengthBuffer->OffsetInstanceData = totalDataSize;
|
|
|
|
instanceLengthBuffer->LengthInstanceData =
|
|
sizeof(ULONG)*2 + (elementCount * sizeof(IRPLOG_SNAPSHOT));
|
|
|
|
instanceLengthBuffer++;
|
|
|
|
//
|
|
// Write out the device type.
|
|
//
|
|
*((PULONG) instanceDataBuffer) = irpLogData->DeviceType;
|
|
instanceDataBuffer += sizeof(ULONG);
|
|
|
|
//
|
|
// Write out the instance data count
|
|
//
|
|
*((PULONG) instanceDataBuffer) = elementCount;
|
|
instanceDataBuffer += sizeof(ULONG);
|
|
|
|
//
|
|
// Don't bother with reordering the data appropriately. Also note
|
|
// that we have 8 byte alignment here - very important!!!
|
|
//
|
|
RtlCopyMemory(
|
|
instanceDataBuffer,
|
|
irpLogData->SnapshotArray,
|
|
elementCount * sizeof(IRPLOG_SNAPSHOT)
|
|
);
|
|
|
|
instanceDataBuffer += elementCount * sizeof(IRPLOG_SNAPSHOT);
|
|
}
|
|
|
|
totalDataSize += sizeof(ULONG)*2;
|
|
totalDataSize += elementCount * sizeof(IRPLOG_SNAPSHOT);
|
|
}
|
|
|
|
*OffsetInstanceNameOffsets = nameOffsetArrayOffset;
|
|
*InstanceCount = instances;
|
|
*DataBlockOffset = instanceDataOffset;
|
|
*TotalRequiredSize = totalDataSize;
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
VOID
|
|
VfIrpLogUnlockDatabase(
|
|
IN ULONG SiloNumber
|
|
)
|
|
{
|
|
KIRQL oldIrql;
|
|
PIRPLOG_DATA irpLogData;
|
|
PLIST_ENTRY listEntry, listHead;
|
|
|
|
ASSERT(SiloNumber < VI_IRPLOG_DATABASE_HASH_SIZE);
|
|
|
|
//
|
|
// Reenable logging to present devices
|
|
//
|
|
ViIrpLogDatabase[SiloNumber].Locked = FALSE;
|
|
|
|
//
|
|
// Clean up any lingering deleted device data
|
|
//
|
|
ExAcquireSpinLock(&ViIrpLogDatabaseLock, &oldIrql);
|
|
|
|
listHead = &ViIrpLogDatabase[SiloNumber].ListHead;
|
|
|
|
for(listEntry = listHead;
|
|
listEntry->Flink != listHead;
|
|
listEntry = listEntry->Flink) {
|
|
|
|
irpLogData = CONTAINING_RECORD(listEntry->Flink, IRPLOG_DATA, HashLink);
|
|
|
|
if (irpLogData->Flags & IRPLOG_FLAG_DELETED) {
|
|
|
|
ObDereferenceObject(irpLogData->DeviceObject);
|
|
RemoveEntryList(&irpLogData->HashLink);
|
|
ExFreePool(irpLogData);
|
|
}
|
|
}
|
|
|
|
ExReleaseSpinLock(&ViIrpLogDatabaseLock, oldIrql);
|
|
}
|
|
|
|
|
|
VOID
|
|
VfIrpLogDeleteDeviceLogs(
|
|
IN PDEVICE_OBJECT DeviceObject
|
|
)
|
|
{
|
|
PIRPLOG_DATA irpLogData;
|
|
PIRPLOG_HEAD hashHead;
|
|
KIRQL oldIrql;
|
|
|
|
ExAcquireSpinLock(&ViIrpLogDatabaseLock, &oldIrql);
|
|
|
|
irpLogData = ViIrpLogDatabaseFindPointer(DeviceObject, &hashHead);
|
|
|
|
if (irpLogData != NULL) {
|
|
|
|
if (!hashHead->Locked) {
|
|
|
|
ObDereferenceObject(irpLogData->DeviceObject);
|
|
RemoveEntryList(&irpLogData->HashLink);
|
|
|
|
ExFreePool(irpLogData);
|
|
|
|
} else {
|
|
|
|
irpLogData->Flags |= IRPLOG_FLAG_DELETED;
|
|
}
|
|
}
|
|
|
|
ExReleaseSpinLock(&ViIrpLogDatabaseLock, oldIrql);
|
|
}
|
|
|
|
|
|
|