Reactos
at master 227 lines 5.6 kB view raw
1/* 2 * CSQ Test Driver 3 * Copyright (c) 2004, Vizzini (vizzini@plasmic.com) 4 * Released under the GNU GPL for the ReactOS project 5 * 6 * This driver is designed to exercise the cancel-safe IRP queue logic. 7 * Please refer to reactos/include/ddk/csq.h and reactos/drivers/lib/csq. 8 */ 9#include <ntddk.h> 10#include <csq.h> 11 12/* XXX shortcomings in our headers... */ 13#define assert(x) 14#ifndef KdPrint 15#define KdPrint(x) DbgPrint x 16#endif 17 18/* Device name */ 19#define NT_DEVICE_NAME L"\\Device\\csqtest" 20 21/* DosDevices name */ 22#define DOS_DEVICE_NAME L"\\??\\csqtest" 23 24/* Global CSQ struct that the CSQ functions init */ 25IO_CSQ Csq; 26 27/* List and lock for the actual IRP queue */ 28LIST_ENTRY IrpQueue; 29KSPIN_LOCK IrpQueueLock; 30 31/* Device object */ 32PDEVICE_OBJECT DeviceObject; 33 34/* 35 * CSQ Callbacks 36 */ 37VOID NTAPI CsqInsertIrp(PIO_CSQ Csq, PIRP Irp) 38{ 39 KdPrint(("Inserting IRP 0x%x into CSQ\n", Irp)); 40 InsertTailList(&IrpQueue, &Irp->Tail.Overlay.ListEntry); 41} 42 43VOID NTAPI CsqRemoveIrp(PIO_CSQ Csq, PIRP Irp) 44{ 45 KdPrint(("Removing IRP 0x%x from CSQ\n", Irp)); 46 RemoveEntryList(&Irp->Tail.Overlay.ListEntry); 47} 48 49PIRP NTAPI CsqPeekNextIrp(PIO_CSQ Csq, PIRP Irp, PVOID PeekContext) 50{ 51 KdPrint(("Peeking for next IRP\n")); 52 53 if(Irp) 54 return CONTAINING_RECORD(&Irp->Tail.Overlay.ListEntry.Flink, IRP, Tail.Overlay.ListEntry); 55 56 if(IsListEmpty(&IrpQueue)) 57 return NULL; 58 59 return CONTAINING_RECORD(IrpQueue.Flink, IRP, Tail.Overlay.ListEntry); 60} 61 62VOID NTAPI CsqAcquireLock(PIO_CSQ Csq, PKIRQL Irql) 63{ 64 KdPrint(("Acquiring spin lock\n")); 65 KeAcquireSpinLock(&IrpQueueLock, Irql); 66} 67 68VOID NTAPI CsqReleaseLock(PIO_CSQ Csq, KIRQL Irql) 69{ 70 KdPrint(("Releasing spin lock\n")); 71 KeReleaseSpinLock(&IrpQueueLock, Irql); 72} 73 74VOID NTAPI CsqCompleteCancelledIrp(PIO_CSQ Csq, PIRP Irp) 75{ 76 KdPrint(("cancelling irp 0x%x\n", Irp)); 77 Irp->IoStatus.Status = STATUS_CANCELLED; 78 Irp->IoStatus.Information = 0; 79 IoCompleteRequest(Irp, IO_NO_INCREMENT); 80} 81 82NTSTATUS NTAPI CsqInsertIrpEx(PIO_CSQ Csq, PIRP Irp, PVOID InsertContext) 83/* 84 * FUNCTION: Insert into IRP queue, with extra context 85 * 86 * NOTE: Switch call in DriverEntry to IoCsqInitializeEx to use this 87 */ 88{ 89 CsqInsertIrp(Csq, Irp); 90 return STATUS_PENDING; 91} 92 93/* 94 * DISPATCH ROUTINES 95 */ 96 97NTSTATUS NTAPI DispatchCreateCloseCleanup(PDEVICE_OBJECT DeviceObject, PIRP Irp) 98{ 99 PIO_STACK_LOCATION StackLocation = IoGetCurrentIrpStackLocation(Irp); 100 101 if(StackLocation->MajorFunction == IRP_MJ_CLEANUP) 102 { 103 /* flush the irp queue */ 104 PIRP CurrentIrp; 105 106 KdPrint(("csqtest: Cleanup received; flushing the IRP queue with cancel\n")); 107 108 while((CurrentIrp = IoCsqRemoveNextIrp(&Csq, 0))) 109 { 110 CurrentIrp->IoStatus.Status = STATUS_CANCELLED; 111 CurrentIrp->IoStatus.Information = 0; 112 113 IoCompleteRequest(CurrentIrp, IO_NO_INCREMENT); 114 } 115 } 116 117 Irp->IoStatus.Status = STATUS_SUCCESS; 118 Irp->IoStatus.Information = 0; 119 120 IoCompleteRequest(Irp, IO_NO_INCREMENT); 121 122 return STATUS_SUCCESS; 123} 124 125NTSTATUS NTAPI DispatchReadWrite(PDEVICE_OBJECT DeviceObject, PIRP Irp) 126{ 127 /* According to the cancel sample in the DDK, IoCsqInsertIrp() marks the irp pending */ 128 /* However, I think it's wrong. */ 129 IoMarkIrpPending(Irp); 130 IoCsqInsertIrp(&Csq, Irp, 0); 131 132 return STATUS_PENDING; 133} 134 135NTSTATUS NTAPI DispatchIoctl(PDEVICE_OBJECT DeviceObject, PIRP Irp) 136/* 137 * all IOCTL requests flush the irp queue 138 */ 139{ 140 PIRP CurrentIrp; 141 142 KdPrint(("csqtest: Ioctl received; flushing the IRP queue with success\n")); 143 144 while((CurrentIrp = IoCsqRemoveNextIrp(&Csq, 0))) 145 { 146 CurrentIrp->IoStatus.Status = STATUS_SUCCESS; 147 CurrentIrp->IoStatus.Information = 0; 148 149 IoCompleteRequest(CurrentIrp, IO_NO_INCREMENT); 150 } 151 152 Irp->IoStatus.Status = STATUS_SUCCESS; 153 Irp->IoStatus.Information = 0; 154 155 IoCompleteRequest(Irp, IO_NO_INCREMENT); 156 157 return STATUS_SUCCESS; 158} 159 160VOID NTAPI Unload(PDRIVER_OBJECT DriverObject) 161/* 162 * Function: called by the OS to release resources before unload 163 */ 164{ 165 UNICODE_STRING LinkName; 166 167 RtlInitUnicodeString(&LinkName, DOS_DEVICE_NAME); 168 169 IoDeleteSymbolicLink(&LinkName); 170 171 if(DeviceObject) 172 IoDeleteDevice(DeviceObject); 173} 174 175/* 176 * DriverEntry 177 */ 178 179NTSTATUS NTAPI DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath) 180{ 181 NTSTATUS Status; 182 UNICODE_STRING NtName; 183 UNICODE_STRING DosName; 184 185 DriverObject->MajorFunction[IRP_MJ_CREATE] = DispatchCreateCloseCleanup; 186 DriverObject->MajorFunction[IRP_MJ_CLOSE] = DispatchCreateCloseCleanup; 187 DriverObject->MajorFunction[IRP_MJ_CLEANUP] = DispatchCreateCloseCleanup; 188 DriverObject->MajorFunction[IRP_MJ_READ] = DispatchReadWrite; 189 DriverObject->MajorFunction[IRP_MJ_WRITE] = DispatchReadWrite; 190 DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = DispatchIoctl; 191 DriverObject->DriverUnload = Unload; 192 193 Status = IoCsqInitialize(&Csq, CsqInsertIrp, CsqRemoveIrp, CsqPeekNextIrp, 194 CsqAcquireLock, CsqReleaseLock, CsqCompleteCancelledIrp); 195 196 if(Status != STATUS_SUCCESS) 197 KdPrint(("csqtest: IoCsqInitialize failed: 0x%x\n", Status)); 198 else 199 KdPrint(("csqtest: IoCsqInitialize succeeded\n")); 200 201 InitializeListHead(&IrpQueue); 202 KeInitializeSpinLock(&IrpQueueLock); 203 204 /* Set up a device */ 205 RtlInitUnicodeString(&NtName, NT_DEVICE_NAME); 206 Status = IoCreateDevice(DriverObject, 0, &NtName, FILE_DEVICE_UNKNOWN, 0, 0, &DeviceObject); 207 208 if(!NT_SUCCESS(Status)) 209 { 210 KdPrint(("csqtest: Unable to create device: 0x%x\n", Status)); 211 return Status; 212 } 213 214 RtlInitUnicodeString(&DosName, DOS_DEVICE_NAME); 215 Status = IoCreateSymbolicLink(&DosName, &NtName); 216 217 if(!NT_SUCCESS(Status)) 218 { 219 KdPrint(("csqtest: Unable to create link: 0x%x\n", Status)); 220 return Status; 221 } 222 223 DeviceObject->Flags |= DO_BUFFERED_IO; 224 225 return STATUS_SUCCESS; 226} 227