Irp splitting in filter driver;

I have a disk class upper filter where I'm splitting the incoming read/write IRPs to smaller size and forwarding the driver allocated secondary irps to the lower drivers. I observe the all my secondary irps passed with with success status and even the IoStatus.Information of all the secondary irps adds upto the original Irp's Parameters.Read.Length. But still I'm not able to boot. I see lots of irps being received by my driver and completed successfull but after some time I get a bug check with following message. It appears that somehow my driver is not returning the correct data even though they have completed successfully.

Any help or pointers. Below is the code snippet. Thanks.

UNMOUNTABLE_BOOT_VOLUME (ed)
The IO subsystem attempted to mount the boot volume and it failed.
Arguments:
Arg1: 85a66340, Device object of the boot volume
Arg2: c000014f, Status code from the filesystem on why it failed to mount the volume
Arg3: 00000000
Arg4: 00000000

Debugging Details:

DEFAULT_BUCKET_ID: VISTA_DRIVER_FAULT

BUGCHECK_STR: 0xED

PROCESS_NAME: System

CURRENT_IRQL: 0

LAST_CONTROL_TRANSFER: from 818d873f to 81881760

STACK_TEXT:
804043a4 818d873f 00000003 8040f8b4 00000000 nt!RtlpBreakWithStatusInstruction
804043f4 818d91ac 00000003 00000000 85a66340 nt!KiBugCheckDebugBreak+0x1c
804047a0 818d85c9 000000ed 85a66340 c000014f nt!KeBugCheck2+0x5f4
804047c4 81987b0b 000000ed 85a66340 c000014f nt!KeBugCheckEx+0x1e
8040483c 81827583 85a66340 844a4d00 00000000 nt!IopMountVolume+0x459
80404874 8199678a 844a4d20 804049b8 80404914 nt!IopCheckVpbMounted+0x64
80404938 819eef0d 85a66340 00000000 851c7800 nt!IopParseDevice+0x537
804049c8 819ec6b9 00000000 80404a20 00000040 nt!ObpLookupObjectName+0x615
80404a2c 819839e0 80404b08 00000000 00240000 nt!ObOpenObjectByName+0x13c
80404aa0 81b46a89 80404af4 c0000000 80404b08 nt!IopCreateFile+0x5ec
80404b20 81a3722c 8333b418 00000001 8333b3e8 nt!IopInitCrashDumpRegCallback+0xa2
80404b58 81a37641 00000007 80806d20 00000001 nt!RtlpCallQueryRegistryRoutine+0x201
80404bc4 81b46b0a 00000002 81b17f70 80404be4 nt!RtlQueryRegistryValues+0x31b
80404c24 81b44b3d 80806d20 8080fbe0 00000000 nt!IopInitCrashDumpDuringSysInit+0x50
80404c84 81b3ba32 80806d20 8443b198 8447dd78 nt!IoInitSystem+0x5da
80404d74 81933018 80404dc0 81a254a8 80806d20 nt!Phase1InitializationDiscard+0xba5
80404d7c 81a254a8 80806d20 8040f680 00000000 nt!Phase1Initialization+0xd
80404dc0 8189145e 8193300b 80806d20 00000000 nt!PspSystemThreadStartup+0x9d
00000000 00000000 00000000 00000000 00000000 nt!KiThreadStartup+0x16

/* get read/write buffer from the origianlIrp buffer
*
* B = new buffer
* OB = original Irp buffer
* L = new LBA
* OL = size original LBA
* S = LBA size
*/
#define GET_RW_BUFFER(B, OB, L, OL, S) B = (PCHAR)OB + ((L - OL) * S)

