1 /* $Id: irp.c,v 1.68 2004/10/22 20:25:53 ekohl 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 ****************************************************************/
35 #include <internal/debug.h>
37 /* GLOBALS *******************************************************************/
39 #define TAG_IRP TAG('I', 'R', 'P', ' ')
42 /* FUNCTIONS ****************************************************************/
49 IoForwardIrpSynchronously(
50 IN PDEVICE_OBJECT DeviceObject
,
64 * FUNCTION: Releases a caller allocated irp
77 IoGetRequestorProcessId(
90 IoGetRequestorSessionId(
96 return STATUS_NOT_IMPLEMENTED
;
105 IoIsValidNameGraftingBuffer(
107 IN PREPARSE_DATA_BUFFER ReparseBuffer
118 IoMakeAssociatedIrp(PIRP Irp
,
121 * FUNCTION: Allocates and initializes an irp to associated with a master irp
124 * StackSize = Number of stack locations to be allocated in the irp
125 * RETURNS: The irp allocated
126 * NOTE: The caller is responsible for incrementing
127 * Irp->AssociatedIrp.IrpCount.
132 /* Allocate the IRP */
133 AssocIrp
= IoAllocateIrp(StackSize
,FALSE
);
134 if (AssocIrp
== NULL
)
138 AssocIrp
->Flags
|= IRP_ASSOCIATED_IRP
;
141 AssocIrp
->Tail
.Overlay
.Thread
= Irp
->Tail
.Overlay
.Thread
;
144 AssocIrp
->AssociatedIrp
.MasterIrp
= Irp
;
154 IoInitializeIrp(PIRP Irp
,
158 * FUNCTION: Initalizes an irp allocated by the caller
160 * Irp = IRP to initalize
161 * PacketSize = Size in bytes of the IRP
162 * StackSize = Number of stack locations in the 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
= &Irp
->Stack
[(ULONG
)StackSize
];
173 Irp
->ApcEnvironment
= KeGetCurrentThread()->ApcStateIndex
;
181 IofCallDriver(PDEVICE_OBJECT DeviceObject
,
184 * FUNCTION: Sends an IRP to the next lower driver
187 PDRIVER_OBJECT DriverObject
;
188 PIO_STACK_LOCATION Param
;
190 DPRINT("IofCallDriver(DeviceObject %x, Irp %x)\n",DeviceObject
,Irp
);
193 ASSERT(DeviceObject
);
195 DriverObject
= DeviceObject
->DriverObject
;
197 ASSERT(DriverObject
);
199 IoSetNextIrpStackLocation(Irp
);
200 Param
= IoGetCurrentIrpStackLocation(Irp
);
202 DPRINT("IrpSp 0x%X\n", Param
);
204 Param
->DeviceObject
= DeviceObject
;
206 DPRINT("MajorFunction %d\n", Param
->MajorFunction
);
207 DPRINT("DriverObject->MajorFunction[Param->MajorFunction] %x\n",
208 DriverObject
->MajorFunction
[Param
->MajorFunction
]);
210 return DriverObject
->MajorFunction
[Param
->MajorFunction
](DeviceObject
, Irp
);
219 IoCallDriver (PDEVICE_OBJECT DeviceObject
, PIRP Irp
)
221 return(IofCallDriver(DeviceObject
,
230 IoAllocateIrp(CCHAR StackSize
,
233 * FUNCTION: Allocates an IRP
235 * StackSize = the size of the stack required for the irp
236 * ChargeQuota = Charge allocation to current threads quota
237 * RETURNS: Irp allocated
243 DbgPrint("IoAllocateIrp(StackSize %d ChargeQuota %d)\n",
246 KeDumpStackFrames(0,8);
251 // Irp = ExAllocatePoolWithQuota(NonPagedPool,IoSizeOfIrp(StackSize));
252 Irp
= ExAllocatePoolWithTag(NonPagedPool
,
253 IoSizeOfIrp(StackSize
),
258 Irp
= ExAllocatePoolWithTag(NonPagedPool
,
259 IoSizeOfIrp(StackSize
),
268 RtlZeroMemory(Irp
, IoSizeOfIrp(StackSize
));
270 IoSizeOfIrp(StackSize
),
273 // DPRINT("Irp %x Irp->StackPtr %d\n", Irp, Irp->CurrentLocation);
283 IofCompleteRequest(PIRP Irp
,
286 * FUNCTION: Indicates the caller has finished all processing for a given
287 * I/O request and is returning the given IRP to the I/O manager
289 * Irp = Irp to be cancelled
290 * PriorityBoost = Increment by which to boost the priority of the
291 * thread making the request
296 PFILE_OBJECT OriginalFileObject
;
297 PDEVICE_OBJECT DeviceObject
;
301 DPRINT("IoCompleteRequest(Irp %x, PriorityBoost %d) Event %x THread %x\n",
302 Irp
,PriorityBoost
, Irp
->UserEvent
, PsGetCurrentThread());
304 ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL
);
305 ASSERT(Irp
->CancelRoutine
== NULL
);
306 ASSERT(Irp
->IoStatus
.Status
!= STATUS_PENDING
);
308 if (IoGetCurrentIrpStackLocation(Irp
)->Control
& SL_PENDING_RETURNED
)
310 Irp
->PendingReturned
= TRUE
;
314 * Run the completion routines.
317 for (i
=Irp
->CurrentLocation
;i
<(ULONG
)Irp
->StackCount
;i
++)
320 Completion routines expect the current irp stack location to be the same as when
321 IoSetCompletionRoutine was called to set them. A side effect is that completion
322 routines set by highest level drivers without their own stack location will receive
323 an invalid current stack location (at least it should be considered as invalid).
324 Since the DeviceObject argument passed is taken from the current stack, this value
325 is also invalid (NULL).
327 if (Irp
->CurrentLocation
< Irp
->StackCount
- 1)
329 IoSetPreviousIrpStackLocation(Irp
);
330 DeviceObject
= IoGetCurrentIrpStackLocation(Irp
)->DeviceObject
;
337 if (Irp
->Stack
[i
].CompletionRoutine
!= NULL
&&
338 ((NT_SUCCESS(Irp
->IoStatus
.Status
) && (Irp
->Stack
[i
].Control
& SL_INVOKE_ON_SUCCESS
)) ||
339 (!NT_SUCCESS(Irp
->IoStatus
.Status
) && (Irp
->Stack
[i
].Control
& SL_INVOKE_ON_ERROR
)) ||
340 (Irp
->Cancel
&& (Irp
->Stack
[i
].Control
& SL_INVOKE_ON_CANCEL
))))
342 Status
= Irp
->Stack
[i
].CompletionRoutine(DeviceObject
,
344 Irp
->Stack
[i
].Context
);
346 if (Status
== STATUS_MORE_PROCESSING_REQUIRED
)
352 if (IoGetCurrentIrpStackLocation(Irp
)->Control
& SL_PENDING_RETURNED
)
354 Irp
->PendingReturned
= TRUE
;
358 /* Windows NT File System Internals, page 165 */
359 if (Irp
->Flags
& IRP_ASSOCIATED_IRP
)
361 ULONG MasterIrpCount
;
362 PIRP MasterIrp
= Irp
->AssociatedIrp
.MasterIrp
;
364 MasterIrpCount
= InterlockedDecrement(&MasterIrp
->AssociatedIrp
.IrpCount
);
365 while ((Mdl
= Irp
->MdlAddress
))
367 Irp
->MdlAddress
= Mdl
->Next
;
371 if (MasterIrpCount
== 0)
373 IofCompleteRequest(MasterIrp
, IO_NO_INCREMENT
);
379 * Were done calling completion routines. Now do any cleanup that can be
380 * done in an arbitrarily context.
383 /* Windows NT File System Internals, page 165 */
384 if (Irp
->Flags
& (IRP_PAGING_IO
|IRP_CLOSE_OPERATION
))
387 * If MDL_IO_PAGE_READ is set, then the caller is responsible
388 * for deallocating of the mdl.
390 if (Irp
->Flags
& IRP_PAGING_IO
&&
392 !(Irp
->MdlAddress
->MdlFlags
& MDL_IO_PAGE_READ
))
395 if (Irp
->MdlAddress
->MdlFlags
& MDL_MAPPED_TO_SYSTEM_VA
)
397 MmUnmapLockedPages(Irp
->MdlAddress
->MappedSystemVa
, Irp
->MdlAddress
);
400 ExFreePool(Irp
->MdlAddress
);
405 *Irp
->UserIosb
= Irp
->IoStatus
;
410 KeSetEvent(Irp
->UserEvent
, PriorityBoost
, FALSE
);
413 /* io manager frees the irp for close operations */
414 // if (Irp->Flags & IRP_PAGING_IO)
426 I went through my old notes. You are correct and in most cases
427 IoCompleteRequest() will issue an MmUnlockPages() for each MDL in the IRP
428 chain. There are however few exceptions: one is MDLs for associated IRPs,
429 it's expected that those MDLs have been initialized with
430 IoBuildPartialMdl(). Another exception is PAGING_IO irps, the i/o completion
431 code doesn't do anything to MDLs of those IRPs.
438 for (Mdl
= Irp
->MdlAddress
; Mdl
; Mdl
= Mdl
->Next
)
441 * Undo the MmProbeAndLockPages. If MmGetSystemAddressForMdl was called
442 * on this mdl, this mapping (if any) is also undone by MmUnlockPages.
447 //Windows NT File System Internals, page 154
448 OriginalFileObject
= Irp
->Tail
.Overlay
.OriginalFileObject
;
450 if (Irp
->PendingReturned
|| KeGetCurrentIrql() == DISPATCH_LEVEL
)
454 DPRINT("Dispatching APC\n");
455 KeInitializeApc( &Irp
->Tail
.Apc
,
456 &Irp
->Tail
.Overlay
.Thread
->Tcb
,
458 IoSecondStageCompletion
,//kernel routine
460 (PKNORMAL_ROUTINE
) NULL
,
464 bStatus
= KeInsertQueueApc(&Irp
->Tail
.Apc
,
466 (PVOID
)(ULONG
)PriorityBoost
,
469 if (bStatus
== FALSE
)
471 DPRINT1("Error queueing APC for thread. Thread has probably exited.\n");
474 DPRINT("Finished dispatching APC\n");
478 DPRINT("Calling IoSecondStageCompletion routine directly\n");
479 KeRaiseIrql(APC_LEVEL
, &oldIrql
);
480 IoSecondStageCompletion(NULL
,NULL
,(PVOID
)&OriginalFileObject
,(PVOID
) &Irp
,(PVOID
) &PriorityBoost
);
481 KeLowerIrql(oldIrql
);
482 DPRINT("Finished completition routine\n");
491 IoCompleteRequest(PIRP Irp
,
494 IofCompleteRequest(Irp
, PriorityBoost
);
498 /**********************************************************************
500 * IoIsOperationSynchronous@4
503 * Check if the I/O operation associated with the given IRP
507 * Irp Packet to check.
510 * TRUE if Irp's operation is synchronous; otherwise FALSE.
515 IoIsOperationSynchronous(IN PIRP Irp
)
517 PFILE_OBJECT FileObject
= NULL
;
519 FileObject
= IoGetCurrentIrpStackLocation(Irp
)->FileObject
;
521 if (Irp
->Flags
& IRP_SYNCHRONOUS_PAGING_IO
)
526 if (Irp
->Flags
& IRP_PAGING_IO
)
531 //NOTE: Windows 2000 crash if IoStack->FileObject == NULL, so I guess we should too;-)
532 if (Irp
->Flags
& IRP_SYNCHRONOUS_API
|| FileObject
->Flags
& FO_SYNCHRONOUS_IO
)
537 /* Otherwise, it is an asynchronous operation. */
546 IoEnqueueIrp(IN PIRP Irp
)
548 IoQueueThreadIrp(Irp
);
556 IoSetTopLevelIrp(IN PIRP Irp
)
560 Thread
= PsGetCurrentThread();
561 Thread
->TopLevelIrp
= Irp
;
569 IoGetTopLevelIrp(VOID
)
571 return(PsGetCurrentThread()->TopLevelIrp
);
579 IoQueueThreadIrp(IN PIRP Irp
)
581 /* undefine this when (if ever) implementing irp cancellation */
585 oldIrql
= KfRaiseIrql(APC_LEVEL
);
587 /* Synchronous irp's are queued to requestor thread. If they are not completed
588 when the thread exits, they are canceled (cleaned up).
590 InsertTailList(&PsGetCurrentThread()->IrpList
, &Irp
->ThreadListEntry
);
592 KfLowerIrql(oldIrql
);
606 UCHAR AllocationFlags
;
608 /* Reference: Chris Cant's "Writing WDM Device Drivers" */
609 AllocationFlags
= Irp
->AllocationFlags
;
610 IoInitializeIrp(Irp
, Irp
->Size
, Irp
->StackCount
);
611 Irp
->IoStatus
.Status
= Status
;
612 Irp
->AllocationFlags
= AllocationFlags
;