2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: ntoskrnl/io/irp.c
7 * PROGRAMMERS: Hartmut Birr
8 * Alex Ionescu (alex@relsoft.net)
9 * David Welch (welch@mcmail.com)
12 /* INCLUDES ****************************************************************/
16 #include <internal/debug.h>
18 /* GLOBALS *******************************************************************/
20 #define TAG_IRP TAG('I', 'R', 'P', ' ')
21 #define TAG_SYS_BUF TAG('S', 'Y', 'S' , 'B')
23 /* PRIVATE FUNCTIONS ********************************************************/
27 IopFreeIrpKernelApc(PKAPC Apc
,
28 PKNORMAL_ROUTINE
*NormalRoutine
,
30 PVOID
*SystemArgument1
,
31 PVOID
*SystemArgument2
)
34 IoFreeIrp(CONTAINING_RECORD(Apc
, IRP
, Tail
.Apc
));
39 IopAbortIrpKernelApc(PKAPC Apc
)
42 IoFreeIrp(CONTAINING_RECORD(Apc
, IRP
, Tail
.Apc
));
46 * FUNCTION: Performs the second stage of irp completion for read/write irps
48 * Called as a special kernel APC kernel-routine or directly from IofCompleteRequest()
50 * Note that we'll never see irp's flagged IRP_PAGING_IO (IRP_MOUNT_OPERATION)
51 * or IRP_CLOSE_OPERATION (IRP_MJ_CLOSE and IRP_MJ_CLEANUP) here since their
52 * cleanup/completion is fully taken care of in IoCompleteRequest.
57 IopCompleteRequest(PKAPC Apc
,
58 PKNORMAL_ROUTINE
* NormalRoutine
,
60 PVOID
* SystemArgument1
,
61 PVOID
* SystemArgument2
)
63 PFILE_OBJECT FileObject
;
69 if (Apc
) DPRINT("IoSecondStageCompletition with APC: %x\n", Apc
);
71 /* Get data from the APC */
72 FileObject
= (PFILE_OBJECT
)(*SystemArgument1
);
73 Irp
= CONTAINING_RECORD(Apc
, IRP
, Tail
.Apc
);
74 DPRINT("IoSecondStageCompletition, %x\n", Irp
);
76 /* Save the User Event */
77 UserEvent
= Irp
->UserEvent
;
79 /* Remember if the IRP is Sync or not */
80 SyncIrp
= Irp
->Flags
& IRP_SYNCHRONOUS_API
? TRUE
: FALSE
;
82 /* Handle Buffered case first */
83 if (Irp
->Flags
& IRP_BUFFERED_IO
)
85 /* Check if we have an input buffer and if we suceeded */
86 if (Irp
->Flags
& IRP_INPUT_OPERATION
&& NT_SUCCESS(Irp
->IoStatus
.Status
))
88 /* Copy the buffer back to the user */
89 RtlCopyMemory(Irp
->UserBuffer
,
90 Irp
->AssociatedIrp
.SystemBuffer
,
91 Irp
->IoStatus
.Information
);
94 /* Also check if we should de-allocate it */
95 if (Irp
->Flags
& IRP_DEALLOCATE_BUFFER
)
97 ExFreePoolWithTag(Irp
->AssociatedIrp
.SystemBuffer
, TAG_SYS_BUF
);
101 /* Now we got rid of these two... */
102 Irp
->Flags
&= ~(IRP_BUFFERED_IO
| IRP_DEALLOCATE_BUFFER
);
104 /* Check if there's an MDL */
105 while ((Mdl
= Irp
->MdlAddress
))
107 /* Clear all of them */
108 Irp
->MdlAddress
= Mdl
->Next
;
112 /* Remove the IRP from the list of Thread Pending IRPs */
113 RemoveEntryList(&Irp
->ThreadListEntry
);
114 InitializeListHead(&Irp
->ThreadListEntry
);
117 /* Check for Success but allow failure for Async IRPs */
118 if (NT_SUCCESS(Irp
->IoStatus
.Status
) ||
119 (Irp
->PendingReturned
&&
121 (FileObject
== NULL
|| FileObject
->Flags
& FO_SYNCHRONOUS_IO
)))
125 /* Save the IOSB Information */
126 *Irp
->UserIosb
= Irp
->IoStatus
;
130 /* Ignore any error */
134 /* Check if there's an event */
137 /* Check if we should signal the File Object Event as well */
140 /* If the File Object is SYNC, then we need to signal its event too */
141 if (FileObject
->Flags
& FO_SYNCHRONOUS_IO
)
144 FileObject
->FinalStatus
= Irp
->IoStatus
.Status
;
147 KeSetEvent(&FileObject
->Event
, 0, FALSE
);
150 /* Signal the Event */
151 KeSetEvent(UserEvent
, 0, FALSE
);
153 /* Dereference the Event if this is an ASYNC IRP */
154 if (FileObject
&& !SyncIrp
&& UserEvent
!= &FileObject
->Event
)
156 ObDereferenceObject(UserEvent
);
162 FileObject
->FinalStatus
= Irp
->IoStatus
.Status
;
164 /* Signal the File Object Instead */
165 KeSetEvent(&FileObject
->Event
, 0, FALSE
);
169 /* Now call the User APC if one was requested */
170 if (Irp
->Overlay
.AsynchronousParameters
.UserApcRoutine
!= NULL
)
172 KeInitializeApc(&Irp
->Tail
.Apc
,
173 KeGetCurrentThread(),
174 CurrentApcEnvironment
,
176 IopAbortIrpKernelApc
,
177 (PKNORMAL_ROUTINE
)Irp
->Overlay
.AsynchronousParameters
.UserApcRoutine
,
179 Irp
->Overlay
.AsynchronousParameters
.UserApcContext
);
181 KeInsertQueueApc(&Irp
->Tail
.Apc
,
187 else if (FileObject
&& FileObject
->CompletionContext
)
189 /* Call the IO Completion Port if we have one, instead */
190 Irp
->Tail
.CompletionKey
= FileObject
->CompletionContext
->Key
;
191 Irp
->Tail
.Overlay
.PacketType
= IrpCompletionPacket
;
192 KeInsertQueue(FileObject
->CompletionContext
->Port
,
193 &Irp
->Tail
.Overlay
.ListEntry
);
199 /* Signal the Events only if PendingReturned and we have a File Object */
200 if (FileObject
&& Irp
->PendingReturned
)
202 /* Check for SYNC IRP */
205 /* Set the status in this case only */
208 *Irp
->UserIosb
= Irp
->IoStatus
;
212 /* Ignore any error */
216 /* Signal our event if we have one */
219 KeSetEvent(UserEvent
, 0, FALSE
);
223 /* Signal the File's Event instead */
224 KeSetEvent(&FileObject
->Event
, 0, FALSE
);
230 /* FIXME: This is necessary to fix bug #609 */
233 *Irp
->UserIosb
= Irp
->IoStatus
;
237 /* Ignore any error */
241 /* We'll report the Status to the File Object, not the IRP */
242 FileObject
->FinalStatus
= Irp
->IoStatus
.Status
;
244 /* Signal the File Object ONLY if this was Async */
245 KeSetEvent(&FileObject
->Event
, 0, FALSE
);
249 /* Dereference the Event if it's an ASYNC IRP on a File Object */
250 if (UserEvent
&& !SyncIrp
&& FileObject
)
252 if (UserEvent
!= &FileObject
->Event
)
254 ObDereferenceObject(UserEvent
);
259 /* Dereference the File Object */
260 if (FileObject
) ObDereferenceObject(FileObject
);
263 if (Irp
) IoFreeIrp(Irp
);
267 if (NT_SUCCESS(Irp
->IoStatus
.Status
) || Irp
->PendingReturned
)
271 /* Save the IOSB Information */
272 *Irp
->UserIosb
= Irp
->IoStatus
;
276 /* Ignore any error */
282 if (FileObject
->Flags
& FO_SYNCHRONOUS_IO
)
285 FileObject
->FinalStatus
= Irp
->IoStatus
.Status
;
287 /* FIXME: Remove this check when I/O code is fixed */
288 if (UserEvent
!= &FileObject
->Event
)
291 KeSetEvent(&FileObject
->Event
, 0, FALSE
);
296 /* Signal the user event, if one exist */
299 KeSetEvent(UserEvent
, 0, FALSE
);
302 /* Now call the User APC if one was requested */
303 if (Irp
->Overlay
.AsynchronousParameters
.UserApcRoutine
)
305 KeInitializeApc(&Irp
->Tail
.Apc
,
306 KeGetCurrentThread(),
307 CurrentApcEnvironment
,
309 IopAbortIrpKernelApc
,
310 (PKNORMAL_ROUTINE
)Irp
->Overlay
.AsynchronousParameters
.UserApcRoutine
,
312 Irp
->Overlay
.AsynchronousParameters
.UserApcContext
);
314 KeInsertQueueApc(&Irp
->Tail
.Apc
,
320 else if (FileObject
&& FileObject
->CompletionContext
)
322 /* Call the IO Completion Port if we have one, instead */
323 IoSetIoCompletion(FileObject
->CompletionContext
->Port
,
324 FileObject
->CompletionContext
->Key
,
325 Irp
->Overlay
.AsynchronousParameters
.UserApcContext
,
326 Irp
->IoStatus
.Status
,
327 Irp
->IoStatus
.Information
,
333 /* Free the Irp if it hasn't already */
334 if (Irp
) IoFreeIrp(Irp
);
338 /* Dereference the user event, if it is an event object */
339 /* FIXME: Remove last check when I/O code is fixed */
340 if (UserEvent
&& !SyncIrp
&& UserEvent
!= &FileObject
->Event
)
342 ObDereferenceObject(UserEvent
);
345 /* Dereference the File Object */
346 ObDereferenceObject(FileObject
);
351 /* FUNCTIONS *****************************************************************/
356 * FUNCTION: Allocates an IRP
358 * StackSize = the size of the stack required for the irp
359 * ChargeQuota = Charge allocation to current threads quota
360 * RETURNS: Irp allocated
364 IoAllocateIrp(CCHAR StackSize
,
368 USHORT Size
= IoSizeOfIrp(StackSize
);
371 PNPAGED_LOOKASIDE_LIST List
;
372 PP_NPAGED_LOOKASIDE_NUMBER ListType
= LookasideSmallIrpList
;
374 /* Figure out which Lookaside List to use */
375 if ((StackSize
<= 8) && (ChargeQuota
== FALSE
))
377 DPRINT("Using lookaside, %d\n", StackSize
);
378 /* Set Fixed Size Flag */
379 Flags
= IRP_ALLOCATED_FIXED_SIZE
;
381 /* See if we should use big list */
384 DPRINT("Using large lookaside\n");
385 Size
= IoSizeOfIrp(8);
386 ListType
= LookasideLargeIrpList
;
390 Prcb
= KeGetCurrentPrcb();
392 /* Get the P List First */
393 List
= (PNPAGED_LOOKASIDE_LIST
)Prcb
->PPLookasideList
[ListType
].P
;
395 /* Attempt allocation */
396 List
->L
.TotalAllocates
++;
397 DPRINT("Total allocates: %d\n", List
->L
.TotalAllocates
);
398 Irp
= (PIRP
)InterlockedPopEntrySList(&List
->L
.ListHead
);
399 DPRINT("Alloc attempt on CPU list: %p\n", Irp
);
401 /* Check if the P List failed */
404 /* Let the balancer know */
405 List
->L
.AllocateMisses
++;
406 DPRINT("Total misses: %d\n", List
->L
.AllocateMisses
);
409 List
= (PNPAGED_LOOKASIDE_LIST
)Prcb
->PPLookasideList
[ListType
].L
;
410 List
->L
.TotalAllocates
++;
411 Irp
= (PIRP
)InterlockedPopEntrySList(&List
->L
.ListHead
);
412 DPRINT("Alloc attempt on SYS list: %p\n", Irp
);
416 /* Check if we have to use the pool */
419 DPRINT("Using pool\n");
420 /* Did we try lookaside and fail? */
421 if (Flags
& IRP_ALLOCATED_FIXED_SIZE
) List
->L
.AllocateMisses
++;
423 /* Check if we shoudl charge quota */
426 /* Irp = ExAllocatePoolWithQuotaTag(NonPagedPool, Size, TAG_IRP); */
428 Irp
= ExAllocatePoolWithTag(NonPagedPool
, Size
, TAG_IRP
);
432 /* Allocate the IRP With no Quota charge */
433 Irp
= ExAllocatePoolWithTag(NonPagedPool
, Size
, TAG_IRP
);
436 /* Make sure it was sucessful */
437 if (!Irp
) return(NULL
);
441 /* We have an IRP from Lookaside */
442 Flags
|= IRP_LOOKASIDE_ALLOCATION
;
446 if (ChargeQuota
) Flags
|= IRP_QUOTA_CHARGED
;
448 /* Now Initialize it */
449 DPRINT("irp allocated\n");
450 IoInitializeIrp(Irp
, Size
, StackSize
);
452 /* Set the Allocation Flags */
453 Irp
->AllocationFlags
= Flags
;
462 * FUNCTION: Allocates and sets up an IRP to be sent to lower level drivers
464 * MajorFunction = One of IRP_MJ_READ, IRP_MJ_WRITE,
465 * IRP_MJ_FLUSH_BUFFERS or IRP_MJ_SHUTDOWN
466 * DeviceObject = Device object to send the irp to
467 * Buffer = Buffer into which data will be read or written
468 * Length = Length in bytes of the irp to be allocated
469 * StartingOffset = Starting offset on the device
470 * IoStatusBlock (OUT) = Storage for the result of the operation
471 * RETURNS: The IRP allocated on success, or
476 IoBuildAsynchronousFsdRequest(ULONG MajorFunction
,
477 PDEVICE_OBJECT DeviceObject
,
480 PLARGE_INTEGER StartingOffset
,
481 PIO_STATUS_BLOCK IoStatusBlock
)
484 PIO_STACK_LOCATION StackPtr
;
485 LOCK_OPERATION AccessType
;
487 DPRINT("IoBuildAsynchronousFsdRequest(MajorFunction %x, DeviceObject %x, "
488 "Buffer %x, Length %x, StartingOffset %x, "
489 "IoStatusBlock %x\n",MajorFunction
,DeviceObject
,Buffer
,Length
,
490 StartingOffset
,IoStatusBlock
);
493 if (!(Irp
= IoAllocateIrp(DeviceObject
->StackSize
, FALSE
))) return Irp
;
496 StackPtr
= IoGetNextIrpStackLocation(Irp
);
498 /* Write the Major function and then deal with it */
499 StackPtr
->MajorFunction
= (UCHAR
)MajorFunction
;
501 /* Do not handle the following here */
502 if (MajorFunction
!= IRP_MJ_FLUSH_BUFFERS
&&
503 MajorFunction
!= IRP_MJ_SHUTDOWN
&&
504 MajorFunction
!= IRP_MJ_PNP
)
506 /* Check if this is Buffered IO */
507 if (DeviceObject
->Flags
& DO_BUFFERED_IO
)
509 /* Allocate the System Buffer */
510 Irp
->AssociatedIrp
.SystemBuffer
= ExAllocatePoolWithTag(NonPagedPool
,
515 Irp
->Flags
= IRP_BUFFERED_IO
| IRP_DEALLOCATE_BUFFER
;
517 /* Handle special IRP_MJ_WRITE Case */
518 if (MajorFunction
== IRP_MJ_WRITE
)
520 /* Copy the buffer data */
521 RtlCopyMemory(Irp
->AssociatedIrp
.SystemBuffer
, Buffer
, Length
);
525 /* Set the Input Operation flag and set this as a User Buffer */
526 Irp
->Flags
|= IRP_INPUT_OPERATION
;
527 Irp
->UserBuffer
= Buffer
;
530 else if (DeviceObject
->Flags
& DO_DIRECT_IO
)
532 /* Use an MDL for Direct I/O */
533 Irp
->MdlAddress
= MmCreateMdl(NULL
, Buffer
, Length
);
536 if (MajorFunction
== IRP_MJ_READ
)
538 AccessType
= IoWriteAccess
;
542 AccessType
= IoReadAccess
;
546 _SEH_FILTER(FreeAndGoOn
)
548 /* Free the IRP and its MDL */
549 IoFreeMdl(Irp
->MdlAddress
);
551 return EXCEPTION_CONTINUE_SEARCH
;
556 MmProbeAndLockPages(Irp
->MdlAddress
, KernelMode
, AccessType
);
560 /* Free the IRP and its MDL */
561 IoFreeMdl(Irp
->MdlAddress
);
563 /* FIXME - pass the exception to the caller? */
573 /* Neither, use the buffer */
574 Irp
->UserBuffer
= Buffer
;
577 if (MajorFunction
== IRP_MJ_READ
)
579 StackPtr
->Parameters
.Read
.Length
= Length
;
580 StackPtr
->Parameters
.Read
.ByteOffset
= *StartingOffset
;
582 else if (MajorFunction
== IRP_MJ_WRITE
)
584 StackPtr
->Parameters
.Write
.Length
= Length
;
585 StackPtr
->Parameters
.Write
.ByteOffset
= *StartingOffset
;
589 /* Set the Current Thread and IOSB */
590 if (!IoStatusBlock
) KEBUGCHECK(0); /* Temporary to catch illegal ROS Drivers */
591 Irp
->UserIosb
= IoStatusBlock
;
592 Irp
->Tail
.Overlay
.Thread
= PsGetCurrentThread();
594 /* Set the Status Block after all is done */
602 * FUNCTION: Allocates and sets up an IRP to be sent to drivers
604 * IoControlCode = Device io control code
605 * DeviceObject = Device object to send the irp to
606 * InputBuffer = Buffer from which data will be read by the driver
607 * InputBufferLength = Length in bytes of the input buffer
608 * OutputBuffer = Buffer into which data will be written by the driver
609 * OutputBufferLength = Length in bytes of the output buffer
610 * InternalDeviceIoControl = Determines weather
611 * IRP_MJ_INTERNAL_DEVICE_CONTROL or
612 * IRP_MJ_DEVICE_CONTROL will be used
613 * Event = Event used to notify the caller of completion
614 * IoStatusBlock (OUT) = Storage for the result of the operation
615 * RETURNS: The IRP allocated on success, or
620 IoBuildDeviceIoControlRequest (ULONG IoControlCode
,
621 PDEVICE_OBJECT DeviceObject
,
623 ULONG InputBufferLength
,
625 ULONG OutputBufferLength
,
626 BOOLEAN InternalDeviceIoControl
,
628 PIO_STATUS_BLOCK IoStatusBlock
)
631 PIO_STACK_LOCATION StackPtr
;
633 LOCK_OPERATION AccessType
;
635 DPRINT("IoBuildDeviceIoRequest(IoControlCode %x, DeviceObject %x, "
636 "InputBuffer %x, InputBufferLength %x, OutputBuffer %x, "
637 "OutputBufferLength %x, InternalDeviceIoControl %x "
638 "Event %x, IoStatusBlock %x\n",IoControlCode
,DeviceObject
,
639 InputBuffer
,InputBufferLength
,OutputBuffer
,OutputBufferLength
,
640 InternalDeviceIoControl
,Event
,IoStatusBlock
);
643 if (!(Irp
= IoAllocateIrp(DeviceObject
->StackSize
, FALSE
))) return Irp
;
646 StackPtr
= IoGetNextIrpStackLocation(Irp
);
648 /* Set the DevCtl Type */
649 StackPtr
->MajorFunction
= InternalDeviceIoControl
?
650 IRP_MJ_INTERNAL_DEVICE_CONTROL
: IRP_MJ_DEVICE_CONTROL
;
652 /* Set the IOCTL Data */
653 StackPtr
->Parameters
.DeviceIoControl
.IoControlCode
= IoControlCode
;
654 StackPtr
->Parameters
.DeviceIoControl
.InputBufferLength
= InputBufferLength
;
655 StackPtr
->Parameters
.DeviceIoControl
.OutputBufferLength
= OutputBufferLength
;
657 /* Handle the Methods */
658 switch (IO_METHOD_FROM_CTL_CODE(IoControlCode
))
660 case METHOD_BUFFERED
:
661 DPRINT("Using METHOD_BUFFERED!\n");
663 /* Select the right Buffer Length */
664 BufferLength
= InputBufferLength
> OutputBufferLength
? InputBufferLength
: OutputBufferLength
;
666 /* Make sure there is one */
669 /* Allocate the System Buffer */
670 Irp
->AssociatedIrp
.SystemBuffer
= ExAllocatePoolWithTag(NonPagedPool
,
674 /* Fail if we couldn't */
675 if (Irp
->AssociatedIrp
.SystemBuffer
== NULL
)
681 /* Check if we got a buffer */
684 /* Copy into the System Buffer */
685 RtlCopyMemory(Irp
->AssociatedIrp
.SystemBuffer
,
690 /* Write the flags */
691 Irp
->Flags
= IRP_BUFFERED_IO
| IRP_DEALLOCATE_BUFFER
;
692 if (OutputBuffer
) Irp
->Flags
|= IRP_INPUT_OPERATION
;
694 /* Save the Buffer */
695 Irp
->UserBuffer
= OutputBuffer
;
699 /* Clear the Flags and Buffer */
701 Irp
->UserBuffer
= NULL
;
705 case METHOD_IN_DIRECT
:
706 case METHOD_OUT_DIRECT
:
707 DPRINT("Using METHOD_IN/OUT DIRECT!\n");
709 /* Check if we got an input buffer */
712 /* Allocate the System Buffer */
713 Irp
->AssociatedIrp
.SystemBuffer
= ExAllocatePoolWithTag(NonPagedPool
,
717 /* Fail if we couldn't */
718 if (Irp
->AssociatedIrp
.SystemBuffer
== NULL
)
724 /* Copy into the System Buffer */
725 RtlCopyMemory(Irp
->AssociatedIrp
.SystemBuffer
,
729 /* Write the flags */
730 Irp
->Flags
= IRP_BUFFERED_IO
| IRP_DEALLOCATE_BUFFER
;
737 /* Check if we got an output buffer */
740 /* Allocate the System Buffer */
741 Irp
->MdlAddress
= IoAllocateMdl(OutputBuffer
,
747 /* Fail if we couldn't */
748 if (Irp
->MdlAddress
== NULL
)
757 /* Use the right Access Type */
758 if (IO_METHOD_FROM_CTL_CODE(IoControlCode
) == METHOD_IN_DIRECT
)
760 AccessType
= IoReadAccess
;
764 AccessType
= IoWriteAccess
;
768 MmProbeAndLockPages(Irp
->MdlAddress
, KernelMode
, AccessType
);
772 /* Free the MDL and IRP */
773 IoFreeMdl(Irp
->MdlAddress
);
775 /* FIXME - pass the exception to the caller? */
787 /* Just save the Buffer */
788 Irp
->UserBuffer
= OutputBuffer
;
789 StackPtr
->Parameters
.DeviceIoControl
.Type3InputBuffer
= InputBuffer
;
793 /* Now write the Event and IoSB */
794 if (!IoStatusBlock
) KEBUGCHECK(0); /* Temporary to catch illegal ROS Drivers */
795 Irp
->UserIosb
= IoStatusBlock
;
796 Irp
->UserEvent
= Event
;
798 /* Sync IRPs are queued to requestor thread's irp cancel/cleanup list */
799 Irp
->Tail
.Overlay
.Thread
= PsGetCurrentThread();
800 IoQueueThreadIrp(Irp
);
809 * FUNCTION: Allocates and builds an IRP to be sent synchronously to lower
812 * MajorFunction = Major function code, one of IRP_MJ_READ,
813 * IRP_MJ_WRITE, IRP_MJ_FLUSH_BUFFERS, IRP_MJ_SHUTDOWN
814 * DeviceObject = Target device object
815 * Buffer = Buffer containing data for a read or write
816 * Length = Length in bytes of the information to be transferred
817 * StartingOffset = Offset to begin the read/write from
818 * Event (OUT) = Will be set when the operation is complete
819 * IoStatusBlock (OUT) = Set to the status of the operation
820 * RETURNS: The IRP allocated on success, or
825 IoBuildSynchronousFsdRequest(ULONG MajorFunction
,
826 PDEVICE_OBJECT DeviceObject
,
829 PLARGE_INTEGER StartingOffset
,
831 PIO_STATUS_BLOCK IoStatusBlock
)
835 DPRINT("IoBuildSynchronousFsdRequest(MajorFunction %x, DeviceObject %x, "
836 "Buffer %x, Length %x, StartingOffset %x, Event %x, "
837 "IoStatusBlock %x\n",MajorFunction
,DeviceObject
,Buffer
,Length
,
838 StartingOffset
,Event
,IoStatusBlock
);
840 /* Do the big work to set up the IRP */
841 Irp
= IoBuildAsynchronousFsdRequest(MajorFunction
,
848 /* Set the Event which makes it Syncronous */
849 Irp
->UserEvent
= Event
;
851 /* Sync IRPs are queued to requestor thread's irp cancel/cleanup list */
852 IoQueueThreadIrp(Irp
);
861 IoCancelIrp(PIRP Irp
)
864 PDRIVER_CANCEL CancelRoutine
;
866 DPRINT("IoCancelIrp(Irp %x)\n",Irp
);
868 IoAcquireCancelSpinLock(&oldlvl
);
872 CancelRoutine
= IoSetCancelRoutine(Irp
, NULL
);
873 if (CancelRoutine
== NULL
)
875 IoReleaseCancelSpinLock(oldlvl
);
879 Irp
->CancelIrql
= oldlvl
;
880 CancelRoutine(IoGetCurrentIrpStackLocation(Irp
)->DeviceObject
, Irp
);
885 * @name IoCancelThreadIo
887 * Cancel all pending I/O request associated with specified thread.
890 * Thread to cancel requests for.
895 IoCancelThreadIo(PETHREAD Thread
)
897 PLIST_ENTRY IrpEntry
;
900 ULONG Retries
= 3000;
901 LARGE_INTEGER Interval
;
903 OldIrql
= KfRaiseIrql(APC_LEVEL
);
906 * Start by cancelling all the IRPs in the current thread queue.
909 for (IrpEntry
= Thread
->IrpList
.Flink
;
910 IrpEntry
!= &Thread
->IrpList
;
911 IrpEntry
= IrpEntry
->Flink
)
913 Irp
= CONTAINING_RECORD(IrpEntry
, IRP
, ThreadListEntry
);
918 * Wait till all the IRPs are completed or cancelled.
921 while (!IsListEmpty(&Thread
->IrpList
))
923 KfLowerIrql(OldIrql
);
925 /* Wait a short while and then look if all our IRPs were completed. */
926 Interval
.QuadPart
= -1000000; /* 100 milliseconds */
927 KeDelayExecutionThread(KernelMode
, FALSE
, &Interval
);
930 * Don't stay here forever if some broken driver doesn't complete
936 /* FIXME: Handle this gracefully. */
937 DPRINT1("Thread with dead IRPs!");
941 OldIrql
= KfRaiseIrql(APC_LEVEL
);
944 KfLowerIrql(OldIrql
);
955 IoCallDriver (PDEVICE_OBJECT DeviceObject
, PIRP Irp
)
958 return IofCallDriver(DeviceObject
, Irp
);
966 IoCompleteRequest(PIRP Irp
,
969 /* Call the fastcall */
970 IofCompleteRequest(Irp
, PriorityBoost
);
978 IoEnqueueIrp(IN PIRP Irp
)
980 IoQueueThreadIrp(Irp
);
986 * FUNCTION: Sends an IRP to the next lower driver
990 IofCallDriver(PDEVICE_OBJECT DeviceObject
,
994 PDRIVER_OBJECT DriverObject
;
995 PIO_STACK_LOCATION Param
;
997 DPRINT("IofCallDriver(DeviceObject %x, Irp %x)\n",DeviceObject
,Irp
);
999 /* Get the Driver Object */
1000 DriverObject
= DeviceObject
->DriverObject
;
1002 /* Set the Stack Location */
1003 IoSetNextIrpStackLocation(Irp
);
1005 /* Get the current one */
1006 Param
= IoGetCurrentIrpStackLocation(Irp
);
1008 DPRINT("IrpSp 0x%X\n", Param
);
1010 /* Get the Device Object */
1011 Param
->DeviceObject
= DeviceObject
;
1014 return DriverObject
->MajorFunction
[Param
->MajorFunction
](DeviceObject
, Irp
);
1017 #ifdef IoCompleteRequest
1018 #undef IoCompleteRequest
1023 * FUNCTION: Indicates the caller has finished all processing for a given
1024 * I/O request and is returning the given IRP to the I/O manager
1026 * Irp = Irp to be cancelled
1027 * PriorityBoost = Increment by which to boost the priority of the
1028 * thread making the request
1032 IofCompleteRequest(PIRP Irp
,
1033 CCHAR PriorityBoost
)
1035 PIO_STACK_LOCATION StackPtr
;
1036 PDEVICE_OBJECT DeviceObject
;
1037 PFILE_OBJECT FileObject
= Irp
->Tail
.Overlay
.OriginalFileObject
;
1038 PETHREAD Thread
= Irp
->Tail
.Overlay
.Thread
;
1042 DPRINT("IofCompleteRequest(Irp %x, PriorityBoost %d) Event %x THread %x\n",
1043 Irp
,PriorityBoost
, Irp
->UserEvent
, PsGetCurrentThread());
1045 ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL
);
1046 ASSERT(!Irp
->CancelRoutine
);
1047 ASSERT(Irp
->IoStatus
.Status
!= STATUS_PENDING
);
1049 /* Get the Current Stack */
1050 StackPtr
= IoGetCurrentIrpStackLocation(Irp
);
1051 IoSkipCurrentIrpStackLocation(Irp
);
1053 /* Loop the Stacks and complete the IRPs */
1054 for (;Irp
->CurrentLocation
<= (Irp
->StackCount
+ 1); StackPtr
++)
1056 /* Set Pending Returned */
1057 Irp
->PendingReturned
= StackPtr
->Control
& SL_PENDING_RETURNED
;
1060 * Completion routines expect the current irp stack location to be the same as when
1061 * IoSetCompletionRoutine was called to set them. A side effect is that completion
1062 * routines set by highest level drivers without their own stack location will receive
1063 * an invalid current stack location (at least it should be considered as invalid).
1064 * Since the DeviceObject argument passed is taken from the current stack, this value
1065 * is also invalid (NULL).
1067 if (Irp
->CurrentLocation
== (Irp
->StackCount
+ 1))
1069 DeviceObject
= NULL
;
1073 DeviceObject
= IoGetCurrentIrpStackLocation(Irp
)->DeviceObject
;
1076 /* Check if there is a Completion Routine to Call */
1077 if ((NT_SUCCESS(Irp
->IoStatus
.Status
) &&
1078 (StackPtr
->Control
& SL_INVOKE_ON_SUCCESS
)) ||
1079 (!NT_SUCCESS(Irp
->IoStatus
.Status
) &&
1080 (StackPtr
->Control
& SL_INVOKE_ON_ERROR
)) ||
1081 (Irp
->Cancel
&& (StackPtr
->Control
& SL_INVOKE_ON_CANCEL
)))
1084 Status
= StackPtr
->CompletionRoutine(DeviceObject
,
1088 /* Don't touch the Packet if this was returned. It might be gone! */
1089 if (Status
== STATUS_MORE_PROCESSING_REQUIRED
) return;
1093 if ((Irp
->CurrentLocation
<= Irp
->StackCount
) && (Irp
->PendingReturned
))
1095 if (IoGetCurrentIrpStackLocation(Irp
)->Control
& SL_PENDING_RETURNED
)
1097 Irp
->PendingReturned
= TRUE
;
1102 /* Move to next stack */
1103 IoSkipCurrentIrpStackLocation(Irp
);
1106 /* Windows NT File System Internals, page 165 */
1107 if (Irp
->Flags
& IRP_ASSOCIATED_IRP
)
1109 ULONG MasterIrpCount
;
1110 PIRP MasterIrp
= Irp
->AssociatedIrp
.MasterIrp
;
1112 DPRINT("Handling Associated IRP\n");
1113 /* This should never happen! */
1114 ASSERT(IsListEmpty(&Irp
->ThreadListEntry
));
1116 /* Decrement and get the old count */
1117 MasterIrpCount
= InterlockedDecrement(&MasterIrp
->AssociatedIrp
.IrpCount
);
1119 /* Free MDLs and IRP */
1120 while ((Mdl
= Irp
->MdlAddress
))
1122 Irp
->MdlAddress
= Mdl
->Next
;
1127 /* Complete the Master IRP */
1128 if (!MasterIrpCount
) IofCompleteRequest(MasterIrp
, IO_NO_INCREMENT
);
1132 /* Windows NT File System Internals, page 165 */
1133 if (Irp
->Flags
& (IRP_PAGING_IO
|IRP_CLOSE_OPERATION
))
1135 DPRINT("Handling Paging or Close I/O\n");
1136 /* This should never happen! */
1137 ASSERT(IsListEmpty(&Irp
->ThreadListEntry
));
1139 /* Handle a Close Operation or Sync Paging I/O (see page 165) */
1140 if (Irp
->Flags
& (IRP_SYNCHRONOUS_PAGING_IO
| IRP_CLOSE_OPERATION
))
1142 /* Set the I/O Status and Signal the Event */
1143 DPRINT("Handling Sync Paging or Close I/O\n");
1144 *Irp
->UserIosb
= Irp
->IoStatus
;
1145 KeSetEvent(Irp
->UserEvent
, PriorityBoost
, FALSE
);
1147 /* Free the IRP for a Paging I/O Only, Close is handled by us */
1148 if (Irp
->Flags
& IRP_SYNCHRONOUS_PAGING_IO
)
1150 DPRINT("Handling Sync Paging I/O\n");
1156 DPRINT1("BUG BUG, YOU SHOULDNT BE HERE\n");
1159 /* When we'll actually support Async Paging I/O Properly... */
1160 KeInitializeApc(&Irp
->Tail
.Apc
1161 &Irp
->tail
.Overlay
.Thread
->Tcb
,
1162 Irp
->ApcEnvironment
,
1163 IopCompletePageWrite
,
1168 KeInsertQueueApc(&Irp
->Tail
.Apc
,
1177 /* Unlock MDL Pages, page 167. */
1178 Mdl
= Irp
->MdlAddress
;
1181 DPRINT("Unlocking MDL: %x\n", Mdl
);
1186 /* Check if we should exit because of a Deferred I/O (page 168) */
1187 if (Irp
->Flags
& IRP_DEFER_IO_COMPLETION
&& !Irp
->PendingReturned
)
1189 DPRINT("Quick return\n");
1193 /* Now queue the special APC */
1196 DPRINT("KMODE APC QUEUE\n");
1197 KeInitializeApc(&Irp
->Tail
.Apc
,
1199 Irp
->ApcEnvironment
,
1202 (PKNORMAL_ROUTINE
) NULL
,
1205 KeInsertQueueApc(&Irp
->Tail
.Apc
,
1207 NULL
, /* This is used for REPARSE stuff */
1212 /* The IRP just got cancelled... don't think this happens in ROS yet */
1213 DPRINT1("The IRP was cancelled. Go Bug Alex\n");
1222 IoForwardIrpSynchronously(IN PDEVICE_OBJECT DeviceObject
,
1232 * FUNCTION: Releases a caller allocated irp
1240 PNPAGED_LOOKASIDE_LIST List
;
1241 PP_NPAGED_LOOKASIDE_NUMBER ListType
= LookasideSmallIrpList
;
1244 /* If this was a pool alloc, free it with the pool */
1245 if (!(Irp
->AllocationFlags
& IRP_ALLOCATED_FIXED_SIZE
))
1248 DPRINT("Freeing pool IRP\n");
1253 DPRINT("Freeing Lookaside IRP\n");
1255 /* Check if this was a Big IRP */
1256 if (Irp
->StackCount
!= 1)
1258 DPRINT("Large IRP\n");
1259 ListType
= LookasideLargeIrpList
;
1263 Prcb
= KeGetCurrentPrcb();
1265 /* Use the P List */
1266 List
= (PNPAGED_LOOKASIDE_LIST
)Prcb
->PPLookasideList
[ListType
].P
;
1267 List
->L
.TotalFrees
++;
1269 /* Check if the Free was within the Depth or not */
1270 if (ExQueryDepthSList(&List
->L
.ListHead
) >= List
->L
.Depth
)
1272 /* Let the balancer know */
1273 List
->L
.FreeMisses
++;
1275 /* Use the L List */
1276 List
= (PNPAGED_LOOKASIDE_LIST
)Prcb
->PPLookasideList
[ListType
].L
;
1277 List
->L
.TotalFrees
++;
1279 /* Check if the Free was within the Depth or not */
1280 if (ExQueryDepthSList(&List
->L
.ListHead
) >= List
->L
.Depth
)
1282 /* All lists failed, use the pool */
1283 List
->L
.FreeMisses
++;
1288 /* The free was within dhe Depth */
1289 InterlockedPushEntrySList(&List
->L
.ListHead
, (PSINGLE_LIST_ENTRY
)Irp
);
1292 DPRINT("Free done\n");
1299 IoGetRequestorProcess(IN PIRP Irp
)
1301 return(Irp
->Tail
.Overlay
.Thread
->ThreadsProcess
);
1309 IoGetRequestorProcessId(IN PIRP Irp
)
1311 return (ULONG
)(IoGetRequestorProcess(Irp
)->UniqueProcessId
);
1319 IoGetRequestorSessionId(IN PIRP Irp
,
1320 OUT PULONG pSessionId
)
1322 *pSessionId
= IoGetRequestorProcess(Irp
)->Session
;
1324 return STATUS_SUCCESS
;
1332 IoGetTopLevelIrp(VOID
)
1334 return (PIRP
)PsGetCurrentThread()->TopLevelIrp
;
1340 * FUNCTION: Initalizes an irp allocated by the caller
1342 * Irp = IRP to initalize
1343 * PacketSize = Size in bytes of the IRP
1344 * StackSize = Number of stack locations in the IRP
1348 IoInitializeIrp(PIRP Irp
,
1352 ASSERT(Irp
!= NULL
);
1354 DPRINT("IoInitializeIrp(StackSize %x, Irp %x)\n",StackSize
, Irp
);
1357 RtlZeroMemory(Irp
, PacketSize
);
1359 /* Set the Header and other data */
1360 Irp
->Type
= IO_TYPE_IRP
;
1361 Irp
->Size
= PacketSize
;
1362 Irp
->StackCount
= StackSize
;
1363 Irp
->CurrentLocation
= StackSize
+ 1;
1364 Irp
->ApcEnvironment
= KeGetCurrentThread()->ApcStateIndex
;
1365 Irp
->Tail
.Overlay
.CurrentStackLocation
= (PIO_STACK_LOCATION
)(Irp
+ 1) + StackSize
;
1367 /* Initialize the Thread List */
1368 InitializeListHead(&Irp
->ThreadListEntry
);
1370 DPRINT("Irp->Tail.Overlay.CurrentStackLocation %x\n", Irp
->Tail
.Overlay
.CurrentStackLocation
);
1375 * IoIsOperationSynchronous@4
1378 * Check if the I/O operation associated with the given IRP
1382 * Irp Packet to check.
1385 * TRUE if Irp's operation is synchronous; otherwise FALSE.
1391 IoIsOperationSynchronous(IN PIRP Irp
)
1393 /* Check the flags */
1394 if ((Irp
->Flags
& IRP_SYNCHRONOUS_PAGING_IO
) ||
1395 (Irp
->Flags
& IRP_SYNCHRONOUS_API
) ||
1396 (IoGetCurrentIrpStackLocation(Irp
)->FileObject
->Flags
&
1399 /* Synch API or Paging I/O is OK, as is Sync File I/O */
1403 /* Otherwise, it is an asynchronous operation. */
1412 IoIsValidNameGraftingBuffer(IN PIRP Irp
,
1413 IN PREPARSE_DATA_BUFFER ReparseBuffer
)
1422 * FUNCTION: Allocates and initializes an irp to associated with a master irp
1425 * StackSize = Number of stack locations to be allocated in the irp
1426 * RETURNS: The irp allocated
1427 * NOTE: The caller is responsible for incrementing
1428 * Irp->AssociatedIrp.IrpCount.
1432 IoMakeAssociatedIrp(PIRP Irp
,
1437 /* Allocate the IRP */
1438 AssocIrp
= IoAllocateIrp(StackSize
, FALSE
);
1439 if (AssocIrp
== NULL
) return NULL
;
1442 AssocIrp
->Flags
|= IRP_ASSOCIATED_IRP
;
1444 /* Set the Thread */
1445 AssocIrp
->Tail
.Overlay
.Thread
= Irp
->Tail
.Overlay
.Thread
;
1447 /* Associate them */
1448 AssocIrp
->AssociatedIrp
.MasterIrp
= Irp
;
1458 IoPageRead(PFILE_OBJECT FileObject
,
1460 PLARGE_INTEGER Offset
,
1462 PIO_STATUS_BLOCK StatusBlock
)
1465 PIO_STACK_LOCATION StackPtr
;
1466 PDEVICE_OBJECT DeviceObject
;
1468 DPRINT("IoPageRead(FileObject %x, Mdl %x)\n",
1471 /* Get the Device Object */
1472 DeviceObject
= IoGetRelatedDeviceObject(FileObject
);
1475 Irp
= IoAllocateIrp(DeviceObject
->StackSize
, FALSE
);
1478 StackPtr
= IoGetNextIrpStackLocation(Irp
);
1480 /* Create the IRP Settings */
1481 Irp
->MdlAddress
= Mdl
;
1482 Irp
->UserBuffer
= MmGetMdlVirtualAddress(Mdl
);
1483 Irp
->UserIosb
= StatusBlock
;
1484 Irp
->UserEvent
= Event
;
1485 Irp
->RequestorMode
= KernelMode
;
1486 Irp
->Flags
= IRP_PAGING_IO
| IRP_NOCACHE
| IRP_SYNCHRONOUS_PAGING_IO
| IRP_INPUT_OPERATION
;
1487 Irp
->Tail
.Overlay
.OriginalFileObject
= FileObject
;
1488 Irp
->Tail
.Overlay
.Thread
= PsGetCurrentThread();
1490 /* Set the Stack Settings */
1491 StackPtr
->Parameters
.Read
.Length
= MmGetMdlByteCount(Mdl
);
1492 StackPtr
->Parameters
.Read
.ByteOffset
= *Offset
;
1493 StackPtr
->MajorFunction
= IRP_MJ_READ
;
1494 StackPtr
->FileObject
= FileObject
;
1496 /* Call the Driver */
1497 return IofCallDriver(DeviceObject
, Irp
);
1505 IoQueueThreadIrp(IN PIRP Irp
)
1510 OldIrql
= KfRaiseIrql(APC_LEVEL
);
1513 * Synchronous irp's are queued to requestor thread. If they are not
1514 * completed when the thread exits, they are canceled (cleaned up).
1517 InsertTailList(&Irp
->Tail
.Overlay
.Thread
->IrpList
, &Irp
->ThreadListEntry
);
1520 KfLowerIrql(OldIrql
);
1525 * Reference: Chris Cant's "Writing WDM Device Drivers"
1529 IoReuseIrp(IN OUT PIRP Irp
,
1532 UCHAR AllocationFlags
;
1534 /* Get the old flags */
1535 AllocationFlags
= Irp
->AllocationFlags
;
1537 /* Reinitialize the IRP */
1538 IoInitializeIrp(Irp
, Irp
->Size
, Irp
->StackCount
);
1540 /* Duplicate the data */
1541 Irp
->IoStatus
.Status
= Status
;
1542 Irp
->AllocationFlags
= AllocationFlags
;
1550 IoSetTopLevelIrp(IN PIRP Irp
)
1552 PsGetCurrentThread()->TopLevelIrp
= (ULONG
)Irp
;
1560 IoSynchronousPageWrite(PFILE_OBJECT FileObject
,
1562 PLARGE_INTEGER Offset
,
1564 PIO_STATUS_BLOCK StatusBlock
)
1567 PIO_STACK_LOCATION StackPtr
;
1568 PDEVICE_OBJECT DeviceObject
;
1570 DPRINT("IoSynchronousPageWrite(FileObject %x, Mdl %x)\n",
1573 /* Get the Device Object */
1574 DeviceObject
= IoGetRelatedDeviceObject(FileObject
);
1577 Irp
= IoAllocateIrp(DeviceObject
->StackSize
, FALSE
);
1580 StackPtr
= IoGetNextIrpStackLocation(Irp
);
1582 /* Create the IRP Settings */
1583 Irp
->MdlAddress
= Mdl
;
1584 Irp
->UserBuffer
= MmGetMdlVirtualAddress(Mdl
);
1585 Irp
->UserIosb
= StatusBlock
;
1586 Irp
->UserEvent
= Event
;
1587 Irp
->RequestorMode
= KernelMode
;
1588 Irp
->Flags
= IRP_PAGING_IO
| IRP_NOCACHE
| IRP_SYNCHRONOUS_PAGING_IO
;
1589 Irp
->Tail
.Overlay
.OriginalFileObject
= FileObject
;
1590 Irp
->Tail
.Overlay
.Thread
= PsGetCurrentThread();
1592 /* Set the Stack Settings */
1593 StackPtr
->Parameters
.Write
.Length
= MmGetMdlByteCount(Mdl
);
1594 StackPtr
->Parameters
.Write
.ByteOffset
= *Offset
;
1595 StackPtr
->MajorFunction
= IRP_MJ_WRITE
;
1596 StackPtr
->FileObject
= FileObject
;
1598 /* Call the Driver */
1599 return IofCallDriver(DeviceObject
, Irp
);