VOID MySplitRequest (PDEVICE_OBJECT DeviceObject,
PIRP OriginalIrp)
{
PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
PIO_STACK_LOCATION originalStack;
PVOID originalBuffer, buffer;
ULONG originalBeginLba, originalEndLba, originalCnt;
ULONG beginLba, endLba, cnt;

if (!OriginalIrp->MdlAddress) {
return;
}
originalBuffer = MmGetMdlVirtualAddress (OriginalIrp->MdlAddress);
originalStack = IoGetCurrentIrpStackLocation (OriginalIrp);

switch (stack->MajorFunction) {
case IRP_MJ_READ:
originalCnt = stack->Parameters.Read.Length / deviceExtension->BytesPerSector;
originalBeginLba = stack->Parameters.Read.ByteOffset.QuadPart / deviceExtension->BytesPerSector;
break;

case IRP_MJ_WRITE:
originalCnt = stack->Parameters.Write.Length / deviceExtension->BytesPerSector;
originalBeginLba = stack->Parameters.Write.ByteOffset.QuadPart / deviceExtension->BytesPerSector;
break;

default:
ASSERT (0);
}

originalEndLba = originalBeginLba + originalCnt;

/* set the irp status to success and change it if any of the secondary
* irps does not complete with STATUS_SUCCESS
*/
OriginalIrp->IoStatus.Status = STATUS_SUCCESS;
OriginalIrp->IoStatus.Information = 0;

OriginalIrp->Tail.Overlay.DriverContext[0] = ULongToPtr (0);

for (beginLba = originalBeginLba; beginLba < originalEndLba; beginLba += cnt) {
if ((originalEndLba - beginLba) > TRANSFER_SIZE) {
cnt = TRANSFER_SIZE;
}
else {
cnt = originalEndLba - beginLba;
}
GET_RW_BUFFER (buffer,
originalBuffer,
beginLba,
OriginalBeginLba,
deviceExtension->BytesPerSector);

status = MyMgmtBuildDiskIrp (DeviceObject,
DeviceObject,
stack->MajorFunction,
OriginalIrp,
buffer,
TRUE,
beginLba,
cnt,
&secIrpInfo);
if (NT_SUCCESS (status)) {
IoSetCompletionRoutine (secIrpInfo->Irp,
MySecIrpCompletion,
secIrpInfo,
TRUE,
TRUE,
TRUE);

IoCallDriver (deviceExtension->TargetDeviceObject, secIrpInfo->Irp);
/* count of secondary irps
*/
InterlockedIncrement ((PULONG)&(OriginalIrp->Tail.Overlay.DriverContext[0]));
}
}
}

NTSTATUS MyBuildDiskIrp (IN PDEVICE_OBJECT DeviceObject,
IN PDEVICE_OBJECT TargetDeviceObject,
IN UCHAR RequestCode,
IN PIRP OriginalIrp,
IN PVOID Buffer,
IN BOOLEAN PartialXfer,
IN ULONG LBA,
IN ULONG Count,
IN PMY_SEC_IRP_INFO SecIrpInfo)
{
NTSTATUS status = STATUS_SUCCESS;
PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
PIRP irp = NULL;
LARGE_INTEGER startingOffset;
ULONG numOfBytes;
PIO_STACK_LOCATION stack;
BOOLEAN freeBufferOnError = FALSE;
LOCK_OPERATION operation;

if (SecIrpInfo) {
*SecIrpInfo = NULL;
}

startingOffset.QuadPart = (LONGLONG)(LBA * deviceExtension->BytesPerSector);
numOfBytes = Count * deviceExtension->BytesPerSector;

switch (RequestCode) {
case IRP_MJ_WRITE:
ASSERT (Buffer != NULL);
operation = IoReadAccess;
break;

case IRP_MJ_READ:
if (!Buffer) {
Buffer = ExAllocatePool (NonPagedPool, numOfBytes);

if (!Buffer) {
status = STATUS_INSUFFICIENT_RESOURCES;
goto END;
}
freeBufferOnError = TRUE;
}
operation = IoWriteAccess;
break;

default:
ASSERT (0);
numOfBytes = 0;
startingOffset.QuadPart = 0;
operation = IoModifyAccess;
}

irp = IoAllocateIrp (TargetDeviceObject->StackSize, FALSE);
if (!irp) {
status = STATUS_INSUFFICIENT_RESOURCES;
goto END;
}
stack = IoGetNextIrpStackLocation (irp);
stack->MajorFunction = RequestCode;

switch (RequestCode) {
case IRP_MJ_WRITE:
stack->Parameters.Write.Length = numOfBytes;
stack->Parameters.Write.ByteOffset= startingOffset;
break;

case IRP_MJ_READ:
stack->Parameters.Read.Length = numOfBytes;
stack->Parameters.Read.ByteOffset= startingOffset;
break;

default:
ASSERT (0);
break;
}

ASSERT (TargetDeviceObject->Flags & DO_DIRECT_IO);
/* The target device supports direct I/O operations. Allocate
* an MDL large enough to map the buffer and lock the pages into
* memory.
*/
if (PartialXfer) {
irp->MdlAddress = IoAllocateMdl (NULL,
numOfBytes,
FALSE,
FALSE,
NULL);
if (!irp->MdlAddress) {
status = STATUS_INSUFFICIENT_RESOURCES;
goto END;
}
IoBuildPartialMdl (OriginalIrp->MdlAddress,
irp->MdlAddress,
Buffer,
numOfBytes);
}
else {
irp->MdlAddress = IoAllocateMdl (Buffer,
numOfBytes,
FALSE,
FALSE,
NULL);
if (!irp->MdlAddress) {
status = STATUS_INSUFFICIENT_RESOURCES;
goto END;
}

try {
MmProbeAndLockPages (irp->MdlAddress,
KernelMode,
(LOCK_OPERATION)operation);

}
except (EXCEPTION_EXECUTE_HANDLER) {
status = GetExceptionCode ();
goto END;
}
}
/* init secondary irp info if required
*/
if (SecIrpInfo) {
status = MyMgmtInitSecIrpInfo (irp,
OriginalIrp,
PartialXfer,
DeviceObject,
SecIrpInfo);
}

END:
if (!NT_SUCCESS (status)) {
// cleanup
}

return (status);
}

