Raw disk IO IRP_MJ_WRITE fails

Hi,
I’m new to this forum. I was trying to figure out a way to perform direct reads and writes to disk. I tried using the ZwXX functions as mentioned in http://www.osronline.com/showthread.cfm?link=178960 but found that ZwWriteFile fails with Access denied error because SL_FORCE_DIRECT_WRITE is not set and that could not be set unless I create my own IRP.
Then I tried out http://www.codeproject.com/Articles/28314/Reading-and-Writing-to-Raw-Disk-Sectors
But a similar problem is occurring for this approach as well. I’m getting back STATUS_INVALID_DEVICE_REQUEST.
I replaced the classpnp.sys and disk.sys drivers with the wdk example drivers to step through them. I found out that IoStatus is being set to this value in classpnp’s completion routine TransferPktComplete:
pkt->OriginalIrp->IoStatus.Status = Irp->IoStatus.Status;

Now, When I add a write access breakpoint on pkt->OriginalIrp->IoStatus.Status, I find that its being set in storport:

Breakpoint 16 hit
storport!RaUnitAsyncError+0x142:
83a127ea 0fb64703 movzx eax,byte ptr [edi+3]

0: kd> kp
ChildEBP RetAddr
8078aeec 83a12a65 storport!RaUnitAsyncError+0x142
8078af20 83a041d9 storport!RaidUnitCompleteRequest+0x101
8078af48 828733b5 storport!RaidpAdapterDpcRoutine+0x51
8078afa4 82873218 nt!KiExecuteAllDpcs+0xf9
8078aff4 828729dc nt!KiRetireDpcList+0xd5
8078aff8 903d3674 nt!KiDispatchInterrupt+0x2c
WARNING: Frame IP not in any known module. Following frames may be wrong.
828729dc 00000000 0x903d3674

Read is working for both the aproaches (Zwxx and IRP). In the IRP approach, I just changed it to include the SL_FORCE_DIRECT_WRITE flag:

IoCtl = pIsl->Parameters.DeviceIoControl.IoControlCode;
switch(IoCtl)
{
case IOCTL_GET_SECTOR_SIZE:

if (BuffSize >= sizeof(ULONG))
{
*(PULONG) pBuff = pDiskObj->ulSectorSize;
Irp->IoStatus.Information = sizeof(ULONG);
status = STATUS_SUCCESS;
}
else
status = STATUS_INFO_LENGTH_MISMATCH;

break;

case IOCTL_SECTOR_WRITE:
sprintf(fa, “BAASDFASDFASFESVDVDFSDFGDFGSDFGSDGSDFGDGSDFGSDFGSDFGSDFG”);
(ULONG) pBuff = ((ULONG) pBuff) + sizeof(DISK_LOCATION); // To accomodate the very ugly hack of transferring write
// information and input buffer into the same buffer
InputBuffLen = InputBuffLen + (pDiskObj->ulSectorSize); // Inputbufflen shud be DISK_LOCATION + sectorsize as we
// are recieving data in the same buffer
OutputBuffLen = 0; //Outputbufflen for write operations shud be zero
DbgPrint(“Inside DriverIoDeviceDispatchRoutine, called for write operation\n”);

send_write(pDiskObj->pDiskDevObj, pDiskLoc->ullSectorNum, pBuff, pDiskObj->ulSectorSize);
break;
case IOCTL_SECTOR_READ:

if (InputBuffLen > pIsl->Parameters.DeviceIoControl.InputBufferLength)
{
status = STATUS_INFO_LENGTH_MISMATCH;
goto end;
}
if (OutputBuffLen > pIsl->Parameters.DeviceIoControl.OutputBufferLength)
{
status = STATUS_INFO_LENGTH_MISMATCH;
goto end;
}

MajorFunc = (IoCtl==IOCTL_SECTOR_READ) ? IRP_MJ_READ : IRP_MJ_WRITE;

lDiskOffset.QuadPart = (pDiskObj->ulSectorSize) * (pDiskLoc->ullSectorNum);
KeInitializeEvent(&Event, NotificationEvent, FALSE);
pIrp = IoBuildSynchronousFsdRequest(MajorFunc, pDiskObj->pDiskDevObj, fa, // pBuff,
pDiskObj->ulSectorSize, &lDiskOffset,
&Event, &ioStatus);

if (!pIrp) {
status = STATUS_INSUFFICIENT_RESOURCES;
goto end;
}

if(IoCtl != IOCTL_SECTOR_READ) {
IrpSp = IoGetNextIrpStackLocation(pIrp);
IrpSp->Flags = IrpSp->Flags | SL_FORCE_DIRECT_WRITE;
}

status = IoCallDriver(pDiskObj->pDiskDevObj, pIrp);

if (status == STATUS_PENDING)
{
KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
status = ioStatus.Status;

if (NT_SUCCESS(status))
{
Irp->IoStatus.Information = pDiskObj->ulSectorSize;
}
}
break;
}

