2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/io/iomgr/irp.c
5 * PURPOSE: IRP Handling Functions
6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
8 * Filip Navara (navaraf@reactos.org)
9 * Pierre Schweitzer (pierre@reactos.org)
12 /* INCLUDES ****************************************************************/
19 RESERVE_IRP_ALLOCATOR IopReserveIrpAllocator
;
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 OPTIONAL
,
47 IN PVOID Buffer OPTIONAL
)
51 /* Dereference the event */
52 if (EventObject
) ObDereferenceObject(EventObject
);
54 /* Free a buffer, if any */
55 if (Buffer
) ExFreePool(Buffer
);
57 /* If this was a file opened for synch I/O, then unlock it */
58 if (FileObject
->Flags
& FO_SYNCHRONOUS_IO
) IopUnlockFileObject(FileObject
);
60 /* Now dereference it and return */
61 ObDereferenceObject(FileObject
);
62 return STATUS_INSUFFICIENT_RESOURCES
;
67 IopAbortInterruptedIrp(IN PKEVENT EventObject
,
75 /* Raise IRQL to APC */
76 KeRaiseIrql(APC_LEVEL
, &OldIrql
);
78 /* Check if nobody completed it yet */
79 if (!KeReadStateEvent(EventObject
))
81 /* First, cancel it */
82 CancelResult
= IoCancelIrp(Irp
);
85 /* Check if we cancelled it */
88 /* Wait for the IRP to be cancelled */
89 Wait
.QuadPart
= -100000;
90 while (!KeReadStateEvent(EventObject
))
92 /* Delay indefintely */
93 KeDelayExecutionThread(KernelMode
, FALSE
, &Wait
);
98 /* No cancellation done, so wait for the I/O system to kill it */
99 KeWaitForSingleObject(EventObject
,
108 /* We got preempted, so give up */
109 KeLowerIrql(OldIrql
);
115 IopDisassociateThreadIrp(VOID
)
117 KIRQL OldIrql
, LockIrql
;
119 PLIST_ENTRY IrpEntry
;
120 PIO_ERROR_LOG_PACKET ErrorLogEntry
;
121 PDEVICE_OBJECT DeviceObject
= NULL
;
122 PIO_STACK_LOCATION IoStackLocation
;
124 /* First, raise to APC to protect IrpList */
125 KeRaiseIrql(APC_LEVEL
, &OldIrql
);
127 /* Get the Thread and check the list */
128 IrpThread
= PsGetCurrentThread();
129 if (IsListEmpty(&IrpThread
->IrpList
))
131 /* It got completed now, so quit */
132 KeLowerIrql(OldIrql
);
136 /* Ensure no one will come disturb */
137 LockIrql
= KeAcquireQueuedSpinLock(LockQueueIoCompletionLock
);
139 /* Get the misbehaving IRP */
140 IrpEntry
= IrpThread
->IrpList
.Flink
;
141 IopDeadIrp
= CONTAINING_RECORD(IrpEntry
, IRP
, ThreadListEntry
);
142 IOTRACE(IO_IRP_DEBUG
,
143 "%s - Deassociating IRP %p for %p\n",
148 /* Don't cancel the IRP if it's already been completed far */
149 if (IopDeadIrp
->CurrentLocation
== (IopDeadIrp
->StackCount
+ 2))
152 KeReleaseQueuedSpinLock(LockQueueIoCompletionLock
, LockIrql
);
153 KeLowerIrql(OldIrql
);
157 /* Disown the IRP! */
158 IopDeadIrp
->Tail
.Overlay
.Thread
= NULL
;
159 RemoveHeadList(&IrpThread
->IrpList
);
160 InitializeListHead(&IopDeadIrp
->ThreadListEntry
);
162 /* Get the stack location and check if it's valid */
163 IoStackLocation
= IoGetCurrentIrpStackLocation(IopDeadIrp
);
164 if (IopDeadIrp
->CurrentLocation
<= IopDeadIrp
->StackCount
)
166 /* Get the device object */
167 DeviceObject
= IoStackLocation
->DeviceObject
;
170 KeReleaseQueuedSpinLock(LockQueueIoCompletionLock
, LockIrql
);
171 /* Lower IRQL now, since we have the pointers we need */
172 KeLowerIrql(OldIrql
);
174 /* Check if we can send an Error Log Entry*/
177 /* Allocate an entry */
178 ErrorLogEntry
= IoAllocateErrorLogEntry(DeviceObject
,
179 sizeof(IO_ERROR_LOG_PACKET
));
182 /* Write the entry */
183 ErrorLogEntry
->ErrorCode
= IO_DRIVER_CANCEL_TIMEOUT
;
184 IoWriteErrorLogEntry(ErrorLogEntry
);
191 IopCleanupIrp(IN PIRP Irp
,
192 IN PFILE_OBJECT FileObject
)
195 IOTRACE(IO_IRP_DEBUG
,
196 "%s - Cleaning IRP %p for %p\n",
201 /* Check if there's an MDL */
202 while ((Mdl
= Irp
->MdlAddress
))
204 /* Clear all of them */
205 Irp
->MdlAddress
= Mdl
->Next
;
209 /* Check if the IRP has system buffer */
210 if (Irp
->Flags
& IRP_DEALLOCATE_BUFFER
)
212 /* Free the buffer */
213 ExFreePoolWithTag(Irp
->AssociatedIrp
.SystemBuffer
, TAG_SYS_BUF
);
216 /* Check if this IRP has a user event, a file object, and is async */
217 if ((Irp
->UserEvent
) &&
218 !(Irp
->Flags
& IRP_SYNCHRONOUS_API
) &&
221 /* Dereference the User Event */
222 ObDereferenceObject(Irp
->UserEvent
);
225 /* Check if we have a file object and this isn't a create operation */
226 if ((FileObject
) && !(Irp
->Flags
& IRP_CREATE_OPERATION
))
228 /* Dereference the file object */
229 ObDereferenceObject(FileObject
);
238 IopCompleteRequest(IN PKAPC Apc
,
239 IN PKNORMAL_ROUTINE
* NormalRoutine
,
240 IN PVOID
* NormalContext
,
241 IN PVOID
* SystemArgument1
,
242 IN PVOID
* SystemArgument2
)
244 PFILE_OBJECT FileObject
;
247 PVOID Port
= NULL
, Key
= NULL
;
248 BOOLEAN SignaledCreateRequest
= FALSE
;
250 /* Get data from the APC */
251 FileObject
= (PFILE_OBJECT
)*SystemArgument1
;
252 Irp
= CONTAINING_RECORD(Apc
, IRP
, Tail
.Apc
);
253 IOTRACE(IO_IRP_DEBUG
,
254 "%s - Completing IRP %p for %p\n",
260 ASSERT(Irp
->IoStatus
.Status
!= (NTSTATUS
)0xFFFFFFFF);
262 /* Check if we have a file object */
263 if (*SystemArgument2
)
265 /* Check if we're reparsing */
266 if ((Irp
->IoStatus
.Status
== STATUS_REPARSE
) &&
267 (Irp
->IoStatus
.Information
== IO_REPARSE_TAG_MOUNT_POINT
))
269 PREPARSE_DATA_BUFFER ReparseData
;
271 ReparseData
= (PREPARSE_DATA_BUFFER
)*SystemArgument2
;
273 ASSERT(ReparseData
->ReparseTag
== IO_REPARSE_TAG_MOUNT_POINT
);
274 ASSERT(ReparseData
->ReparseDataLength
< MAXIMUM_REPARSE_DATA_BUFFER_SIZE
);
275 ASSERT(ReparseData
->Reserved
< MAXIMUM_REPARSE_DATA_BUFFER_SIZE
);
277 IopDoNameTransmogrify(Irp
, FileObject
, ReparseData
);
281 /* Handle Buffered case first */
282 if (Irp
->Flags
& IRP_BUFFERED_IO
)
284 /* Check if we have an input buffer and if we succeeded */
285 if ((Irp
->Flags
& IRP_INPUT_OPERATION
) &&
286 (Irp
->IoStatus
.Status
!= STATUS_VERIFY_REQUIRED
) &&
287 !(NT_ERROR(Irp
->IoStatus
.Status
)))
291 /* Copy the buffer back to the user */
292 RtlCopyMemory(Irp
->UserBuffer
,
293 Irp
->AssociatedIrp
.SystemBuffer
,
294 Irp
->IoStatus
.Information
);
296 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
299 Irp
->IoStatus
.Status
= _SEH2_GetExceptionCode();
304 /* Also check if we should de-allocate it */
305 if (Irp
->Flags
& IRP_DEALLOCATE_BUFFER
)
308 ExFreePool(Irp
->AssociatedIrp
.SystemBuffer
);
312 /* Now we got rid of these two... */
313 Irp
->Flags
&= ~(IRP_BUFFERED_IO
| IRP_DEALLOCATE_BUFFER
);
315 /* Check if there's an MDL */
316 for (Mdl
= Irp
->MdlAddress
; Mdl
; Mdl
= NextMdl
)
324 Irp
->MdlAddress
= NULL
;
327 * Check if either the request was completed without any errors
328 * (but warnings are OK!), or if it was completed with an error, but
329 * did return from a pending I/O Operation and is not synchronous.
331 if (!NT_ERROR(Irp
->IoStatus
.Status
) ||
332 (Irp
->PendingReturned
&&
333 !IsIrpSynchronous(Irp
, FileObject
)))
335 /* Get any information we need from the FO before we kill it */
336 if ((FileObject
) && (FileObject
->CompletionContext
))
338 /* Save Completion Data */
339 Port
= FileObject
->CompletionContext
->Port
;
340 Key
= FileObject
->CompletionContext
->Key
;
343 /* Check for UserIos */
344 if (Irp
->UserIosb
!= NULL
)
346 /* Use SEH to make sure we don't write somewhere invalid */
349 /* Save the IOSB Information */
350 *Irp
->UserIosb
= Irp
->IoStatus
;
352 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
354 /* Ignore any error */
359 /* Check if we have an event or a file object */
362 /* At the very least, this is a PKEVENT, so signal it always */
363 KeSetEvent(Irp
->UserEvent
, 0, FALSE
);
365 /* Check if we also have a File Object */
368 /* Check if this is an Asynch API */
369 if (!(Irp
->Flags
& IRP_SYNCHRONOUS_API
))
371 /* Dereference the event */
372 ObDereferenceObject(Irp
->UserEvent
);
376 * Now, if this is a Synch I/O File Object, then this event is
377 * NOT an actual Executive Event, so we won't dereference it,
378 * and instead, we will signal the File Object
380 if ((FileObject
->Flags
& FO_SYNCHRONOUS_IO
) &&
381 !(Irp
->Flags
& IRP_OB_QUERY_NAME
))
383 /* Signal the file object and set the status */
384 KeSetEvent(&FileObject
->Event
, 0, FALSE
);
385 FileObject
->FinalStatus
= Irp
->IoStatus
.Status
;
389 * This could also be a create operation, in which case we want
390 * to make sure there's no APC fired.
392 if (Irp
->Flags
& IRP_CREATE_OPERATION
)
394 /* Clear the APC Routine and remember this */
395 Irp
->Overlay
.AsynchronousParameters
.UserApcRoutine
= NULL
;
396 SignaledCreateRequest
= TRUE
;
402 /* Signal the file object and set the status */
403 KeSetEvent(&FileObject
->Event
, 0, FALSE
);
404 FileObject
->FinalStatus
= Irp
->IoStatus
.Status
;
407 * This could also be a create operation, in which case we want
408 * to make sure there's no APC fired.
410 if (Irp
->Flags
& IRP_CREATE_OPERATION
)
412 /* Clear the APC Routine and remember this */
413 Irp
->Overlay
.AsynchronousParameters
.UserApcRoutine
= NULL
;
414 SignaledCreateRequest
= TRUE
;
418 /* Update transfer count for everything but create operation */
419 if (!(Irp
->Flags
& IRP_CREATE_OPERATION
))
421 if (Irp
->Flags
& IRP_WRITE_OPERATION
)
423 /* Update write transfer count */
424 IopUpdateTransferCount(IopWriteTransfer
,
425 (ULONG
)Irp
->IoStatus
.Information
);
427 else if (Irp
->Flags
& IRP_READ_OPERATION
)
429 /* Update read transfer count */
430 IopUpdateTransferCount(IopReadTransfer
,
431 (ULONG
)Irp
->IoStatus
.Information
);
435 /* Update other transfer count */
436 IopUpdateTransferCount(IopOtherTransfer
,
437 (ULONG
)Irp
->IoStatus
.Information
);
441 /* Now that we've signaled the events, de-associate the IRP */
442 IopUnQueueIrpFromThread(Irp
);
444 /* Now check if a User APC Routine was requested */
445 if (Irp
->Overlay
.AsynchronousParameters
.UserApcRoutine
)
448 KeInitializeApc(&Irp
->Tail
.Apc
,
449 KeGetCurrentThread(),
450 CurrentApcEnvironment
,
452 IopAbortIrpKernelApc
,
453 (PKNORMAL_ROUTINE
)Irp
->
454 Overlay
.AsynchronousParameters
.UserApcRoutine
,
457 Overlay
.AsynchronousParameters
.UserApcContext
);
460 KeInsertQueueApc(&Irp
->Tail
.Apc
, Irp
->UserIosb
, NULL
, 2);
463 (Irp
->Overlay
.AsynchronousParameters
.UserApcContext
))
465 /* We have an I/O Completion setup... create the special Overlay */
466 Irp
->Tail
.CompletionKey
= Key
;
467 Irp
->Tail
.Overlay
.PacketType
= IopCompletionPacketIrp
;
468 KeInsertQueue(Port
, &Irp
->Tail
.Overlay
.ListEntry
);
472 /* Free the IRP since we don't need it anymore */
476 /* Check if we have a file object that wasn't part of a create */
477 if ((FileObject
) && !(SignaledCreateRequest
))
479 /* Dereference it, since it's not needed anymore either */
480 ObDereferenceObjectDeferDelete(FileObject
);
486 * Either we didn't return from the request, or we did return but this
487 * request was synchronous.
489 if ((Irp
->PendingReturned
) && (FileObject
))
491 /* So we did return with a synch operation, was it the IRP? */
492 if (Irp
->Flags
& IRP_SYNCHRONOUS_API
)
494 /* Yes, this IRP was synchronous, so return the I/O Status */
495 *Irp
->UserIosb
= Irp
->IoStatus
;
497 /* Now check if the user gave an event */
501 KeSetEvent(Irp
->UserEvent
, 0, FALSE
);
505 /* No event was given, so signal the FO instead */
506 KeSetEvent(&FileObject
->Event
, 0, FALSE
);
512 * It's not the IRP that was synchronous, it was the FO
513 * that was opened this way. Signal its event.
515 FileObject
->FinalStatus
= Irp
->IoStatus
.Status
;
516 KeSetEvent(&FileObject
->Event
, 0, FALSE
);
520 /* Now that we got here, we do this for incomplete I/Os as well */
521 if ((FileObject
) && !(Irp
->Flags
& IRP_CREATE_OPERATION
))
523 /* Dereference the File Object unless this was a create */
524 ObDereferenceObjectDeferDelete(FileObject
);
528 * Check if this was an Executive Event (remember that we know this
529 * by checking if the IRP is synchronous)
531 if ((Irp
->UserEvent
) &&
533 !(Irp
->Flags
& IRP_SYNCHRONOUS_API
))
535 /* This isn't a PKEVENT, so dereference it */
536 ObDereferenceObject(Irp
->UserEvent
);
539 /* Now that we've signaled the events, de-associate the IRP */
540 IopUnQueueIrpFromThread(Irp
);
542 /* Free the IRP as well */
549 IopInitializeReserveIrp(IN PRESERVE_IRP_ALLOCATOR ReserveIrpAllocator
)
551 /* Our allocated stack size */
552 ReserveIrpAllocator
->StackSize
= 20;
554 /* Allocate the IRP now */
555 ReserveIrpAllocator
->ReserveIrp
= IoAllocateIrp(ReserveIrpAllocator
->StackSize
, FALSE
);
556 /* If we cannot, abort system boot */
557 if (ReserveIrpAllocator
->ReserveIrp
== NULL
)
562 /* It's not in use */
563 ReserveIrpAllocator
->ReserveIrpInUse
= 0;
564 /* And init the event */
565 KeInitializeEvent(&ReserveIrpAllocator
->WaitEvent
, SynchronizationEvent
, FALSE
);
567 /* All good, keep booting */
573 IopAllocateReserveIrp(IN CCHAR StackSize
)
575 /* If we need a stack size higher than what was allocated, then fail */
576 if (StackSize
> IopReserveIrpAllocator
.StackSize
)
581 /* Now, wait until the IRP becomes available and reserve it immediately */
582 while (InterlockedExchange(&IopReserveIrpAllocator
.ReserveIrpInUse
, 1) == 1)
584 KeWaitForSingleObject(&IopReserveIrpAllocator
.WaitEvent
,
591 /* It's ours! Initialize it */
592 IoInitializeIrp(IopReserveIrpAllocator
.ReserveIrp
, IoSizeOfIrp(StackSize
), StackSize
);
594 /* And return it to the caller */
595 return IopReserveIrpAllocator
.ReserveIrp
;
599 IopFreeReserveIrp(IN CCHAR PriorityBoost
)
601 /* Mark we don't use the IRP anymore */
602 InterlockedExchange(&IopReserveIrpAllocator
.ReserveIrpInUse
, 0);
604 /* And set the event if someone is waiting on the IRP */
605 KeSetEvent(&IopReserveIrpAllocator
.WaitEvent
, PriorityBoost
, FALSE
);
608 /* FUNCTIONS *****************************************************************/
615 IoAllocateIrp(IN CCHAR StackSize
,
616 IN BOOLEAN ChargeQuota
)
619 USHORT Size
= IoSizeOfIrp(StackSize
);
622 PNPAGED_LOOKASIDE_LIST List
= NULL
;
623 PP_NPAGED_LOOKASIDE_NUMBER ListType
= LookasideSmallIrpList
;
625 /* Set Charge Quota Flag */
626 if (ChargeQuota
) Flags
|= IRP_QUOTA_CHARGED
;
629 Prcb
= KeGetCurrentPrcb();
631 /* Figure out which Lookaside List to use */
632 if ((StackSize
<= 8) && (ChargeQuota
== FALSE
|| Prcb
->LookasideIrpFloat
> 0))
634 /* Set Fixed Size Flag */
635 Flags
|= IRP_ALLOCATED_FIXED_SIZE
;
637 /* See if we should use big list */
640 Size
= IoSizeOfIrp(8);
641 ListType
= LookasideLargeIrpList
;
644 /* Get the P List First */
645 List
= (PNPAGED_LOOKASIDE_LIST
)Prcb
->PPLookasideList
[ListType
].P
;
647 /* Attempt allocation */
648 List
->L
.TotalAllocates
++;
649 Irp
= (PIRP
)InterlockedPopEntrySList(&List
->L
.ListHead
);
651 /* Check if the P List failed */
654 /* Let the balancer know */
655 List
->L
.AllocateMisses
++;
658 List
= (PNPAGED_LOOKASIDE_LIST
)Prcb
->PPLookasideList
[ListType
].L
;
659 List
->L
.TotalAllocates
++;
660 Irp
= (PIRP
)InterlockedPopEntrySList(&List
->L
.ListHead
);
664 /* Check if we have to use the pool */
667 /* Did we try lookaside and fail? */
668 if (Flags
& IRP_ALLOCATED_FIXED_SIZE
) List
->L
.AllocateMisses
++;
670 /* Check if we should charge quota */
673 Irp
= ExAllocatePoolWithQuotaTag(NonPagedPool
| POOL_QUOTA_FAIL_INSTEAD_OF_RAISE
,
679 /* Allocate the IRP with no quota charge */
680 Irp
= ExAllocatePoolWithTag(NonPagedPool
, Size
, TAG_IRP
);
683 /* Make sure it was sucessful */
684 if (!Irp
) return NULL
;
686 else if (Flags
& IRP_QUOTA_CHARGED
)
688 /* Decrement lookaside float */
689 InterlockedDecrement(&Prcb
->LookasideIrpFloat
);
690 Flags
|= IRP_LOOKASIDE_ALLOCATION
;
692 /* In this case there is no charge quota */
693 Flags
&= ~IRP_QUOTA_CHARGED
;
696 /* Now Initialize it */
697 IoInitializeIrp(Irp
, Size
, StackSize
);
699 /* Set the Allocation Flags */
700 Irp
->AllocationFlags
= Flags
;
703 IOTRACE(IO_IRP_DEBUG
,
704 "%s - Allocated IRP %p with allocation flags %lx\n",
716 IopAllocateIrpMustSucceed(IN CCHAR StackSize
)
722 /* Try to get an IRP */
723 Irp
= IoAllocateIrp(StackSize
, FALSE
);
727 /* If we fail, start looping till we may get one */
732 /* First, sleep for 10ms */
733 Sleep
.QuadPart
= -10 * 1000 * 10;
734 KeDelayExecutionThread(KernelMode
, FALSE
, &Sleep
);
736 /* Then, retry allocation */
737 Irp
= IoAllocateIrp(StackSize
, FALSE
);
750 IoBuildAsynchronousFsdRequest(IN ULONG MajorFunction
,
751 IN PDEVICE_OBJECT DeviceObject
,
754 IN PLARGE_INTEGER StartingOffset
,
755 IN PIO_STATUS_BLOCK IoStatusBlock
)
758 PIO_STACK_LOCATION StackPtr
;
761 Irp
= IoAllocateIrp(DeviceObject
->StackSize
, FALSE
);
762 if (!Irp
) return NULL
;
765 StackPtr
= IoGetNextIrpStackLocation(Irp
);
767 /* Write the Major function and then deal with it */
768 StackPtr
->MajorFunction
= (UCHAR
)MajorFunction
;
770 /* Do not handle the following here */
771 if ((MajorFunction
!= IRP_MJ_FLUSH_BUFFERS
) &&
772 (MajorFunction
!= IRP_MJ_SHUTDOWN
) &&
773 (MajorFunction
!= IRP_MJ_PNP
) &&
774 (MajorFunction
!= IRP_MJ_POWER
))
776 /* Check if this is Buffered IO */
777 if (DeviceObject
->Flags
& DO_BUFFERED_IO
)
779 /* Allocate the System Buffer */
780 Irp
->AssociatedIrp
.SystemBuffer
=
781 ExAllocatePoolWithTag(NonPagedPool
, Length
, TAG_SYS_BUF
);
782 if (!Irp
->AssociatedIrp
.SystemBuffer
)
784 /* Free the IRP and fail */
790 Irp
->Flags
= IRP_BUFFERED_IO
| IRP_DEALLOCATE_BUFFER
;
792 /* Handle special IRP_MJ_WRITE Case */
793 if (MajorFunction
== IRP_MJ_WRITE
)
795 /* Copy the buffer data */
796 RtlCopyMemory(Irp
->AssociatedIrp
.SystemBuffer
, Buffer
, Length
);
800 /* Set the Input Operation flag and set this as a User Buffer */
801 Irp
->Flags
|= IRP_INPUT_OPERATION
;
802 Irp
->UserBuffer
= Buffer
;
805 else if (DeviceObject
->Flags
& DO_DIRECT_IO
)
807 /* Use an MDL for Direct I/O */
808 Irp
->MdlAddress
= IoAllocateMdl(Buffer
,
813 if (!Irp
->MdlAddress
)
815 /* Free the IRP and fail */
824 MmProbeAndLockPages(Irp
->MdlAddress
,
826 MajorFunction
== IRP_MJ_READ
?
827 IoWriteAccess
: IoReadAccess
);
829 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
831 /* Free the IRP and its MDL */
832 IoFreeMdl(Irp
->MdlAddress
);
836 _SEH2_YIELD(return NULL
);
842 /* Neither, use the buffer */
843 Irp
->UserBuffer
= Buffer
;
846 /* Check if this is a read */
847 if (MajorFunction
== IRP_MJ_READ
)
849 /* Set the parameters for a read */
850 StackPtr
->Parameters
.Read
.Length
= Length
;
851 StackPtr
->Parameters
.Read
.ByteOffset
= *StartingOffset
;
853 else if (MajorFunction
== IRP_MJ_WRITE
)
855 /* Otherwise, set write parameters */
856 StackPtr
->Parameters
.Write
.Length
= Length
;
857 StackPtr
->Parameters
.Write
.ByteOffset
= *StartingOffset
;
861 /* Set the Current Thread and IOSB */
862 Irp
->UserIosb
= IoStatusBlock
;
863 Irp
->Tail
.Overlay
.Thread
= PsGetCurrentThread();
866 IOTRACE(IO_IRP_DEBUG
,
867 "%s - Built IRP %p with Major, Buffer, DO %lx %p %p\n",
881 IoBuildDeviceIoControlRequest(IN ULONG IoControlCode
,
882 IN PDEVICE_OBJECT DeviceObject
,
883 IN PVOID InputBuffer
,
884 IN ULONG InputBufferLength
,
885 IN PVOID OutputBuffer
,
886 IN ULONG OutputBufferLength
,
887 IN BOOLEAN InternalDeviceIoControl
,
889 IN PIO_STATUS_BLOCK IoStatusBlock
)
892 PIO_STACK_LOCATION StackPtr
;
896 Irp
= IoAllocateIrp(DeviceObject
->StackSize
, FALSE
);
897 if (!Irp
) return NULL
;
900 StackPtr
= IoGetNextIrpStackLocation(Irp
);
902 /* Set the DevCtl Type */
903 StackPtr
->MajorFunction
= InternalDeviceIoControl
?
904 IRP_MJ_INTERNAL_DEVICE_CONTROL
:
905 IRP_MJ_DEVICE_CONTROL
;
907 /* Set the IOCTL Data */
908 StackPtr
->Parameters
.DeviceIoControl
.IoControlCode
= IoControlCode
;
909 StackPtr
->Parameters
.DeviceIoControl
.InputBufferLength
= InputBufferLength
;
910 StackPtr
->Parameters
.DeviceIoControl
.OutputBufferLength
=
913 /* Handle the Methods */
914 switch (IO_METHOD_FROM_CTL_CODE(IoControlCode
))
917 case METHOD_BUFFERED
:
919 /* Select the right Buffer Length */
920 BufferLength
= InputBufferLength
> OutputBufferLength
?
921 InputBufferLength
: OutputBufferLength
;
923 /* Make sure there is one */
926 /* Allocate the System Buffer */
927 Irp
->AssociatedIrp
.SystemBuffer
=
928 ExAllocatePoolWithTag(NonPagedPool
,
931 if (!Irp
->AssociatedIrp
.SystemBuffer
)
933 /* Free the IRP and fail */
938 /* Check if we got a buffer */
941 /* Copy into the System Buffer */
942 RtlCopyMemory(Irp
->AssociatedIrp
.SystemBuffer
,
947 /* Write the flags */
948 Irp
->Flags
= IRP_BUFFERED_IO
| IRP_DEALLOCATE_BUFFER
;
949 if (OutputBuffer
) Irp
->Flags
|= IRP_INPUT_OPERATION
;
951 /* Save the Buffer */
952 Irp
->UserBuffer
= OutputBuffer
;
956 /* Clear the Flags and Buffer */
958 Irp
->UserBuffer
= NULL
;
963 case METHOD_IN_DIRECT
:
964 case METHOD_OUT_DIRECT
:
966 /* Check if we got an input buffer */
969 /* Allocate the System Buffer */
970 Irp
->AssociatedIrp
.SystemBuffer
=
971 ExAllocatePoolWithTag(NonPagedPool
,
974 if (!Irp
->AssociatedIrp
.SystemBuffer
)
976 /* Free the IRP and fail */
981 /* Copy into the System Buffer */
982 RtlCopyMemory(Irp
->AssociatedIrp
.SystemBuffer
,
986 /* Write the flags */
987 Irp
->Flags
= IRP_BUFFERED_IO
| IRP_DEALLOCATE_BUFFER
;
991 /* Clear the flags */
995 /* Check if we got an output buffer */
998 /* Allocate the System Buffer */
999 Irp
->MdlAddress
= IoAllocateMdl(OutputBuffer
,
1004 if (!Irp
->MdlAddress
)
1006 /* Free the IRP and fail */
1011 /* Probe and Lock */
1015 MmProbeAndLockPages(Irp
->MdlAddress
,
1017 IO_METHOD_FROM_CTL_CODE(IoControlCode
) ==
1019 IoReadAccess
: IoWriteAccess
);
1021 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1024 IoFreeMdl(Irp
->MdlAddress
);
1026 /* Free the input buffer and IRP */
1027 if (InputBuffer
) ExFreePool(Irp
->AssociatedIrp
.SystemBuffer
);
1031 _SEH2_YIELD(return NULL
);
1037 case METHOD_NEITHER
:
1039 /* Just save the Buffer */
1040 Irp
->UserBuffer
= OutputBuffer
;
1041 StackPtr
->Parameters
.DeviceIoControl
.Type3InputBuffer
= InputBuffer
;
1044 /* Now write the Event and IoSB */
1045 Irp
->UserIosb
= IoStatusBlock
;
1046 Irp
->UserEvent
= Event
;
1048 /* Sync IRPs are queued to requestor thread's irp cancel/cleanup list */
1049 Irp
->Tail
.Overlay
.Thread
= PsGetCurrentThread();
1050 IoQueueThreadIrp(Irp
);
1052 /* Return the IRP */
1053 IOTRACE(IO_IRP_DEBUG
,
1054 "%s - Built IRP %p with IOCTL, Buffers, DO %lx %p %p %p\n",
1069 IoBuildSynchronousFsdRequest(IN ULONG MajorFunction
,
1070 IN PDEVICE_OBJECT DeviceObject
,
1073 IN PLARGE_INTEGER StartingOffset
,
1075 IN PIO_STATUS_BLOCK IoStatusBlock
)
1079 /* Do the big work to set up the IRP */
1080 Irp
= IoBuildAsynchronousFsdRequest(MajorFunction
,
1086 if (!Irp
) return NULL
;
1088 /* Set the Event which makes it Syncronous */
1089 Irp
->UserEvent
= Event
;
1091 /* Sync IRPs are queued to requestor thread's irp cancel/cleanup list */
1092 IoQueueThreadIrp(Irp
);
1101 IoCancelIrp(IN PIRP Irp
)
1104 PDRIVER_CANCEL CancelRoutine
;
1105 IOTRACE(IO_IRP_DEBUG
,
1106 "%s - Canceling IRP %p\n",
1109 ASSERT(Irp
->Type
== IO_TYPE_IRP
);
1111 /* Acquire the cancel lock and cancel the IRP */
1112 IoAcquireCancelSpinLock(&OldIrql
);
1115 /* Clear the cancel routine and get the old one */
1116 CancelRoutine
= IoSetCancelRoutine(Irp
, NULL
);
1119 /* We had a routine, make sure the IRP isn't completed */
1120 if (Irp
->CurrentLocation
> (Irp
->StackCount
+ 1))
1122 /* It is, bugcheck */
1123 KeBugCheckEx(CANCEL_STATE_IN_COMPLETED_IRP
,
1125 (ULONG_PTR
)CancelRoutine
,
1130 /* Set the cancel IRQL And call the routine */
1131 Irp
->CancelIrql
= OldIrql
;
1132 CancelRoutine(IoGetCurrentIrpStackLocation(Irp
)->DeviceObject
, Irp
);
1136 /* Otherwise, release the cancel lock and fail */
1137 IoReleaseCancelSpinLock(OldIrql
);
1146 IoCancelThreadIo(IN PETHREAD Thread
)
1149 ULONG Retries
= 3000;
1150 LARGE_INTEGER Interval
;
1151 PLIST_ENTRY ListHead
, NextEntry
;
1155 /* Windows isn't using given thread, but using current. */
1156 Thread
= PsGetCurrentThread();
1158 IOTRACE(IO_IRP_DEBUG
,
1159 "%s - Canceling IRPs for Thread %p\n",
1163 /* Raise to APC to protect the IrpList */
1164 KeRaiseIrql(APC_LEVEL
, &OldIrql
);
1166 /* Start by cancelling all the IRPs in the current thread queue. */
1167 ListHead
= &Thread
->IrpList
;
1168 NextEntry
= ListHead
->Flink
;
1169 while (ListHead
!= NextEntry
)
1172 Irp
= CONTAINING_RECORD(NextEntry
, IRP
, ThreadListEntry
);
1177 /* Move to the next entry */
1178 NextEntry
= NextEntry
->Flink
;
1181 /* Wait 100 milliseconds */
1182 Interval
.QuadPart
= -1000000;
1184 /* Wait till all the IRPs are completed or cancelled. */
1185 while (!IsListEmpty(&Thread
->IrpList
))
1187 /* Now we can lower */
1188 KeLowerIrql(OldIrql
);
1190 /* Wait a short while and then look if all our IRPs were completed. */
1191 KeDelayExecutionThread(KernelMode
, FALSE
, &Interval
);
1194 * Don't stay here forever if some broken driver doesn't complete
1199 /* Print out a message and remove the IRP */
1200 DPRINT1("Broken driver did not complete!\n");
1201 IopDisassociateThreadIrp();
1204 /* Raise the IRQL Again */
1205 KeRaiseIrql(APC_LEVEL
, &OldIrql
);
1208 /* We're done, lower the IRQL */
1209 KeLowerIrql(OldIrql
);
1218 IoCallDriver(IN PDEVICE_OBJECT DeviceObject
,
1222 return IofCallDriver(DeviceObject
, Irp
);
1225 #define IoCallDriver IofCallDriver
1230 #undef IoCompleteRequest
1233 IoCompleteRequest(IN PIRP Irp
,
1234 IN CCHAR PriorityBoost
)
1236 /* Call the fastcall */
1237 IofCompleteRequest(Irp
, PriorityBoost
);
1240 #define IoCompleteRequest IofCompleteRequest
1247 IoEnqueueIrp(IN PIRP Irp
)
1249 /* This is the same as calling IoQueueThreadIrp */
1250 IoQueueThreadIrp(Irp
);
1258 IofCallDriver(IN PDEVICE_OBJECT DeviceObject
,
1261 PDRIVER_OBJECT DriverObject
;
1262 PIO_STACK_LOCATION StackPtr
;
1264 /* Make sure this is a valid IRP */
1265 ASSERT(Irp
->Type
== IO_TYPE_IRP
);
1267 /* Get the Driver Object */
1268 DriverObject
= DeviceObject
->DriverObject
;
1270 /* Decrease the current location and check if */
1271 Irp
->CurrentLocation
--;
1272 if (Irp
->CurrentLocation
<= 0)
1274 /* This IRP ran out of stack, bugcheck */
1275 KeBugCheckEx(NO_MORE_IRP_STACK_LOCATIONS
, (ULONG_PTR
)Irp
, 0, 0, 0);
1278 /* Now update the stack location */
1279 StackPtr
= IoGetNextIrpStackLocation(Irp
);
1280 Irp
->Tail
.Overlay
.CurrentStackLocation
= StackPtr
;
1282 /* Get the Device Object */
1283 StackPtr
->DeviceObject
= DeviceObject
;
1286 return DriverObject
->MajorFunction
[StackPtr
->MajorFunction
](DeviceObject
,
1292 IopClearStackLocation(IN PIO_STACK_LOCATION IoStackLocation
)
1294 IoStackLocation
->MinorFunction
= 0;
1295 IoStackLocation
->Flags
= 0;
1296 IoStackLocation
->Control
&= SL_ERROR_RETURNED
;
1297 IoStackLocation
->Parameters
.Others
.Argument1
= 0;
1298 IoStackLocation
->Parameters
.Others
.Argument2
= 0;
1299 IoStackLocation
->Parameters
.Others
.Argument3
= 0;
1300 IoStackLocation
->FileObject
= NULL
;
1308 IofCompleteRequest(IN PIRP Irp
,
1309 IN CCHAR PriorityBoost
)
1311 PIO_STACK_LOCATION StackPtr
, LastStackPtr
;
1312 PDEVICE_OBJECT DeviceObject
;
1313 PFILE_OBJECT FileObject
;
1320 NTSTATUS ErrorCode
= STATUS_SUCCESS
;
1321 PREPARSE_DATA_BUFFER DataBuffer
= NULL
;
1322 IOTRACE(IO_IRP_DEBUG
,
1323 "%s - Completing IRP %p\n",
1327 /* Make sure this IRP isn't getting completed twice or is invalid */
1328 if ((Irp
->CurrentLocation
) > (Irp
->StackCount
+ 1))
1331 KeBugCheckEx(MULTIPLE_IRP_COMPLETE_REQUESTS
, (ULONG_PTR
)Irp
, 0, 0, 0);
1334 /* Some sanity checks */
1335 ASSERT(Irp
->Type
== IO_TYPE_IRP
);
1336 ASSERT(!Irp
->CancelRoutine
);
1337 ASSERT(Irp
->IoStatus
.Status
!= STATUS_PENDING
);
1338 ASSERT(Irp
->IoStatus
.Status
!= (NTSTATUS
)0xFFFFFFFF);
1340 /* Get the last stack */
1341 LastStackPtr
= (PIO_STACK_LOCATION
)(Irp
+ 1);
1342 if (LastStackPtr
->Control
& SL_ERROR_RETURNED
)
1344 /* Get the error code */
1345 ErrorCode
= PtrToUlong(LastStackPtr
->Parameters
.Others
.Argument4
);
1349 * Start the loop with the current stack and point the IRP to the next stack
1350 * and then keep incrementing the stack as we loop through. The IRP should
1351 * always point to the next stack location w.r.t the one currently being
1352 * analyzed, so completion routine code will see the appropriate value.
1353 * Because of this, we must loop until the current stack location is +1 of
1354 * the stack count, because when StackPtr is at the end, CurrentLocation is +1.
1356 for (StackPtr
= IoGetCurrentIrpStackLocation(Irp
),
1357 Irp
->CurrentLocation
++,
1358 Irp
->Tail
.Overlay
.CurrentStackLocation
++;
1359 Irp
->CurrentLocation
<= (Irp
->StackCount
+ 1);
1361 Irp
->CurrentLocation
++,
1362 Irp
->Tail
.Overlay
.CurrentStackLocation
++)
1364 /* Set Pending Returned */
1365 Irp
->PendingReturned
= StackPtr
->Control
& SL_PENDING_RETURNED
;
1367 /* Check if we failed */
1368 if (!NT_SUCCESS(Irp
->IoStatus
.Status
))
1370 /* Check if it was changed by a completion routine */
1371 if (Irp
->IoStatus
.Status
!= ErrorCode
)
1373 /* Update the error for the current stack */
1374 ErrorCode
= Irp
->IoStatus
.Status
;
1375 StackPtr
->Control
|= SL_ERROR_RETURNED
;
1376 LastStackPtr
->Parameters
.Others
.Argument4
= UlongToPtr(ErrorCode
);
1377 LastStackPtr
->Control
|= SL_ERROR_RETURNED
;
1381 /* Check if there is a Completion Routine to Call */
1382 if ((NT_SUCCESS(Irp
->IoStatus
.Status
) &&
1383 (StackPtr
->Control
& SL_INVOKE_ON_SUCCESS
)) ||
1384 (!NT_SUCCESS(Irp
->IoStatus
.Status
) &&
1385 (StackPtr
->Control
& SL_INVOKE_ON_ERROR
)) ||
1387 (StackPtr
->Control
& SL_INVOKE_ON_CANCEL
)))
1389 /* Clear the stack location */
1390 IopClearStackLocation(StackPtr
);
1392 /* Check for highest-level device completion routines */
1393 if (Irp
->CurrentLocation
== (Irp
->StackCount
+ 1))
1395 /* Clear the DO, since the current stack location is invalid */
1396 DeviceObject
= NULL
;
1400 /* Otherwise, return the real one */
1401 DeviceObject
= IoGetCurrentIrpStackLocation(Irp
)->DeviceObject
;
1404 /* Call the completion routine */
1405 Status
= StackPtr
->CompletionRoutine(DeviceObject
,
1409 /* Don't touch the Packet in this case, since it might be gone! */
1410 if (Status
== STATUS_MORE_PROCESSING_REQUIRED
) return;
1414 /* Otherwise, check if this is a completed IRP */
1415 if ((Irp
->CurrentLocation
<= Irp
->StackCount
) &&
1416 (Irp
->PendingReturned
))
1418 /* Mark it as pending */
1419 IoMarkIrpPending(Irp
);
1422 /* Clear the stack location */
1423 IopClearStackLocation(StackPtr
);
1427 /* Check if the IRP is an associated IRP */
1428 if (Irp
->Flags
& IRP_ASSOCIATED_IRP
)
1430 /* Get the master IRP and count */
1431 MasterIrp
= Irp
->AssociatedIrp
.MasterIrp
;
1432 MasterCount
= InterlockedDecrement(&MasterIrp
->AssociatedIrp
.IrpCount
);
1435 for (Mdl
= Irp
->MdlAddress
; Mdl
; Mdl
= NextMdl
)
1437 /* Go to the next one */
1438 NextMdl
= Mdl
->Next
;
1442 /* Free the IRP itself */
1445 /* Complete the Master IRP */
1446 if (!MasterCount
) IofCompleteRequest(MasterIrp
, PriorityBoost
);
1450 /* Check whether we have to reparse */
1451 if (Irp
->IoStatus
.Status
== STATUS_REPARSE
)
1453 if (Irp
->IoStatus
.Information
> IO_REMOUNT
)
1455 /* If that's a reparse tag we understand, save the buffer from deletion */
1456 if (Irp
->IoStatus
.Information
== IO_REPARSE_TAG_MOUNT_POINT
)
1458 ASSERT(Irp
->Tail
.Overlay
.AuxiliaryBuffer
!= NULL
);
1459 DataBuffer
= (PREPARSE_DATA_BUFFER
)Irp
->Tail
.Overlay
.AuxiliaryBuffer
;
1460 Irp
->Tail
.Overlay
.AuxiliaryBuffer
= NULL
;
1464 Irp
->IoStatus
.Status
= STATUS_IO_REPARSE_TAG_NOT_HANDLED
;
1469 /* Check if we have an auxiliary buffer */
1470 if (Irp
->Tail
.Overlay
.AuxiliaryBuffer
)
1473 ExFreePool(Irp
->Tail
.Overlay
.AuxiliaryBuffer
);
1474 Irp
->Tail
.Overlay
.AuxiliaryBuffer
= NULL
;
1477 /* Check if this is a Paging I/O or Close Operation */
1478 if (Irp
->Flags
& (IRP_PAGING_IO
| IRP_CLOSE_OPERATION
))
1480 /* Handle a Close Operation or Sync Paging I/O */
1481 if (Irp
->Flags
& (IRP_SYNCHRONOUS_PAGING_IO
| IRP_CLOSE_OPERATION
))
1483 /* Set the I/O Status and Signal the Event */
1484 Flags
= Irp
->Flags
& (IRP_SYNCHRONOUS_PAGING_IO
| IRP_PAGING_IO
);
1485 *Irp
->UserIosb
= Irp
->IoStatus
;
1486 KeSetEvent(Irp
->UserEvent
, PriorityBoost
, FALSE
);
1488 /* Free the IRP for a Paging I/O Only, Close is handled by us */
1491 /* If we were using the reserve IRP, then call the appropriate
1492 * free function (to make the IRP available again)
1494 if (Irp
== IopReserveIrpAllocator
.ReserveIrp
)
1496 IopFreeReserveIrp(PriorityBoost
);
1498 /* Otherwise, free for real! */
1509 KeInitializeApc(&Irp
->Tail
.Apc
1510 &Irp
->Tail
.Overlay
.Thread
->Tcb
,
1511 Irp
->ApcEnvironment
,
1512 IopCompletePageWrite
,
1517 KeInsertQueueApc(&Irp
->Tail
.Apc
,
1522 /* Not implemented yet. */
1523 UNIMPLEMENTED_DBGBREAK("Not supported!\n");
1527 /* Get out of here */
1531 /* Unlock MDL Pages, page 167. */
1532 Mdl
= Irp
->MdlAddress
;
1539 /* Check if we should exit because of a Deferred I/O (page 168) */
1540 if ((Irp
->Flags
& IRP_DEFER_IO_COMPLETION
) && !(Irp
->PendingReturned
))
1542 /* Restore the saved reparse buffer for the caller */
1543 if (Irp
->IoStatus
.Status
== STATUS_REPARSE
&&
1544 Irp
->IoStatus
.Information
== IO_REPARSE_TAG_MOUNT_POINT
)
1546 Irp
->Tail
.Overlay
.AuxiliaryBuffer
= (PCHAR
)DataBuffer
;
1550 * Return without queuing the completion APC, since the caller will
1551 * take care of doing its own optimized completion at PASSIVE_LEVEL.
1556 /* Get the thread and file object */
1557 Thread
= Irp
->Tail
.Overlay
.Thread
;
1558 FileObject
= Irp
->Tail
.Overlay
.OriginalFileObject
;
1560 /* Make sure the IRP isn't canceled */
1563 /* Initialize the APC */
1564 KeInitializeApc(&Irp
->Tail
.Apc
,
1566 Irp
->ApcEnvironment
,
1574 KeInsertQueueApc(&Irp
->Tail
.Apc
,
1581 /* The IRP just got canceled... does a thread still own it? */
1584 /* Yes! There is still hope! Initialize the APC */
1585 KeInitializeApc(&Irp
->Tail
.Apc
,
1587 Irp
->ApcEnvironment
,
1595 KeInsertQueueApc(&Irp
->Tail
.Apc
,
1602 /* Nothing left for us to do, kill it */
1603 ASSERT(Irp
->Cancel
);
1604 IopCleanupIrp(Irp
, FileObject
);
1611 IopSynchronousCompletion(IN PDEVICE_OBJECT DeviceObject
,
1615 if (Irp
->PendingReturned
)
1616 KeSetEvent((PKEVENT
)Context
, IO_NO_INCREMENT
, FALSE
);
1617 return STATUS_MORE_PROCESSING_REQUIRED
;
1625 IoForwardIrpSynchronously(IN PDEVICE_OBJECT DeviceObject
,
1631 /* Check if next stack location is available */
1632 if (Irp
->CurrentLocation
> Irp
->StackCount
|| Irp
->CurrentLocation
<= 1)
1634 /* No more stack location */
1638 /* Initialize event */
1639 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
1641 /* Copy stack location for next driver */
1642 IoCopyCurrentIrpStackLocationToNext(Irp
);
1644 /* Set a completion routine, which will signal the event */
1645 IoSetCompletionRoutine(Irp
, IopSynchronousCompletion
, &Event
, TRUE
, TRUE
, TRUE
);
1647 /* Call next driver */
1648 Status
= IoCallDriver(DeviceObject
, Irp
);
1650 /* Check if irp is pending */
1651 if (Status
== STATUS_PENDING
)
1653 /* Yes, wait for its completion */
1654 KeWaitForSingleObject(&Event
, Suspended
, KernelMode
, FALSE
, NULL
);
1657 /* Return success */
1666 IoFreeIrp(IN PIRP Irp
)
1668 PNPAGED_LOOKASIDE_LIST List
;
1669 PP_NPAGED_LOOKASIDE_NUMBER ListType
= LookasideSmallIrpList
;
1671 IOTRACE(IO_IRP_DEBUG
,
1672 "%s - Freeing IRPs %p\n",
1676 /* Make sure the Thread IRP list is empty and that it OK to free it */
1677 ASSERT(Irp
->Type
== IO_TYPE_IRP
);
1678 ASSERT(IsListEmpty(&Irp
->ThreadListEntry
));
1679 ASSERT(Irp
->CurrentLocation
>= Irp
->StackCount
);
1682 Prcb
= KeGetCurrentPrcb();
1684 /* If this was a lookaside alloc, increment lookaside float */
1685 if (Irp
->AllocationFlags
& IRP_LOOKASIDE_ALLOCATION
)
1687 Irp
->AllocationFlags
&= ~IRP_LOOKASIDE_ALLOCATION
;
1688 InterlockedIncrement(&Prcb
->LookasideIrpFloat
);
1691 /* If this was a pool alloc, free it with the pool */
1692 if (!(Irp
->AllocationFlags
& IRP_ALLOCATED_FIXED_SIZE
))
1695 ExFreePoolWithTag(Irp
, TAG_IRP
);
1699 /* Check if this was a Big IRP */
1700 if (Irp
->StackCount
!= 1) ListType
= LookasideLargeIrpList
;
1702 /* Use the P List */
1703 List
= (PNPAGED_LOOKASIDE_LIST
)Prcb
->PPLookasideList
[ListType
].P
;
1704 List
->L
.TotalFrees
++;
1706 /* Check if the Free was within the Depth or not */
1707 if (ExQueryDepthSList(&List
->L
.ListHead
) >= List
->L
.Depth
)
1709 /* Let the balancer know */
1710 List
->L
.FreeMisses
++;
1712 /* Use the L List */
1713 List
= (PNPAGED_LOOKASIDE_LIST
)Prcb
->PPLookasideList
[ListType
].L
;
1714 List
->L
.TotalFrees
++;
1716 /* Check if the Free was within the Depth or not */
1717 if (ExQueryDepthSList(&List
->L
.ListHead
) >= List
->L
.Depth
)
1719 /* All lists failed, use the pool */
1720 List
->L
.FreeMisses
++;
1721 ExFreePoolWithTag(Irp
, TAG_IRP
);
1726 /* The free was within the Depth */
1729 /* Remove the association with the process */
1730 if (Irp
->AllocationFlags
& IRP_QUOTA_CHARGED
)
1732 ExReturnPoolQuota(Irp
);
1733 Irp
->AllocationFlags
&= ~IRP_QUOTA_CHARGED
;
1736 /* Add it to the lookaside list */
1737 InterlockedPushEntrySList(&List
->L
.ListHead
,
1748 IoGetPagingIoPriority(IN PIRP Irp
)
1750 IO_PAGING_PRIORITY Priority
;
1756 /* Check what priority it has */
1757 if (Flags
& IRP_CLASS_CACHE_OPERATION
)
1760 Priority
= IoPagingPriorityHigh
;
1762 else if (Flags
& IRP_PAGING_IO
)
1764 /* Normal priority */
1765 Priority
= IoPagingPriorityNormal
;
1769 /* Invalid -- not a paging IRP */
1770 Priority
= IoPagingPriorityInvalid
;
1773 /* Return the priority */
1782 IoGetRequestorProcess(IN PIRP Irp
)
1784 /* Return the requestor process */
1785 if (Irp
->Tail
.Overlay
.Thread
)
1787 if (Irp
->ApcEnvironment
== OriginalApcEnvironment
)
1789 return Irp
->Tail
.Overlay
.Thread
->ThreadsProcess
;
1791 else if (Irp
->ApcEnvironment
== AttachedApcEnvironment
)
1793 return (PEPROCESS
)Irp
->Tail
.Overlay
.Thread
->Tcb
.ApcState
.Process
;
1805 IoGetRequestorProcessId(IN PIRP Irp
)
1809 /* Return the requestor process' id */
1810 Process
= IoGetRequestorProcess(Irp
);
1811 if (Process
) return PtrToUlong(Process
->UniqueProcessId
);
1821 IoGetRequestorSessionId(IN PIRP Irp
,
1822 OUT PULONG pSessionId
)
1826 /* Return the session */
1827 if (Irp
->Tail
.Overlay
.Thread
)
1829 Process
= Irp
->Tail
.Overlay
.Thread
->ThreadsProcess
;
1830 *pSessionId
= MmGetSessionId(Process
);
1831 return STATUS_SUCCESS
;
1834 *pSessionId
= (ULONG
)-1;
1835 return STATUS_UNSUCCESSFUL
;
1843 IoGetTopLevelIrp(VOID
)
1845 /* Return the IRP */
1846 return (PIRP
)PsGetCurrentThread()->TopLevelIrp
;
1854 IoInitializeIrp(IN PIRP Irp
,
1855 IN USHORT PacketSize
,
1859 IOTRACE(IO_IRP_DEBUG
,
1860 "%s - Initializing IRP %p\n",
1863 RtlZeroMemory(Irp
, PacketSize
);
1865 /* Set the Header and other data */
1866 Irp
->Type
= IO_TYPE_IRP
;
1867 Irp
->Size
= PacketSize
;
1868 Irp
->StackCount
= StackSize
;
1869 Irp
->CurrentLocation
= StackSize
+ 1;
1870 Irp
->ApcEnvironment
= KeGetCurrentThread()->ApcStateIndex
;
1871 Irp
->Tail
.Overlay
.CurrentStackLocation
= (PIO_STACK_LOCATION
)(Irp
+ 1) + StackSize
;
1873 /* Initialize the Thread List */
1874 InitializeListHead(&Irp
->ThreadListEntry
);
1882 IoIsOperationSynchronous(IN PIRP Irp
)
1887 /* If the IRP requests synchronous paging I/O, if the file object was opened
1888 for synchronous I/O, if the IRP_SYNCHRONOUS_API flag is set in the IRP
1889 the operation is synchronous */
1890 SynchIO
= (IoGetCurrentIrpStackLocation(Irp
)->FileObject
->Flags
& FO_SYNCHRONOUS_IO
) ||
1891 (Irp
->Flags
& IRP_SYNCHRONOUS_API
) || (Irp
->Flags
& IRP_SYNCHRONOUS_PAGING_IO
);
1893 /* If the IRP requests asynchronous paging I/O, the operation is asynchronous,
1894 even if one of the above conditions is true */
1895 ForceAsync
= (Irp
->Flags
& IRP_PAGING_IO
) && !(Irp
->Flags
& IRP_SYNCHRONOUS_PAGING_IO
);
1897 /* Check the flags */
1898 if (SynchIO
&& !ForceAsync
)
1900 /* Synch API or Paging I/O is OK, as is Sync File I/O */
1904 /* Otherwise, it is an asynchronous operation. */
1913 IoIsValidNameGraftingBuffer(IN PIRP Irp
,
1914 IN PREPARSE_DATA_BUFFER ReparseBuffer
)
1925 IoMakeAssociatedIrp(IN PIRP Irp
,
1929 IOTRACE(IO_IRP_DEBUG
,
1930 "%s - Associating IRP %p\n",
1934 /* Allocate the IRP */
1935 AssocIrp
= IoAllocateIrp(StackSize
, FALSE
);
1936 if (!AssocIrp
) return NULL
;
1939 AssocIrp
->Flags
|= IRP_ASSOCIATED_IRP
;
1941 /* Set the Thread */
1942 AssocIrp
->Tail
.Overlay
.Thread
= Irp
->Tail
.Overlay
.Thread
;
1944 /* Associate them */
1945 AssocIrp
->AssociatedIrp
.MasterIrp
= Irp
;
1954 IoQueueThreadIrp(IN PIRP Irp
)
1956 IOTRACE(IO_IRP_DEBUG
,
1957 "%s - Queueing IRP %p\n",
1961 /* Use our inlined routine */
1962 IopQueueIrpToThread(Irp
);
1967 * Reference: Chris Cant's "Writing WDM Device Drivers"
1971 IoReuseIrp(IN OUT PIRP Irp
,
1974 UCHAR AllocationFlags
;
1975 IOTRACE(IO_IRP_DEBUG
,
1976 "%s - Reusing IRP %p\n",
1980 /* Make sure it's OK to reuse it */
1981 ASSERT(!Irp
->CancelRoutine
);
1982 ASSERT(IsListEmpty(&Irp
->ThreadListEntry
));
1984 /* Get the old flags */
1985 AllocationFlags
= Irp
->AllocationFlags
;
1987 /* Reinitialize the IRP */
1988 IoInitializeIrp(Irp
, Irp
->Size
, Irp
->StackCount
);
1990 /* Duplicate the data */
1991 Irp
->IoStatus
.Status
= Status
;
1992 Irp
->AllocationFlags
= AllocationFlags
;
2000 IoSetTopLevelIrp(IN PIRP Irp
)
2003 PsGetCurrentThread()->TopLevelIrp
= (ULONG_PTR
)Irp
;
2006 #if defined (_WIN64)
2010 IN PIRP Irp OPTIONAL
)