NTSTATUS MyMgmtSecIrpCompletion (IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PVOID Context)
{
PMY_SEC_IRP_INFO irpInfo = Context;
PIRP originalIrp = irpInfo->OriginalIrp;
PDEVICE_OBJECT diskDeviceObject = irpInfo->DiskDeviceObject;
PIO_STACK_LOCATION originalStack = IoGetCurrentIrpStackLocation (originalIrp);
PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation (Irp);
PVOID buffer;
ULONG numOfBytes;

ASSERT (PtrToUlong (originalIrp->Tail.Overlay.DriverContext[0]) > 0);
/* update the status of the OriginalIrp if the secondary Irp
* did not succeed
*/
if (!NT_SUCCESS (Irp->IoStatus.Status)) {
InterlockedExchange ((PLONG)&originalIrp->IoStatus.Status,
Irp->IoStatus.Status);
}
/* update the information (the bytes transferred count) from the
* secondary Irp to the OriginalIrp
*/
InterlockedExchangeAdd ((PLONG)&originalIrp->IoStatus.Information,
Irp->IoStatus.Information);

...
// cleanup for driver allocated irp
...

if (!InterlockedDecrement ((PULONG)&(originalIrp->Tail.Overlay.DriverContext[0]))) {
PDEVICE_EXTENSION deviceExtension = diskDeviceObject->DeviceExtension;
PIO_STACK_LOCATION originalStack = IoGetCurrentIrpStackLocation (originalIrp);

switch (originalStack->MajorFunction) {
case IRP_MJ_READ:
if (NT_SUCCESS (originalIrp->IoStatus.Status)) {
ASSERT (stack->Parameters.Read.Length == OriginalIrp->IoStatus.Information);
}
break;

case IRP_MJ_WRITE:
if (NT_SUCCESS (originalIrp->IoStatus.Status)) {
ASSERT (stack->Parameters.Write.Length == OriginalIrp->IoStatus.Information);
}
break;

default:
ASSERT (0);
break;
}
}

return (STATUS_MORE_PROCESSING_REQUIRED);
}

EDIT:

> ASSERT (stack->Parameters.Read.Length == OriginalIrp->IoStatus.Information);

ASSERT (originalStack->Parameters.Read.Length == OriginalIrp->IoStatus.Information);

I fixed this but still no luck:
irp->MdlAddress = IoAllocateMdl (MmGetMdlVirtualAddress (OriginalIrp->MdlAddress) /* NULL */,
/* MmGetMdlByteCount (OriginalIrp->MdlAddress) */ numOfBytes,
FALSE,
FALSE,
NULL);

Hmmmm… Well, looks like you’re failing on the very first I/O operation to the volume via your driver. In other words, the first I/O after the BIOS has finished doing its reads.

It’s not clear – at least to me – what your code is trying to do. The lack of useful comments makes it hard to interpret your intent.

What I *can* say is that the following:

looks awfully suspicious to me. Did you read the description of this function? This pointer (a) Can be zero, (b) Represents the requesters VA, which may be from an entirely different process context.

