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.
908 lines
24 KiB
908 lines
24 KiB
/*++
|
|
|
|
Copyright (c) 1999 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
sessnirp.c
|
|
|
|
Abstract:
|
|
|
|
I/O Verifier irp support routines.
|
|
|
|
Author:
|
|
|
|
Adrian Oney (adriao)
|
|
|
|
Environment:
|
|
|
|
Kernel mode
|
|
|
|
Revision History:
|
|
|
|
|
|
--*/
|
|
|
|
#include "iop.h"
|
|
#include "srb.h"
|
|
|
|
//
|
|
// This entire file is only present if NO_SPECIAL_IRP isn't defined
|
|
//
|
|
#ifndef NO_SPECIAL_IRP
|
|
|
|
//
|
|
// When enabled, everything is locked down on demand...
|
|
//
|
|
#ifdef ALLOC_PRAGMA
|
|
#pragma alloc_text(PAGEVRFY, IovpSessionDataCreate)
|
|
#pragma alloc_text(PAGEVRFY, IovpSessionDataAdvance)
|
|
#pragma alloc_text(PAGEVRFY, IovpSessionDataReference)
|
|
#pragma alloc_text(PAGEVRFY, IovpSessionDataDereference)
|
|
#pragma alloc_text(PAGEVRFY, IovpSessionDataClose)
|
|
#pragma alloc_text(PAGEVRFY, IovpSessionDataDeterminePolicy)
|
|
#pragma alloc_text(PAGEVRFY, IovpSessionDataAttachSurrogate)
|
|
#pragma alloc_text(PAGEVRFY, IovpSessionDataFinalizeSurrogate)
|
|
#pragma alloc_text(PAGEVRFY, IovpSessionDataBufferIO)
|
|
#pragma alloc_text(PAGEVRFY, IovpSessionDataUnbufferIO)
|
|
#endif
|
|
|
|
#define POOL_TAG_SESSION_DATA 'sprI'
|
|
#define POOL_TAG_DIRECT_BUFFER 'BprI'
|
|
|
|
PIOV_SESSION_DATA
|
|
FASTCALL
|
|
IovpSessionDataCreate(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN OUT PIOV_REQUEST_PACKET *IovPacketPointer,
|
|
OUT PBOOLEAN SurrogateSpawned
|
|
)
|
|
/*++
|
|
|
|
Description:
|
|
|
|
This routine creates tracking data for a new IRP. It must be called on the
|
|
thread the IRP was originally sent down...
|
|
|
|
Arguments:
|
|
|
|
Irp - Irp to track.
|
|
|
|
Return Value:
|
|
|
|
iovPacket block, NULL if no memory.
|
|
|
|
--*/
|
|
{
|
|
PIRP irp, surrogateIrp;
|
|
PIOV_SESSION_DATA iovSessionData;
|
|
PIOV_REQUEST_PACKET headPacket;
|
|
ULONG sessionDataSize;
|
|
BOOLEAN trackable, useSurrogateIrp;
|
|
|
|
*SurrogateSpawned = FALSE;
|
|
|
|
headPacket = (PIOV_REQUEST_PACKET) (*IovPacketPointer)->ChainHead;
|
|
ASSERT(headPacket == (*IovPacketPointer));
|
|
irp = headPacket->TrackedIrp;
|
|
|
|
//
|
|
// Check the IRP appropriately
|
|
//
|
|
IovpSessionDataDeterminePolicy(
|
|
headPacket,
|
|
DeviceObject,
|
|
&trackable,
|
|
&useSurrogateIrp
|
|
);
|
|
|
|
if (!trackable) {
|
|
|
|
return NULL;
|
|
}
|
|
|
|
//
|
|
// One extra stack location is allocated as the "zero'th" is used to
|
|
// simplify some logic...
|
|
//
|
|
sessionDataSize =
|
|
sizeof(IOV_SESSION_DATA)+
|
|
irp->StackCount*sizeof(IOV_STACK_LOCATION) +
|
|
VfSettingsGetSnapshotSize();
|
|
|
|
iovSessionData = ExAllocatePoolWithTag(
|
|
NonPagedPool,
|
|
sessionDataSize,
|
|
POOL_TAG_SESSION_DATA
|
|
);
|
|
|
|
if (iovSessionData == NULL) {
|
|
|
|
return NULL;
|
|
}
|
|
|
|
RtlZeroMemory(iovSessionData, sessionDataSize);
|
|
|
|
iovSessionData->VerifierSettings = (PVERIFIER_SETTINGS_SNAPSHOT)
|
|
(((PUCHAR) iovSessionData) + (sessionDataSize-VfSettingsGetSnapshotSize()));
|
|
|
|
RtlCopyMemory(
|
|
iovSessionData->VerifierSettings,
|
|
headPacket->VerifierSettings,
|
|
VfSettingsGetSnapshotSize()
|
|
);
|
|
|
|
iovSessionData->IovRequestPacket = headPacket;
|
|
InsertHeadList(&headPacket->SessionHead, &iovSessionData->SessionLink);
|
|
|
|
if (VfSettingsIsOptionEnabled(iovSessionData->VerifierSettings, VERIFIER_OPTION_DEFER_COMPLETION)||
|
|
VfSettingsIsOptionEnabled(iovSessionData->VerifierSettings, VERIFIER_OPTION_COMPLETE_AT_PASSIVE)) {
|
|
|
|
VfSettingsSetOption(iovSessionData->VerifierSettings, VERIFIER_OPTION_FORCE_PENDING, TRUE);
|
|
}
|
|
|
|
//
|
|
// If DeferIoCompletion is set we definitely want to monitor pending I/O, as
|
|
// screwing it up is gaurenteed to be fatal!
|
|
//
|
|
if ((irp->Flags & IRP_DEFER_IO_COMPLETION) &&
|
|
VfSettingsIsOptionEnabled(iovSessionData->VerifierSettings, VERIFIER_OPTION_POLICE_IRPS)) {
|
|
|
|
VfSettingsSetOption(iovSessionData->VerifierSettings, VERIFIER_OPTION_MONITOR_PENDING_IO, TRUE);
|
|
}
|
|
|
|
headPacket->pIovSessionData = iovSessionData;
|
|
headPacket->TopStackLocation = irp->CurrentLocation;
|
|
headPacket->Flags |= TRACKFLAG_ACTIVE;
|
|
headPacket->Flags &= ~
|
|
(
|
|
TRACKFLAG_QUEUED_INTERNALLY|
|
|
TRACKFLAG_RELEASED|
|
|
TRACKFLAG_SRB_MUNGED|
|
|
TRACKFLAG_SWAPPED_BACK
|
|
);
|
|
|
|
iovSessionData->BestVisibleIrp = irp;
|
|
if (useSurrogateIrp) {
|
|
|
|
//
|
|
// We will track the IRP using a surrogate.
|
|
//
|
|
*SurrogateSpawned = IovpSessionDataAttachSurrogate(
|
|
IovPacketPointer,
|
|
iovSessionData
|
|
);
|
|
}
|
|
|
|
TRACKIRP_DBGPRINT((
|
|
" SSN CREATE(%x)->%x\n",
|
|
headPacket,
|
|
iovSessionData
|
|
), 3);
|
|
|
|
return iovSessionData;
|
|
}
|
|
|
|
|
|
VOID
|
|
FASTCALL
|
|
IovpSessionDataAdvance(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIOV_SESSION_DATA IovSessionData,
|
|
IN OUT PIOV_REQUEST_PACKET *IovPacketPointer,
|
|
OUT PBOOLEAN SurrogateSpawned
|
|
)
|
|
{
|
|
*SurrogateSpawned = FALSE;
|
|
}
|
|
|
|
|
|
VOID
|
|
FASTCALL
|
|
IovpSessionDataDereference(
|
|
IN PIOV_SESSION_DATA IovSessionData
|
|
)
|
|
{
|
|
PIOV_REQUEST_PACKET iovPacket;
|
|
|
|
iovPacket = IovSessionData->IovRequestPacket;
|
|
ASSERT((PIOV_REQUEST_PACKET) iovPacket->ChainHead == iovPacket);
|
|
|
|
ASSERT_SPINLOCK_HELD(&iovPacket->HeaderLock);
|
|
ASSERT(IovSessionData->SessionRefCount > 0);
|
|
ASSERT(iovPacket->ReferenceCount >= 0);
|
|
|
|
TRACKIRP_DBGPRINT((
|
|
" SSN DEREF(%x) %x--\n",
|
|
IovSessionData,
|
|
IovSessionData->SessionRefCount
|
|
), 3);
|
|
|
|
IovSessionData->SessionRefCount--;
|
|
if (!IovSessionData->SessionRefCount) {
|
|
|
|
ASSERT(iovPacket->pIovSessionData != IovSessionData);
|
|
ASSERT(iovPacket->ReferenceCount > iovPacket->PointerCount);
|
|
//ASSERT(IsListEmpty(&IovSessionData->SessionLink));
|
|
RemoveEntryList(&IovSessionData->SessionLink);
|
|
InitializeListHead(&IovSessionData->SessionLink);
|
|
|
|
VfPacketDereference(iovPacket, IOVREFTYPE_PACKET);
|
|
|
|
ExFreePool(IovSessionData);
|
|
}
|
|
}
|
|
|
|
|
|
VOID
|
|
FASTCALL
|
|
IovpSessionDataReference(
|
|
IN PIOV_SESSION_DATA IovSessionData
|
|
)
|
|
{
|
|
PIOV_REQUEST_PACKET iovPacket;
|
|
|
|
iovPacket = IovSessionData->IovRequestPacket;
|
|
ASSERT((PIOV_REQUEST_PACKET) iovPacket->ChainHead == iovPacket);
|
|
|
|
ASSERT_SPINLOCK_HELD(&iovPacket->HeaderLock);
|
|
ASSERT(IovSessionData->SessionRefCount >= 0);
|
|
ASSERT(iovPacket->ReferenceCount >= 0);
|
|
|
|
TRACKIRP_DBGPRINT((
|
|
" SSN REF(%x) %x++\n",
|
|
IovSessionData,
|
|
IovSessionData->SessionRefCount
|
|
), 3);
|
|
|
|
if (!IovSessionData->SessionRefCount) {
|
|
|
|
VfPacketReference(iovPacket, IOVREFTYPE_PACKET);
|
|
}
|
|
IovSessionData->SessionRefCount++;
|
|
}
|
|
|
|
|
|
VOID
|
|
FASTCALL
|
|
IovpSessionDataClose(
|
|
IN PIOV_SESSION_DATA IovSessionData
|
|
)
|
|
{
|
|
PIOV_REQUEST_PACKET iovPacket = IovSessionData->IovRequestPacket;
|
|
|
|
ASSERT_SPINLOCK_HELD(&iovPacket->HeaderLock);
|
|
|
|
ASSERT(iovPacket == (PIOV_REQUEST_PACKET) iovPacket->ChainHead);
|
|
ASSERT(iovPacket->pIovSessionData == IovSessionData);
|
|
|
|
TRACKIRP_DBGPRINT((
|
|
" SSN CLOSE(%x)\n",
|
|
IovSessionData
|
|
), 3);
|
|
|
|
iovPacket->Flags &= ~TRACKFLAG_ACTIVE;
|
|
iovPacket->pIovSessionData = NULL;
|
|
}
|
|
|
|
|
|
VOID
|
|
IovpSessionDataDeterminePolicy(
|
|
IN PIOV_REQUEST_PACKET IovRequestPacket,
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
OUT PBOOLEAN Trackable,
|
|
OUT PBOOLEAN UseSurrogateIrp
|
|
)
|
|
/*++
|
|
|
|
Description:
|
|
|
|
This routine is called by IovpCallDriver1 to determine which IRPs should
|
|
be tracked and how that tracking should be done.
|
|
|
|
Arguments:
|
|
|
|
IovRequestPacket - Verifier data representing the incoming IRP
|
|
|
|
DeviceObject - Device object the IRP is being forwarded to
|
|
|
|
Trackable - Set if the IRP should be marked trackable
|
|
|
|
UseSurrogateIrp - Set a surrogate should be created for this IRP
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
PIO_STACK_LOCATION irpSp;
|
|
PIRP irp;
|
|
|
|
irp = IovRequestPacket->TrackedIrp;
|
|
|
|
//
|
|
// Determine whether we are to monitor this IRP. If we are going to test
|
|
// any one driver in a stack, then we must unfortunately monitor the IRP's
|
|
// progress through the *entire* stack. Thus our granularity here is stack
|
|
// based, not device based! We will compensate for this somewhat in the
|
|
// driver check code, which will attempt to ignore asserts from those
|
|
// "non-targetted" drivers who happen to have messed up in our stack...
|
|
//
|
|
*Trackable = IovUtilIsVerifiedDeviceStack(DeviceObject);
|
|
|
|
irpSp = IoGetNextIrpStackLocation(irp);
|
|
|
|
if (VfSettingsIsOptionEnabled(IovRequestPacket->VerifierSettings, VERIFIER_OPTION_POLICE_IRPS)) {
|
|
|
|
*UseSurrogateIrp = VfSettingsIsOptionEnabled(NULL, VERIFIER_OPTION_SURROGATE_IRPS);
|
|
*UseSurrogateIrp &= (VfSettingsIsOptionEnabled(NULL, VERIFIER_OPTION_SMASH_SRBS) ||
|
|
(irpSp->MajorFunction != IRP_MJ_SCSI));
|
|
} else {
|
|
|
|
*UseSurrogateIrp = FALSE;
|
|
}
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
FASTCALL
|
|
IovpSessionDataAttachSurrogate(
|
|
IN OUT PIOV_REQUEST_PACKET *IovPacketPointer,
|
|
IN PIOV_SESSION_DATA IovSessionData
|
|
)
|
|
/*++
|
|
|
|
Description:
|
|
|
|
This routine creates tracking data for a new IRP. It must be called on the
|
|
thread the IRP was originally sent down...
|
|
|
|
Arguments:
|
|
|
|
IovPacketPointer - Pointer to IRP packet to attach surrogate to. If
|
|
a surrogate can be attached the packet will be
|
|
updated to track the surrogate.
|
|
|
|
SurrogateIrp - Prepared surrogate IRP to attach.
|
|
|
|
Return Value:
|
|
|
|
iovPacket block, NULL if no memory.
|
|
|
|
--*/
|
|
{
|
|
|
|
PIOV_REQUEST_PACKET iovSurrogatePacket, iovPacket, headPacket;
|
|
PIRP surrogateIrp, irp;
|
|
PIO_STACK_LOCATION irpSp;
|
|
PSCSI_REQUEST_BLOCK srb;
|
|
CCHAR activeSize;
|
|
|
|
iovPacket = *IovPacketPointer;
|
|
ASSERT_SPINLOCK_HELD(&iovPacket->HeaderLock);
|
|
|
|
ASSERT(VfIrpDatabaseEntryGetChainNext((PIOV_DATABASE_HEADER) iovPacket) == NULL);
|
|
|
|
ASSERT(iovPacket->Flags & TRACKFLAG_ACTIVE);
|
|
|
|
irp = iovPacket->TrackedIrp;
|
|
activeSize = (irp->CurrentLocation-1);
|
|
ASSERT(activeSize);
|
|
|
|
//
|
|
// We now try to make a copy of this new IRP which we will track. We
|
|
// do this so that we may free *every* tracked IRP immediately upon
|
|
// completion.
|
|
// Technically speaking, we only need to allocate what's left of the
|
|
// stack, not the entire thing. But using the entire stack makes our
|
|
// work much much easier. Specifically the session stack array may depend
|
|
// on this.
|
|
//
|
|
// ADRIAO N.B. 03/04/1999 - Make this work only copying a portion of the
|
|
// IRP.
|
|
//
|
|
surrogateIrp = VfIrpAllocate(irp->StackCount); // activeSize
|
|
|
|
if (surrogateIrp == NULL) {
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Now set up the new IRP - we do this here so VfPacketCreateAndLock
|
|
// can peek at it's fields. Start with the IRP header.
|
|
//
|
|
RtlCopyMemory(surrogateIrp, irp, sizeof(IRP));
|
|
|
|
//
|
|
// Adjust StackCount and CurrentLocation
|
|
//
|
|
surrogateIrp->StackCount = irp->StackCount; // activeSize
|
|
surrogateIrp->Tail.Overlay.CurrentStackLocation =
|
|
((PIO_STACK_LOCATION) (surrogateIrp+1))+activeSize;
|
|
|
|
//
|
|
// Our new IRP "floats", and is not attached to any thread.
|
|
// Note that all cancels due to thread death will come through the
|
|
// original IRP.
|
|
//
|
|
InitializeListHead(&surrogateIrp->ThreadListEntry);
|
|
|
|
//
|
|
// Our new IRP also is not connected to user mode.
|
|
//
|
|
surrogateIrp->UserEvent = NULL;
|
|
surrogateIrp->UserIosb = NULL;
|
|
|
|
//
|
|
// Now copy over only the active portions of IRP. Be very careful to not
|
|
// assume that the last stack location is right after the end of the IRP,
|
|
// as we may change this someday!
|
|
//
|
|
irpSp = (IoGetCurrentIrpStackLocation(irp)-activeSize);
|
|
RtlCopyMemory(surrogateIrp+1, irpSp, sizeof(IO_STACK_LOCATION)*activeSize);
|
|
|
|
//
|
|
// Zero the portion of the new IRP we won't be using (this should
|
|
// eventually go away).
|
|
//
|
|
RtlZeroMemory(
|
|
((PIO_STACK_LOCATION) (surrogateIrp+1))+activeSize,
|
|
sizeof(IO_STACK_LOCATION)*(surrogateIrp->StackCount - activeSize)
|
|
);
|
|
|
|
//
|
|
// Now create a surrogate packet to track the new IRP.
|
|
//
|
|
iovSurrogatePacket = VfPacketCreateAndLock(surrogateIrp);
|
|
if (iovSurrogatePacket == NULL) {
|
|
|
|
VfIrpFree(surrogateIrp);
|
|
return FALSE;
|
|
}
|
|
|
|
headPacket = (PIOV_REQUEST_PACKET) iovPacket->ChainHead;
|
|
|
|
ASSERT(iovSurrogatePacket->LockIrql == DISPATCH_LEVEL);
|
|
irpSp = IoGetNextIrpStackLocation(irp);
|
|
|
|
//
|
|
// We will flag this bug later.
|
|
//
|
|
irp->CancelRoutine = NULL;
|
|
|
|
//
|
|
// Let's take advantage of the original IRP not being the thing partied on
|
|
// now; store a pointer to our tracking data in the information field. We
|
|
// don't use this, but it's nice when debugging...
|
|
//
|
|
irp->IoStatus.Information = (ULONG_PTR) iovPacket;
|
|
|
|
//
|
|
// ADRIAO N.B. #28 06/10/98 - This is absolutely *gross*, and not
|
|
// deterministic enough for my tastes.
|
|
//
|
|
// For IRP_MJ_SCSI (ie, IRP_MJ_INTERNAL_DEVICE_CONTROL), look and see
|
|
// if we have an SRB coming through. If so, fake out the OriginalRequest
|
|
// IRP pointer as appropriate.
|
|
//
|
|
if (irpSp->MajorFunction == IRP_MJ_SCSI) {
|
|
srb = irpSp->Parameters.Others.Argument1;
|
|
if (VfUtilIsMemoryRangeReadable(srb, SCSI_REQUEST_BLOCK_SIZE, VFMP_INSTANT_NONPAGED)) {
|
|
if ((srb->Length == SCSI_REQUEST_BLOCK_SIZE)&&(srb->OriginalRequest == irp)) {
|
|
srb->OriginalRequest = surrogateIrp;
|
|
headPacket->Flags |= TRACKFLAG_SRB_MUNGED;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Since the replacement will never make it back to user mode (the real
|
|
// IRP shall of course), we will steal a field or two for debugging info.
|
|
//
|
|
surrogateIrp->UserIosb = (PIO_STATUS_BLOCK) iovPacket;
|
|
|
|
//
|
|
// Now that everything is built correctly, attach the surrogate. The
|
|
// surrogate holds down the packet we are attaching to. When the surrogate
|
|
// dies we will remove this reference.
|
|
//
|
|
VfPacketReference(iovPacket, IOVREFTYPE_POINTER);
|
|
|
|
//
|
|
// Stamp IRPs appropriately.
|
|
//
|
|
surrogateIrp->Flags |= IRP_DIAG_IS_SURROGATE;
|
|
irp->Flags |= IRP_DIAG_HAS_SURROGATE;
|
|
|
|
//
|
|
// Mark packet as surrogate and inherit appropriate fields from iovPacket.
|
|
//
|
|
iovSurrogatePacket->Flags |= TRACKFLAG_SURROGATE | TRACKFLAG_ACTIVE;
|
|
iovSurrogatePacket->pIovSessionData = iovPacket->pIovSessionData;
|
|
|
|
RtlCopyMemory(
|
|
iovSurrogatePacket->VerifierSettings,
|
|
iovPacket->VerifierSettings,
|
|
VfSettingsGetSnapshotSize()
|
|
);
|
|
|
|
iovSurrogatePacket->LastLocation = iovPacket->LastLocation;
|
|
iovSurrogatePacket->TopStackLocation = irp->CurrentLocation;
|
|
|
|
iovSurrogatePacket->ArrivalIrql = iovPacket->ArrivalIrql;
|
|
iovSurrogatePacket->DepartureIrql = iovPacket->DepartureIrql;
|
|
|
|
iovPacket->Flags |= TRACKFLAG_HAS_SURROGATE;
|
|
|
|
//
|
|
// Link in the new surrogate
|
|
//
|
|
VfIrpDatabaseEntryAppendToChain(
|
|
(PIOV_DATABASE_HEADER) iovPacket,
|
|
(PIOV_DATABASE_HEADER) iovSurrogatePacket
|
|
);
|
|
|
|
*IovPacketPointer = iovSurrogatePacket;
|
|
|
|
IovpSessionDataBufferIO(
|
|
iovSurrogatePacket,
|
|
surrogateIrp
|
|
);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
VOID
|
|
FASTCALL
|
|
IovpSessionDataFinalizeSurrogate(
|
|
IN PIOV_SESSION_DATA IovSessionData,
|
|
IN OUT PIOV_REQUEST_PACKET IovPacket,
|
|
IN PIRP SurrogateIrp
|
|
)
|
|
/*++
|
|
|
|
Description:
|
|
|
|
This routine removes the flags from both the real and
|
|
surrogate IRP and records the final IRP settings. Finally,
|
|
the surrogate IRP is made "untouchable" (decommitted).
|
|
|
|
Arguments:
|
|
|
|
iovPacket - Pointer to the IRP tracking data.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
--*/
|
|
{
|
|
PIOV_REQUEST_PACKET iovPrevPacket;
|
|
NTSTATUS status, lockedStatus;
|
|
ULONG nonInterestingFlags;
|
|
PIO_STACK_LOCATION irpSp;
|
|
PIRP irp;
|
|
|
|
ASSERT(IovPacket->Flags&TRACKFLAG_SURROGATE);
|
|
|
|
ASSERT(VfPacketGetCurrentSessionData(IovPacket) == IovSessionData);
|
|
|
|
IovPacket->pIovSessionData = NULL;
|
|
|
|
//
|
|
// It's a surrogate, do as appropriate.
|
|
//
|
|
ASSERT(IovPacket->TopStackLocation == SurrogateIrp->CurrentLocation+1);
|
|
|
|
IovpSessionDataUnbufferIO(IovPacket, SurrogateIrp);
|
|
|
|
iovPrevPacket = (PIOV_REQUEST_PACKET) VfIrpDatabaseEntryGetChainPrevious(
|
|
(PIOV_DATABASE_HEADER) IovPacket
|
|
);
|
|
|
|
irp = iovPrevPacket->TrackedIrp;
|
|
|
|
//
|
|
// Carry the pending bit over.
|
|
//
|
|
if (SurrogateIrp->PendingReturned) {
|
|
IoMarkIrpPending(irp);
|
|
}
|
|
|
|
nonInterestingFlags = (
|
|
IRPFLAG_EXAMINE_MASK |
|
|
IRP_DIAG_IS_SURROGATE|
|
|
IRP_DIAG_HAS_SURROGATE
|
|
);
|
|
|
|
//
|
|
// Wipe the flags nice and clean
|
|
//
|
|
SurrogateIrp->Flags &= ~IRP_DIAG_IS_SURROGATE;
|
|
irp->Flags &= ~IRP_DIAG_HAS_SURROGATE;
|
|
|
|
//
|
|
// ASSERT portions of the IRP header have not changed.
|
|
//
|
|
ASSERT(irp->StackCount == SurrogateIrp->StackCount); // Later to be removed
|
|
|
|
ASSERT(irp->Type == SurrogateIrp->Type);
|
|
ASSERT(irp->RequestorMode == SurrogateIrp->RequestorMode);
|
|
ASSERT(irp->ApcEnvironment == SurrogateIrp->ApcEnvironment);
|
|
ASSERT(irp->AllocationFlags == SurrogateIrp->AllocationFlags);
|
|
ASSERT(irp->Tail.Overlay.Thread == SurrogateIrp->Tail.Overlay.Thread);
|
|
|
|
ASSERT(
|
|
irp->Overlay.AsynchronousParameters.UserApcRoutine ==
|
|
SurrogateIrp->Overlay.AsynchronousParameters.UserApcRoutine
|
|
);
|
|
|
|
ASSERT(
|
|
irp->Overlay.AsynchronousParameters.UserApcContext ==
|
|
SurrogateIrp->Overlay.AsynchronousParameters.UserApcContext
|
|
);
|
|
|
|
ASSERT(
|
|
irp->Tail.Overlay.OriginalFileObject ==
|
|
SurrogateIrp->Tail.Overlay.OriginalFileObject
|
|
);
|
|
|
|
ASSERT(
|
|
irp->Tail.Overlay.AuxiliaryBuffer ==
|
|
SurrogateIrp->Tail.Overlay.AuxiliaryBuffer
|
|
);
|
|
|
|
/*
|
|
ASSERT(
|
|
irp->AssociatedIrp.SystemBuffer ==
|
|
SurrogateIrp->AssociatedIrp.SystemBuffer
|
|
);
|
|
|
|
ASSERT(
|
|
(irp->Flags & ~nonInterestingFlags) ==
|
|
(SurrogateIrp->Flags & ~nonInterestingFlags)
|
|
);
|
|
|
|
ASSERT(irp->MdlAddress == SurrogateIrp->MdlAddress);
|
|
*/
|
|
//
|
|
// ADRIAO N.B. 02/28/1999 -
|
|
// How do these change as an IRP progresses?
|
|
//
|
|
irp->Flags |= SurrogateIrp->Flags;
|
|
irp->MdlAddress = SurrogateIrp->MdlAddress;
|
|
irp->AssociatedIrp.SystemBuffer = SurrogateIrp->AssociatedIrp.SystemBuffer;
|
|
|
|
//
|
|
// ADRIAO N.B. 10/18/1999 - UserBuffer is edited by netbios on Type3 device
|
|
// ioctls. Yuck!
|
|
//
|
|
irp->UserBuffer = SurrogateIrp->UserBuffer;
|
|
|
|
if ((irp->Flags&IRP_DEALLOCATE_BUFFER)&&
|
|
(irp->AssociatedIrp.SystemBuffer == NULL)) {
|
|
|
|
irp->Flags &= ~IRP_DEALLOCATE_BUFFER;
|
|
}
|
|
|
|
//
|
|
// Copy the salient fields back. We only need to touch certain areas of the
|
|
// header.
|
|
//
|
|
irp->IoStatus = SurrogateIrp->IoStatus;
|
|
irp->PendingReturned = SurrogateIrp->PendingReturned;
|
|
irp->Cancel = SurrogateIrp->Cancel;
|
|
|
|
iovPrevPacket->Flags &= ~TRACKFLAG_HAS_SURROGATE;
|
|
|
|
//
|
|
// Record data from it and make the system fault if the IRP is touched
|
|
// after this completion routine.
|
|
//
|
|
IovSessionData->BestVisibleIrp = irp;
|
|
|
|
IovSessionData->IovRequestPacket = iovPrevPacket;
|
|
|
|
VfIrpDatabaseEntryRemoveFromChain((PIOV_DATABASE_HEADER) IovPacket);
|
|
|
|
VfPacketDereference(iovPrevPacket, IOVREFTYPE_POINTER);
|
|
|
|
ASSERT(IovPacket->PointerCount == 0);
|
|
|
|
VfIrpFree(SurrogateIrp);
|
|
}
|
|
|
|
|
|
VOID
|
|
FASTCALL
|
|
IovpSessionDataBufferIO(
|
|
IN OUT PIOV_REQUEST_PACKET IovSurrogatePacket,
|
|
IN PIRP SurrogateIrp
|
|
)
|
|
{
|
|
PMDL mdl;
|
|
ULONG bufferLength;
|
|
PUCHAR bufferVA, systemDestVA;
|
|
PVOID systemBuffer;
|
|
PIO_STACK_LOCATION irpSp;
|
|
|
|
if (!VfSettingsIsOptionEnabled(IovSurrogatePacket->VerifierSettings, VERIFIER_OPTION_BUFFER_DIRECT_IO)) {
|
|
|
|
return;
|
|
}
|
|
|
|
if (SurrogateIrp->Flags & IRP_PAGING_IO) {
|
|
|
|
return;
|
|
}
|
|
|
|
if (SurrogateIrp->MdlAddress == NULL) {
|
|
|
|
return;
|
|
}
|
|
|
|
if (SurrogateIrp->MdlAddress->Next) {
|
|
|
|
return;
|
|
}
|
|
|
|
if (SurrogateIrp->Flags & IRP_BUFFERED_IO) {
|
|
|
|
return;
|
|
}
|
|
|
|
irpSp = IoGetNextIrpStackLocation(SurrogateIrp);
|
|
|
|
if (irpSp->MajorFunction != IRP_MJ_READ) {
|
|
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Extract length and VA from the MDL.
|
|
//
|
|
bufferLength = SurrogateIrp->MdlAddress->ByteCount;
|
|
bufferVA = (PUCHAR) SurrogateIrp->MdlAddress->StartVa +
|
|
SurrogateIrp->MdlAddress->ByteOffset;
|
|
|
|
//
|
|
// Allocate memory and make it the target of the MDL
|
|
//
|
|
systemBuffer = ExAllocatePoolWithTagPriority(
|
|
NonPagedPool,
|
|
bufferLength,
|
|
POOL_TAG_DIRECT_BUFFER,
|
|
HighPoolPrioritySpecialPoolOverrun
|
|
);
|
|
|
|
if (systemBuffer == NULL) {
|
|
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Save off a pointer to the Mdl's buffer. This should never fail, but
|
|
// one never knows...
|
|
//
|
|
systemDestVA =
|
|
MmGetSystemAddressForMdlSafe(SurrogateIrp->MdlAddress, HighPagePriority);
|
|
|
|
if (systemDestVA == NULL) {
|
|
|
|
ASSERT(0);
|
|
ExFreePool(systemBuffer);
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Allocate a MDL, update the IRP.
|
|
//
|
|
mdl = IoAllocateMdl(
|
|
systemBuffer,
|
|
bufferLength,
|
|
FALSE,
|
|
TRUE,
|
|
SurrogateIrp
|
|
);
|
|
|
|
if (mdl == NULL) {
|
|
|
|
ExFreePool(systemBuffer);
|
|
return;
|
|
}
|
|
|
|
MmProbeAndLockPages( mdl, KernelMode, IoWriteAccess );
|
|
IovSurrogatePacket->SystemDestVA = systemDestVA;
|
|
IovSurrogatePacket->Flags |= TRACKFLAG_DIRECT_BUFFERED;
|
|
}
|
|
|
|
|
|
VOID
|
|
FASTCALL
|
|
IovpSessionDataUnbufferIO(
|
|
IN OUT PIOV_REQUEST_PACKET IovSurrogatePacket,
|
|
IN PIRP SurrogateIrp
|
|
)
|
|
{
|
|
PMDL mdl;
|
|
ULONG surrogateLength, originalLength;
|
|
ULONG_PTR bufferLength;
|
|
PUCHAR surrogateVA, originalVA, systemDestVA;
|
|
PVOID systemBuffer;
|
|
PIOV_REQUEST_PACKET iovPrevPacket;
|
|
PIRP irp;
|
|
|
|
if (!(IovSurrogatePacket->Flags & TRACKFLAG_DIRECT_BUFFERED)) {
|
|
|
|
return;
|
|
}
|
|
|
|
iovPrevPacket = (PIOV_REQUEST_PACKET) VfIrpDatabaseEntryGetChainPrevious(
|
|
(PIOV_DATABASE_HEADER) IovSurrogatePacket
|
|
);
|
|
|
|
irp = iovPrevPacket->TrackedIrp;
|
|
|
|
ASSERT(SurrogateIrp->MdlAddress);
|
|
ASSERT(SurrogateIrp->MdlAddress->Next == NULL);
|
|
ASSERT(irp->MdlAddress);
|
|
ASSERT(irp->MdlAddress->Next == NULL);
|
|
ASSERT(!(SurrogateIrp->Flags & IRP_BUFFERED_IO));
|
|
ASSERT(!(irp->Flags & IRP_BUFFERED_IO));
|
|
|
|
//
|
|
// Extract length and VA from the MDLs.
|
|
//
|
|
surrogateLength = SurrogateIrp->MdlAddress->ByteCount;
|
|
surrogateVA = (PUCHAR) SurrogateIrp->MdlAddress->StartVa +
|
|
SurrogateIrp->MdlAddress->ByteOffset;
|
|
|
|
//
|
|
// We use these only for the purpose of assertions.
|
|
//
|
|
originalLength = irp->MdlAddress->ByteCount;
|
|
originalVA = (PUCHAR) irp->MdlAddress->StartVa +
|
|
irp->MdlAddress->ByteOffset;
|
|
|
|
ASSERT(surrogateLength == originalLength);
|
|
ASSERT(SurrogateIrp->IoStatus.Information <= originalLength);
|
|
|
|
//
|
|
// Get the target buffer address and the length to write.
|
|
//
|
|
bufferLength = SurrogateIrp->IoStatus.Information;
|
|
systemDestVA = IovSurrogatePacket->SystemDestVA;
|
|
|
|
//
|
|
// Copy things over.
|
|
//
|
|
RtlCopyMemory(systemDestVA, surrogateVA, bufferLength);
|
|
|
|
//
|
|
// Unlock the MDL. We have to do this ourselves as this IRP is not going to
|
|
// progress through all of IoCompleteRequest.
|
|
//
|
|
MmUnlockPages(SurrogateIrp->MdlAddress);
|
|
|
|
//
|
|
// Cleanup.
|
|
//
|
|
IoFreeMdl(SurrogateIrp->MdlAddress);
|
|
|
|
//
|
|
// Free our allocated VA
|
|
//
|
|
ExFreePool(surrogateVA);
|
|
|
|
//
|
|
// Hack the MDL back as IovpSessionDataFinalizeSurrogate requires it.
|
|
//
|
|
SurrogateIrp->MdlAddress = irp->MdlAddress;
|
|
|
|
IovSurrogatePacket->Flags &= ~TRACKFLAG_DIRECT_BUFFERED;
|
|
}
|
|
|
|
#endif // NO_SPECIAL_IRP
|
|
|