3 * PROJECT: ReactOS Kernel
4 * LICENSE: GPL - See COPYING in the top level directory
5 * FILE: ntoskrnl/io/irp.c
6 * PURPOSE: IRP Handling Functions
7 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
9 * Filip Navara (navaraf@reactos.org)
12 /* INCLUDES ****************************************************************/
16 #include <internal/debug.h>
18 /* Undefine some macros we implement here */
20 #undef IoCompleteRequest
22 /* PRIVATE FUNCTIONS ********************************************************/
26 IopFreeIrpKernelApc(IN PKAPC Apc
,
27 IN PKNORMAL_ROUTINE
*NormalRoutine
,
28 IN PVOID
*NormalContext
,
29 IN PVOID
*SystemArgument1
,
30 IN PVOID
*SystemArgument2
)
33 IoFreeIrp(CONTAINING_RECORD(Apc
, IRP
, Tail
.Apc
));
38 IopAbortIrpKernelApc(IN PKAPC Apc
)
41 IoFreeIrp(CONTAINING_RECORD(Apc
, IRP
, Tail
.Apc
));
46 IopCleanupFailedIrp(IN PFILE_OBJECT FileObject
,
47 IN PKEVENT EventObject OPTIONAL
,
48 IN PVOID Buffer OPTIONAL
)
52 /* Dereference the event */
53 if (EventObject
) ObDereferenceObject(EventObject
);
55 /* Free a buffer, if any */
56 if (Buffer
) ExFreePool(Buffer
);
58 /* If this was a file opened for synch I/O, then unlock it */
59 if (FileObject
->Flags
& FO_SYNCHRONOUS_IO
) IopUnlockFileObject(FileObject
);
61 /* Now dereference it and return */
62 ObDereferenceObject(FileObject
);
63 return STATUS_INSUFFICIENT_RESOURCES
;
68 IopAbortInterruptedIrp(IN PKEVENT EventObject
,
76 /* Raise IRQL to APC */
77 KeRaiseIrql(APC_LEVEL
, &OldIrql
);
79 /* Check if nobody completed it yet */
80 if (!KeReadStateEvent(EventObject
))
82 /* First, cancel it */
83 CancelResult
= IoCancelIrp(Irp
);
86 /* Check if we cancelled it */
89 /* Wait for the IRP to be cancelled */
90 Wait
.QuadPart
= -100000;
91 while (!KeReadStateEvent(EventObject
))
93 /* Delay indefintely */
94 KeDelayExecutionThread(KernelMode
, FALSE
, &Wait
);
99 /* No cancellation done, so wait for the I/O system to kill it */
100 KeWaitForSingleObject(EventObject
,
109 /* We got preempted, so give up */
110 KeLowerIrql(OldIrql
);
116 IopRemoveThreadIrp(VOID
)
121 PLIST_ENTRY IrpEntry
;
122 PIO_ERROR_LOG_PACKET ErrorLogEntry
;
123 PDEVICE_OBJECT DeviceObject
= NULL
;
124 PIO_STACK_LOCATION IoStackLocation
;
126 /* First, raise to APC to protect IrpList */
127 KeRaiseIrql(APC_LEVEL
, &OldIrql
);
129 /* Get the Thread and check the list */
130 IrpThread
= PsGetCurrentThread();
131 if (IsListEmpty(&IrpThread
->IrpList
))
133 /* It got completed now, so quit */
134 KeLowerIrql(OldIrql
);
138 /* Get the misbehaving IRP */
139 IrpEntry
= IrpThread
->IrpList
.Flink
;
140 DeadIrp
= CONTAINING_RECORD(IrpEntry
, IRP
, ThreadListEntry
);
141 IOTRACE(IO_IRP_DEBUG
,
142 "%s - Deassociating IRP %p for %p\n",
147 /* Don't cancel the IRP if it's already been completed far */
148 if (DeadIrp
->CurrentLocation
== (DeadIrp
->StackCount
+ 2))
151 KeLowerIrql(OldIrql
);
155 /* Disown the IRP! */
156 DeadIrp
->Tail
.Overlay
.Thread
= NULL
;
157 RemoveHeadList(&IrpThread
->IrpList
);
158 InitializeListHead(&DeadIrp
->ThreadListEntry
);
160 /* Get the stack location and check if it's valid */
161 IoStackLocation
= IoGetCurrentIrpStackLocation(DeadIrp
);
162 if (DeadIrp
->CurrentLocation
<= DeadIrp
->StackCount
)
164 /* Get the device object */
165 DeviceObject
= IoStackLocation
->DeviceObject
;
168 /* Lower IRQL now, since we have the pointers we need */
169 KeLowerIrql(OldIrql
);
171 /* Check if we can send an Error Log Entry*/
174 /* Allocate an entry */
175 ErrorLogEntry
= IoAllocateErrorLogEntry(DeviceObject
,
176 sizeof(IO_ERROR_LOG_PACKET
));
179 /* Write the entry */
180 ErrorLogEntry
->ErrorCode
= 0xBAADF00D; /* FIXME */
181 IoWriteErrorLogEntry(ErrorLogEntry
);
188 IopCleanupIrp(IN PIRP Irp
,
189 IN PFILE_OBJECT FileObject
)
192 IOTRACE(IO_IRP_DEBUG
,
193 "%s - Cleaning IRP %p for %p\n",
198 /* Check if there's an MDL */
199 while ((Mdl
= Irp
->MdlAddress
))
201 /* Clear all of them */
202 Irp
->MdlAddress
= Mdl
->Next
;
206 /* Check if the IRP has system buffer */
207 if (Irp
->Flags
& IRP_DEALLOCATE_BUFFER
)
209 /* Free the buffer */
210 ExFreePoolWithTag(Irp
->AssociatedIrp
.SystemBuffer
, TAG_SYS_BUF
);
213 /* Check if this IRP has a user event, a file object, and is async */
214 if ((Irp
->UserEvent
) &&
215 !(Irp
->Flags
& IRP_SYNCHRONOUS_API
) &&
218 /* Dereference the User Event */
219 ObDereferenceObject(Irp
->UserEvent
);
222 /* Check if we have a file object and this isn't a create operation */
223 if ((FileObject
) && !(Irp
->Flags
& IRP_CREATE_OPERATION
))
225 /* Dereference the file object */
226 ObDereferenceObject(FileObject
);
235 IopCompleteRequest(IN PKAPC Apc
,
236 IN PKNORMAL_ROUTINE
* NormalRoutine
,
237 IN PVOID
* NormalContext
,
238 IN PVOID
* SystemArgument1
,
239 IN PVOID
* SystemArgument2
)
241 PFILE_OBJECT FileObject
;
244 PVOID Port
= NULL
, Key
= NULL
;
245 BOOLEAN SignaledCreateRequest
= FALSE
;
247 /* Get data from the APC */
248 FileObject
= (PFILE_OBJECT
)*SystemArgument1
;
249 Irp
= CONTAINING_RECORD(Apc
, IRP
, Tail
.Apc
);
250 IOTRACE(IO_IRP_DEBUG
,
251 "%s - Completing IRP %p for %p\n",
257 ASSERT(Irp
->IoStatus
.Status
!= 0xFFFFFFFF);
259 /* Check if we have a file object */
260 if (*SystemArgument2
)
262 /* Check if we're reparsing */
263 if ((Irp
->IoStatus
.Status
== STATUS_REPARSE
) &&
264 (Irp
->IoStatus
.Information
== IO_REPARSE_TAG_MOUNT_POINT
))
266 /* We should never get this yet */
267 DPRINT1("Reparse support not yet present!\n");
272 /* Handle Buffered case first */
273 if (Irp
->Flags
& IRP_BUFFERED_IO
)
275 /* Check if we have an input buffer and if we succeeded */
276 if ((Irp
->Flags
& IRP_INPUT_OPERATION
) &&
277 (Irp
->IoStatus
.Status
!= STATUS_VERIFY_REQUIRED
) &&
278 !(NT_ERROR(Irp
->IoStatus
.Status
)))
280 /* Copy the buffer back to the user */
281 RtlCopyMemory(Irp
->UserBuffer
,
282 Irp
->AssociatedIrp
.SystemBuffer
,
283 Irp
->IoStatus
.Information
);
286 /* Also check if we should de-allocate it */
287 if (Irp
->Flags
& IRP_DEALLOCATE_BUFFER
)
290 ExFreePoolWithTag(Irp
->AssociatedIrp
.SystemBuffer
, TAG_SYS_BUF
);
294 /* Now we got rid of these two... */
295 Irp
->Flags
&= ~(IRP_BUFFERED_IO
| IRP_DEALLOCATE_BUFFER
);
297 /* Check if there's an MDL */
298 for (Mdl
= Irp
->MdlAddress
; Mdl
; Mdl
= NextMdl
)
306 Irp
->MdlAddress
= NULL
;
309 * Check if either the request was completed without any errors
310 * (but warnings are OK!), or if it was completed with an error, but
311 * did return from a pending I/O Operation and is not synchronous.
313 if (!(NT_ERROR(Irp
->IoStatus
.Status
)) ||
314 (NT_ERROR(Irp
->IoStatus
.Status
) &&
315 (Irp
->PendingReturned
) &&
316 !(IsIrpSynchronous(Irp
, FileObject
))))
318 /* Get any information we need from the FO before we kill it */
319 if ((FileObject
) && (FileObject
->CompletionContext
))
321 /* Save Completion Data */
322 Port
= FileObject
->CompletionContext
->Port
;
323 Key
= FileObject
->CompletionContext
->Key
;
326 /* Use SEH to make sure we don't write somewhere invalid */
329 /* Save the IOSB Information */
330 *Irp
->UserIosb
= Irp
->IoStatus
;
334 /* Ignore any error */
338 /* Check if we have an event or a file object */
341 /* At the very least, this is a PKEVENT, so signal it always */
342 KeSetEvent(Irp
->UserEvent
, 0, FALSE
);
344 /* Check if we also have a File Object */
347 /* Check if this is an Asynch API */
348 if (!(Irp
->Flags
& IRP_SYNCHRONOUS_API
))
351 if (*((PULONG
)(Irp
->UserEvent
) - 1) != 0x87878787)
353 /* Dereference the event */
354 ObDereferenceObject(Irp
->UserEvent
);
358 DPRINT1("Not an executive event -- should not be dereferenced\n");
363 * Now, if this is a Synch I/O File Object, then this event is
364 * NOT an actual Executive Event, so we won't dereference it,
365 * and instead, we will signal the File Object
367 if ((FileObject
->Flags
& FO_SYNCHRONOUS_IO
) &&
368 !(Irp
->Flags
& IRP_OB_QUERY_NAME
))
370 /* Signal the file object and set the status */
371 KeSetEvent(&FileObject
->Event
, 0, FALSE
);
372 FileObject
->FinalStatus
= Irp
->IoStatus
.Status
;
376 * This could also be a create operation, in which case we want
377 * to make sure there's no APC fired.
379 if (Irp
->Flags
& IRP_CREATE_OPERATION
)
381 /* Clear the APC Routine and remember this */
382 Irp
->Overlay
.AsynchronousParameters
.UserApcRoutine
= NULL
;
383 SignaledCreateRequest
= TRUE
;
389 /* Signal the file object and set the status */
390 KeSetEvent(&FileObject
->Event
, 0, FALSE
);
391 FileObject
->FinalStatus
= Irp
->IoStatus
.Status
;
394 * This could also be a create operation, in which case we want
395 * to make sure there's no APC fired.
397 if (Irp
->Flags
& IRP_CREATE_OPERATION
)
399 /* Clear the APC Routine and remember this */
400 Irp
->Overlay
.AsynchronousParameters
.UserApcRoutine
= NULL
;
401 SignaledCreateRequest
= TRUE
;
405 /* Now that we've signaled the events, de-associate the IRP */
406 IopUnQueueIrpFromThread(Irp
);
408 /* Now check if a User APC Routine was requested */
409 if (Irp
->Overlay
.AsynchronousParameters
.UserApcRoutine
)
412 KeInitializeApc(&Irp
->Tail
.Apc
,
413 KeGetCurrentThread(),
414 CurrentApcEnvironment
,
416 IopAbortIrpKernelApc
,
417 (PKNORMAL_ROUTINE
)Irp
->
418 Overlay
.AsynchronousParameters
.UserApcRoutine
,
421 Overlay
.AsynchronousParameters
.UserApcContext
);
424 KeInsertQueueApc(&Irp
->Tail
.Apc
, Irp
->UserIosb
, NULL
, 2);
427 (Irp
->Overlay
.AsynchronousParameters
.UserApcContext
))
429 /* We have an I/O Completion setup... create the special Overlay */
430 Irp
->Tail
.CompletionKey
= Key
;
431 Irp
->Tail
.Overlay
.PacketType
= IrpCompletionPacket
;
432 KeInsertQueue(Port
, &Irp
->Tail
.Overlay
.ListEntry
);
436 /* Free the IRP since we don't need it anymore */
440 /* Check if we have a file object that wasn't part of a create */
441 if ((FileObject
) && !(SignaledCreateRequest
))
443 /* Dereference it, since it's not needed anymore either */
444 ObDereferenceObjectDeferDelete(FileObject
);
450 * Either we didn't return from the request, or we did return but this
451 * request was synchronous.
453 if ((Irp
->PendingReturned
) && (FileObject
))
455 /* So we did return with a synch operation, was it the IRP? */
456 if (Irp
->Flags
& IRP_SYNCHRONOUS_API
)
458 /* Yes, this IRP was synchronous, so return the I/O Status */
459 *Irp
->UserIosb
= Irp
->IoStatus
;
461 /* Now check if the user gave an event */
465 KeSetEvent(Irp
->UserEvent
, 0, FALSE
);
469 /* No event was given, so signal the FO instead */
470 KeSetEvent(&FileObject
->Event
, 0, FALSE
);
476 * It's not the IRP that was synchronous, it was the FO
477 * that was opened this way. Signal its event.
479 FileObject
->FinalStatus
= Irp
->IoStatus
.Status
;
480 KeSetEvent(&FileObject
->Event
, 0, FALSE
);
484 /* Now that we got here, we do this for incomplete I/Os as well */
485 if ((FileObject
) && !(Irp
->Flags
& IRP_CREATE_OPERATION
))
487 /* Dereference the File Object unless this was a create */
488 ObDereferenceObjectDeferDelete(FileObject
);
492 * Check if this was an Executive Event (remember that we know this
493 * by checking if the IRP is synchronous)
495 if ((Irp
->UserEvent
) &&
497 !(Irp
->Flags
& IRP_SYNCHRONOUS_API
))
499 /* This isn't a PKEVENT, so dereference it */
500 ObDereferenceObject(Irp
->UserEvent
);
503 /* Now that we've signaled the events, de-associate the IRP */
504 IopUnQueueIrpFromThread(Irp
);
506 /* Free the IRP as well */
511 /* FUNCTIONS *****************************************************************/
518 IoAllocateIrp(IN CCHAR StackSize
,
519 IN BOOLEAN ChargeQuota
)
522 USHORT Size
= IoSizeOfIrp(StackSize
);
525 PNPAGED_LOOKASIDE_LIST List
= NULL
;
526 PP_NPAGED_LOOKASIDE_NUMBER ListType
= LookasideSmallIrpList
;
528 /* Set Charge Quota Flag */
529 if (ChargeQuota
) Flags
|= IRP_QUOTA_CHARGED
;
531 /* Figure out which Lookaside List to use */
532 if ((StackSize
<= 8) && (ChargeQuota
== FALSE
))
534 /* Set Fixed Size Flag */
535 Flags
= IRP_ALLOCATED_FIXED_SIZE
;
537 /* See if we should use big list */
540 Size
= IoSizeOfIrp(8);
541 ListType
= LookasideLargeIrpList
;
545 Prcb
= KeGetCurrentPrcb();
547 /* Get the P List First */
548 List
= (PNPAGED_LOOKASIDE_LIST
)Prcb
->PPLookasideList
[ListType
].P
;
550 /* Attempt allocation */
551 List
->L
.TotalAllocates
++;
552 Irp
= (PIRP
)InterlockedPopEntrySList(&List
->L
.ListHead
);
554 /* Check if the P List failed */
557 /* Let the balancer know */
558 List
->L
.AllocateMisses
++;
561 List
= (PNPAGED_LOOKASIDE_LIST
)Prcb
->PPLookasideList
[ListType
].L
;
562 List
->L
.TotalAllocates
++;
563 Irp
= (PIRP
)InterlockedPopEntrySList(&List
->L
.ListHead
);
567 /* Check if we have to use the pool */
570 /* Did we try lookaside and fail? */
571 if (Flags
& IRP_ALLOCATED_FIXED_SIZE
) List
->L
.AllocateMisses
++;
573 /* Check if we should charge quota */
576 /* Irp = ExAllocatePoolWithQuotaTag(NonPagedPool, Size, TAG_IRP); */
578 Irp
= ExAllocatePoolWithTag(NonPagedPool
, Size
, TAG_IRP
);
582 /* Allocate the IRP With no Quota charge */
583 Irp
= ExAllocatePoolWithTag(NonPagedPool
, Size
, TAG_IRP
);
586 /* Make sure it was sucessful */
587 if (!Irp
) return(NULL
);
591 /* We have an IRP from Lookaside */
592 if (ChargeQuota
) Flags
|= IRP_LOOKASIDE_ALLOCATION
;
594 /* In this case there is no charge quota */
595 Flags
&= ~IRP_QUOTA_CHARGED
;
598 /* Now Initialize it */
599 IoInitializeIrp(Irp
, Size
, StackSize
);
601 /* Set the Allocation Flags */
602 Irp
->AllocationFlags
= Flags
;
605 IOTRACE(IO_IRP_DEBUG
,
606 "%s - Allocated IRP %p with allocation flags %lx\n",
618 IoBuildAsynchronousFsdRequest(IN ULONG MajorFunction
,
619 IN PDEVICE_OBJECT DeviceObject
,
622 IN PLARGE_INTEGER StartingOffset
,
623 IN PIO_STATUS_BLOCK IoStatusBlock
)
626 PIO_STACK_LOCATION StackPtr
;
629 Irp
= IoAllocateIrp(DeviceObject
->StackSize
, FALSE
);
630 if (!Irp
) return Irp
;
633 StackPtr
= IoGetNextIrpStackLocation(Irp
);
635 /* Write the Major function and then deal with it */
636 StackPtr
->MajorFunction
= (UCHAR
)MajorFunction
;
638 /* Do not handle the following here */
639 if ((MajorFunction
!= IRP_MJ_FLUSH_BUFFERS
) &&
640 (MajorFunction
!= IRP_MJ_SHUTDOWN
) &&
641 (MajorFunction
!= IRP_MJ_PNP
) &&
642 (MajorFunction
!= IRP_MJ_POWER
))
644 /* Check if this is Buffered IO */
645 if (DeviceObject
->Flags
& DO_BUFFERED_IO
)
647 /* Allocate the System Buffer */
648 Irp
->AssociatedIrp
.SystemBuffer
=
649 ExAllocatePoolWithTag(NonPagedPool
, Length
, TAG_SYS_BUF
);
650 if (!Irp
->AssociatedIrp
.SystemBuffer
)
652 /* Free the IRP and fail */
658 Irp
->Flags
= IRP_BUFFERED_IO
| IRP_DEALLOCATE_BUFFER
;
660 /* Handle special IRP_MJ_WRITE Case */
661 if (MajorFunction
== IRP_MJ_WRITE
)
663 /* Copy the buffer data */
664 RtlCopyMemory(Irp
->AssociatedIrp
.SystemBuffer
, Buffer
, Length
);
668 /* Set the Input Operation flag and set this as a User Buffer */
669 Irp
->Flags
|= IRP_INPUT_OPERATION
;
670 Irp
->UserBuffer
= Buffer
;
673 else if (DeviceObject
->Flags
& DO_DIRECT_IO
)
675 /* Use an MDL for Direct I/O */
676 Irp
->MdlAddress
= IoAllocateMdl(Buffer
,
681 if (!Irp
->MdlAddress
)
683 /* Free the IRP and fail */
692 MmProbeAndLockPages(Irp
->MdlAddress
,
694 MajorFunction
== IRP_MJ_READ
?
695 IoWriteAccess
: IoReadAccess
);
699 /* Free the IRP and its MDL */
700 IoFreeMdl(Irp
->MdlAddress
);
706 /* This is how we know if we failed during the probe */
707 if (!Irp
) return NULL
;
711 /* Neither, use the buffer */
712 Irp
->UserBuffer
= Buffer
;
715 /* Check if this is a read */
716 if (MajorFunction
== IRP_MJ_READ
)
718 /* Set the parameters for a read */
719 StackPtr
->Parameters
.Read
.Length
= Length
;
720 StackPtr
->Parameters
.Read
.ByteOffset
= *StartingOffset
;
722 else if (MajorFunction
== IRP_MJ_WRITE
)
724 /* Otherwise, set write parameters */
725 StackPtr
->Parameters
.Write
.Length
= Length
;
726 StackPtr
->Parameters
.Write
.ByteOffset
= *StartingOffset
;
730 /* Set the Current Thread and IOSB */
731 Irp
->UserIosb
= IoStatusBlock
;
732 Irp
->Tail
.Overlay
.Thread
= PsGetCurrentThread();
734 /* Set the Status Block after all is done */
735 IOTRACE(IO_IRP_DEBUG
,
736 "%s - Built IRP %p with Major, Buffer, DO %lx %p %p\n",
750 IoBuildDeviceIoControlRequest(IN ULONG IoControlCode
,
751 IN PDEVICE_OBJECT DeviceObject
,
752 IN PVOID InputBuffer
,
753 IN ULONG InputBufferLength
,
754 IN PVOID OutputBuffer
,
755 IN ULONG OutputBufferLength
,
756 IN BOOLEAN InternalDeviceIoControl
,
758 IN PIO_STATUS_BLOCK IoStatusBlock
)
761 PIO_STACK_LOCATION StackPtr
;
765 Irp
= IoAllocateIrp(DeviceObject
->StackSize
, FALSE
);
766 if (!Irp
) return Irp
;
769 StackPtr
= IoGetNextIrpStackLocation(Irp
);
771 /* Set the DevCtl Type */
772 StackPtr
->MajorFunction
= InternalDeviceIoControl
?
773 IRP_MJ_INTERNAL_DEVICE_CONTROL
:
774 IRP_MJ_DEVICE_CONTROL
;
776 /* Set the IOCTL Data */
777 StackPtr
->Parameters
.DeviceIoControl
.IoControlCode
= IoControlCode
;
778 StackPtr
->Parameters
.DeviceIoControl
.InputBufferLength
= InputBufferLength
;
779 StackPtr
->Parameters
.DeviceIoControl
.OutputBufferLength
=
782 /* Handle the Methods */
783 switch (IO_METHOD_FROM_CTL_CODE(IoControlCode
))
786 case METHOD_BUFFERED
:
788 /* Select the right Buffer Length */
789 BufferLength
= InputBufferLength
> OutputBufferLength
?
790 InputBufferLength
: OutputBufferLength
;
792 /* Make sure there is one */
795 /* Allocate the System Buffer */
796 Irp
->AssociatedIrp
.SystemBuffer
=
797 ExAllocatePoolWithTag(NonPagedPool
,
800 if (!Irp
->AssociatedIrp
.SystemBuffer
)
802 /* Free the IRP and fail */
807 /* Check if we got a buffer */
810 /* Copy into the System Buffer */
811 RtlCopyMemory(Irp
->AssociatedIrp
.SystemBuffer
,
816 /* Write the flags */
817 Irp
->Flags
= IRP_BUFFERED_IO
| IRP_DEALLOCATE_BUFFER
;
818 if (OutputBuffer
) Irp
->Flags
|= IRP_INPUT_OPERATION
;
820 /* Save the Buffer */
821 Irp
->UserBuffer
= OutputBuffer
;
825 /* Clear the Flags and Buffer */
827 Irp
->UserBuffer
= NULL
;
832 case METHOD_IN_DIRECT
:
833 case METHOD_OUT_DIRECT
:
835 /* Check if we got an input buffer */
838 /* Allocate the System Buffer */
839 Irp
->AssociatedIrp
.SystemBuffer
=
840 ExAllocatePoolWithTag(NonPagedPool
,
843 if (!Irp
->AssociatedIrp
.SystemBuffer
)
845 /* Free the IRP and fail */
850 /* Copy into the System Buffer */
851 RtlCopyMemory(Irp
->AssociatedIrp
.SystemBuffer
,
855 /* Write the flags */
856 Irp
->Flags
= IRP_BUFFERED_IO
| IRP_DEALLOCATE_BUFFER
;
863 /* Check if we got an output buffer */
866 /* Allocate the System Buffer */
867 Irp
->MdlAddress
= IoAllocateMdl(OutputBuffer
,
872 if (!Irp
->MdlAddress
)
874 /* Free the IRP and fail */
883 MmProbeAndLockPages(Irp
->MdlAddress
,
885 IO_METHOD_FROM_CTL_CODE(IoControlCode
) ==
887 IoReadAccess
: IoWriteAccess
);
892 IoFreeMdl(Irp
->MdlAddress
);
894 /* Free the input buffer and IRP */
895 if (InputBuffer
) ExFreePool(Irp
->AssociatedIrp
.SystemBuffer
);
901 /* This is how we know if probing failed */
902 if (!Irp
) return NULL
;
908 /* Just save the Buffer */
909 Irp
->UserBuffer
= OutputBuffer
;
910 StackPtr
->Parameters
.DeviceIoControl
.Type3InputBuffer
= InputBuffer
;
913 /* Now write the Event and IoSB */
914 Irp
->UserIosb
= IoStatusBlock
;
915 Irp
->UserEvent
= Event
;
917 /* Sync IRPs are queued to requestor thread's irp cancel/cleanup list */
918 Irp
->Tail
.Overlay
.Thread
= PsGetCurrentThread();
919 IoQueueThreadIrp(Irp
);
922 IOTRACE(IO_IRP_DEBUG
,
923 "%s - Built IRP %p with IOCTL, Buffers, DO %lx %p %p %p\n",
938 IoBuildSynchronousFsdRequest(IN ULONG MajorFunction
,
939 IN PDEVICE_OBJECT DeviceObject
,
942 IN PLARGE_INTEGER StartingOffset
,
944 IN PIO_STATUS_BLOCK IoStatusBlock
)
948 /* Do the big work to set up the IRP */
949 Irp
= IoBuildAsynchronousFsdRequest(MajorFunction
,
955 if (!Irp
) return NULL
;
957 /* Set the Event which makes it Syncronous */
958 Irp
->UserEvent
= Event
;
960 /* Sync IRPs are queued to requestor thread's irp cancel/cleanup list */
961 IoQueueThreadIrp(Irp
);
970 IoCancelIrp(IN PIRP Irp
)
973 PDRIVER_CANCEL CancelRoutine
;
974 IOTRACE(IO_IRP_DEBUG
,
975 "%s - Canceling IRP %p\n",
978 ASSERT(Irp
->Type
== IO_TYPE_IRP
);
980 /* Acquire the cancel lock and cancel the IRP */
981 IoAcquireCancelSpinLock(&OldIrql
);
984 /* Clear the cancel routine and get the old one */
985 CancelRoutine
= IoSetCancelRoutine(Irp
, NULL
);
988 /* We had a routine, make sure the IRP isn't completed */
989 if (Irp
->CurrentLocation
> (Irp
->StackCount
+ 1))
991 /* It is, bugcheck */
992 KeBugCheckEx(CANCEL_STATE_IN_COMPLETED_IRP
,
999 /* Set the cancel IRQL And call the routine */
1000 Irp
->CancelIrql
= OldIrql
;
1001 CancelRoutine(IoGetCurrentIrpStackLocation(Irp
)->DeviceObject
, Irp
);
1005 /* Otherwise, release the cancel lock and fail */
1006 IoReleaseCancelSpinLock(OldIrql
);
1015 IoCancelThreadIo(IN PETHREAD Thread
)
1018 ULONG Retries
= 3000;
1019 LARGE_INTEGER Interval
;
1020 PLIST_ENTRY ListHead
, NextEntry
;
1022 IOTRACE(IO_IRP_DEBUG
,
1023 "%s - Canceling IRPs for Thread %p\n",
1027 /* Raise to APC to protect the IrpList */
1028 KeRaiseIrql(APC_LEVEL
, &OldIrql
);
1030 /* Start by cancelling all the IRPs in the current thread queue. */
1031 ListHead
= &Thread
->IrpList
;
1032 NextEntry
= ListHead
->Flink
;
1033 while (ListHead
!= NextEntry
)
1036 Irp
= CONTAINING_RECORD(NextEntry
, IRP
, ThreadListEntry
);
1041 /* Move to the next entry */
1042 NextEntry
= NextEntry
->Flink
;
1045 /* Wait 100 milliseconds */
1046 Interval
.QuadPart
= -1000000;
1048 /* Wait till all the IRPs are completed or cancelled. */
1049 while (!IsListEmpty(&Thread
->IrpList
))
1051 /* Now we can lower */
1052 KeLowerIrql(OldIrql
);
1054 /* Wait a short while and then look if all our IRPs were completed. */
1055 KeDelayExecutionThread(KernelMode
, FALSE
, &Interval
);
1058 * Don't stay here forever if some broken driver doesn't complete
1061 if (!(Retries
--)) IopRemoveThreadIrp();
1063 /* Raise the IRQL Again */
1064 KeRaiseIrql(APC_LEVEL
, &OldIrql
);
1067 /* We're done, lower the IRQL */
1068 KeLowerIrql(OldIrql
);
1076 IoCallDriver(IN PDEVICE_OBJECT DeviceObject
,
1079 /* Call fast call */
1080 return IofCallDriver(DeviceObject
, Irp
);
1088 IoCompleteRequest(IN PIRP Irp
,
1089 IN CCHAR PriorityBoost
)
1091 /* Call the fastcall */
1092 IofCompleteRequest(Irp
, PriorityBoost
);
1100 IoEnqueueIrp(IN PIRP Irp
)
1102 /* This is the same as calling IoQueueThreadIrp */
1103 IoQueueThreadIrp(Irp
);
1111 IofCallDriver(IN PDEVICE_OBJECT DeviceObject
,
1114 PDRIVER_OBJECT DriverObject
;
1115 PIO_STACK_LOCATION Param
;
1117 /* Get the Driver Object */
1118 DriverObject
= DeviceObject
->DriverObject
;
1120 /* Decrease the current location and check if */
1121 Irp
->CurrentLocation
--;
1122 if (Irp
->CurrentLocation
<= 0)
1124 /* This IRP ran out of stack, bugcheck */
1125 KeBugCheckEx(NO_MORE_IRP_STACK_LOCATIONS
, (ULONG_PTR
)Irp
, 0, 0, 0);
1128 /* Now update the stack location */
1129 Param
= IoGetNextIrpStackLocation(Irp
);
1130 Irp
->Tail
.Overlay
.CurrentStackLocation
= Param
;
1132 /* Get the Device Object */
1133 Param
->DeviceObject
= DeviceObject
;
1136 return DriverObject
->MajorFunction
[Param
->MajorFunction
](DeviceObject
,
1142 IopClearStackLocation(IN PIO_STACK_LOCATION IoStackLocation
)
1144 IoStackLocation
->MinorFunction
= 0;
1145 IoStackLocation
->Flags
= 0;
1146 IoStackLocation
->Control
&= SL_ERROR_RETURNED
;
1147 IoStackLocation
->Parameters
.Others
.Argument1
= 0;
1148 IoStackLocation
->Parameters
.Others
.Argument2
= 0;
1149 IoStackLocation
->Parameters
.Others
.Argument3
= 0;
1150 IoStackLocation
->FileObject
= NULL
;
1158 IofCompleteRequest(IN PIRP Irp
,
1159 IN CCHAR PriorityBoost
)
1161 PIO_STACK_LOCATION StackPtr
, LastStackPtr
;
1162 PDEVICE_OBJECT DeviceObject
;
1163 PFILE_OBJECT FileObject
;
1170 NTSTATUS ErrorCode
= STATUS_SUCCESS
;
1171 IOTRACE(IO_IRP_DEBUG
,
1172 "%s - Completing IRP %p\n",
1176 /* Make sure this IRP isn't getting completed twice or is invalid */
1177 if ((Irp
->CurrentLocation
) > (Irp
->StackCount
+ 1))
1180 KeBugCheckEx(MULTIPLE_IRP_COMPLETE_REQUESTS
, (ULONG_PTR
)Irp
, 0, 0, 0);
1183 /* Some sanity checks */
1184 ASSERT(Irp
->Type
== IO_TYPE_IRP
);
1185 ASSERT(!Irp
->CancelRoutine
);
1186 ASSERT(Irp
->IoStatus
.Status
!= STATUS_PENDING
);
1187 ASSERT(Irp
->IoStatus
.Status
!= 0xFFFFFFFF);
1189 /* Get the last stack */
1190 LastStackPtr
= (PIO_STACK_LOCATION
)(Irp
+ 1);
1191 if (LastStackPtr
->Control
& SL_ERROR_RETURNED
)
1193 /* Get the error code */
1194 ErrorCode
= (NTSTATUS
)LastStackPtr
->Parameters
.Others
.Argument4
;
1197 /* Get the Current Stack and skip it */
1198 StackPtr
= IoGetCurrentIrpStackLocation(Irp
);
1199 IoSkipCurrentIrpStackLocation(Irp
);
1201 /* Loop the Stacks and complete the IRPs */
1204 /* Set Pending Returned */
1205 Irp
->PendingReturned
= StackPtr
->Control
& SL_PENDING_RETURNED
;
1207 /* Check if we failed */
1208 if (!NT_SUCCESS(Irp
->IoStatus
.Status
))
1210 /* Check if it was changed by a completion routine */
1211 if (Irp
->IoStatus
.Status
!= ErrorCode
)
1213 /* Update the error for the current stack */
1214 ErrorCode
= Irp
->IoStatus
.Status
;
1215 StackPtr
->Control
|= SL_ERROR_RETURNED
;
1216 LastStackPtr
->Parameters
.Others
.Argument4
= (PVOID
)ErrorCode
;
1217 LastStackPtr
->Control
|= SL_ERROR_RETURNED
;
1221 /* Check if there is a Completion Routine to Call */
1222 if ((NT_SUCCESS(Irp
->IoStatus
.Status
) &&
1223 (StackPtr
->Control
& SL_INVOKE_ON_SUCCESS
)) ||
1224 (!NT_SUCCESS(Irp
->IoStatus
.Status
) &&
1225 (StackPtr
->Control
& SL_INVOKE_ON_ERROR
)) ||
1227 (StackPtr
->Control
& SL_INVOKE_ON_CANCEL
)))
1229 /* Clear the stack location */
1230 IopClearStackLocation(StackPtr
);
1232 /* Check for highest-level device completion routines */
1233 if (Irp
->CurrentLocation
== (Irp
->StackCount
+ 1))
1235 /* Clear the DO, since the current stack location is invalid */
1236 DeviceObject
= NULL
;
1240 /* Otherwise, return the real one */
1241 DeviceObject
= IoGetCurrentIrpStackLocation(Irp
)->DeviceObject
;
1244 /* Call the completion routine */
1245 Status
= StackPtr
->CompletionRoutine(DeviceObject
,
1249 /* Don't touch the Packet in this case, since it might be gone! */
1250 if (Status
== STATUS_MORE_PROCESSING_REQUIRED
) return;
1254 /* Otherwise, check if this is a completed IRP */
1255 if ((Irp
->CurrentLocation
<= Irp
->StackCount
) &&
1256 (Irp
->PendingReturned
))
1258 /* Mark it as pending */
1259 IoMarkIrpPending(Irp
);
1262 /* Clear the stack location */
1263 IopClearStackLocation(StackPtr
);
1266 /* Move to next stack location and pointer */
1267 IoSkipCurrentIrpStackLocation(Irp
);
1269 } while (Irp
->CurrentLocation
<= (Irp
->StackCount
+ 1));
1271 /* Check if the IRP is an associated IRP */
1272 if (Irp
->Flags
& IRP_ASSOCIATED_IRP
)
1274 /* Get the master IRP and count */
1275 MasterIrp
= Irp
->AssociatedIrp
.MasterIrp
;
1276 MasterCount
= InterlockedDecrement(&MasterIrp
->AssociatedIrp
.IrpCount
);
1279 for (Mdl
= Irp
->MdlAddress
; Mdl
; Mdl
= NextMdl
)
1281 /* Go to the next one */
1282 NextMdl
= Mdl
->Next
;
1286 /* Free the IRP itself */
1289 /* Complete the Master IRP */
1290 if (!MasterCount
) IofCompleteRequest(MasterIrp
, PriorityBoost
);
1294 /* We don't support this yet */
1295 ASSERT(Irp
->IoStatus
.Status
!= STATUS_REPARSE
);
1297 /* Check if we have an auxiliary buffer */
1298 if (Irp
->Tail
.Overlay
.AuxiliaryBuffer
)
1301 ExFreePool(Irp
->Tail
.Overlay
.AuxiliaryBuffer
);
1302 Irp
->Tail
.Overlay
.AuxiliaryBuffer
= NULL
;
1305 /* Check if this is a Paging I/O or Close Operation */
1306 if (Irp
->Flags
& (IRP_PAGING_IO
| IRP_CLOSE_OPERATION
))
1308 /* Handle a Close Operation or Sync Paging I/O */
1309 if (Irp
->Flags
& (IRP_SYNCHRONOUS_PAGING_IO
| IRP_CLOSE_OPERATION
))
1311 /* Set the I/O Status and Signal the Event */
1312 Flags
= Irp
->Flags
& (IRP_SYNCHRONOUS_PAGING_IO
| IRP_PAGING_IO
);
1313 *Irp
->UserIosb
= Irp
->IoStatus
;
1314 KeSetEvent(Irp
->UserEvent
, PriorityBoost
, FALSE
);
1316 /* Free the IRP for a Paging I/O Only, Close is handled by us */
1317 if (Flags
) IoFreeIrp(Irp
);
1323 KeInitializeApc(&Irp
->Tail
.Apc
1324 &Irp
->Tail
.Overlay
.Thread
->Tcb
,
1325 Irp
->ApcEnvironment
,
1326 IopCompletePageWrite
,
1331 KeInsertQueueApc(&Irp
->Tail
.Apc
,
1336 /* Not implemented yet. */
1337 DPRINT1("Not supported!\n");
1342 /* Get out of here */
1346 /* Unlock MDL Pages, page 167. */
1347 Mdl
= Irp
->MdlAddress
;
1354 /* Check if we should exit because of a Deferred I/O (page 168) */
1355 if ((Irp
->Flags
& IRP_DEFER_IO_COMPLETION
) && !(Irp
->PendingReturned
))
1358 * Return without queuing the completion APC, since the caller will
1359 * take care of doing its own optimized completion at PASSIVE_LEVEL.
1364 /* Get the thread and file object */
1365 Thread
= Irp
->Tail
.Overlay
.Thread
;
1366 FileObject
= Irp
->Tail
.Overlay
.OriginalFileObject
;
1368 /* Make sure the IRP isn't canceled */
1371 /* Initialize the APC */
1372 KeInitializeApc(&Irp
->Tail
.Apc
,
1374 Irp
->ApcEnvironment
,
1382 KeInsertQueueApc(&Irp
->Tail
.Apc
,
1384 NULL
, /* This is used for REPARSE stuff */
1389 /* The IRP just got canceled... does a thread still own it? */
1390 Thread
= Irp
->Tail
.Overlay
.Thread
;
1393 /* Yes! There is still hope! Initialize the APC */
1394 KeInitializeApc(&Irp
->Tail
.Apc
,
1396 Irp
->ApcEnvironment
,
1404 KeInsertQueueApc(&Irp
->Tail
.Apc
,
1406 NULL
, /* This is used for REPARSE stuff */
1411 /* Nothing left for us to do, kill it */
1412 ASSERT(Irp
->Cancel
);
1413 IopCleanupIrp(Irp
, FileObject
);
1420 IopSynchronousCompletion(
1421 IN PDEVICE_OBJECT DeviceObject
,
1425 if (Irp
->PendingReturned
)
1426 KeSetEvent((PKEVENT
)Context
, IO_NO_INCREMENT
, FALSE
);
1427 return STATUS_MORE_PROCESSING_REQUIRED
;
1435 IoForwardIrpSynchronously(IN PDEVICE_OBJECT DeviceObject
,
1441 /* Check if next stack location is available */
1442 if (Irp
->CurrentLocation
< Irp
->StackCount
)
1444 /* No more stack location */
1448 /* Initialize event */
1449 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
1451 /* Copy stack location for next driver */
1452 IoCopyCurrentIrpStackLocationToNext(Irp
);
1454 /* Set a completion routine, which will signal the event */
1455 IoSetCompletionRoutine(Irp
, IopSynchronousCompletion
, &Event
, TRUE
, TRUE
, TRUE
);
1457 /* Call next driver */
1458 Status
= IoCallDriver(DeviceObject
, Irp
);
1460 /* Check if irp is pending */
1461 if (Status
== STATUS_PENDING
)
1463 /* Yes, wait for its completion */
1464 KeWaitForSingleObject(&Event
, Suspended
, KernelMode
, FALSE
, NULL
);
1475 IoFreeIrp(IN PIRP Irp
)
1477 PNPAGED_LOOKASIDE_LIST List
;
1478 PP_NPAGED_LOOKASIDE_NUMBER ListType
= LookasideSmallIrpList
;
1480 IOTRACE(IO_IRP_DEBUG
,
1481 "%s - Freeing IRPs %p\n",
1485 /* Make sure the Thread IRP list is empty and that it OK to free it */
1486 ASSERT(Irp
->Type
== IO_TYPE_IRP
);
1487 ASSERT(IsListEmpty(&Irp
->ThreadListEntry
));
1488 ASSERT(Irp
->CurrentLocation
>= Irp
->StackCount
);
1490 /* If this was a pool alloc, free it with the pool */
1491 if (!(Irp
->AllocationFlags
& IRP_ALLOCATED_FIXED_SIZE
))
1498 /* Check if this was a Big IRP */
1499 if (Irp
->StackCount
!= 1) ListType
= LookasideLargeIrpList
;
1502 Prcb
= KeGetCurrentPrcb();
1504 /* Use the P List */
1505 List
= (PNPAGED_LOOKASIDE_LIST
)Prcb
->PPLookasideList
[ListType
].P
;
1506 List
->L
.TotalFrees
++;
1508 /* Check if the Free was within the Depth or not */
1509 if (ExQueryDepthSList(&List
->L
.ListHead
) >= List
->L
.Depth
)
1511 /* Let the balancer know */
1512 List
->L
.FreeMisses
++;
1514 /* Use the L List */
1515 List
= (PNPAGED_LOOKASIDE_LIST
)Prcb
->PPLookasideList
[ListType
].L
;
1516 List
->L
.TotalFrees
++;
1518 /* Check if the Free was within the Depth or not */
1519 if (ExQueryDepthSList(&List
->L
.ListHead
) >= List
->L
.Depth
)
1521 /* All lists failed, use the pool */
1522 List
->L
.FreeMisses
++;
1528 /* The free was within the Depth */
1531 InterlockedPushEntrySList(&List
->L
.ListHead
,
1532 (PSINGLE_LIST_ENTRY
)Irp
);
1542 IoGetPagingIoPriority(IN PIRP Irp
)
1546 /* Lie and say this isn't a paging IRP -- FIXME! */
1547 return IoPagingPriorityInvalid
;
1554 IoGetRequestorProcess(IN PIRP Irp
)
1556 return(Irp
->Tail
.Overlay
.Thread
->ThreadsProcess
);
1564 IoGetRequestorProcessId(IN PIRP Irp
)
1566 return (ULONG
)(IoGetRequestorProcess(Irp
)->UniqueProcessId
);
1574 IoGetRequestorSessionId(IN PIRP Irp
,
1575 OUT PULONG pSessionId
)
1577 /* Return the session */
1578 *pSessionId
= IoGetRequestorProcess(Irp
)->Session
;
1579 return STATUS_SUCCESS
;
1587 IoGetTopLevelIrp(VOID
)
1589 return (PIRP
)PsGetCurrentThread()->TopLevelIrp
;
1597 IoInitializeIrp(IN PIRP Irp
,
1598 IN USHORT PacketSize
,
1602 IOTRACE(IO_IRP_DEBUG
,
1603 "%s - Initializing IRP %p\n",
1606 RtlZeroMemory(Irp
, PacketSize
);
1608 /* Set the Header and other data */
1609 Irp
->Type
= IO_TYPE_IRP
;
1610 Irp
->Size
= PacketSize
;
1611 Irp
->StackCount
= StackSize
;
1612 Irp
->CurrentLocation
= StackSize
+ 1;
1613 Irp
->ApcEnvironment
= KeGetCurrentThread()->ApcStateIndex
;
1614 Irp
->Tail
.Overlay
.CurrentStackLocation
= (PIO_STACK_LOCATION
)(Irp
+ 1) + StackSize
;
1616 /* Initialize the Thread List */
1617 InitializeListHead(&Irp
->ThreadListEntry
);
1625 IoIsOperationSynchronous(IN PIRP Irp
)
1627 /* Check the flags */
1628 if (!(Irp
->Flags
& (IRP_PAGING_IO
| IRP_SYNCHRONOUS_PAGING_IO
)) &&
1629 ((Irp
->Flags
& IRP_SYNCHRONOUS_PAGING_IO
) ||
1630 (Irp
->Flags
& IRP_SYNCHRONOUS_API
) ||
1631 (IoGetCurrentIrpStackLocation(Irp
)->FileObject
->Flags
&
1632 FO_SYNCHRONOUS_IO
)))
1634 /* Synch API or Paging I/O is OK, as is Sync File I/O */
1638 /* Otherwise, it is an asynchronous operation. */
1647 IoIsValidNameGraftingBuffer(IN PIRP Irp
,
1648 IN PREPARSE_DATA_BUFFER ReparseBuffer
)
1659 IoMakeAssociatedIrp(IN PIRP Irp
,
1663 IOTRACE(IO_IRP_DEBUG
,
1664 "%s - Associating IRP %p\n",
1668 /* Allocate the IRP */
1669 AssocIrp
= IoAllocateIrp(StackSize
, FALSE
);
1670 if (!AssocIrp
) return NULL
;
1673 AssocIrp
->Flags
|= IRP_ASSOCIATED_IRP
;
1675 /* Set the Thread */
1676 AssocIrp
->Tail
.Overlay
.Thread
= Irp
->Tail
.Overlay
.Thread
;
1678 /* Associate them */
1679 AssocIrp
->AssociatedIrp
.MasterIrp
= Irp
;
1688 IoQueueThreadIrp(IN PIRP Irp
)
1690 IOTRACE(IO_IRP_DEBUG
,
1691 "%s - Queueing IRP %p\n",
1695 /* Use our inlined routine */
1696 IopQueueIrpToThread(Irp
);
1701 * Reference: Chris Cant's "Writing WDM Device Drivers"
1705 IoReuseIrp(IN OUT PIRP Irp
,
1708 UCHAR AllocationFlags
;
1709 IOTRACE(IO_IRP_DEBUG
,
1710 "%s - Reusing IRP %p\n",
1714 /* Make sure it's OK to reuse it */
1715 ASSERT(!Irp
->CancelRoutine
);
1716 ASSERT(IsListEmpty(&Irp
->ThreadListEntry
));
1718 /* Get the old flags */
1719 AllocationFlags
= Irp
->AllocationFlags
;
1721 /* Reinitialize the IRP */
1722 IoInitializeIrp(Irp
, Irp
->Size
, Irp
->StackCount
);
1724 /* Duplicate the data */
1725 Irp
->IoStatus
.Status
= Status
;
1726 Irp
->AllocationFlags
= AllocationFlags
;
1734 IoSetTopLevelIrp(IN PIRP Irp
)
1737 PsGetCurrentThread()->TopLevelIrp
= (ULONG
)Irp
;