If you want the user data buffer mapped into the high half of kernel virtual address space, you need to call MmGetSystemAddressForMdlSafe

Peter
OSR

Hi Peter,
I was using MmGetMdlVirtualAddress instead of MmGetSystemAddressForMdlSafe as in the following two threads Maxim/Peter W suggested. But I have tried the latter also resulting in the same bug check.

http://www.osronline.com/showThread.cfm?link=107582
http://www.osronline.com/showThread.cfm?link=76349

Below is the code with more comments:

/* get read/write buffer from the origianlIrp buffer
*
* B = new buffer
* OB = original Irp buffer
* L = new LBA
* OL = size original LBA
* S = LBA size
*/
#define GET_RW_BUFFER(B, OB, L, OL, S) B = (PCHAR)OB + ((L - OL) * S)

VOID MySplitRequest (PDEVICE_OBJECT DeviceObject,
PIRP OriginalIrp)
{
PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
PIO_STACK_LOCATION originalStack;
PVOID originalBuffer, buffer;
ULONG originalBeginLba, originalEndLba, originalCnt;
ULONG beginLba, endLba, cnt;

if (!OriginalIrp->MdlAddress) {
return;
}
originalBuffer = MmGetMdlVirtualAddress (OriginalIrp->MdlAddress);
originalStack = IoGetCurrentIrpStackLocation (OriginalIrp);

/* get the LBA (logical block address) and LBA count
*/
switch (stack->MajorFunction) {
case IRP_MJ_READ:
originalCnt = stack->Parameters.Read.Length / deviceExtension->BytesPerSector;
originalBeginLba = stack->Parameters.Read.ByteOffset.QuadPart / deviceExtension->BytesPerSector;
break;

case IRP_MJ_WRITE:
originalCnt = stack->Parameters.Write.Length / deviceExtension->BytesPerSector;
originalBeginLba = stack->Parameters.Write.ByteOffset.QuadPart / deviceExtension->BytesPerSector;
break;

default:
ASSERT (0);
}

originalEndLba = originalBeginLba + originalCnt;

/* set the irp status to success and change it if any of the secondary
* irps does not complete with STATUS_SUCCESS
*/
OriginalIrp->IoStatus.Status = STATUS_SUCCESS;
OriginalIrp->IoStatus.Information = 0;

OriginalIrp->Tail.Overlay.DriverContext[0] = ULongToPtr (0);

/* build a small IRP to be sent to the disk. Each Irp will transfer
* maximum of TRANSFER_SIZE LBAs
*/
for (beginLba = originalBeginLba; beginLba < originalEndLba; beginLba += cnt) {
if ((originalEndLba - beginLba) > TRANSFER_SIZE) {
cnt = TRANSFER_SIZE;
}
else {
cnt = originalEndLba - beginLba;
}
/* get the offset in the OriginalIrp buffer
*/
GET_RW_BUFFER (buffer,
originalBuffer,
beginLba,
OriginalBeginLba,
deviceExtension->BytesPerSector);

/* now build the secondary irp describing the range [beginLba:beginLba+cnt-1]
*/
status = MyBuildDiskIrp (DeviceObject,
DeviceObject,
stack->MajorFunction,
OriginalIrp,
buffer,
TRUE,
beginLba,
cnt,
&secIrpInfo);
if (NT_SUCCESS (status)) {
IoSetCompletionRoutine (secIrpInfo->Irp,
MySecIrpCompletion,
secIrpInfo,
TRUE,
TRUE,
TRUE);

IoCallDriver (deviceExtension->TargetDeviceObject, secIrpInfo->Irp);
/* count of secondary Irps describing the OriginalIrp
*/
InterlockedIncrement ((PULONG)&(OriginalIrp->Tail.Overlay.DriverContext[0]));
}
}
}

