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);
}