3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: ntoskrnl/io/irp.c
8 * PROGRAMMERS: David Welch (welch@mcmail.com)
11 /* NOTES *******************************************************************
30 /* INCLUDES ****************************************************************/
34 #include <internal/debug.h>
36 /* GLOBALS *******************************************************************/
38 #define TAG_IRP TAG('I', 'R', 'P', ' ')
41 /* FUNCTIONS ****************************************************************/
48 IoForwardIrpSynchronously(
49 IN PDEVICE_OBJECT DeviceObject
,
63 * FUNCTION: Releases a caller allocated irp
76 IoGetRequestorProcessId(
89 IoGetRequestorSessionId(
95 return STATUS_NOT_IMPLEMENTED
;
104 IoIsValidNameGraftingBuffer(
106 IN PREPARSE_DATA_BUFFER ReparseBuffer
117 IoMakeAssociatedIrp(PIRP Irp
,
120 * FUNCTION: Allocates and initializes an irp to associated with a master irp
123 * StackSize = Number of stack locations to be allocated in the irp
124 * RETURNS: The irp allocated
125 * NOTE: The caller is responsible for incrementing
126 * Irp->AssociatedIrp.IrpCount.
131 /* Allocate the IRP */
132 AssocIrp
= IoAllocateIrp(StackSize
,FALSE
);
133 if (AssocIrp
== NULL
)
137 AssocIrp
->Flags
|= IRP_ASSOCIATED_IRP
;
140 AssocIrp
->Tail
.Overlay
.Thread
= Irp
->Tail
.Overlay
.Thread
;
143 AssocIrp
->AssociatedIrp
.MasterIrp
= Irp
;
153 IoInitializeIrp(PIRP Irp
,
157 * FUNCTION: Initalizes an irp allocated by the caller
159 * Irp = IRP to initalize
160 * PacketSize = Size in bytes of the IRP
161 * StackSize = Number of stack locations in the IRP
166 DPRINT("IoInitializeIrp(StackSize %x, Irp %x)\n",StackSize
, Irp
);
167 memset(Irp
, 0, PacketSize
);
168 Irp
->Size
= PacketSize
;
169 Irp
->StackCount
= StackSize
;
170 Irp
->CurrentLocation
= StackSize
;
171 InitializeListHead(&Irp
->ThreadListEntry
);
172 Irp
->Tail
.Overlay
.CurrentStackLocation
= (PIO_STACK_LOCATION
)(Irp
+ 1) + StackSize
;
173 DPRINT("Irp->Tail.Overlay.CurrentStackLocation %x\n", Irp
->Tail
.Overlay
.CurrentStackLocation
);
174 Irp
->ApcEnvironment
= KeGetCurrentThread()->ApcStateIndex
;
182 IofCallDriver(PDEVICE_OBJECT DeviceObject
,
185 * FUNCTION: Sends an IRP to the next lower driver
188 PDRIVER_OBJECT DriverObject
;
189 PIO_STACK_LOCATION Param
;
191 DPRINT("IofCallDriver(DeviceObject %x, Irp %x)\n",DeviceObject
,Irp
);
194 ASSERT(DeviceObject
);
196 DriverObject
= DeviceObject
->DriverObject
;
198 ASSERT(DriverObject
);
200 IoSetNextIrpStackLocation(Irp
);
201 Param
= IoGetCurrentIrpStackLocation(Irp
);
203 DPRINT("IrpSp 0x%X\n", Param
);
205 Param
->DeviceObject
= DeviceObject
;
207 DPRINT("MajorFunction %d\n", Param
->MajorFunction
);
208 DPRINT("DriverObject->MajorFunction[Param->MajorFunction] %x\n",
209 DriverObject
->MajorFunction
[Param
->MajorFunction
]);
211 return DriverObject
->MajorFunction
[Param
->MajorFunction
](DeviceObject
, Irp
);
222 IoCallDriver (PDEVICE_OBJECT DeviceObject
, PIRP Irp
)
224 return(IofCallDriver(DeviceObject
,
233 IoAllocateIrp(CCHAR StackSize
,
236 * FUNCTION: Allocates an IRP
238 * StackSize = the size of the stack required for the irp
239 * ChargeQuota = Charge allocation to current threads quota
240 * RETURNS: Irp allocated
246 DbgPrint("IoAllocateIrp(StackSize %d ChargeQuota %d)\n",
249 KeDumpStackFrames(0,8);
254 // Irp = ExAllocatePoolWithQuota(NonPagedPool,IoSizeOfIrp(StackSize));
255 Irp
= ExAllocatePoolWithTag(NonPagedPool
,
256 IoSizeOfIrp(StackSize
),
261 Irp
= ExAllocatePoolWithTag(NonPagedPool
,
262 IoSizeOfIrp(StackSize
),
271 RtlZeroMemory(Irp
, IoSizeOfIrp(StackSize
));
273 IoSizeOfIrp(StackSize
),
276 // DPRINT("Irp %x Irp->StackPtr %d\n", Irp, Irp->CurrentLocation);
281 #ifdef IoCompleteRequest
282 #undef IoCompleteRequest
288 IofCompleteRequest(PIRP Irp
,
291 * FUNCTION: Indicates the caller has finished all processing for a given
292 * I/O request and is returning the given IRP to the I/O manager
294 * Irp = Irp to be cancelled
295 * PriorityBoost = Increment by which to boost the priority of the
296 * thread making the request
301 PFILE_OBJECT OriginalFileObject
;
302 PDEVICE_OBJECT DeviceObject
;
305 PIO_STACK_LOCATION Stack
= (PIO_STACK_LOCATION
)(Irp
+ 1);
307 DPRINT("IoCompleteRequest(Irp %x, PriorityBoost %d) Event %x THread %x\n",
308 Irp
,PriorityBoost
, Irp
->UserEvent
, PsGetCurrentThread());
310 ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL
);
311 ASSERT(Irp
->CancelRoutine
== NULL
);
312 ASSERT(Irp
->IoStatus
.Status
!= STATUS_PENDING
);
314 Irp
->PendingReturned
= IoGetCurrentIrpStackLocation(Irp
)->Control
& SL_PENDING_RETURNED
;
317 * Run the completion routines.
320 for (i
=Irp
->CurrentLocation
;i
<(ULONG
)Irp
->StackCount
;i
++)
323 Completion routines expect the current irp stack location to be the same as when
324 IoSetCompletionRoutine was called to set them. A side effect is that completion
325 routines set by highest level drivers without their own stack location will receive
326 an invalid current stack location (at least it should be considered as invalid).
327 Since the DeviceObject argument passed is taken from the current stack, this value
328 is also invalid (NULL).
330 if (Irp
->CurrentLocation
< Irp
->StackCount
- 1)
332 IoSkipCurrentIrpStackLocation(Irp
);
333 DeviceObject
= IoGetCurrentIrpStackLocation(Irp
)->DeviceObject
;
340 if (Stack
[i
].CompletionRoutine
!= NULL
&&
341 ((NT_SUCCESS(Irp
->IoStatus
.Status
) && (Stack
[i
].Control
& SL_INVOKE_ON_SUCCESS
)) ||
342 (!NT_SUCCESS(Irp
->IoStatus
.Status
) && (Stack
[i
].Control
& SL_INVOKE_ON_ERROR
)) ||
343 (Irp
->Cancel
&& (Stack
[i
].Control
& SL_INVOKE_ON_CANCEL
))))
345 Status
= Stack
[i
].CompletionRoutine(DeviceObject
,
349 if (Status
== STATUS_MORE_PROCESSING_REQUIRED
)
355 if (IoGetCurrentIrpStackLocation(Irp
)->Control
& SL_PENDING_RETURNED
)
357 Irp
->PendingReturned
= TRUE
;
361 /* Windows NT File System Internals, page 165 */
362 if (Irp
->Flags
& IRP_ASSOCIATED_IRP
)
364 ULONG MasterIrpCount
;
365 PIRP MasterIrp
= Irp
->AssociatedIrp
.MasterIrp
;
367 MasterIrpCount
= InterlockedDecrement(&MasterIrp
->AssociatedIrp
.IrpCount
);
368 while ((Mdl
= Irp
->MdlAddress
))
370 Irp
->MdlAddress
= Mdl
->Next
;
374 if (MasterIrpCount
== 0)
376 IofCompleteRequest(MasterIrp
, IO_NO_INCREMENT
);
382 * Were done calling completion routines. Now do any cleanup that can be
383 * done in an arbitrarily context.
386 /* Windows NT File System Internals, page 165 */
387 if (Irp
->Flags
& (IRP_PAGING_IO
|IRP_CLOSE_OPERATION
))
390 * If MDL_IO_PAGE_READ is set, then the caller is responsible
391 * for deallocating of the mdl.
393 if (Irp
->Flags
& IRP_PAGING_IO
&&
395 !(Irp
->MdlAddress
->MdlFlags
& MDL_IO_PAGE_READ
))
398 if (Irp
->MdlAddress
->MdlFlags
& MDL_MAPPED_TO_SYSTEM_VA
)
400 MmUnmapLockedPages(Irp
->MdlAddress
->MappedSystemVa
, Irp
->MdlAddress
);
403 ExFreePool(Irp
->MdlAddress
);
408 *Irp
->UserIosb
= Irp
->IoStatus
;
413 KeSetEvent(Irp
->UserEvent
, PriorityBoost
, FALSE
);
416 /* io manager frees the irp for close operations */
417 // if (Irp->Flags & IRP_PAGING_IO)
429 I went through my old notes. You are correct and in most cases
430 IoCompleteRequest() will issue an MmUnlockPages() for each MDL in the IRP
431 chain. There are however few exceptions: one is MDLs for associated IRPs,
432 it's expected that those MDLs have been initialized with
433 IoBuildPartialMdl(). Another exception is PAGING_IO irps, the i/o completion
434 code doesn't do anything to MDLs of those IRPs.
441 for (Mdl
= Irp
->MdlAddress
; Mdl
; Mdl
= Mdl
->Next
)
444 * Undo the MmProbeAndLockPages. If MmGetSystemAddressForMdl was called
445 * on this mdl, this mapping (if any) is also undone by MmUnlockPages.
450 //Windows NT File System Internals, page 154
451 OriginalFileObject
= Irp
->Tail
.Overlay
.OriginalFileObject
;
453 if (Irp
->PendingReturned
|| KeGetCurrentIrql() == DISPATCH_LEVEL
)
457 DPRINT("Dispatching APC\n");
459 KeInitializeApc( &Irp
->Tail
.Apc
,
460 &Irp
->Tail
.Overlay
.Thread
->Tcb
,
462 IoSecondStageCompletion
,//kernel routine
464 (PKNORMAL_ROUTINE
) NULL
,
468 bStatus
= KeInsertQueueApc(&Irp
->Tail
.Apc
,
469 (PVOID
)OriginalFileObject
,
470 NULL
, // This is used for REPARSE stuff
473 if (bStatus
== FALSE
)
475 DPRINT1("Error queueing APC for thread. Thread has probably exited.\n");
478 DPRINT("Finished dispatching APC\n");
482 DPRINT("Calling IoSecondStageCompletion routine directly\n");
483 KeRaiseIrql(APC_LEVEL
, &oldIrql
);
484 IoSecondStageCompletion(&Irp
->Tail
.Apc
,NULL
,NULL
,(PVOID
)&OriginalFileObject
, NULL
);
485 KeLowerIrql(oldIrql
);
486 DPRINT("Finished completition routine\n");
495 IoCompleteRequest(PIRP Irp
,
498 IofCompleteRequest(Irp
, PriorityBoost
);
502 /**********************************************************************
504 * IoIsOperationSynchronous@4
507 * Check if the I/O operation associated with the given IRP
511 * Irp Packet to check.
514 * TRUE if Irp's operation is synchronous; otherwise FALSE.
519 IoIsOperationSynchronous(IN PIRP Irp
)
521 PFILE_OBJECT FileObject
= NULL
;
523 FileObject
= IoGetCurrentIrpStackLocation(Irp
)->FileObject
;
525 if (Irp
->Flags
& IRP_SYNCHRONOUS_PAGING_IO
)
530 if (Irp
->Flags
& IRP_PAGING_IO
)
535 //NOTE: Windows 2000 crash if IoStack->FileObject == NULL, so I guess we should too;-)
536 if (Irp
->Flags
& IRP_SYNCHRONOUS_API
|| FileObject
->Flags
& FO_SYNCHRONOUS_IO
)
541 /* Otherwise, it is an asynchronous operation. */
550 IoEnqueueIrp(IN PIRP Irp
)
552 IoQueueThreadIrp(Irp
);
560 IoSetTopLevelIrp(IN PIRP Irp
)
564 Thread
= PsGetCurrentThread();
565 Thread
->TopLevelIrp
= Irp
;
573 IoGetTopLevelIrp(VOID
)
575 return(PsGetCurrentThread()->TopLevelIrp
);
583 IoQueueThreadIrp(IN PIRP Irp
)
585 /* undefine this when (if ever) implementing irp cancellation */
589 oldIrql
= KfRaiseIrql(APC_LEVEL
);
591 /* Synchronous irp's are queued to requestor thread. If they are not completed
592 when the thread exits, they are canceled (cleaned up).
594 InsertTailList(&PsGetCurrentThread()->IrpList
, &Irp
->ThreadListEntry
);
596 KfLowerIrql(oldIrql
);
610 UCHAR AllocationFlags
;
612 /* Reference: Chris Cant's "Writing WDM Device Drivers" */
613 AllocationFlags
= Irp
->AllocationFlags
;
614 IoInitializeIrp(Irp
, Irp
->Size
, Irp
->StackCount
);
615 Irp
->IoStatus
.Status
= Status
;
616 Irp
->AllocationFlags
= AllocationFlags
;