NTSTATUS MyBuildDiskIrp (IN PDEVICE_OBJECT DeviceObject,
IN PDEVICE_OBJECT TargetDeviceObject,
IN UCHAR RequestCode,
IN PIRP OriginalIrp,
IN PVOID Buffer,
IN BOOLEAN PartialXfer,
IN ULONG LBA,
IN ULONG Count,
IN PMY_SEC_IRP_INFO SecIrpInfo)
{
NTSTATUS status = STATUS_SUCCESS;
PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
PIRP irp = NULL;
LARGE_INTEGER startingOffset;
ULONG numOfBytes;
PIO_STACK_LOCATION stack;
BOOLEAN freeBufferOnError = FALSE;
LOCK_OPERATION operation;

if (SecIrpInfo) {
*SecIrpInfo = NULL;
}
/* get the ByteOffset and Length
*/
startingOffset.QuadPart = (LONGLONG)(LBA * deviceExtension->BytesPerSector);
numOfBytes = Count * deviceExtension->BytesPerSector;

irp = IoAllocateIrp (TargetDeviceObject->StackSize, FALSE);
if (!irp) {
status = STATUS_INSUFFICIENT_RESOURCES;
goto END;
}
stack = IoGetNextIrpStackLocation (irp);
stack->MajorFunction = RequestCode;

switch (RequestCode) {
case IRP_MJ_WRITE:
stack->Parameters.Write.Length = numOfBytes;
stack->Parameters.Write.ByteOffset = startingOffset;
break;

case IRP_MJ_READ:
stack->Parameters.Read.Length = numOfBytes;
stack->Parameters.Read.ByteOffset = startingOffset;
break;

default:
ASSERT (0);
break;
}

ASSERT (TargetDeviceObject->Flags & DO_DIRECT_IO);
/* The target device supports direct I/O operations. Allocate
* an MDL large enough to map the buffer and lock the pages into
* memory.
*/
if (PartialXfer) {
irp->MdlAddress = IoAllocateMdl (MmGetMdlVirtualAddress (OriginalIrp->MdlAddress),
numOfBytes,
FALSE,
FALSE,
NULL);
if (!irp->MdlAddress) {
status = STATUS_INSUFFICIENT_RESOURCES;
goto END;
}
IoBuildPartialMdl (OriginalIrp->MdlAddress,
irp->MdlAddress,
Buffer,
numOfBytes);
}
/* init secondary irp info if required
* this will be used as context
*/
if (SecIrpInfo) {
status = MyInitSecIrpInfo (irp,
OriginalIrp,
PartialXfer,
DeviceObject,
SecIrpInfo);
}

END:
if (!NT_SUCCESS (status)) {
// cleanup
}

return (status);
}

NTSTATUS MySecIrpCompletion (IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PVOID Context)
{
PMY_SEC_IRP_INFO irpInfo = Context;
PIRP originalIrp = irpInfo->OriginalIrp;
PDEVICE_OBJECT diskDeviceObject = irpInfo->DiskDeviceObject;
PIO_STACK_LOCATION originalStack = IoGetCurrentIrpStackLocation (originalIrp);
PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation (Irp);
PVOID buffer;
ULONG numOfBytes;

ASSERT (PtrToUlong (originalIrp->Tail.Overlay.DriverContext[0]) > 0);
/* update the status of the OriginalIrp if the secondary Irp
* did not succeed
*/
if (!NT_SUCCESS (Irp->IoStatus.Status)) {
InterlockedExchange ((PLONG)&originalIrp->IoStatus.Status,
Irp->IoStatus.Status);
}
/* update the information (the bytes transferred count) from the
* secondary Irp to the OriginalIrp
*/
InterlockedExchangeAdd ((PLONG)&originalIrp->IoStatus.Information,
Irp->IoStatus.Information);


// cleanup for driver allocated irp

if (!InterlockedDecrement ((PULONG)&(originalIrp->Tail.Overlay.DriverContext[0]))) {
PDEVICE_EXTENSION deviceExtension = diskDeviceObject->DeviceExtension;
PIO_STACK_LOCATION originalStack = IoGetCurrentIrpStackLocation (originalIrp);

switch (originalStack->MajorFunction) {
case IRP_MJ_READ:
if (NT_SUCCESS (originalIrp->IoStatus.Status)) {
ASSERT (stack->Parameters.Read.Length == OriginalIrp->IoStatus.Information);
}
break;

case IRP_MJ_WRITE:
if (NT_SUCCESS (originalIrp->IoStatus.Status)) {
ASSERT (stack->Parameters.Write.Length == OriginalIrp->IoStatus.Information);
}
break;

default:
ASSERT (0);
break;
}
}

return (STATUS_MORE_PROCESSING_REQUIRED);
}

Posting code and asking what’s wrong with it is not something to do
too often, yes you’re stuck, but what about learning some debugging
techniques ? For things like this you can end up putting in tracing
on every other line to trace out all the values of the variables
until you understand what’s going on. It’s hard work but it’s not
rocket science and you’re kind of expected to do it.

