2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: ntoskrnl/io/irp.c
7 * PROGRAMMERS: Alex Ionescu (alex@relsoft.net)
8 * David Welch (welch@mcmail.com)
11 /* INCLUDES ****************************************************************/
15 #include <internal/debug.h>
17 /* GLOBALS *******************************************************************/
19 #define TAG_IRP TAG('I', 'R', 'P', ' ')
20 #define TAG_SYS_BUF TAG('I', 'o', ' ' , ' ')
22 /* FUNCTIONS *****************************************************************/
27 * FUNCTION: Allocates an IRP
29 * StackSize = the size of the stack required for the irp
30 * ChargeQuota = Charge allocation to current threads quota
31 * RETURNS: Irp allocated
35 IoAllocateIrp(CCHAR StackSize
,
39 USHORT Size
= IoSizeOfIrp(StackSize
);
41 /* Check if we shoudl charge quota */
44 /* Irp = ExAllocatePoolWithQuotaTag(NonPagedPool,IoSizeOfIrp(StackSize), TAG_IRP); */
46 Irp
= ExAllocatePoolWithTag(NonPagedPool
,
52 /* Allocate the IRP With no Quota charge */
53 Irp
= ExAllocatePoolWithTag(NonPagedPool
,
58 /* Make sure it was sucessful */
59 if (Irp
==NULL
) return(NULL
);
61 /* Now Initialize it */
62 IoInitializeIrp(Irp
, Size
, StackSize
);
71 * FUNCTION: Allocates and sets up an IRP to be sent to lower level drivers
73 * MajorFunction = One of IRP_MJ_READ, IRP_MJ_WRITE,
74 * IRP_MJ_FLUSH_BUFFERS or IRP_MJ_SHUTDOWN
75 * DeviceObject = Device object to send the irp to
76 * Buffer = Buffer into which data will be read or written
77 * Length = Length in bytes of the irp to be allocated
78 * StartingOffset = Starting offset on the device
79 * IoStatusBlock (OUT) = Storage for the result of the operation
80 * RETURNS: The IRP allocated on success, or
85 IoBuildAsynchronousFsdRequest(ULONG MajorFunction
,
86 PDEVICE_OBJECT DeviceObject
,
89 PLARGE_INTEGER StartingOffset
,
90 PIO_STATUS_BLOCK IoStatusBlock
)
93 PIO_STACK_LOCATION StackPtr
;
94 LOCK_OPERATION AccessType
;
96 DPRINT("IoBuildAsynchronousFsdRequest(MajorFunction %x, DeviceObject %x, "
97 "Buffer %x, Length %x, StartingOffset %x, "
98 "IoStatusBlock %x\n",MajorFunction
,DeviceObject
,Buffer
,Length
,
99 StartingOffset
,IoStatusBlock
);
102 if (!(Irp
= IoAllocateIrp(DeviceObject
->StackSize
,TRUE
))) return Irp
;
105 StackPtr
= IoGetNextIrpStackLocation(Irp
);
107 /* Write the Major function and then deal with it */
108 StackPtr
->MajorFunction
= (UCHAR
)MajorFunction
;
110 /* Do not handle the following here */
111 if (MajorFunction
!= IRP_MJ_FLUSH_BUFFERS
&&
112 MajorFunction
!= IRP_MJ_SHUTDOWN
&&
113 MajorFunction
!= IRP_MJ_PNP
)
115 /* Check if this is Buffered IO */
116 if (DeviceObject
->Flags
& DO_BUFFERED_IO
)
118 /* Allocate the System Buffer */
119 Irp
->AssociatedIrp
.SystemBuffer
= ExAllocatePoolWithTag(NonPagedPool
,
124 Irp
->Flags
= IRP_BUFFERED_IO
| IRP_DEALLOCATE_BUFFER
;
126 /* Handle special IRP_MJ_WRITE Case */
127 if (MajorFunction
== IRP_MJ_WRITE
)
129 /* Copy the buffer data */
130 RtlCopyMemory(Irp
->AssociatedIrp
.SystemBuffer
, Buffer
, Length
);
134 /* Set the Input Operation flag and set this as a User Buffer */
135 Irp
->Flags
|= IRP_INPUT_OPERATION
;
136 Irp
->UserBuffer
= Buffer
;
139 else if (DeviceObject
->Flags
& DO_DIRECT_IO
)
141 /* Use an MDL for Direct I/O */
142 Irp
->MdlAddress
= MmCreateMdl(NULL
, Buffer
, Length
);
144 /* Use the right Access Type */
145 if (MajorFunction
== IRP_MJ_READ
)
147 AccessType
= IoReadAccess
;
151 AccessType
= IoWriteAccess
;
155 _SEH_FILTER(FreeAndGoOn
)
157 /* Free the IRP and its MDL */
158 IoFreeMdl(Irp
->MdlAddress
);
160 return EXCEPTION_CONTINUE_SEARCH
;
162 _SEH_TRY_FILTER(FreeAndGoOn
)
165 MmProbeAndLockPages(Irp
->MdlAddress
, KernelMode
, AccessType
);
175 /* Neither, use the buffer */
176 Irp
->UserBuffer
= Buffer
;
179 if (MajorFunction
== IRP_MJ_READ
)
181 StackPtr
->Parameters
.Read
.Length
= Length
;
182 StackPtr
->Parameters
.Read
.ByteOffset
= *StartingOffset
;
184 else if (MajorFunction
== IRP_MJ_WRITE
)
186 StackPtr
->Parameters
.Write
.Length
= Length
;
187 StackPtr
->Parameters
.Write
.ByteOffset
= *StartingOffset
;
191 /* Set the Current Thread and IOSB */
192 if (!IoStatusBlock
) KEBUGCHECK(0); /* Temporary to catch illegal ROS Drivers */
193 Irp
->UserIosb
= IoStatusBlock
;
194 Irp
->Tail
.Overlay
.Thread
= PsGetCurrentThread();
196 /* Set the Status Block after all is done */
203 * FUNCTION: Allocates and sets up an IRP to be sent to drivers
205 * IoControlCode = Device io control code
206 * DeviceObject = Device object to send the irp to
207 * InputBuffer = Buffer from which data will be read by the driver
208 * InputBufferLength = Length in bytes of the input buffer
209 * OutputBuffer = Buffer into which data will be written by the driver
210 * OutputBufferLength = Length in bytes of the output buffer
211 * InternalDeviceIoControl = Determines weather
212 * IRP_MJ_INTERNAL_DEVICE_CONTROL or
213 * IRP_MJ_DEVICE_CONTROL will be used
214 * Event = Event used to notify the caller of completion
215 * IoStatusBlock (OUT) = Storage for the result of the operation
216 * RETURNS: The IRP allocated on success, or
221 IoBuildDeviceIoControlRequest(ULONG IoControlCode
,
222 PDEVICE_OBJECT DeviceObject
,
224 ULONG InputBufferLength
,
226 ULONG OutputBufferLength
,
227 BOOLEAN InternalDeviceIoControl
,
229 PIO_STATUS_BLOCK IoStatusBlock
)
232 PIO_STACK_LOCATION StackPtr
;
234 LOCK_OPERATION AccessType
;
236 DPRINT("IoBuildDeviceIoRequest(IoControlCode %x, DeviceObject %x, "
237 "InputBuffer %x, InputBufferLength %x, OutputBuffer %x, "
238 "OutputBufferLength %x, InternalDeviceIoControl %x "
239 "Event %x, IoStatusBlock %x\n",IoControlCode
,DeviceObject
,
240 InputBuffer
,InputBufferLength
,OutputBuffer
,OutputBufferLength
,
241 InternalDeviceIoControl
,Event
,IoStatusBlock
);
244 if (!(Irp
= IoAllocateIrp(DeviceObject
->StackSize
,TRUE
))) return Irp
;
247 StackPtr
= IoGetNextIrpStackLocation(Irp
);
249 /* Set the DevCtl Type */
250 StackPtr
->MajorFunction
= InternalDeviceIoControl
?
251 IRP_MJ_INTERNAL_DEVICE_CONTROL
: IRP_MJ_DEVICE_CONTROL
;
253 /* Set the IOCTL Data */
254 StackPtr
->Parameters
.DeviceIoControl
.IoControlCode
= IoControlCode
;
255 StackPtr
->Parameters
.DeviceIoControl
.InputBufferLength
= InputBufferLength
;
256 StackPtr
->Parameters
.DeviceIoControl
.OutputBufferLength
= OutputBufferLength
;
258 /* Handle the Methods */
259 switch (IO_METHOD_FROM_CTL_CODE(IoControlCode
))
261 case METHOD_BUFFERED
:
262 DPRINT("Using METHOD_BUFFERED!\n");
264 /* Select the right Buffer Length */
265 BufferLength
= InputBufferLength
> OutputBufferLength
? InputBufferLength
: OutputBufferLength
;
267 /* Make sure there is one */
270 /* Allocate the System Buffer */
271 Irp
->AssociatedIrp
.SystemBuffer
= ExAllocatePoolWithTag(NonPagedPool
,
275 /* Fail if we couldn't */
276 if (Irp
->AssociatedIrp
.SystemBuffer
== NULL
)
282 /* Check if we got a buffer */
285 /* Copy into the System Buffer */
286 RtlCopyMemory(Irp
->AssociatedIrp
.SystemBuffer
,
291 /* Write the flags */
292 Irp
->Flags
= IRP_BUFFERED_IO
| IRP_DEALLOCATE_BUFFER
;
293 if (OutputBuffer
) Irp
->Flags
|= IRP_INPUT_OPERATION
;
295 /* Save the Buffer */
296 Irp
->UserBuffer
= OutputBuffer
;
300 /* Clear the Flags and Buffer */
302 Irp
->UserBuffer
= NULL
;
306 case METHOD_IN_DIRECT
:
307 case METHOD_OUT_DIRECT
:
308 DPRINT("Using METHOD_IN/OUT DIRECT!\n");
310 /* Check if we got an input buffer */
313 /* Allocate the System Buffer */
314 Irp
->AssociatedIrp
.SystemBuffer
= ExAllocatePoolWithTag(NonPagedPool
,
318 /* Fail if we couldn't */
319 if (Irp
->AssociatedIrp
.SystemBuffer
== NULL
)
325 /* Copy into the System Buffer */
326 RtlCopyMemory(Irp
->AssociatedIrp
.SystemBuffer
,
330 /* Write the flags */
331 Irp
->Flags
= IRP_BUFFERED_IO
| IRP_DEALLOCATE_BUFFER
;
338 /* Check if we got an output buffer */
341 /* Allocate the System Buffer */
342 Irp
->MdlAddress
= IoAllocateMdl(OutputBuffer
,
348 /* Fail if we couldn't */
349 if (Irp
->MdlAddress
== NULL
)
356 _SEH_FILTER(FreeAndGoOn
)
358 /* Free the MDL and IRP */
359 IoFreeMdl(Irp
->MdlAddress
);
361 return EXCEPTION_CONTINUE_SEARCH
;
363 _SEH_TRY_FILTER(FreeAndGoOn
)
365 /* Use the right Access Type */
366 if (IO_METHOD_FROM_CTL_CODE(IoControlCode
) == METHOD_IN_DIRECT
)
368 AccessType
= IoReadAccess
;
372 AccessType
= IoWriteAccess
;
376 MmProbeAndLockPages(Irp
->MdlAddress
, KernelMode
, AccessType
);
388 /* Just save the Buffer */
389 Irp
->UserBuffer
= OutputBuffer
;
390 StackPtr
->Parameters
.DeviceIoControl
.Type3InputBuffer
= InputBuffer
;
394 /* Now write the Event and IoSB */
395 if (!IoStatusBlock
) KEBUGCHECK(0); /* Temporary to catch illegal ROS Drivers */
396 Irp
->UserIosb
= IoStatusBlock
;
397 Irp
->UserEvent
= Event
;
399 /* Sync IRPs are queued to requestor thread's irp cancel/cleanup list */
400 Irp
->Tail
.Overlay
.Thread
= PsGetCurrentThread();
401 IoQueueThreadIrp(Irp
);
410 * FUNCTION: Allocates and builds an IRP to be sent synchronously to lower
413 * MajorFunction = Major function code, one of IRP_MJ_READ,
414 * IRP_MJ_WRITE, IRP_MJ_FLUSH_BUFFERS, IRP_MJ_SHUTDOWN
415 * DeviceObject = Target device object
416 * Buffer = Buffer containing data for a read or write
417 * Length = Length in bytes of the information to be transferred
418 * StartingOffset = Offset to begin the read/write from
419 * Event (OUT) = Will be set when the operation is complete
420 * IoStatusBlock (OUT) = Set to the status of the operation
421 * RETURNS: The IRP allocated on success, or
426 IoBuildSynchronousFsdRequest(ULONG MajorFunction
,
427 PDEVICE_OBJECT DeviceObject
,
430 PLARGE_INTEGER StartingOffset
,
432 PIO_STATUS_BLOCK IoStatusBlock
)
436 DPRINT("IoBuildSynchronousFsdRequest(MajorFunction %x, DeviceObject %x, "
437 "Buffer %x, Length %x, StartingOffset %x, Event %x, "
438 "IoStatusBlock %x\n",MajorFunction
,DeviceObject
,Buffer
,Length
,
439 StartingOffset
,Event
,IoStatusBlock
);
441 /* Do the big work to set up the IRP */
442 Irp
= IoBuildAsynchronousFsdRequest(MajorFunction
,
449 /* Set the Event which makes it Syncronous */
450 Irp
->UserEvent
= Event
;
452 /* Sync IRPs are queued to requestor thread's irp cancel/cleanup list */
453 IoQueueThreadIrp(Irp
);
462 IoCancelIrp(PIRP Irp
)
465 PDRIVER_CANCEL CancelRoutine
;
467 DPRINT("IoCancelIrp(Irp %x)\n",Irp
);
469 IoAcquireCancelSpinLock(&oldlvl
);
473 CancelRoutine
= IoSetCancelRoutine(Irp
, NULL
);
474 if (CancelRoutine
== NULL
)
476 IoReleaseCancelSpinLock(oldlvl
);
480 Irp
->CancelIrql
= oldlvl
;
481 CancelRoutine(IoGetCurrentIrpStackLocation(Irp
)->DeviceObject
, Irp
);
486 * @name IoCancelThreadIo
488 * Cancel all pending I/O request associated with specified thread.
491 * Thread to cancel requests for.
496 IoCancelThreadIo(PETHREAD Thread
)
498 PLIST_ENTRY IrpEntry
;
501 ULONG Retries
= 3000;
502 LARGE_INTEGER Interval
;
504 OldIrql
= KfRaiseIrql(APC_LEVEL
);
507 * Start by cancelling all the IRPs in the current thread queue.
510 for (IrpEntry
= Thread
->IrpList
.Flink
;
511 IrpEntry
!= &Thread
->IrpList
;
512 IrpEntry
= IrpEntry
->Flink
)
514 Irp
= CONTAINING_RECORD(IrpEntry
, IRP
, ThreadListEntry
);
519 * Wait till all the IRPs are completed or cancelled.
522 while (!IsListEmpty(&Thread
->IrpList
))
524 KfLowerIrql(OldIrql
);
526 /* Wait a short while and then look if all our IRPs were completed. */
527 Interval
.QuadPart
= -1000000; /* 100 milliseconds */
528 KeDelayExecutionThread(KernelMode
, FALSE
, &Interval
);
531 * Don't stay here forever if some broken driver doesn't complete
537 /* FIXME: Handle this gracefully. */
538 DPRINT1("Thread with dead IRPs!");
542 OldIrql
= KfRaiseIrql(APC_LEVEL
);
545 KfLowerIrql(OldIrql
);
556 IoCallDriver (PDEVICE_OBJECT DeviceObject
, PIRP Irp
)
559 return IofCallDriver(DeviceObject
, Irp
);
567 IoCompleteRequest(PIRP Irp
,
570 /* Call the fastcall */
571 IofCompleteRequest(Irp
, PriorityBoost
);
579 IoEnqueueIrp(IN PIRP Irp
)
581 IoQueueThreadIrp(Irp
);
587 * FUNCTION: Sends an IRP to the next lower driver
591 IofCallDriver(PDEVICE_OBJECT DeviceObject
,
595 PDRIVER_OBJECT DriverObject
;
596 PIO_STACK_LOCATION Param
;
598 DPRINT("IofCallDriver(DeviceObject %x, Irp %x)\n",DeviceObject
,Irp
);
600 /* Get the Driver Object */
601 DriverObject
= DeviceObject
->DriverObject
;
603 /* Set the Stack Location */
604 IoSetNextIrpStackLocation(Irp
);
606 /* Get the current one */
607 Param
= IoGetCurrentIrpStackLocation(Irp
);
609 DPRINT("IrpSp 0x%X\n", Param
);
611 /* Get the Device Object */
612 Param
->DeviceObject
= DeviceObject
;
615 return DriverObject
->MajorFunction
[Param
->MajorFunction
](DeviceObject
, Irp
);
618 #ifdef IoCompleteRequest
619 #undef IoCompleteRequest
625 IofCompleteRequest(PIRP Irp
,
628 * FUNCTION: Indicates the caller has finished all processing for a given
629 * I/O request and is returning the given IRP to the I/O manager
631 * Irp = Irp to be cancelled
632 * PriorityBoost = Increment by which to boost the priority of the
633 * thread making the request
638 PFILE_OBJECT OriginalFileObject
;
639 PDEVICE_OBJECT DeviceObject
;
642 PIO_STACK_LOCATION Stack
= (PIO_STACK_LOCATION
)(Irp
+ 1);
644 DPRINT("IoCompleteRequest(Irp %x, PriorityBoost %d) Event %x THread %x\n",
645 Irp
,PriorityBoost
, Irp
->UserEvent
, PsGetCurrentThread());
647 ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL
);
648 ASSERT(Irp
->CancelRoutine
== NULL
);
649 ASSERT(Irp
->IoStatus
.Status
!= STATUS_PENDING
);
651 Irp
->PendingReturned
= IoGetCurrentIrpStackLocation(Irp
)->Control
& SL_PENDING_RETURNED
;
654 * Run the completion routines.
657 for (i
=Irp
->CurrentLocation
;i
<(ULONG
)Irp
->StackCount
;i
++)
660 Completion routines expect the current irp stack location to be the same as when
661 IoSetCompletionRoutine was called to set them. A side effect is that completion
662 routines set by highest level drivers without their own stack location will receive
663 an invalid current stack location (at least it should be considered as invalid).
664 Since the DeviceObject argument passed is taken from the current stack, this value
665 is also invalid (NULL).
667 if (Irp
->CurrentLocation
< Irp
->StackCount
- 1)
669 IoSkipCurrentIrpStackLocation(Irp
);
670 DeviceObject
= IoGetCurrentIrpStackLocation(Irp
)->DeviceObject
;
677 if (Stack
[i
].CompletionRoutine
!= NULL
&&
678 ((NT_SUCCESS(Irp
->IoStatus
.Status
) && (Stack
[i
].Control
& SL_INVOKE_ON_SUCCESS
)) ||
679 (!NT_SUCCESS(Irp
->IoStatus
.Status
) && (Stack
[i
].Control
& SL_INVOKE_ON_ERROR
)) ||
680 (Irp
->Cancel
&& (Stack
[i
].Control
& SL_INVOKE_ON_CANCEL
))))
682 Status
= Stack
[i
].CompletionRoutine(DeviceObject
,
686 if (Status
== STATUS_MORE_PROCESSING_REQUIRED
)
692 if (IoGetCurrentIrpStackLocation(Irp
)->Control
& SL_PENDING_RETURNED
)
694 Irp
->PendingReturned
= TRUE
;
698 /* Windows NT File System Internals, page 165 */
699 if (Irp
->Flags
& IRP_ASSOCIATED_IRP
)
701 ULONG MasterIrpCount
;
702 PIRP MasterIrp
= Irp
->AssociatedIrp
.MasterIrp
;
704 /* This should never happen! */
705 ASSERT(IsListEmpty(&Irp
->ThreadListEntry
));
707 MasterIrpCount
= InterlockedDecrement(&MasterIrp
->AssociatedIrp
.IrpCount
);
708 while ((Mdl
= Irp
->MdlAddress
))
710 Irp
->MdlAddress
= Mdl
->Next
;
714 if (MasterIrpCount
== 0)
716 IofCompleteRequest(MasterIrp
, IO_NO_INCREMENT
);
722 * Were done calling completion routines. Now do any cleanup that can be
723 * done in an arbitrarily context.
726 /* Windows NT File System Internals, page 165 */
727 if (Irp
->Flags
& (IRP_PAGING_IO
|IRP_CLOSE_OPERATION
))
729 /* This should never happen! */
730 ASSERT(IsListEmpty(&Irp
->ThreadListEntry
));
733 * If MDL_IO_PAGE_READ is set, then the caller is responsible
734 * for deallocating of the mdl.
736 if (Irp
->Flags
& IRP_PAGING_IO
&&
738 !(Irp
->MdlAddress
->MdlFlags
& MDL_IO_PAGE_READ
))
741 if (Irp
->MdlAddress
->MdlFlags
& MDL_MAPPED_TO_SYSTEM_VA
)
743 MmUnmapLockedPages(Irp
->MdlAddress
->MappedSystemVa
, Irp
->MdlAddress
);
746 ExFreePool(Irp
->MdlAddress
);
753 *Irp
->UserIosb
= Irp
->IoStatus
;
757 DPRINT1("Unable to set UserIosb (at 0x%x) to 0x%x, Error: 0x%x\n",
758 Irp
->UserIosb
, Irp
->IoStatus
, _SEH_GetExceptionCode());
765 KeSetEvent(Irp
->UserEvent
, PriorityBoost
, FALSE
);
768 /* io manager frees the irp for close operations */
769 // if (Irp->Flags & IRP_PAGING_IO)
781 I went through my old notes. You are correct and in most cases
782 IoCompleteRequest() will issue an MmUnlockPages() for each MDL in the IRP
783 chain. There are however few exceptions: one is MDLs for associated IRPs,
784 it's expected that those MDLs have been initialized with
785 IoBuildPartialMdl(). Another exception is PAGING_IO irps, the i/o completion
786 code doesn't do anything to MDLs of those IRPs.
793 for (Mdl
= Irp
->MdlAddress
; Mdl
; Mdl
= Mdl
->Next
)
796 * Undo the MmProbeAndLockPages. If MmGetSystemAddressForMdl was called
797 * on this mdl, this mapping (if any) is also undone by MmUnlockPages.
802 //Windows NT File System Internals, page 154
803 OriginalFileObject
= Irp
->Tail
.Overlay
.OriginalFileObject
;
805 if (Irp
->PendingReturned
|| KeGetCurrentIrql() == DISPATCH_LEVEL
)
809 DPRINT("Dispatching APC\n");
811 KeInitializeApc( &Irp
->Tail
.Apc
,
812 &Irp
->Tail
.Overlay
.Thread
->Tcb
,
814 IoSecondStageCompletion
,//kernel routine
816 (PKNORMAL_ROUTINE
) NULL
,
820 bStatus
= KeInsertQueueApc(&Irp
->Tail
.Apc
,
821 (PVOID
)OriginalFileObject
,
822 NULL
, // This is used for REPARSE stuff
825 if (bStatus
== FALSE
)
827 DPRINT1("Error queueing APC for thread. Thread has probably exited.\n");
830 DPRINT("Finished dispatching APC\n");
834 DPRINT("Calling IoSecondStageCompletion routine directly\n");
835 KeRaiseIrql(APC_LEVEL
, &oldIrql
);
836 IoSecondStageCompletion(&Irp
->Tail
.Apc
,NULL
,NULL
,(PVOID
)&OriginalFileObject
, NULL
);
837 KeLowerIrql(oldIrql
);
838 DPRINT("Finished completition routine\n");
847 IoForwardIrpSynchronously(IN PDEVICE_OBJECT DeviceObject
,
857 * FUNCTION: Releases a caller allocated irp
865 /* Free the pool memory associated with it */
873 IoGetRequestorProcess(IN PIRP Irp
)
875 return(Irp
->Tail
.Overlay
.Thread
->ThreadsProcess
);
883 IoGetRequestorProcessId(IN PIRP Irp
)
885 return (ULONG
)(IoGetRequestorProcess(Irp
)->UniqueProcessId
);
893 IoGetRequestorSessionId(IN PIRP Irp
,
894 OUT PULONG pSessionId
)
896 *pSessionId
= IoGetRequestorProcess(Irp
)->SessionId
;
898 return STATUS_SUCCESS
;
906 IoGetTopLevelIrp(VOID
)
908 return(PsGetCurrentThread()->TopLevelIrp
);
914 * FUNCTION: Initalizes an irp allocated by the caller
916 * Irp = IRP to initalize
917 * PacketSize = Size in bytes of the IRP
918 * StackSize = Number of stack locations in the IRP
922 IoInitializeIrp(PIRP Irp
,
928 DPRINT("IoInitializeIrp(StackSize %x, Irp %x)\n",StackSize
, Irp
);
931 RtlZeroMemory(Irp
, PacketSize
);
933 /* Set the Header and other data */
934 Irp
->Type
= IO_TYPE_IRP
;
935 Irp
->Size
= PacketSize
;
936 Irp
->StackCount
= StackSize
;
937 Irp
->CurrentLocation
= StackSize
;
938 Irp
->ApcEnvironment
= KeGetCurrentThread()->ApcStateIndex
;
939 Irp
->Tail
.Overlay
.CurrentStackLocation
= (PIO_STACK_LOCATION
)(Irp
+ 1) + StackSize
;
941 /* Initialize the Thread List */
942 InitializeListHead(&Irp
->ThreadListEntry
);
944 DPRINT("Irp->Tail.Overlay.CurrentStackLocation %x\n", Irp
->Tail
.Overlay
.CurrentStackLocation
);
949 * IoIsOperationSynchronous@4
952 * Check if the I/O operation associated with the given IRP
956 * Irp Packet to check.
959 * TRUE if Irp's operation is synchronous; otherwise FALSE.
965 IoIsOperationSynchronous(IN PIRP Irp
)
967 /* Check the flags */
968 if ((Irp
->Flags
& IRP_SYNCHRONOUS_PAGING_IO
) ||
969 (Irp
->Flags
& IRP_SYNCHRONOUS_API
) ||
970 (IoGetCurrentIrpStackLocation(Irp
)->FileObject
->Flags
&
973 /* Synch API or Paging I/O is OK, as is Sync File I/O */
977 /* Otherwise, it is an asynchronous operation. */
986 IoIsValidNameGraftingBuffer(IN PIRP Irp
,
987 IN PREPARSE_DATA_BUFFER ReparseBuffer
)
996 * FUNCTION: Allocates and initializes an irp to associated with a master irp
999 * StackSize = Number of stack locations to be allocated in the irp
1000 * RETURNS: The irp allocated
1001 * NOTE: The caller is responsible for incrementing
1002 * Irp->AssociatedIrp.IrpCount.
1006 IoMakeAssociatedIrp(PIRP Irp
,
1011 /* Allocate the IRP */
1012 AssocIrp
= IoAllocateIrp(StackSize
,FALSE
);
1013 if (AssocIrp
== NULL
) return NULL
;
1016 AssocIrp
->Flags
|= IRP_ASSOCIATED_IRP
;
1018 /* Set the Thread */
1019 AssocIrp
->Tail
.Overlay
.Thread
= Irp
->Tail
.Overlay
.Thread
;
1021 /* Associate them */
1022 AssocIrp
->AssociatedIrp
.MasterIrp
= Irp
;
1032 IoPageRead(PFILE_OBJECT FileObject
,
1034 PLARGE_INTEGER Offset
,
1036 PIO_STATUS_BLOCK StatusBlock
)
1039 PIO_STACK_LOCATION StackPtr
;
1040 PDEVICE_OBJECT DeviceObject
;
1042 DPRINT("IoPageRead(FileObject %x, Mdl %x)\n",
1045 /* Get the Device Object */
1046 DeviceObject
= IoGetRelatedDeviceObject(FileObject
);
1049 Irp
= IoAllocateIrp(DeviceObject
->StackSize
, FALSE
);
1052 StackPtr
= IoGetNextIrpStackLocation(Irp
);
1054 /* Create the IRP Settings */
1055 Irp
->MdlAddress
= Mdl
;
1056 Irp
->UserBuffer
= MmGetMdlVirtualAddress(Mdl
);
1057 Irp
->UserIosb
= StatusBlock
;
1058 Irp
->UserEvent
= Event
;
1059 Irp
->RequestorMode
= KernelMode
;
1060 Irp
->Flags
= IRP_PAGING_IO
| IRP_NOCACHE
| IRP_SYNCHRONOUS_PAGING_IO
| IRP_INPUT_OPERATION
;
1061 Irp
->Tail
.Overlay
.OriginalFileObject
= FileObject
;
1062 Irp
->Tail
.Overlay
.Thread
= PsGetCurrentThread();
1064 /* Set the Stack Settings */
1065 StackPtr
->Parameters
.Read
.Length
= MmGetMdlByteCount(Mdl
);
1066 StackPtr
->Parameters
.Read
.ByteOffset
= *Offset
;
1067 StackPtr
->MajorFunction
= IRP_MJ_READ
;
1068 StackPtr
->FileObject
= FileObject
;
1070 /* Call the Driver */
1071 return IofCallDriver(DeviceObject
, Irp
);
1079 IoQueueThreadIrp(IN PIRP Irp
)
1084 OldIrql
= KfRaiseIrql(APC_LEVEL
);
1087 * Synchronous irp's are queued to requestor thread. If they are not
1088 * completed when the thread exits, they are canceled (cleaned up).
1091 InsertTailList(&Irp
->Tail
.Overlay
.Thread
->IrpList
, &Irp
->ThreadListEntry
);
1094 KfLowerIrql(OldIrql
);
1099 * Reference: Chris Cant's "Writing WDM Device Drivers"
1103 IoReuseIrp(IN OUT PIRP Irp
,
1106 UCHAR AllocationFlags
;
1108 /* Get the old flags */
1109 AllocationFlags
= Irp
->AllocationFlags
;
1111 /* Reinitialize the IRP */
1112 IoInitializeIrp(Irp
, Irp
->Size
, Irp
->StackCount
);
1114 /* Duplicate the data */
1115 Irp
->IoStatus
.Status
= Status
;
1116 Irp
->AllocationFlags
= AllocationFlags
;
1124 IoSetTopLevelIrp(IN PIRP Irp
)
1126 PsGetCurrentThread()->TopLevelIrp
= Irp
;
1134 IoSynchronousPageWrite(PFILE_OBJECT FileObject
,
1136 PLARGE_INTEGER Offset
,
1138 PIO_STATUS_BLOCK StatusBlock
)
1141 PIO_STACK_LOCATION StackPtr
;
1142 PDEVICE_OBJECT DeviceObject
;
1144 DPRINT("IoSynchronousPageWrite(FileObject %x, Mdl %x)\n",
1147 /* Get the Device Object */
1148 DeviceObject
= IoGetRelatedDeviceObject(FileObject
);
1151 Irp
= IoAllocateIrp(DeviceObject
->StackSize
, FALSE
);
1154 StackPtr
= IoGetNextIrpStackLocation(Irp
);
1156 /* Create the IRP Settings */
1157 Irp
->MdlAddress
= Mdl
;
1158 Irp
->UserBuffer
= MmGetMdlVirtualAddress(Mdl
);
1159 Irp
->UserIosb
= StatusBlock
;
1160 Irp
->UserEvent
= Event
;
1161 Irp
->RequestorMode
= KernelMode
;
1162 Irp
->Flags
= IRP_PAGING_IO
| IRP_NOCACHE
| IRP_SYNCHRONOUS_PAGING_IO
;
1163 Irp
->Tail
.Overlay
.OriginalFileObject
= FileObject
;
1164 Irp
->Tail
.Overlay
.Thread
= PsGetCurrentThread();
1166 /* Set the Stack Settings */
1167 StackPtr
->Parameters
.Write
.Length
= MmGetMdlByteCount(Mdl
);
1168 StackPtr
->Parameters
.Write
.ByteOffset
= *Offset
;
1169 StackPtr
->MajorFunction
= IRP_MJ_WRITE
;
1170 StackPtr
->FileObject
= FileObject
;
1172 /* Call the Driver */
1173 return IofCallDriver(DeviceObject
, Irp
);
1178 IoSecondStageCompletion_KernelApcRoutine(PKAPC Apc
,
1179 PKNORMAL_ROUTINE
*NormalRoutine
,
1180 PVOID
*NormalContext
,
1181 PVOID
*SystemArgument1
,
1182 PVOID
*SystemArgument2
)
1185 IoFreeIrp(CONTAINING_RECORD(Apc
, IRP
, Tail
.Apc
));
1190 IoSecondStageCompletion_RundownApcRoutine(PKAPC Apc
)
1193 IoFreeIrp(CONTAINING_RECORD(Apc
, IRP
, Tail
.Apc
));
1197 * FUNCTION: Performs the second stage of irp completion for read/write irps
1199 * Called as a special kernel APC kernel-routine or directly from IofCompleteRequest()
1201 * Note that we'll never see irp's flagged IRP_PAGING_IO (IRP_MOUNT_OPERATION)
1202 * or IRP_CLOSE_OPERATION (IRP_MJ_CLOSE and IRP_MJ_CLEANUP) here since their
1203 * cleanup/completion is fully taken care of in IoCompleteRequest.
1208 IoSecondStageCompletion(PKAPC Apc
,
1209 PKNORMAL_ROUTINE
* NormalRoutine
,
1210 PVOID
* NormalContext
,
1211 PVOID
* SystemArgument1
,
1212 PVOID
* SystemArgument2
)
1214 PFILE_OBJECT FileObject
;
1218 if (Apc
) DPRINT("IoSecondStageCompletition with APC: %x\n", Apc
);
1220 /* Get data from the APC */
1221 FileObject
= (PFILE_OBJECT
)(*SystemArgument1
);
1222 Irp
= CONTAINING_RECORD(Apc
, IRP
, Tail
.Apc
);
1223 DPRINT("IoSecondStageCompletition, %x\n", Irp
);
1225 /* Handle Buffered case first */
1226 if (Irp
->Flags
& IRP_BUFFERED_IO
)
1228 /* Check if we have an input buffer and if we suceeded */
1229 if (Irp
->Flags
& IRP_INPUT_OPERATION
&& NT_SUCCESS(Irp
->IoStatus
.Status
))
1231 /* Copy the buffer back to the user */
1232 RtlCopyMemory(Irp
->UserBuffer
,
1233 Irp
->AssociatedIrp
.SystemBuffer
,
1234 Irp
->IoStatus
.Information
);
1237 /* Also check if we should de-allocate it */
1238 if (Irp
->Flags
& IRP_DEALLOCATE_BUFFER
)
1240 ExFreePool(Irp
->AssociatedIrp
.SystemBuffer
);
1244 /* Now we got rid of these two... */
1245 Irp
->Flags
&= ~(IRP_BUFFERED_IO
| IRP_DEALLOCATE_BUFFER
);
1247 /* Check if there's an MDL */
1248 if ((Mdl
= Irp
->MdlAddress
))
1250 /* Clear all of them */
1253 NextMdl
= Mdl
->Next
;
1258 Irp
->MdlAddress
= NULL
;
1260 /* Check for Success but allow failure for Async IRPs */
1261 if (NT_SUCCESS(Irp
->IoStatus
.Status
) ||
1262 (Irp
->PendingReturned
&&
1263 !(Irp
->Flags
& IRP_SYNCHRONOUS_API
) &&
1264 (FileObject
== NULL
|| FileObject
->Flags
& FO_SYNCHRONOUS_IO
)))
1266 /* Save the IOSB Information */
1267 *Irp
->UserIosb
= Irp
->IoStatus
;
1269 /* Check if there's an event */
1272 /* Signal the Event */
1273 KeSetEvent(Irp
->UserEvent
, 0, FALSE
);
1276 else if (FileObject
)
1278 /* Signal the File Object Instead */
1279 KeSetEvent(&FileObject
->Event
, 0, FALSE
);
1281 /* Set the Status */
1282 FileObject
->FinalStatus
= Irp
->IoStatus
.Status
;
1285 /* Check if there's a File Object */
1288 /* Dereference the Event if this is an ASYNC IRP */
1289 if (!Irp
->Flags
& IRP_SYNCHRONOUS_API
)
1291 if (Irp
->UserEvent
!= &FileObject
->Event
)
1293 ObDereferenceObject(Irp
->UserEvent
);
1297 /* If the File Object is SYNC, then we need to signal its event too */
1298 if (FileObject
->Flags
& FO_SYNCHRONOUS_IO
)
1302 KeSetEvent(&FileObject
->Event
, 0, FALSE
);
1304 /* Set the Status */
1305 FileObject
->FinalStatus
= Irp
->IoStatus
.Status
;
1309 /* Remove the IRP from the list of Thread Pending IRPs */
1310 RemoveEntryList(&Irp
->ThreadListEntry
);
1311 InitializeListHead(&Irp
->ThreadListEntry
);
1313 /* Now call the User APC if one was requested */
1314 if (Irp
->Overlay
.AsynchronousParameters
.UserApcRoutine
!= NULL
)
1316 KeInitializeApc(&Irp
->Tail
.Apc
,
1317 KeGetCurrentThread(),
1318 CurrentApcEnvironment
,
1319 IoSecondStageCompletion_KernelApcRoutine
,
1320 IoSecondStageCompletion_RundownApcRoutine
,
1321 (PKNORMAL_ROUTINE
)Irp
->Overlay
.AsynchronousParameters
.UserApcRoutine
,
1323 Irp
->Overlay
.AsynchronousParameters
.UserApcContext
);
1325 KeInsertQueueApc(&Irp
->Tail
.Apc
,
1330 else if (FileObject
&& FileObject
->CompletionContext
)
1332 /* Call the IO Completion Port if we have one, instead */
1333 IoSetIoCompletion(FileObject
->CompletionContext
->Port
,
1334 FileObject
->CompletionContext
->Key
,
1335 Irp
->Overlay
.AsynchronousParameters
.UserApcContext
,
1336 Irp
->IoStatus
.Status
,
1337 Irp
->IoStatus
.Information
,
1342 /* Don't have anything, free it */
1346 /* Dereference the File Object */
1347 if (FileObject
) ObDereferenceObject(FileObject
);
1351 /* Remove the IRP from the list of Thread Pending IRPs */
1352 RemoveEntryList(&Irp
->ThreadListEntry
);
1353 InitializeListHead(&Irp
->ThreadListEntry
);
1355 /* Signal the Events only if PendingReturned and we have a File Object */
1356 if (FileObject
&& Irp
->PendingReturned
)
1358 /* Check for SYNC IRP */
1359 if (Irp
->Flags
& IRP_SYNCHRONOUS_API
)
1361 /* Set the status in this case only */
1362 *Irp
->UserIosb
= Irp
->IoStatus
;
1364 /* Signal our event if we have one */
1367 KeSetEvent(Irp
->UserEvent
, 0, FALSE
);
1371 /* Signal the File's Event instead */
1372 KeSetEvent(&FileObject
->Event
, 0, FALSE
);
1377 /* We'll report the Status to the File Object, not the IRP */
1378 FileObject
->FinalStatus
= Irp
->IoStatus
.Status
;
1380 /* Signal the File Object ONLY if this was Async */
1381 KeSetEvent(&FileObject
->Event
, 0, FALSE
);
1385 /* Dereference the Event if it's an ASYNC IRP on a File Object */
1386 if (Irp
->UserEvent
&& !(Irp
->Flags
& IRP_SYNCHRONOUS_API
) && FileObject
)
1388 if (Irp
->UserEvent
!= &FileObject
->Event
)
1390 ObDereferenceObject(Irp
->UserEvent
);
1394 /* Dereference the File Object */
1395 if (FileObject
) ObDereferenceObject(FileObject
);