Am I missing something? Is it something to do with NotificationEvent? Do writes have to be asynchronous?

Hello,

One thing which maybe it’s because you supplied a code snippet only but
I don’t see how you can get into IOCTL_SECTOR_READ case for the case of
sending a write … The code you have in the IOCTL_SECTOR_READ for
handling a write appears to be correct, maybe you did not mean to
include the ‘break;’ at the end of the IOCTL_SECTOR_WRITE? But then what
is the call to send_write()?

Anyway, clean up the code and maybe the problem will be more evident.

Pete

On 8/31/2012 12:13 PM, xxxxx@gmail.com wrote:

IoCtl = pIsl->Parameters.DeviceIoControl.IoControlCode;
switch(IoCtl)
{
case IOCTL_GET_SECTOR_SIZE:

if (BuffSize >= sizeof(ULONG))
{
*(PULONG) pBuff = pDiskObj->ulSectorSize;
Irp->IoStatus.Information = sizeof(ULONG);
status = STATUS_SUCCESS;
}
else
status = STATUS_INFO_LENGTH_MISMATCH;

break;

case IOCTL_SECTOR_WRITE:
sprintf(fa, “BAASDFASDFASFESVDVDFSDFGDFGSDFGSDGSDFGDGSDFGSDFGSDFGSDFG”);
(ULONG) pBuff = ((ULONG) pBuff) + sizeof(DISK_LOCATION); // To accomodate the very ugly hack of transferring write
// information and input buffer into the same buffer
InputBuffLen = InputBuffLen + (pDiskObj->ulSectorSize); // Inputbufflen shud be DISK_LOCATION + sectorsize as we
// are recieving data in the same buffer
OutputBuffLen = 0; //Outputbufflen for write operations shud be zero
DbgPrint(“Inside DriverIoDeviceDispatchRoutine, called for write operation\n”);

send_write(pDiskObj->pDiskDevObj, pDiskLoc->ullSectorNum, pBuff, pDiskObj->ulSectorSize);
break;
case IOCTL_SECTOR_READ:

if (InputBuffLen > pIsl->Parameters.DeviceIoControl.InputBufferLength)
{
status = STATUS_INFO_LENGTH_MISMATCH;
goto end;
}
if (OutputBuffLen > pIsl->Parameters.DeviceIoControl.OutputBufferLength)
{
status = STATUS_INFO_LENGTH_MISMATCH;
goto end;
}

MajorFunc = (IoCtl==IOCTL_SECTOR_READ) ? IRP_MJ_READ : IRP_MJ_WRITE;

lDiskOffset.QuadPart = (pDiskObj->ulSectorSize) * (pDiskLoc->ullSectorNum);
KeInitializeEvent(&Event, NotificationEvent, FALSE);
pIrp = IoBuildSynchronousFsdRequest(MajorFunc, pDiskObj->pDiskDevObj, fa, // pBuff,
pDiskObj->ulSectorSize, &lDiskOffset,
&Event, &ioStatus);

if (!pIrp) {
status = STATUS_INSUFFICIENT_RESOURCES;
goto end;
}

if(IoCtl != IOCTL_SECTOR_READ) {
IrpSp = IoGetNextIrpStackLocation(pIrp);
IrpSp->Flags = IrpSp->Flags | SL_FORCE_DIRECT_WRITE;
}

status = IoCallDriver(pDiskObj->pDiskDevObj, pIrp);

if (status == STATUS_PENDING)
{
KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
status = ioStatus.Status;

if (NT_SUCCESS(status))
{
Irp->IoStatus.Information = pDiskObj->ulSectorSize;
}
}
break;
}

Am I missing something? Is it something to do with NotificationEvent? Do writes have to be asynchronous?


NTFSD is sponsored by OSR

For our schedule of debugging and file system 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


Kernel Drivers
Windows File System and Device Driver Consulting
www.KernelDrivers.com
866.263.9295