Having said that, I’ve briefly browsed through the code posted and I
have my suspicions about:

if (PartialXfer) {
irp->MdlAddress = IoAllocateMdl (MmGetMdlVirtualAddress
(OriginalIrp->MdlAddress),
numOfBytes,
FALSE,
FALSE,
NULL);
if (!irp->MdlAddress) {
status = STATUS_INSUFFICIENT_RESOURCES;
goto END;
}
IoBuildPartialMdl (OriginalIrp->MdlAddress,
irp->MdlAddress,
Buffer,
numOfBytes);
}

The way this is coded every IRP you create has an MDL starting at the
same offset. Then when you build the partial MDL this results in
mapping only the first numOfBytes of the original IRP buffer space in
to the new IRP buffer. In effect if you split in to n IRPs, then you
send the same window of data to the disk n times. For a read, this
results in every read putting its data in the first TRANSFER_SIZE
bytes of the original buffer. For a write the result is the first
TRANSFER_SIZE bytes of the original buffer being written n times to the disk.

Just like you’ve moved the read/write offsets in the parameter stack
you need to do the same when mapping the buffer to your allocated IRP.

This matches what Peter says about you failing on your very first
I/O. Your first split I/O, which will probably be a read will
actually be garbage.

Even if the above is not quite correct, I think that’s where you
should look. But do yourself a favour, add all the tracing you need
to follow the changes in value of so many variables.

Mark.

At 07:57 27/08/2008, xxxxx@yahoo.com wrote:

Hi Peter,
I was using MmGetMdlVirtualAddress instead of
MmGetSystemAddressForMdlSafe as in the following two threads
Maxim/Peter W suggested. But I have tried the latter also resulting
in the same bug check.

http://www.osronline.com/showThread.cfm?link=107582
http://www.osronline.com/showThread.cfm?link=76349

Below is the code with more comments:

/* get read/write buffer from the origianlIrp buffer
*
* B = new buffer
* OB = original Irp buffer
* L = new LBA
* OL = size original LBA
* S = LBA size
*/
#define GET_RW_BUFFER(B, OB, L, OL, S) B = (PCHAR)OB + ((L - OL) * S)

VOID MySplitRequest (PDEVICE_OBJECT DeviceObject,
PIRP OriginalIrp)
{
PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
PIO_STACK_LOCATION originalStack;
PVOID originalBuffer, buffer;
ULONG originalBeginLba, originalEndLba, originalCnt;
ULONG beginLba, endLba, cnt;

if (!OriginalIrp->MdlAddress) {
return;
}
originalBuffer = MmGetMdlVirtualAddress (OriginalIrp->MdlAddress);
originalStack = IoGetCurrentIrpStackLocation (OriginalIrp);

/* get the LBA (logical block address) and LBA count
*/
switch (stack->MajorFunction) {
case IRP_MJ_READ:
originalCnt = stack->Parameters.Read.Length /
deviceExtension->BytesPerSector;
originalBeginLba = stack->Parameters.Read.ByteOffset.QuadPart /
deviceExtension->BytesPerSector;
break;

case IRP_MJ_WRITE:
originalCnt = stack->Parameters.Write.Length /
deviceExtension->BytesPerSector;
originalBeginLba = stack->Parameters.Write.ByteOffset.QuadPart
/ deviceExtension->BytesPerSector;
break;

default:
ASSERT (0);
}

originalEndLba = originalBeginLba + originalCnt;

/* set the irp status to success and change it if any of the secondary
* irps does not complete with STATUS_SUCCESS
*/
OriginalIrp->IoStatus.Status = STATUS_SUCCESS;
OriginalIrp->IoStatus.Information = 0;

OriginalIrp->Tail.Overlay.DriverContext[0] = ULongToPtr (0);

/* build a small IRP to be sent to the disk. Each Irp will transfer
* maximum of TRANSFER_SIZE LBAs
*/
for (beginLba = originalBeginLba; beginLba < originalEndLba;
beginLba += cnt) {
if ((originalEndLba - beginLba) > TRANSFER_SIZE) {
cnt = TRANSFER_SIZE;
}
else {
cnt = originalEndLba - beginLba;
}
/* get the offset in the OriginalIrp buffer
*/
GET_RW_BUFFER (buffer,
originalBuffer,
beginLba,
OriginalBeginLba,
deviceExtension->BytesPerSector);

/* now build the secondary irp describing the range
[beginLba:beginLba+cnt-1]
*/
status = MyBuildDiskIrp (DeviceObject,
DeviceObject,
stack->MajorFunction,
OriginalIrp,
buffer,
TRUE,
beginLba,
cnt,
&secIrpInfo);
if (NT_SUCCESS (status)) {
IoSetCompletionRoutine (secIrpInfo->Irp,
MySecIrpCompletion,
secIrpInfo,
TRUE,
TRUE,
TRUE);

IoCallDriver (deviceExtension->TargetDeviceObject, secIrpInfo->Irp);
/* count of secondary Irps describing the OriginalIrp
*/
InterlockedIncrement
((PULONG)&(OriginalIrp->Tail.Overlay.DriverContext[0]));
}
}
}

