2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/io/irp.c
5 * PURPOSE: IRP Handling Functions
6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
8 * Filip Navara (navaraf@reactos.org)
11 /* INCLUDES ****************************************************************/
15 #include <internal/debug.h>
17 /* Undefine some macros we implement here */
19 #undef IoCompleteRequest
21 /* PRIVATE FUNCTIONS ********************************************************/
25 IopFreeIrpKernelApc(IN PKAPC Apc
,
26 IN PKNORMAL_ROUTINE
*NormalRoutine
,
27 IN PVOID
*NormalContext
,
28 IN PVOID
*SystemArgument1
,
29 IN PVOID
*SystemArgument2
)
32 IoFreeIrp(CONTAINING_RECORD(Apc
, IRP
, Tail
.Apc
));
37 IopAbortIrpKernelApc(IN PKAPC Apc
)
40 IoFreeIrp(CONTAINING_RECORD(Apc
, IRP
, Tail
.Apc
));
45 IopCleanupFailedIrp(IN PFILE_OBJECT FileObject
,
46 IN PKEVENT EventObject
)
50 /* Dereference the event */
51 if (EventObject
) ObDereferenceObject(EventObject
);
53 /* If this was a file opened for synch I/O, then unlock it */
54 if (FileObject
->Flags
& FO_SYNCHRONOUS_IO
) IopUnlockFileObject(FileObject
);
56 /* Now dereference it and return */
57 ObDereferenceObject(FileObject
);
58 return STATUS_INSUFFICIENT_RESOURCES
;
63 IopAbortInterruptedIrp(IN PKEVENT EventObject
,
71 /* Raise IRQL to APC */
72 KeRaiseIrql(APC_LEVEL
, &OldIrql
);
74 /* Check if nobody completed it yet */
75 if (!KeReadStateEvent(EventObject
))
77 /* First, cancel it */
78 CancelResult
= IoCancelIrp(Irp
);
81 /* Check if we cancelled it */
84 /* Wait for the IRP to be cancelled */
85 Wait
.QuadPart
= -100000;
86 while (!KeReadStateEvent(EventObject
))
88 /* Delay indefintely */
89 KeDelayExecutionThread(KernelMode
, FALSE
, &Wait
);
94 /* No cancellation done, so wait for the I/O system to kill it */
95 KeWaitForSingleObject(EventObject
,
104 /* We got preempted, so give up */
105 KeLowerIrql(OldIrql
);
111 IopRemoveThreadIrp(VOID
)
116 PLIST_ENTRY IrpEntry
;
117 PIO_ERROR_LOG_PACKET ErrorLogEntry
;
118 PDEVICE_OBJECT DeviceObject
= NULL
;
119 PIO_STACK_LOCATION IoStackLocation
;
121 /* First, raise to APC to protect IrpList */
122 KeRaiseIrql(APC_LEVEL
, &OldIrql
);
124 /* Get the Thread and check the list */
125 IrpThread
= PsGetCurrentThread();
126 if (IsListEmpty(&IrpThread
->IrpList
))
128 /* It got completed now, so quit */
129 KeLowerIrql(OldIrql
);
133 /* Get the misbehaving IRP */
134 IrpEntry
= IrpThread
->IrpList
.Flink
;
135 DeadIrp
= CONTAINING_RECORD(IrpEntry
, IRP
, ThreadListEntry
);
136 IOTRACE(IO_IRP_DEBUG
,
137 "%s - Deassociating IRP %p for %p\n",
142 /* Don't cancel the IRP if it's already been completed far */
143 if (DeadIrp
->CurrentLocation
== (DeadIrp
->StackCount
+ 2))
146 KeLowerIrql(OldIrql
);
150 /* Disown the IRP! */
151 DeadIrp
->Tail
.Overlay
.Thread
= NULL
;
152 RemoveHeadList(&IrpThread
->IrpList
);
153 InitializeListHead(&DeadIrp
->ThreadListEntry
);
155 /* Get the stack location and check if it's valid */
156 IoStackLocation
= IoGetCurrentIrpStackLocation(DeadIrp
);
157 if (DeadIrp
->CurrentLocation
<= DeadIrp
->StackCount
)
159 /* Get the device object */
160 DeviceObject
= IoStackLocation
->DeviceObject
;
163 /* Lower IRQL now, since we have the pointers we need */
164 KeLowerIrql(OldIrql
);
166 /* Check if we can send an Error Log Entry*/
169 /* Allocate an entry */
170 ErrorLogEntry
= IoAllocateErrorLogEntry(DeviceObject
,
171 sizeof(IO_ERROR_LOG_PACKET
));
174 /* Write the entry */
175 ErrorLogEntry
->ErrorCode
= 0xBAADF00D; /* FIXME */
176 IoWriteErrorLogEntry(ErrorLogEntry
);
183 IopCleanupIrp(IN PIRP Irp
,
184 IN PFILE_OBJECT FileObject
)
187 IOTRACE(IO_IRP_DEBUG
,
188 "%s - Cleaning IRP %p for %p\n",
193 /* Check if there's an MDL */
194 while ((Mdl
= Irp
->MdlAddress
))
196 /* Clear all of them */
197 Irp
->MdlAddress
= Mdl
->Next
;
201 /* Check if the IRP has system buffer */
202 if (Irp
->Flags
& IRP_DEALLOCATE_BUFFER
)
204 /* Free the buffer */
205 ExFreePoolWithTag(Irp
->AssociatedIrp
.SystemBuffer
, TAG_SYS_BUF
);
208 /* Check if this IRP has a user event, a file object, and is async */
209 if ((Irp
->UserEvent
) &&
210 !(Irp
->Flags
& IRP_SYNCHRONOUS_API
) &&
213 /* Derefernce the User Event */
214 ObDereferenceObject(Irp
->UserEvent
);
217 /* Dereference the File Object */
218 if (FileObject
) ObDereferenceObject(FileObject
);
226 IopCompleteRequest(IN PKAPC Apc
,
227 IN PKNORMAL_ROUTINE
* NormalRoutine
,
228 IN PVOID
* NormalContext
,
229 IN PVOID
* SystemArgument1
,
230 IN PVOID
* SystemArgument2
)
232 PFILE_OBJECT FileObject
;
235 PVOID Port
= NULL
, Key
= NULL
;
236 BOOLEAN SignaledCreateRequest
= FALSE
;
238 /* Get data from the APC */
239 FileObject
= (PFILE_OBJECT
)*SystemArgument1
;
240 Irp
= CONTAINING_RECORD(Apc
, IRP
, Tail
.Apc
);
241 IOTRACE(IO_IRP_DEBUG
,
242 "%s - Completing IRP %p for %p\n",
247 /* Handle Buffered case first */
248 if (Irp
->Flags
& IRP_BUFFERED_IO
)
250 /* Check if we have an input buffer and if we suceeded */
251 if ((Irp
->Flags
& IRP_INPUT_OPERATION
) &&
252 (Irp
->IoStatus
.Status
!= STATUS_VERIFY_REQUIRED
) &&
253 !(NT_ERROR(Irp
->IoStatus
.Status
)))
255 /* Copy the buffer back to the user */
256 RtlCopyMemory(Irp
->UserBuffer
,
257 Irp
->AssociatedIrp
.SystemBuffer
,
258 Irp
->IoStatus
.Information
);
261 /* Also check if we should de-allocate it */
262 if (Irp
->Flags
& IRP_DEALLOCATE_BUFFER
)
265 ExFreePoolWithTag(Irp
->AssociatedIrp
.SystemBuffer
, TAG_SYS_BUF
);
269 /* Now we got rid of these two... */
270 Irp
->Flags
&= ~(IRP_BUFFERED_IO
| IRP_DEALLOCATE_BUFFER
);
272 /* Check if there's an MDL */
273 while ((Mdl
= Irp
->MdlAddress
))
275 /* Clear all of them */
276 Irp
->MdlAddress
= Mdl
->Next
;
281 * Check if either the request was completed without any errors
282 * (but warnings are OK!), or if it was completed with an error, but
283 * did return from a pending I/O Operation and is not synchronous.
285 if ((!NT_ERROR(Irp
->IoStatus
.Status
)) ||
286 (NT_ERROR(Irp
->IoStatus
.Status
) &&
287 (Irp
->PendingReturned
) &&
288 !(IsIrpSynchronous(Irp
, FileObject
))))
290 /* Get any information we need from the FO before we kill it */
291 if ((FileObject
) && (FileObject
->CompletionContext
))
293 /* Save Completion Data */
294 Port
= FileObject
->CompletionContext
->Port
;
295 Key
= FileObject
->CompletionContext
->Key
;
298 /* Use SEH to make sure we don't write somewhere invalid */
301 /* Save the IOSB Information */
302 *Irp
->UserIosb
= Irp
->IoStatus
;
306 /* Ignore any error */
310 /* Check if we have an event or a file object */
313 /* At the very least, this is a PKEVENT, so signal it always */
314 KeSetEvent(Irp
->UserEvent
, 0, FALSE
);
316 /* Check if we also have a File Object */
320 * Now, if this is a Synch I/O File Object, then this event is
321 * NOT an actual Executive Event, so we won't dereference it,
322 * and instead, we will signal the File Object
324 if (FileObject
->Flags
& FO_SYNCHRONOUS_IO
)
326 /* Signal the file object and set the status */
327 KeSetEvent(&FileObject
->Event
, 0, FALSE
);
328 FileObject
->FinalStatus
= Irp
->IoStatus
.Status
;
332 * This could also be a create operation, in which case we want
333 * to make sure there's no APC fired.
335 if (Irp
->Flags
& IRP_CREATE_OPERATION
)
337 /* Clear the APC Routine and remmeber this */
338 Irp
->Overlay
.AsynchronousParameters
.UserApcRoutine
= NULL
;
339 SignaledCreateRequest
= TRUE
;
345 /* Signal the file object and set the status */
346 KeSetEvent(&FileObject
->Event
, 0, FALSE
);
347 FileObject
->FinalStatus
= Irp
->IoStatus
.Status
;
350 /* Now that we've signaled the events, de-associate the IRP */
351 RemoveEntryList(&Irp
->ThreadListEntry
);
352 InitializeListHead(&Irp
->ThreadListEntry
);
354 /* Now check if a User APC Routine was requested */
355 if (Irp
->Overlay
.AsynchronousParameters
.UserApcRoutine
)
358 KeInitializeApc(&Irp
->Tail
.Apc
,
359 KeGetCurrentThread(),
360 CurrentApcEnvironment
,
362 IopAbortIrpKernelApc
,
363 (PKNORMAL_ROUTINE
)Irp
->
364 Overlay
.AsynchronousParameters
.UserApcRoutine
,
367 Overlay
.AsynchronousParameters
.UserApcContext
);
370 KeInsertQueueApc(&Irp
->Tail
.Apc
, Irp
->UserIosb
, NULL
, 2);
373 (Irp
->Overlay
.AsynchronousParameters
.UserApcContext
))
375 /* We have an I/O Completion setup... create the special Overlay */
376 Irp
->Tail
.CompletionKey
= Key
;
377 Irp
->Tail
.Overlay
.PacketType
= IrpCompletionPacket
;
378 KeInsertQueue(Port
, &Irp
->Tail
.Overlay
.ListEntry
);
382 /* Free the IRP since we don't need it anymore */
386 /* Check if we have a file object that wasn't part of a create */
387 if ((FileObject
) && !(SignaledCreateRequest
))
389 /* Dereference it, since it's not needed anymore either */
390 ObDereferenceObject(FileObject
);
396 * Either we didn't return from the request, or we did return but this
397 * request was synchronous.
399 if ((Irp
->PendingReturned
) && (FileObject
))
401 /* So we did return with a synch operation, was it the IRP? */
402 if (Irp
->Flags
& IRP_SYNCHRONOUS_API
)
404 /* Yes, this IRP was synchronous, so retrn the I/O Status */
405 *Irp
->UserIosb
= Irp
->IoStatus
;
407 /* Now check if the user gave an event */
411 KeSetEvent(Irp
->UserEvent
, 0, FALSE
);
415 /* No event was given, so signal the FO instead */
416 KeSetEvent(&FileObject
->Event
, 0, FALSE
);
422 * It's not the IRP that was synchronous, it was the FO
423 * that was opened this way. Signal its event.
425 FileObject
->FinalStatus
= Irp
->IoStatus
.Status
;
426 KeSetEvent(&FileObject
->Event
, 0, FALSE
);
430 /* Now that we got here, we do this for incomplete I/Os as well */
431 if ((FileObject
) && !(Irp
->Flags
& IRP_CREATE_OPERATION
))
433 /* Dereference the File Object unless this was a create */
434 ObDereferenceObject(FileObject
);
438 * Check if this was an Executive Event (remember that we know this
439 * by checking if the IRP is synchronous)
441 if ((Irp
->UserEvent
) &&
443 !(Irp
->Flags
& IRP_SYNCHRONOUS_API
))
445 /* This isn't a PKEVENT, so dereference it */
446 ObDereferenceObject(Irp
->UserEvent
);
449 /* Now that we've signaled the events, de-associate the IRP */
450 RemoveEntryList(&Irp
->ThreadListEntry
);
451 InitializeListHead(&Irp
->ThreadListEntry
);
453 /* Free the IRP as well */
458 /* FUNCTIONS *****************************************************************/
465 IoAllocateIrp(IN CCHAR StackSize
,
466 IN BOOLEAN ChargeQuota
)
469 USHORT Size
= IoSizeOfIrp(StackSize
);
472 PNPAGED_LOOKASIDE_LIST List
= NULL
;
473 PP_NPAGED_LOOKASIDE_NUMBER ListType
= LookasideSmallIrpList
;
475 /* Figure out which Lookaside List to use */
476 if ((StackSize
<= 8) && (ChargeQuota
== FALSE
))
478 /* Set Fixed Size Flag */
479 Flags
= IRP_ALLOCATED_FIXED_SIZE
;
481 /* See if we should use big list */
484 Size
= IoSizeOfIrp(8);
485 ListType
= LookasideLargeIrpList
;
489 Prcb
= KeGetCurrentPrcb();
491 /* Get the P List First */
492 List
= (PNPAGED_LOOKASIDE_LIST
)Prcb
->PPLookasideList
[ListType
].P
;
494 /* Attempt allocation */
495 List
->L
.TotalAllocates
++;
496 Irp
= (PIRP
)InterlockedPopEntrySList(&List
->L
.ListHead
);
498 /* Check if the P List failed */
501 /* Let the balancer know */
502 List
->L
.AllocateMisses
++;
505 List
= (PNPAGED_LOOKASIDE_LIST
)Prcb
->PPLookasideList
[ListType
].L
;
506 List
->L
.TotalAllocates
++;
507 Irp
= (PIRP
)InterlockedPopEntrySList(&List
->L
.ListHead
);
511 /* Check if we have to use the pool */
514 /* Did we try lookaside and fail? */
515 if (Flags
& IRP_ALLOCATED_FIXED_SIZE
) List
->L
.AllocateMisses
++;
517 /* Check if we shoudl charge quota */
520 /* Irp = ExAllocatePoolWithQuotaTag(NonPagedPool, Size, TAG_IRP); */
522 Irp
= ExAllocatePoolWithTag(NonPagedPool
, Size
, TAG_IRP
);
526 /* Allocate the IRP With no Quota charge */
527 Irp
= ExAllocatePoolWithTag(NonPagedPool
, Size
, TAG_IRP
);
530 /* Make sure it was sucessful */
531 if (!Irp
) return(NULL
);
535 /* We have an IRP from Lookaside */
536 Flags
|= IRP_LOOKASIDE_ALLOCATION
;
540 if (ChargeQuota
) Flags
|= IRP_QUOTA_CHARGED
;
542 /* Now Initialize it */
543 IoInitializeIrp(Irp
, Size
, StackSize
);
545 /* Set the Allocation Flags */
546 Irp
->AllocationFlags
= Flags
;
549 IOTRACE(IO_IRP_DEBUG
,
550 "%s - Allocated IRP %p with allocation flags %lx\n",
562 IoBuildAsynchronousFsdRequest(IN ULONG MajorFunction
,
563 IN PDEVICE_OBJECT DeviceObject
,
566 IN PLARGE_INTEGER StartingOffset
,
567 IN PIO_STATUS_BLOCK IoStatusBlock
)
570 PIO_STACK_LOCATION StackPtr
;
573 Irp
= IoAllocateIrp(DeviceObject
->StackSize
, FALSE
);
574 if (!Irp
) return Irp
;
577 StackPtr
= IoGetNextIrpStackLocation(Irp
);
579 /* Write the Major function and then deal with it */
580 StackPtr
->MajorFunction
= (UCHAR
)MajorFunction
;
582 /* Do not handle the following here */
583 if ((MajorFunction
!= IRP_MJ_FLUSH_BUFFERS
) &&
584 (MajorFunction
!= IRP_MJ_SHUTDOWN
) &&
585 (MajorFunction
!= IRP_MJ_PNP
) &&
586 (MajorFunction
!= IRP_MJ_POWER
))
588 /* Check if this is Buffered IO */
589 if (DeviceObject
->Flags
& DO_BUFFERED_IO
)
591 /* Allocate the System Buffer */
592 Irp
->AssociatedIrp
.SystemBuffer
=
593 ExAllocatePoolWithTag(NonPagedPool
, Length
, TAG_SYS_BUF
);
594 if (!Irp
->AssociatedIrp
.SystemBuffer
)
596 /* Free the IRP and fail */
602 Irp
->Flags
= IRP_BUFFERED_IO
| IRP_DEALLOCATE_BUFFER
;
604 /* Handle special IRP_MJ_WRITE Case */
605 if (MajorFunction
== IRP_MJ_WRITE
)
607 /* Copy the buffer data */
608 RtlCopyMemory(Irp
->AssociatedIrp
.SystemBuffer
, Buffer
, Length
);
612 /* Set the Input Operation flag and set this as a User Buffer */
613 Irp
->Flags
|= IRP_INPUT_OPERATION
;
614 Irp
->UserBuffer
= Buffer
;
617 else if (DeviceObject
->Flags
& DO_DIRECT_IO
)
619 /* Use an MDL for Direct I/O */
620 Irp
->MdlAddress
= IoAllocateMdl(Buffer
,
625 if (!Irp
->MdlAddress
)
627 /* Free the IRP and fail */
636 MmProbeAndLockPages(Irp
->MdlAddress
,
638 MajorFunction
== IRP_MJ_READ
?
639 IoWriteAccess
: IoReadAccess
);
643 /* Free the IRP and its MDL */
644 IoFreeMdl(Irp
->MdlAddress
);
650 /* This is how we know if we failed during the probe */
651 if (!Irp
) return NULL
;
655 /* Neither, use the buffer */
656 Irp
->UserBuffer
= Buffer
;
659 /* Check if this is a read */
660 if (MajorFunction
== IRP_MJ_READ
)
662 /* Set the parameters for a read */
663 StackPtr
->Parameters
.Read
.Length
= Length
;
664 StackPtr
->Parameters
.Read
.ByteOffset
= *StartingOffset
;
666 else if (MajorFunction
== IRP_MJ_WRITE
)
668 /* Otherwise, set write parameters */
669 StackPtr
->Parameters
.Write
.Length
= Length
;
670 StackPtr
->Parameters
.Write
.ByteOffset
= *StartingOffset
;
674 /* Set the Current Thread and IOSB */
675 Irp
->UserIosb
= IoStatusBlock
;
676 Irp
->Tail
.Overlay
.Thread
= PsGetCurrentThread();
678 /* Set the Status Block after all is done */
679 IOTRACE(IO_IRP_DEBUG
,
680 "%s - Built IRP %p with Major, Buffer, DO %lx %p %p\n",
694 IoBuildDeviceIoControlRequest(IN ULONG IoControlCode
,
695 IN PDEVICE_OBJECT DeviceObject
,
696 IN PVOID InputBuffer
,
697 IN ULONG InputBufferLength
,
698 IN PVOID OutputBuffer
,
699 IN ULONG OutputBufferLength
,
700 IN BOOLEAN InternalDeviceIoControl
,
702 IN PIO_STATUS_BLOCK IoStatusBlock
)
705 PIO_STACK_LOCATION StackPtr
;
709 Irp
= IoAllocateIrp(DeviceObject
->StackSize
, FALSE
);
710 if (!Irp
) return Irp
;
713 StackPtr
= IoGetNextIrpStackLocation(Irp
);
715 /* Set the DevCtl Type */
716 StackPtr
->MajorFunction
= InternalDeviceIoControl
?
717 IRP_MJ_INTERNAL_DEVICE_CONTROL
:
718 IRP_MJ_DEVICE_CONTROL
;
720 /* Set the IOCTL Data */
721 StackPtr
->Parameters
.DeviceIoControl
.IoControlCode
= IoControlCode
;
722 StackPtr
->Parameters
.DeviceIoControl
.InputBufferLength
= InputBufferLength
;
723 StackPtr
->Parameters
.DeviceIoControl
.OutputBufferLength
=
726 /* Handle the Methods */
727 switch (IO_METHOD_FROM_CTL_CODE(IoControlCode
))
730 case METHOD_BUFFERED
:
732 /* Select the right Buffer Length */
733 BufferLength
= InputBufferLength
> OutputBufferLength
?
734 InputBufferLength
: OutputBufferLength
;
736 /* Make sure there is one */
739 /* Allocate the System Buffer */
740 Irp
->AssociatedIrp
.SystemBuffer
=
741 ExAllocatePoolWithTag(NonPagedPool
,
744 if (!Irp
->AssociatedIrp
.SystemBuffer
)
746 /* Free the IRP and fail */
751 /* Check if we got a buffer */
754 /* Copy into the System Buffer */
755 RtlCopyMemory(Irp
->AssociatedIrp
.SystemBuffer
,
760 /* Write the flags */
761 Irp
->Flags
= IRP_BUFFERED_IO
| IRP_DEALLOCATE_BUFFER
;
762 if (OutputBuffer
) Irp
->Flags
|= IRP_INPUT_OPERATION
;
764 /* Save the Buffer */
765 Irp
->UserBuffer
= OutputBuffer
;
769 /* Clear the Flags and Buffer */
771 Irp
->UserBuffer
= NULL
;
776 case METHOD_IN_DIRECT
:
777 case METHOD_OUT_DIRECT
:
779 /* Check if we got an input buffer */
782 /* Allocate the System Buffer */
783 Irp
->AssociatedIrp
.SystemBuffer
=
784 ExAllocatePoolWithTag(NonPagedPool
,
787 if (!Irp
->AssociatedIrp
.SystemBuffer
)
789 /* Free the IRP and fail */
794 /* Copy into the System Buffer */
795 RtlCopyMemory(Irp
->AssociatedIrp
.SystemBuffer
,
799 /* Write the flags */
800 Irp
->Flags
= IRP_BUFFERED_IO
| IRP_DEALLOCATE_BUFFER
;
807 /* Check if we got an output buffer */
810 /* Allocate the System Buffer */
811 Irp
->MdlAddress
= IoAllocateMdl(OutputBuffer
,
816 if (!Irp
->MdlAddress
)
818 /* Free the IRP and fail */
827 MmProbeAndLockPages(Irp
->MdlAddress
,
829 IO_METHOD_FROM_CTL_CODE(IoControlCode
) ==
831 IoReadAccess
: IoWriteAccess
);
836 IoFreeMdl(Irp
->MdlAddress
);
838 /* Free the input buffer and IRP */
839 if (InputBuffer
) ExFreePool(Irp
->AssociatedIrp
.SystemBuffer
);
845 /* This is how we know if probing failed */
846 if (!Irp
) return NULL
;
852 /* Just save the Buffer */
853 Irp
->UserBuffer
= OutputBuffer
;
854 StackPtr
->Parameters
.DeviceIoControl
.Type3InputBuffer
= InputBuffer
;
857 /* Now write the Event and IoSB */
858 Irp
->UserIosb
= IoStatusBlock
;
859 Irp
->UserEvent
= Event
;
861 /* Sync IRPs are queued to requestor thread's irp cancel/cleanup list */
862 Irp
->Tail
.Overlay
.Thread
= PsGetCurrentThread();
863 IoQueueThreadIrp(Irp
);
866 IOTRACE(IO_IRP_DEBUG
,
867 "%s - Built IRP %p with IOCTL, Buffers, DO %lx %p %p %p\n",
882 IoBuildSynchronousFsdRequest(IN ULONG MajorFunction
,
883 IN PDEVICE_OBJECT DeviceObject
,
886 IN PLARGE_INTEGER StartingOffset
,
888 IN PIO_STATUS_BLOCK IoStatusBlock
)
892 /* Do the big work to set up the IRP */
893 Irp
= IoBuildAsynchronousFsdRequest(MajorFunction
,
899 if (!Irp
) return NULL
;
901 /* Set the Event which makes it Syncronous */
902 Irp
->UserEvent
= Event
;
904 /* Sync IRPs are queued to requestor thread's irp cancel/cleanup list */
905 IoQueueThreadIrp(Irp
);
914 IoCancelIrp(IN PIRP Irp
)
917 PDRIVER_CANCEL CancelRoutine
;
918 IOTRACE(IO_IRP_DEBUG
,
919 "%s - Canceling IRP %p\n",
922 ASSERT(Irp
->Type
== IO_TYPE_IRP
);
924 /* Acquire the cancel lock and cancel the IRP */
925 IoAcquireCancelSpinLock(&OldIrql
);
928 /* Clear the cancel routine and get the old one */
929 CancelRoutine
= IoSetCancelRoutine(Irp
, NULL
);
932 /* We had a routine, make sure the IRP isn't completed */
933 if (Irp
->CurrentLocation
> (Irp
->StackCount
+ 1))
935 /* It is, bugcheck */
936 KeBugCheckEx(CANCEL_STATE_IN_COMPLETED_IRP
,
943 /* Set the cancel IRQL And call the routine */
944 Irp
->CancelIrql
= OldIrql
;
945 CancelRoutine(IoGetCurrentIrpStackLocation(Irp
)->DeviceObject
, Irp
);
949 /* Otherwise, release the cancel lock and fail */
950 IoReleaseCancelSpinLock(OldIrql
);
959 IoCancelThreadIo(IN PETHREAD Thread
)
962 ULONG Retries
= 3000;
963 LARGE_INTEGER Interval
;
964 PLIST_ENTRY ListHead
, NextEntry
;
966 IOTRACE(IO_IRP_DEBUG
,
967 "%s - Canceling IRPs for Thread %p\n",
971 /* Raise to APC to protect the IrpList */
972 OldIrql
= KfRaiseIrql(APC_LEVEL
);
974 /* Start by cancelling all the IRPs in the current thread queue. */
975 ListHead
= &Thread
->IrpList
;
976 NextEntry
= ListHead
->Flink
;
977 while (ListHead
!= NextEntry
)
980 Irp
= CONTAINING_RECORD(NextEntry
, IRP
, ThreadListEntry
);
985 /* Move to the next entry */
986 NextEntry
= NextEntry
->Flink
;
989 /* Wait 100 milliseconds */
990 Interval
.QuadPart
= -1000000;
992 /* Wait till all the IRPs are completed or cancelled. */
993 while (!IsListEmpty(&Thread
->IrpList
))
995 /* Now we can lower */
996 KfLowerIrql(OldIrql
);
998 /* Wait a short while and then look if all our IRPs were completed. */
999 KeDelayExecutionThread(KernelMode
, FALSE
, &Interval
);
1002 * Don't stay here forever if some broken driver doesn't complete
1005 if (!(Retries
--)) IopRemoveThreadIrp();
1007 /* Raise the IRQL Again */
1008 OldIrql
= KfRaiseIrql(APC_LEVEL
);
1011 /* We're done, lower the IRQL */
1012 KfLowerIrql(OldIrql
);
1020 IoCallDriver(IN PDEVICE_OBJECT DeviceObject
,
1023 /* Call fast call */
1024 return IofCallDriver(DeviceObject
, Irp
);
1032 IoCompleteRequest(IN PIRP Irp
,
1033 IN CCHAR PriorityBoost
)
1035 /* Call the fastcall */
1036 IofCompleteRequest(Irp
, PriorityBoost
);
1044 IoEnqueueIrp(IN PIRP Irp
)
1046 /* This is the same as calling IoQueueThreadIrp */
1047 IoQueueThreadIrp(Irp
);
1055 IofCallDriver(IN PDEVICE_OBJECT DeviceObject
,
1058 PDRIVER_OBJECT DriverObject
;
1059 PIO_STACK_LOCATION Param
;
1061 /* Get the Driver Object */
1062 DriverObject
= DeviceObject
->DriverObject
;
1064 /* Decrease the current location and check if */
1065 Irp
->CurrentLocation
--;
1066 if (Irp
->CurrentLocation
<= 0)
1068 /* This IRP ran out of stack, bugcheck */
1069 KeBugCheckEx(NO_MORE_IRP_STACK_LOCATIONS
, (ULONG_PTR
)Irp
, 0, 0, 0);
1072 /* Now update the stack location */
1073 Param
= IoGetNextIrpStackLocation(Irp
);
1074 Irp
->Tail
.Overlay
.CurrentStackLocation
= Param
;
1076 /* Get the Device Object */
1077 Param
->DeviceObject
= DeviceObject
;
1080 return DriverObject
->MajorFunction
[Param
->MajorFunction
](DeviceObject
,
1089 IofCompleteRequest(IN PIRP Irp
,
1090 IN CCHAR PriorityBoost
)
1092 PIO_STACK_LOCATION StackPtr
;
1093 PDEVICE_OBJECT DeviceObject
;
1094 PFILE_OBJECT FileObject
;
1098 ULONG MasterIrpCount
;
1100 IOTRACE(IO_IRP_DEBUG
,
1101 "%s - Completing IRP %p\n",
1105 /* Make sure this IRP isn't getting completed more then once */
1106 if ((Irp
->CurrentLocation
) > (Irp
->StackCount
+ 1))
1109 KeBugCheckEx(MULTIPLE_IRP_COMPLETE_REQUESTS
, (ULONG_PTR
)Irp
, 0, 0, 0);
1112 /* Some sanity checks */
1113 ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL
);
1114 ASSERT(!Irp
->CancelRoutine
);
1115 ASSERT(Irp
->IoStatus
.Status
!= STATUS_PENDING
);
1117 /* Get the Current Stack and skip it */
1118 StackPtr
= IoGetCurrentIrpStackLocation(Irp
);
1119 IoSkipCurrentIrpStackLocation(Irp
);
1121 /* Loop the Stacks and complete the IRPs */
1124 /* Set Pending Returned */
1125 Irp
->PendingReturned
= StackPtr
->Control
& SL_PENDING_RETURNED
;
1127 /* Check if there is a Completion Routine to Call */
1128 if ((NT_SUCCESS(Irp
->IoStatus
.Status
) &&
1129 (StackPtr
->Control
& SL_INVOKE_ON_SUCCESS
)) ||
1130 (!NT_SUCCESS(Irp
->IoStatus
.Status
) &&
1131 (StackPtr
->Control
& SL_INVOKE_ON_ERROR
)) ||
1132 (Irp
->Cancel
&& (StackPtr
->Control
& SL_INVOKE_ON_CANCEL
)))
1134 /* Check for highest-level device completion routines */
1135 if (Irp
->CurrentLocation
== (Irp
->StackCount
+ 1))
1137 /* Clear the DO, since the current stack location is invalid */
1138 DeviceObject
= NULL
;
1142 /* Otherwise, return the real one */
1143 DeviceObject
= IoGetCurrentIrpStackLocation(Irp
)->DeviceObject
;
1146 /* Call the completion routine */
1147 Status
= StackPtr
->CompletionRoutine(DeviceObject
,
1151 /* Don't touch the Packet in this case, since it might be gone! */
1152 if (Status
== STATUS_MORE_PROCESSING_REQUIRED
) return;
1156 /* Otherwise, check if this is a completed IRP */
1157 if ((Irp
->CurrentLocation
<= Irp
->StackCount
) &&
1158 (Irp
->PendingReturned
))
1160 /* Mark it as pending */
1161 IoMarkIrpPending(Irp
);
1165 /* Move to next stack location and pointer */
1166 IoSkipCurrentIrpStackLocation(Irp
);
1168 } while (Irp
->CurrentLocation
<= (Irp
->StackCount
+ 1));
1170 /* Check if the IRP is an associated IRP */
1171 if (Irp
->Flags
& IRP_ASSOCIATED_IRP
)
1173 /* This should never happen! */
1174 ASSERT(IsListEmpty(&Irp
->ThreadListEntry
));
1176 /* Get the master IRP and count */
1177 MasterIrp
= Irp
->AssociatedIrp
.MasterIrp
;
1178 MasterIrpCount
= InterlockedDecrement(&MasterIrp
->
1179 AssociatedIrp
.IrpCount
);
1181 /* Set the thread of this IRP as the master's */
1182 Irp
->Tail
.Overlay
.Thread
= MasterIrp
->Tail
.Overlay
.Thread
;
1185 while ((Mdl
= Irp
->MdlAddress
))
1187 /* Go to the next one */
1188 Irp
->MdlAddress
= Mdl
->Next
;
1192 /* Free the IRP itself */
1195 /* Complete the Master IRP */
1196 if (!MasterIrpCount
) IofCompleteRequest(MasterIrp
, PriorityBoost
);
1200 /* Check if we have an auxiliary buffer */
1201 if (Irp
->Tail
.Overlay
.AuxiliaryBuffer
)
1204 ExFreePool(Irp
->Tail
.Overlay
.AuxiliaryBuffer
);
1205 Irp
->Tail
.Overlay
.AuxiliaryBuffer
= NULL
;
1208 /* Check if this is a Paging I/O or Close Operation */
1209 if (Irp
->Flags
& (IRP_PAGING_IO
| IRP_CLOSE_OPERATION
))
1211 /* This should never happen! */
1212 ASSERT(IsListEmpty(&Irp
->ThreadListEntry
));
1214 /* Handle a Close Operation or Sync Paging I/O (see page 165) */
1215 if (Irp
->Flags
& (IRP_SYNCHRONOUS_PAGING_IO
| IRP_CLOSE_OPERATION
))
1217 /* Set the I/O Status and Signal the Event */
1218 *Irp
->UserIosb
= Irp
->IoStatus
;
1219 KeSetEvent(Irp
->UserEvent
, PriorityBoost
, FALSE
);
1221 /* Free the IRP for a Paging I/O Only, Close is handled by us */
1222 if (Irp
->Flags
& IRP_SYNCHRONOUS_PAGING_IO
) IoFreeIrp(Irp
);
1228 KeInitializeApc(&Irp
->Tail
.Apc
1229 &Irp
->Tail
.Overlay
.Thread
->Tcb
,
1230 Irp
->ApcEnvironment
,
1231 IopCompletePageWrite
,
1236 KeInsertQueueApc(&Irp
->Tail
.Apc
,
1241 /* Not implemented yet. */
1246 /* Get out of here */
1250 /* Unlock MDL Pages, page 167. */
1251 Mdl
= Irp
->MdlAddress
;
1258 /* Check if we should exit because of a Deferred I/O (page 168) */
1259 if ((Irp
->Flags
& IRP_DEFER_IO_COMPLETION
) && !(Irp
->PendingReturned
))
1262 * Return without queuing the completion APC, since the caller will
1263 * take care of doing its own optimized completion at PASSIVE_LEVEL.
1268 /* Get the thread and file object */
1269 Thread
= Irp
->Tail
.Overlay
.Thread
;
1270 FileObject
= Irp
->Tail
.Overlay
.OriginalFileObject
;
1272 /* Make sure the IRP isn't cancelled */
1275 /* Initialize the APC */
1276 KeInitializeApc(&Irp
->Tail
.Apc
,
1278 Irp
->ApcEnvironment
,
1286 KeInsertQueueApc(&Irp
->Tail
.Apc
,
1288 NULL
, /* This is used for REPARSE stuff */
1293 /* The IRP just got cancelled... does a thread still own it? */
1294 Thread
= Irp
->Tail
.Overlay
.Thread
;
1297 /* Yes! There is still hope! Initialize the APC */
1298 KeInitializeApc(&Irp
->Tail
.Apc
,
1300 Irp
->ApcEnvironment
,
1308 KeInsertQueueApc(&Irp
->Tail
.Apc
,
1310 NULL
, /* This is used for REPARSE stuff */
1315 /* Nothing left for us to do, kill it */
1316 IopCleanupIrp(Irp
, FileObject
);
1326 IoForwardIrpSynchronously(IN PDEVICE_OBJECT DeviceObject
,
1338 IoFreeIrp(IN PIRP Irp
)
1340 PNPAGED_LOOKASIDE_LIST List
;
1341 PP_NPAGED_LOOKASIDE_NUMBER ListType
= LookasideSmallIrpList
;
1343 IOTRACE(IO_IRP_DEBUG
,
1344 "%s - Freeing IRPs %p\n",
1348 /* Make sure the Thread IRP list is empty and that it OK to free it */
1349 ASSERT(IsListEmpty(&Irp
->ThreadListEntry
));
1350 ASSERT(Irp
->CurrentLocation
>= Irp
->StackCount
);
1352 /* If this was a pool alloc, free it with the pool */
1353 if (!(Irp
->AllocationFlags
& IRP_ALLOCATED_FIXED_SIZE
))
1360 /* Check if this was a Big IRP */
1361 if (Irp
->StackCount
!= 1) ListType
= LookasideLargeIrpList
;
1364 Prcb
= KeGetCurrentPrcb();
1366 /* Use the P List */
1367 List
= (PNPAGED_LOOKASIDE_LIST
)Prcb
->PPLookasideList
[ListType
].P
;
1368 List
->L
.TotalFrees
++;
1370 /* Check if the Free was within the Depth or not */
1371 if (ExQueryDepthSList(&List
->L
.ListHead
) >= List
->L
.Depth
)
1373 /* Let the balancer know */
1374 List
->L
.FreeMisses
++;
1376 /* Use the L List */
1377 List
= (PNPAGED_LOOKASIDE_LIST
)Prcb
->PPLookasideList
[ListType
].L
;
1378 List
->L
.TotalFrees
++;
1380 /* Check if the Free was within the Depth or not */
1381 if (ExQueryDepthSList(&List
->L
.ListHead
) >= List
->L
.Depth
)
1383 /* All lists failed, use the pool */
1384 List
->L
.FreeMisses
++;
1390 /* The free was within the Depth */
1393 InterlockedPushEntrySList(&List
->L
.ListHead
,
1394 (PSINGLE_LIST_ENTRY
)Irp
);
1403 IoGetRequestorProcess(IN PIRP Irp
)
1405 return(Irp
->Tail
.Overlay
.Thread
->ThreadsProcess
);
1413 IoGetRequestorProcessId(IN PIRP Irp
)
1415 return (ULONG
)(IoGetRequestorProcess(Irp
)->UniqueProcessId
);
1423 IoGetRequestorSessionId(IN PIRP Irp
,
1424 OUT PULONG pSessionId
)
1426 /* Return the session */
1427 *pSessionId
= IoGetRequestorProcess(Irp
)->Session
;
1428 return STATUS_SUCCESS
;
1436 IoGetTopLevelIrp(VOID
)
1438 return (PIRP
)PsGetCurrentThread()->TopLevelIrp
;
1446 IoInitializeIrp(IN PIRP Irp
,
1447 IN USHORT PacketSize
,
1451 IOTRACE(IO_IRP_DEBUG
,
1452 "%s - Initializing IRP %p\n",
1455 RtlZeroMemory(Irp
, PacketSize
);
1457 /* Set the Header and other data */
1458 Irp
->Type
= IO_TYPE_IRP
;
1459 Irp
->Size
= PacketSize
;
1460 Irp
->StackCount
= StackSize
;
1461 Irp
->CurrentLocation
= StackSize
+ 1;
1462 Irp
->ApcEnvironment
= KeGetCurrentThread()->ApcStateIndex
;
1463 Irp
->Tail
.Overlay
.CurrentStackLocation
= (PIO_STACK_LOCATION
)(Irp
+ 1) + StackSize
;
1465 /* Initialize the Thread List */
1466 InitializeListHead(&Irp
->ThreadListEntry
);
1474 IoIsOperationSynchronous(IN PIRP Irp
)
1476 /* Check the flags */
1477 if (((Irp
->Flags
& IRP_SYNCHRONOUS_PAGING_IO
) &&
1478 (!(Irp
->Flags
& IRP_PAGING_IO
) &&
1479 !(Irp
->Flags
& IRP_SYNCHRONOUS_PAGING_IO
))) ||
1480 (Irp
->Flags
& IRP_SYNCHRONOUS_API
) ||
1481 (IoGetCurrentIrpStackLocation(Irp
)->FileObject
->Flags
&
1484 /* Synch API or Paging I/O is OK, as is Sync File I/O */
1488 /* Otherwise, it is an asynchronous operation. */
1497 IoIsValidNameGraftingBuffer(IN PIRP Irp
,
1498 IN PREPARSE_DATA_BUFFER ReparseBuffer
)
1509 IoMakeAssociatedIrp(IN PIRP Irp
,
1513 IOTRACE(IO_IRP_DEBUG
,
1514 "%s - Associating IRP %p\n",
1518 /* Allocate the IRP */
1519 AssocIrp
= IoAllocateIrp(StackSize
, FALSE
);
1520 if (!AssocIrp
) return NULL
;
1523 AssocIrp
->Flags
|= IRP_ASSOCIATED_IRP
;
1525 /* Set the Thread */
1526 AssocIrp
->Tail
.Overlay
.Thread
= Irp
->Tail
.Overlay
.Thread
;
1528 /* Associate them */
1529 AssocIrp
->AssociatedIrp
.MasterIrp
= Irp
;
1538 IoQueueThreadIrp(IN PIRP Irp
)
1540 IOTRACE(IO_IRP_DEBUG
,
1541 "%s - Queueing IRP %p\n",
1545 /* Use our inlined routine */
1546 IopQueueIrpToThread(Irp
);
1551 * Reference: Chris Cant's "Writing WDM Device Drivers"
1555 IoReuseIrp(IN OUT PIRP Irp
,
1558 UCHAR AllocationFlags
;
1559 IOTRACE(IO_IRP_DEBUG
,
1560 "%s - Reusing IRP %p\n",
1564 /* Make sure it's OK to reuse it */
1565 ASSERT(!Irp
->CancelRoutine
);
1566 ASSERT(IsListEmpty(&Irp
->ThreadListEntry
));
1568 /* Get the old flags */
1569 AllocationFlags
= Irp
->AllocationFlags
;
1571 /* Reinitialize the IRP */
1572 IoInitializeIrp(Irp
, Irp
->Size
, Irp
->StackCount
);
1574 /* Duplicate the data */
1575 Irp
->IoStatus
.Status
= Status
;
1576 Irp
->AllocationFlags
= AllocationFlags
;
1584 IoSetTopLevelIrp(IN PIRP Irp
)
1587 PsGetCurrentThread()->TopLevelIrp
= (ULONG
)Irp
;