1 /* $Id: irp.c,v 1.60 2004/04/20 23:14:35 gdalsnes Exp $
3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: ntoskrnl/io/irp.c
7 * PROGRAMMER: David Welch (welch@mcmail.com)
12 /* NOTES *******************************************************************
31 /* INCLUDES ****************************************************************/
33 #include <ddk/ntddk.h>
34 #include <internal/io.h>
35 #include <internal/ps.h>
36 #include <internal/pool.h>
39 #include <internal/debug.h>
41 /* GLOBALS *******************************************************************/
43 #define TAG_IRP TAG('I', 'R', 'P', ' ')
46 /* FUNCTIONS ****************************************************************/
55 * FUNCTION: Releases a caller allocated irp
68 IoMakeAssociatedIrp(PIRP Irp
,
71 * FUNCTION: Allocates and initializes an irp to associated with a master irp
74 * StackSize = Number of stack locations to be allocated in the irp
75 * RETURNS: The irp allocated
80 AssocIrp
= IoAllocateIrp(StackSize
,FALSE
);
90 IoInitializeIrp(PIRP Irp
,
94 * FUNCTION: Initalizes an irp allocated by the caller
96 * Irp = IRP to initalize
97 * PacketSize = Size in bytes of the IRP
98 * StackSize = Number of stack locations in the IRP
103 memset(Irp
, 0, PacketSize
);
104 Irp
->Size
= PacketSize
;
105 Irp
->StackCount
= StackSize
;
106 Irp
->CurrentLocation
= StackSize
;
107 InitializeListHead(&Irp
->ThreadListEntry
);
108 Irp
->Tail
.Overlay
.CurrentStackLocation
= &Irp
->Stack
[(ULONG
)StackSize
];
116 IofCallDriver(PDEVICE_OBJECT DeviceObject
,
119 * FUNCTION: Sends an IRP to the next lower driver
122 PDRIVER_OBJECT DriverObject
;
123 PIO_STACK_LOCATION Param
;
125 DPRINT("IofCallDriver(DeviceObject %x, Irp %x)\n",DeviceObject
,Irp
);
128 assert(DeviceObject
);
130 DriverObject
= DeviceObject
->DriverObject
;
132 assert(DriverObject
);
134 IoSetNextIrpStackLocation(Irp
);
135 Param
= IoGetCurrentIrpStackLocation(Irp
);
137 DPRINT("IrpSp 0x%X\n", Param
);
139 Param
->DeviceObject
= DeviceObject
;
141 DPRINT("MajorFunction %d\n", Param
->MajorFunction
);
142 DPRINT("DriverObject->MajorFunction[Param->MajorFunction] %x\n",
143 DriverObject
->MajorFunction
[Param
->MajorFunction
]);
145 return DriverObject
->MajorFunction
[Param
->MajorFunction
](DeviceObject
, Irp
);
154 IoCallDriver (PDEVICE_OBJECT DeviceObject
, PIRP Irp
)
156 return(IofCallDriver(DeviceObject
,
165 IoAllocateIrp(CCHAR StackSize
,
168 * FUNCTION: Allocates an IRP
170 * StackSize = the size of the stack required for the irp
171 * ChargeQuota = Charge allocation to current threads quota
172 * RETURNS: Irp allocated
178 DbgPrint("IoAllocateIrp(StackSize %d ChargeQuota %d)\n",
181 KeDumpStackFrames(0,8);
186 // Irp = ExAllocatePoolWithQuota(NonPagedPool,IoSizeOfIrp(StackSize));
187 Irp
= ExAllocatePoolWithTag(NonPagedPool
,
188 IoSizeOfIrp(StackSize
),
193 Irp
= ExAllocatePoolWithTag(NonPagedPool
,
194 IoSizeOfIrp(StackSize
),
203 RtlZeroMemory(Irp
, IoSizeOfIrp(StackSize
));
205 IoSizeOfIrp(StackSize
),
208 // DPRINT("Irp %x Irp->StackPtr %d\n", Irp, Irp->CurrentLocation);
218 IofCompleteRequest(PIRP Irp
,
221 * FUNCTION: Indicates the caller has finished all processing for a given
222 * I/O request and is returning the given IRP to the I/O manager
224 * Irp = Irp to be cancelled
225 * PriorityBoost = Increment by which to boost the priority of the
226 * thread making the request
231 PDEVICE_OBJECT DeviceObject
;
232 PFILE_OBJECT OriginalFileObject
;
236 DPRINT("IoCompleteRequest(Irp %x, PriorityBoost %d) Event %x THread %x\n",
237 Irp
,PriorityBoost
, Irp
->UserEvent
, PsGetCurrentThread());
239 assert(KeGetCurrentIrql() <= DISPATCH_LEVEL
);
240 assert(Irp
->CancelRoutine
== NULL
);
241 assert(Irp
->IoStatus
.Status
!= STATUS_PENDING
);
243 if (IoGetCurrentIrpStackLocation(Irp
)->Control
& SL_PENDING_RETURNED
)
245 Irp
->PendingReturned
= TRUE
;
248 for (i
=Irp
->CurrentLocation
;i
<(ULONG
)Irp
->StackCount
;i
++)
251 Completion routines expect the current irp stack location to be the same as when
252 IoSetCompletionRoutine was called to set them. A side effect is that completion
253 routines set by highest level drivers without their own stack location will receive
254 an invalid current stack location (at least it should be considered as invalid).
255 Since the DeviceObject argument passed is taken from the current stack, this value
256 is also invalid (NULL).
258 if (Irp
->CurrentLocation
< Irp
->StackCount
- 1)
260 IoSetPreviousIrpStackLocation(Irp
);
261 DeviceObject
= IoGetCurrentIrpStackLocation(Irp
)->DeviceObject
;
268 if (Irp
->Stack
[i
].CompletionRoutine
!= NULL
&&
269 ((NT_SUCCESS(Irp
->IoStatus
.Status
) && (Irp
->Stack
[i
].Control
& SL_INVOKE_ON_SUCCESS
)) ||
270 (!NT_SUCCESS(Irp
->IoStatus
.Status
) && (Irp
->Stack
[i
].Control
& SL_INVOKE_ON_ERROR
)) ||
271 (Irp
->Cancel
&& (Irp
->Stack
[i
].Control
& SL_INVOKE_ON_CANCEL
))))
273 Status
= Irp
->Stack
[i
].CompletionRoutine(DeviceObject
,
275 Irp
->Stack
[i
].Context
);
277 if (Status
== STATUS_MORE_PROCESSING_REQUIRED
)
283 if (IoGetCurrentIrpStackLocation(Irp
)->Control
& SL_PENDING_RETURNED
)
285 Irp
->PendingReturned
= TRUE
;
290 * Were done calling completion routines. Now do any cleanup that can be
291 * done in an arbitrarily context.
294 /* Windows NT File System Internals, page 165 */
295 if (Irp
->Flags
& (IRP_PAGING_IO
|IRP_CLOSE_OPERATION
))
297 if (Irp
->Flags
& IRP_PAGING_IO
)
300 * The mdl should be freed by the caller!
302 if (Irp
->MdlAddress
->MdlFlags
& MDL_MAPPED_TO_SYSTEM_VA
)
304 MmUnmapLockedPages(Irp
->MdlAddress
->MappedSystemVa
, Irp
->MdlAddress
);
307 ExFreePool(Irp
->MdlAddress
);
312 *Irp
->UserIosb
= Irp
->IoStatus
;
317 KeSetEvent(Irp
->UserEvent
, PriorityBoost
, FALSE
);
320 /* io manager frees the irp for close operations */
321 // if (Irp->Flags & IRP_PAGING_IO)
333 I went through my old notes. You are correct and in most cases
334 IoCompleteRequest() will issue an MmUnlockPages() for each MDL in the IRP
335 chain. There are however few exceptions: one is MDLs for associated IRPs,
336 it's expected that those MDLs have been initialized with
337 IoBuildPartialMdl(). Another exception is PAGING_IO irps, the i/o completion
338 code doesn't do anything to MDLs of those IRPs.
344 //Windows NT File System Internals, page 166/167
345 if (!(Irp
->Flags
& IRP_ASSOCIATED_IRP
))
347 for (Mdl
= Irp
->MdlAddress
; Mdl
; Mdl
= Mdl
->Next
)
350 * Undo the MmProbeAndLockPages. If MmGetSystemAddressForMdl was called
351 * on this mdl, this mapping (if any) is also undone by MmUnlockPages.
353 MmUnlockPages(Irp
->MdlAddress
);
357 //Windows NT File System Internals, page 154
358 OriginalFileObject
= Irp
->Tail
.Overlay
.OriginalFileObject
;
360 if (Irp
->PendingReturned
|| KeGetCurrentIrql() == DISPATCH_LEVEL
)
364 DPRINT("Dispatching APC\n");
365 KeInitializeApc( &Irp
->Tail
.Apc
,
366 &Irp
->Tail
.Overlay
.Thread
->Tcb
,
367 OriginalApcEnvironment
,
368 IoSecondStageCompletion
,//kernel routine
370 (PKNORMAL_ROUTINE
) NULL
,
374 bStatus
= KeInsertQueueApc(&Irp
->Tail
.Apc
,
376 (PVOID
)(ULONG
)PriorityBoost
,
379 if (bStatus
== FALSE
)
381 DPRINT1("Error queueing APC for thread. Thread has probably exited.\n");
384 DPRINT("Finished dispatching APC\n");
388 DPRINT("Calling IoSecondStageCompletion routine directly\n");
389 KeRaiseIrql(APC_LEVEL
, &oldIrql
);
390 IoSecondStageCompletion(NULL
,NULL
,(PVOID
)&OriginalFileObject
,(PVOID
) &Irp
,(PVOID
) &PriorityBoost
);
391 KeLowerIrql(oldIrql
);
392 DPRINT("Finished completition routine\n");
403 IoCompleteRequest(PIRP Irp
,
406 IofCompleteRequest(Irp
, PriorityBoost
);
410 /**********************************************************************
412 * IoIsOperationSynchronous@4
415 * Check if the I/O operation associated with the given IRP
419 * Irp Packet to check.
422 * TRUE if Irp's operation is synchronous; otherwise FALSE.
427 IoIsOperationSynchronous(IN PIRP Irp
)
429 PFILE_OBJECT FileObject
= NULL
;
431 FileObject
= IoGetCurrentIrpStackLocation(Irp
)->FileObject
;
433 if (Irp
->Flags
& IRP_SYNCHRONOUS_PAGING_IO
)
438 if (Irp
->Flags
& IRP_PAGING_IO
)
443 //NOTE: Windows 2000 crash if IoStack->FileObject == NULL, so I guess we should too;-)
444 if (Irp
->Flags
& IRP_SYNCHRONOUS_API
|| FileObject
->Flags
& FO_SYNCHRONOUS_IO
)
449 /* Otherwise, it is an asynchronous operation. */
458 IoEnqueueIrp(IN PIRP Irp
)
460 IoQueueThreadIrp(Irp
);
468 IoSetTopLevelIrp(IN PIRP Irp
)
472 Thread
= PsGetCurrentThread();
473 Thread
->TopLevelIrp
->TopLevelIrp
= Irp
;
481 IoGetTopLevelIrp(VOID
)
483 return(PsGetCurrentThread()->TopLevelIrp
->TopLevelIrp
);
491 IoQueueThreadIrp(IN PIRP Irp
)
493 /* undefine this when (if ever) implementing irp cancellation */
497 oldIrql
= KfRaiseIrql(APC_LEVEL
);
499 /* Synchronous irp's are queued to requestor thread. If they are not completed
500 when the thread exits, they are canceled (cleaned up).
502 InsertTailList(&PsGetCurrentThread()->IrpList
, &Irp
->ThreadListEntry
);
504 KfLowerIrql(oldIrql
);
518 UCHAR AllocationFlags
;
520 /* Reference: Chris Cant's "Writing WDM Device Drivers" */
521 AllocationFlags
= Irp
->AllocationFlags
;
522 IoInitializeIrp(Irp
, Irp
->Size
, Irp
->StackCount
);
523 Irp
->IoStatus
.Status
= Status
;
524 Irp
->AllocationFlags
= AllocationFlags
;