NTSTATUS MyBuildDiskIrp (IN PDEVICE_OBJECT DeviceObject,
IN PDEVICE_OBJECT TargetDeviceObject,
IN UCHAR RequestCode,
IN PIRP OriginalIrp,
IN PVOID Buffer,
IN BOOLEAN PartialXfer,
IN ULONG LBA,
IN ULONG Count,
IN PMY_SEC_IRP_INFO SecIrpInfo)
{
NTSTATUS status = STATUS_SUCCESS;
PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
PIRP irp = NULL;
LARGE_INTEGER startingOffset;
ULONG numOfBytes;
PIO_STACK_LOCATION stack;
BOOLEAN freeBufferOnError = FALSE;
LOCK_OPERATION operation;

if (SecIrpInfo) {
*SecIrpInfo = NULL;
}
/* get the ByteOffset and Length
*/
startingOffset.QuadPart = (LONGLONG)(LBA *
deviceExtension->BytesPerSector);
numOfBytes = Count * deviceExtension->BytesPerSector;

irp = IoAllocateIrp (TargetDeviceObject->StackSize, FALSE);
if (!irp) {
status = STATUS_INSUFFICIENT_RESOURCES;
goto END;
}
stack = IoGetNextIrpStackLocation (irp);
stack->MajorFunction = RequestCode;

switch (RequestCode) {
case IRP_MJ_WRITE:
stack->Parameters.Write.Length = numOfBytes;
stack->Parameters.Write.ByteOffset = startingOffset;
break;

case IRP_MJ_READ:
stack->Parameters.Read.Length = numOfBytes;
stack->Parameters.Read.ByteOffset = startingOffset;
break;

default:
ASSERT (0);
break;
}

ASSERT (TargetDeviceObject->Flags & DO_DIRECT_IO);
/* The target device supports direct I/O operations. Allocate
* an MDL large enough to map the buffer and lock the pages into
* memory.
*/
if (PartialXfer) {
irp->MdlAddress = IoAllocateMdl (MmGetMdlVirtualAddress
(OriginalIrp->MdlAddress),
numOfBytes,
FALSE,
FALSE,
NULL);
if (!irp->MdlAddress) {
status = STATUS_INSUFFICIENT_RESOURCES;
goto END;
}
IoBuildPartialMdl (OriginalIrp->MdlAddress,
irp->MdlAddress,
Buffer,
numOfBytes);
}
/* init secondary irp info if required
* this will be used as context
*/
if (SecIrpInfo) {
status = MyInitSecIrpInfo (irp,
OriginalIrp,
PartialXfer,
DeviceObject,
SecIrpInfo);
}

END:
if (!NT_SUCCESS (status)) {
// cleanup
}

return (status);
}

NTSTATUS MySecIrpCompletion (IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PVOID Context)
{
PMY_SEC_IRP_INFO irpInfo = Context;
PIRP originalIrp = irpInfo->OriginalIrp;
PDEVICE_OBJECT diskDeviceObject = irpInfo->DiskDeviceObject;
PIO_STACK_LOCATION originalStack =
IoGetCurrentIrpStackLocation (originalIrp);
PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation (Irp);
PVOID buffer;
ULONG numOfBytes;

ASSERT (PtrToUlong (originalIrp->Tail.Overlay.DriverContext[0]) > 0);
/* update the status of the OriginalIrp if the secondary Irp
* did not succeed
*/
if (!NT_SUCCESS (Irp->IoStatus.Status)) {
InterlockedExchange ((PLONG)&originalIrp->IoStatus.Status,
Irp->IoStatus.Status);
}
/* update the information (the bytes transferred count) from the
* secondary Irp to the OriginalIrp
*/
InterlockedExchangeAdd ((PLONG)&originalIrp->IoStatus.Information,
Irp->IoStatus.Information);


// cleanup for driver allocated irp

if (!InterlockedDecrement
((PULONG)&(originalIrp->Tail.Overlay.DriverContext[0]))) {
PDEVICE_EXTENSION deviceExtension = diskDeviceObject->DeviceExtension;
PIO_STACK_LOCATION originalStack = IoGetCurrentIrpStackLocation
(originalIrp);

switch (originalStack->MajorFunction) {
case IRP_MJ_READ:
if (NT_SUCCESS (originalIrp->IoStatus.Status)) {
ASSERT (stack->Parameters.Read.Length ==
OriginalIrp->IoStatus.Information);
}
break;

case IRP_MJ_WRITE:
if (NT_SUCCESS (originalIrp->IoStatus.Status)) {
ASSERT (stack->Parameters.Write.Length ==
OriginalIrp->IoStatus.Information);
}
break;

default:
ASSERT (0);
break;
}
}

return (STATUS_MORE_PROCESSING_REQUIRED);
}

Hi Edwards, thanks for your valuable comments and suggestions.

> Posting code and asking what’s wrong with it is not something to do too often,

last time I posted a question, experts asked me to post the code as it was easier to understand what I’m trying to do, so this time I pro-actively posted the code :slight_smile:

> yes you’re stuck, but what about learning some debugging techniques ? For things like this you can end up putting in tracing on every other line to trace out all the values of the variables until you understand what’s going on.

I have spent plenty of time going through the debugger and putting dbgprint statement at appropriate positions. the code posted is just the cleaned up part to avoid posting a long code snippet. When I couldn;t figure out what’s going on after spending days, I posted it here :-(.

Also as per your suggestions I changed the call to IoAllocateMdl (Buffer, …) as the Buffer is the offset inside the OriginalBuffer but still no luck. Actually with this change I was not expecting any new results as I don;t think it is required to pass the offset inside the OriginalBuffer to IoAllocaleMdl as we will be calling the IoBuildPartialMdl anyways later on. I have seen code in the WDK which just passes NULL to IoAllocateMdl (NULL, …) which precedes IoBuildPartialMdl (). I’m stuck at this point for almost a week and that’s why I posted the code while asking.

Since you filter is a disk class upper filter, why not take a look at the
disk class source code in DDK? I think you can do the same thing as the disk
class driver to split the I/O request.

On Wed, Aug 27, 2008 at 7:34 AM, wrote:

> Hi Edwards, thanks for your valuable comments and suggestions.
>
> >> Posting code and asking what’s wrong with it is not something to do too
> often,
>
> last time I posted a question, experts asked me to post the code as it was
> easier to understand what I’m trying to do, so this time I pro-actively
> posted the code :slight_smile:
>
> >> yes you’re stuck, but what about learning some debugging techniques ?
> For things like this you can end up putting in tracing on every other line
> to trace out all the values of the variables until you understand what’s
> going on.
>
> I have spent plenty of time going through the debugger and putting dbgprint
> statement at appropriate positions. the code posted is just the cleaned up
> part to avoid posting a long code snippet. When I couldn;t figure out what’s
> going on after spending days, I posted it here :-(.
>
> Also as per your suggestions I changed the call to IoAllocateMdl (Buffer,
> …) as the Buffer is the offset inside the OriginalBuffer but still no
> luck. Actually with this change I was not expecting any new results as I
> don;t think it is required to pass the offset inside the OriginalBuffer to
> IoAllocaleMdl as we will be calling the IoBuildPartialMdl anyways later on.
> I have seen code in the WDK which just passes NULL to IoAllocateMdl (NULL,
> …) which precedes IoBuildPartialMdl (). I’m stuck at this point for almost
> a week and that’s why I posted the code while asking.
>
> —
> NTDEV is sponsored by OSR
>
> For our schedule of WDF, WDM, debugging and other seminars visit:
> http://www.osr.com/seminars
>
> To unsubscribe, visit the List Server section of OSR Online at
> http://www.osronline.com/page.cfm?name=ListServer
>