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 /* PRIVATE FUNCTIONS ********************************************************/
22 IopFreeIrpKernelApc(PKAPC Apc
,
23 PKNORMAL_ROUTINE
*NormalRoutine
,
25 PVOID
*SystemArgument1
,
26 PVOID
*SystemArgument2
)
29 IoFreeIrp(CONTAINING_RECORD(Apc
, IRP
, Tail
.Apc
));
34 IopAbortIrpKernelApc(PKAPC Apc
)
37 IoFreeIrp(CONTAINING_RECORD(Apc
, IRP
, Tail
.Apc
));
42 IopRemoveThreadIrp(VOID
)
48 PIO_ERROR_LOG_PACKET ErrorLogEntry
;
50 /* First, raise to APC to protect IrpList */
51 KeRaiseIrql(APC_LEVEL
, &OldIrql
);
53 /* Get the Thread and check the list */
54 IrpThread
= PsGetCurrentThread();
55 if (IsListEmpty(&IrpThread
->IrpList
))
57 /* It got completed now, so quit */
62 /* Get the misbehaving IRP */
63 IrpEntry
= IrpThread
->IrpList
.Flink
;
64 DeadIrp
= CONTAINING_RECORD(IrpEntry
, IRP
, ThreadListEntry
);
67 DeadIrp
->Tail
.Overlay
.Thread
= NULL
;
68 InitializeListHead(&DeadIrp
->ThreadListEntry
);
69 RemoveHeadList(&IrpThread
->IrpList
);
74 /* Check if we can send an Error Log Entry*/
75 if (DeadIrp
->CurrentLocation
<= DeadIrp
->StackCount
)
77 /* Allocate an entry */
78 ErrorLogEntry
= IoAllocateErrorLogEntry(IoGetCurrentIrpStackLocation(DeadIrp
)->DeviceObject
,
79 sizeof(IO_ERROR_LOG_PACKET
));
82 ErrorLogEntry
->ErrorCode
= 0xBAADF00D; /* FIXME */
83 IoWriteErrorLogEntry(ErrorLogEntry
);
89 IopCleanupIrp(PIRP Irp
,
90 PFILE_OBJECT FileObject
)
94 /* Check if there's an MDL */
95 while ((Mdl
= Irp
->MdlAddress
))
97 /* Clear all of them */
98 Irp
->MdlAddress
= Mdl
->Next
;
102 /* Free the buffer */
103 if (Irp
->Flags
& IRP_DEALLOCATE_BUFFER
)
105 ExFreePoolWithTag(Irp
->AssociatedIrp
.SystemBuffer
, TAG_SYS_BUF
);
108 /* Derefernce the User Event */
109 if (Irp
->UserEvent
&& !(Irp
->Flags
& IRP_SYNCHRONOUS_API
) && FileObject
)
111 ObDereferenceObject(Irp
->UserEvent
);
114 /* Dereference the File Object */
115 if (FileObject
) ObDereferenceObject(FileObject
);
122 * FUNCTION: Performs the second stage of irp completion for read/write irps
124 * Called as a special kernel APC kernel-routine or directly from IofCompleteRequest()
126 * Note that we'll never see irp's flagged IRP_PAGING_IO (IRP_MOUNT_OPERATION)
127 * or IRP_CLOSE_OPERATION (IRP_MJ_CLOSE and IRP_MJ_CLEANUP) here since their
128 * cleanup/completion is fully taken care of in IoCompleteRequest.
133 IopCompleteRequest(PKAPC Apc
,
134 PKNORMAL_ROUTINE
* NormalRoutine
,
135 PVOID
* NormalContext
,
136 PVOID
* SystemArgument1
,
137 PVOID
* SystemArgument2
)
139 PFILE_OBJECT FileObject
;
145 if (Apc
) DPRINT("IoSecondStageCompletition with APC: 0x%p\n", Apc
);
147 /* Get data from the APC */
148 FileObject
= (PFILE_OBJECT
)(*SystemArgument1
);
149 Irp
= CONTAINING_RECORD(Apc
, IRP
, Tail
.Apc
);
150 DPRINT("IoSecondStageCompletition, 0x%p\n", Irp
);
152 /* Save the User Event */
153 UserEvent
= Irp
->UserEvent
;
155 /* Remember if the IRP is Sync or not */
156 SyncIrp
= Irp
->Flags
& IRP_SYNCHRONOUS_API
? TRUE
: FALSE
;
158 /* Handle Buffered case first */
159 if (Irp
->Flags
& IRP_BUFFERED_IO
)
161 /* Check if we have an input buffer and if we suceeded */
162 if (Irp
->Flags
& IRP_INPUT_OPERATION
&& NT_SUCCESS(Irp
->IoStatus
.Status
))
164 /* Copy the buffer back to the user */
165 RtlCopyMemory(Irp
->UserBuffer
,
166 Irp
->AssociatedIrp
.SystemBuffer
,
167 Irp
->IoStatus
.Information
);
170 /* Also check if we should de-allocate it */
171 if (Irp
->Flags
& IRP_DEALLOCATE_BUFFER
)
173 ExFreePoolWithTag(Irp
->AssociatedIrp
.SystemBuffer
, TAG_SYS_BUF
);
177 /* Now we got rid of these two... */
178 Irp
->Flags
&= ~(IRP_BUFFERED_IO
| IRP_DEALLOCATE_BUFFER
);
180 /* Check if there's an MDL */
181 while ((Mdl
= Irp
->MdlAddress
))
183 /* Clear all of them */
184 Irp
->MdlAddress
= Mdl
->Next
;
188 /* Remove the IRP from the list of Thread Pending IRPs */
189 RemoveEntryList(&Irp
->ThreadListEntry
);
190 InitializeListHead(&Irp
->ThreadListEntry
);
193 /* Check for Success but allow failure for Async IRPs */
194 if (NT_SUCCESS(Irp
->IoStatus
.Status
) ||
195 (Irp
->PendingReturned
&&
197 (FileObject
== NULL
|| FileObject
->Flags
& FO_SYNCHRONOUS_IO
)))
201 /* Save the IOSB Information */
202 *Irp
->UserIosb
= Irp
->IoStatus
;
206 /* Ignore any error */
210 /* Check if there's an event */
213 /* Check if we should signal the File Object Event as well */
216 /* If the File Object is SYNC, then we need to signal its event too */
217 if (FileObject
->Flags
& FO_SYNCHRONOUS_IO
)
220 FileObject
->FinalStatus
= Irp
->IoStatus
.Status
;
223 KeSetEvent(&FileObject
->Event
, 0, FALSE
);
226 /* Signal the Event */
227 KeSetEvent(UserEvent
, 0, FALSE
);
229 /* Dereference the Event if this is an ASYNC IRP */
230 if (FileObject
&& !SyncIrp
&& UserEvent
!= &FileObject
->Event
)
232 ObDereferenceObject(UserEvent
);
238 FileObject
->FinalStatus
= Irp
->IoStatus
.Status
;
240 /* Signal the File Object Instead */
241 KeSetEvent(&FileObject
->Event
, 0, FALSE
);
245 /* Now call the User APC if one was requested */
246 if (Irp
->Overlay
.AsynchronousParameters
.UserApcRoutine
!= NULL
)
248 KeInitializeApc(&Irp
->Tail
.Apc
,
249 KeGetCurrentThread(),
250 CurrentApcEnvironment
,
252 IopAbortIrpKernelApc
,
253 (PKNORMAL_ROUTINE
)Irp
->Overlay
.AsynchronousParameters
.UserApcRoutine
,
255 Irp
->Overlay
.AsynchronousParameters
.UserApcContext
);
257 KeInsertQueueApc(&Irp
->Tail
.Apc
,
263 else if (FileObject
&& FileObject
->CompletionContext
)
265 /* Call the IO Completion Port if we have one, instead */
266 Irp
->Tail
.CompletionKey
= FileObject
->CompletionContext
->Key
;
267 Irp
->Tail
.Overlay
.PacketType
= IrpCompletionPacket
;
268 KeInsertQueue(FileObject
->CompletionContext
->Port
,
269 &Irp
->Tail
.Overlay
.ListEntry
);
275 /* Signal the Events only if PendingReturned and we have a File Object */
276 if (FileObject
&& Irp
->PendingReturned
)
278 /* Check for SYNC IRP */
281 /* Set the status in this case only */
284 *Irp
->UserIosb
= Irp
->IoStatus
;
288 /* Ignore any error */
292 /* Signal our event if we have one */
295 KeSetEvent(UserEvent
, 0, FALSE
);
299 /* Signal the File's Event instead */
300 KeSetEvent(&FileObject
->Event
, 0, FALSE
);
306 /* FIXME: This is necessary to fix bug #609 */
309 *Irp
->UserIosb
= Irp
->IoStatus
;
313 /* Ignore any error */
317 /* We'll report the Status to the File Object, not the IRP */
318 FileObject
->FinalStatus
= Irp
->IoStatus
.Status
;
320 /* Signal the File Object ONLY if this was Async */
321 KeSetEvent(&FileObject
->Event
, 0, FALSE
);
325 /* Dereference the Event if it's an ASYNC IRP on a File Object */
326 if (UserEvent
&& !SyncIrp
&& FileObject
)
328 if (UserEvent
!= &FileObject
->Event
)
330 ObDereferenceObject(UserEvent
);
335 /* Dereference the File Object */
336 if (FileObject
) ObDereferenceObject(FileObject
);
339 if (Irp
) IoFreeIrp(Irp
);
343 if (NT_SUCCESS(Irp
->IoStatus
.Status
) || Irp
->PendingReturned
)
347 /* Save the IOSB Information */
348 *Irp
->UserIosb
= Irp
->IoStatus
;
352 /* Ignore any error */
358 if (FileObject
->Flags
& FO_SYNCHRONOUS_IO
)
361 FileObject
->FinalStatus
= Irp
->IoStatus
.Status
;
363 /* FIXME: Remove this check when I/O code is fixed */
364 if (UserEvent
!= &FileObject
->Event
)
367 KeSetEvent(&FileObject
->Event
, 0, FALSE
);
372 /* Signal the user event, if one exist */
375 KeSetEvent(UserEvent
, 0, FALSE
);
378 /* Now call the User APC if one was requested */
379 if (Irp
->Overlay
.AsynchronousParameters
.UserApcRoutine
)
381 KeInitializeApc(&Irp
->Tail
.Apc
,
382 KeGetCurrentThread(),
383 CurrentApcEnvironment
,
385 IopAbortIrpKernelApc
,
386 (PKNORMAL_ROUTINE
)Irp
->Overlay
.AsynchronousParameters
.UserApcRoutine
,
388 Irp
->Overlay
.AsynchronousParameters
.UserApcContext
);
390 KeInsertQueueApc(&Irp
->Tail
.Apc
,
396 else if (FileObject
&& FileObject
->CompletionContext
)
398 /* Call the IO Completion Port if we have one, instead */
399 IoSetIoCompletion(FileObject
->CompletionContext
->Port
,
400 FileObject
->CompletionContext
->Key
,
401 Irp
->Overlay
.AsynchronousParameters
.UserApcContext
,
402 Irp
->IoStatus
.Status
,
403 Irp
->IoStatus
.Information
,
409 /* Free the Irp if it hasn't already */
410 if (Irp
) IoFreeIrp(Irp
);
414 /* Dereference the user event, if it is an event object */
415 /* FIXME: Remove last check when I/O code is fixed */
416 if (UserEvent
&& !SyncIrp
&& UserEvent
!= &FileObject
->Event
)
418 ObDereferenceObject(UserEvent
);
421 /* Dereference the File Object */
422 ObDereferenceObject(FileObject
);
427 /* FUNCTIONS *****************************************************************/
432 * FUNCTION: Allocates an IRP
434 * StackSize = the size of the stack required for the irp
435 * ChargeQuota = Charge allocation to current threads quota
436 * RETURNS: Irp allocated
440 IoAllocateIrp(CCHAR StackSize
,
444 USHORT Size
= IoSizeOfIrp(StackSize
);
447 PNPAGED_LOOKASIDE_LIST List
= NULL
;
448 PP_NPAGED_LOOKASIDE_NUMBER ListType
= LookasideSmallIrpList
;
450 /* Figure out which Lookaside List to use */
451 if ((StackSize
<= 8) && (ChargeQuota
== FALSE
))
453 DPRINT("Using lookaside, %d\n", StackSize
);
454 /* Set Fixed Size Flag */
455 Flags
= IRP_ALLOCATED_FIXED_SIZE
;
457 /* See if we should use big list */
460 DPRINT("Using large lookaside\n");
461 Size
= IoSizeOfIrp(8);
462 ListType
= LookasideLargeIrpList
;
466 Prcb
= KeGetCurrentPrcb();
468 /* Get the P List First */
469 List
= (PNPAGED_LOOKASIDE_LIST
)Prcb
->PPLookasideList
[ListType
].P
;
471 /* Attempt allocation */
472 List
->L
.TotalAllocates
++;
473 DPRINT("Total allocates: %d\n", List
->L
.TotalAllocates
);
474 Irp
= (PIRP
)InterlockedPopEntrySList(&List
->L
.ListHead
);
475 DPRINT("Alloc attempt on CPU list: %p\n", Irp
);
477 /* Check if the P List failed */
480 /* Let the balancer know */
481 List
->L
.AllocateMisses
++;
482 DPRINT("Total misses: %d\n", List
->L
.AllocateMisses
);
485 List
= (PNPAGED_LOOKASIDE_LIST
)Prcb
->PPLookasideList
[ListType
].L
;
486 List
->L
.TotalAllocates
++;
487 Irp
= (PIRP
)InterlockedPopEntrySList(&List
->L
.ListHead
);
488 DPRINT("Alloc attempt on SYS list: %p\n", Irp
);
492 /* Check if we have to use the pool */
495 DPRINT("Using pool\n");
496 /* Did we try lookaside and fail? */
497 if (Flags
& IRP_ALLOCATED_FIXED_SIZE
) List
->L
.AllocateMisses
++;
499 /* Check if we shoudl charge quota */
502 /* Irp = ExAllocatePoolWithQuotaTag(NonPagedPool, Size, TAG_IRP); */
504 Irp
= ExAllocatePoolWithTag(NonPagedPool
, Size
, TAG_IRP
);
508 /* Allocate the IRP With no Quota charge */
509 Irp
= ExAllocatePoolWithTag(NonPagedPool
, Size
, TAG_IRP
);
512 /* Make sure it was sucessful */
513 if (!Irp
) return(NULL
);
517 /* We have an IRP from Lookaside */
518 Flags
|= IRP_LOOKASIDE_ALLOCATION
;
522 if (ChargeQuota
) Flags
|= IRP_QUOTA_CHARGED
;
524 /* Now Initialize it */
525 DPRINT("irp allocated\n");
526 IoInitializeIrp(Irp
, Size
, StackSize
);
528 /* Set the Allocation Flags */
529 Irp
->AllocationFlags
= Flags
;
538 * FUNCTION: Allocates and sets up an IRP to be sent to lower level drivers
540 * MajorFunction = One of IRP_MJ_READ, IRP_MJ_WRITE,
541 * IRP_MJ_FLUSH_BUFFERS or IRP_MJ_SHUTDOWN
542 * DeviceObject = Device object to send the irp to
543 * Buffer = Buffer into which data will be read or written
544 * Length = Length in bytes of the irp to be allocated
545 * StartingOffset = Starting offset on the device
546 * IoStatusBlock (OUT) = Storage for the result of the operation
547 * RETURNS: The IRP allocated on success, or
552 IoBuildAsynchronousFsdRequest(ULONG MajorFunction
,
553 PDEVICE_OBJECT DeviceObject
,
556 PLARGE_INTEGER StartingOffset
,
557 PIO_STATUS_BLOCK IoStatusBlock
)
560 PIO_STACK_LOCATION StackPtr
;
561 LOCK_OPERATION AccessType
;
563 DPRINT("IoBuildAsynchronousFsdRequest(MajorFunction %x, DeviceObject 0x%p, "
564 "Buffer 0x%p, Length %x, StartingOffset 0x%p, "
565 "IoStatusBlock 0x%p\n",MajorFunction
,DeviceObject
,Buffer
,Length
,
566 StartingOffset
,IoStatusBlock
);
569 if (!(Irp
= IoAllocateIrp(DeviceObject
->StackSize
, FALSE
))) return Irp
;
572 StackPtr
= IoGetNextIrpStackLocation(Irp
);
574 /* Write the Major function and then deal with it */
575 StackPtr
->MajorFunction
= (UCHAR
)MajorFunction
;
577 /* Do not handle the following here */
578 if (MajorFunction
!= IRP_MJ_FLUSH_BUFFERS
&&
579 MajorFunction
!= IRP_MJ_SHUTDOWN
&&
580 MajorFunction
!= IRP_MJ_PNP
)
582 /* Check if this is Buffered IO */
583 if (DeviceObject
->Flags
& DO_BUFFERED_IO
)
585 /* Allocate the System Buffer */
586 Irp
->AssociatedIrp
.SystemBuffer
= ExAllocatePoolWithTag(NonPagedPool
,
591 Irp
->Flags
= IRP_BUFFERED_IO
| IRP_DEALLOCATE_BUFFER
;
593 /* Handle special IRP_MJ_WRITE Case */
594 if (MajorFunction
== IRP_MJ_WRITE
)
596 /* Copy the buffer data */
597 RtlCopyMemory(Irp
->AssociatedIrp
.SystemBuffer
, Buffer
, Length
);
601 /* Set the Input Operation flag and set this as a User Buffer */
602 Irp
->Flags
|= IRP_INPUT_OPERATION
;
603 Irp
->UserBuffer
= Buffer
;
606 else if (DeviceObject
->Flags
& DO_DIRECT_IO
)
608 /* Use an MDL for Direct I/O */
609 Irp
->MdlAddress
= MmCreateMdl(NULL
, Buffer
, Length
);
612 if (MajorFunction
== IRP_MJ_READ
)
614 AccessType
= IoWriteAccess
;
618 AccessType
= IoReadAccess
;
625 MmProbeAndLockPages(Irp
->MdlAddress
, KernelMode
, AccessType
);
629 /* Free the IRP and its MDL */
630 IoFreeMdl(Irp
->MdlAddress
);
632 /* FIXME - pass the exception to the caller? */
642 /* Neither, use the buffer */
643 Irp
->UserBuffer
= Buffer
;
646 if (MajorFunction
== IRP_MJ_READ
)
648 StackPtr
->Parameters
.Read
.Length
= Length
;
649 StackPtr
->Parameters
.Read
.ByteOffset
= *StartingOffset
;
651 else if (MajorFunction
== IRP_MJ_WRITE
)
653 StackPtr
->Parameters
.Write
.Length
= Length
;
654 StackPtr
->Parameters
.Write
.ByteOffset
= *StartingOffset
;
658 /* Set the Current Thread and IOSB */
659 if (!IoStatusBlock
) KEBUGCHECK(0); /* Temporary to catch illegal ROS Drivers */
660 Irp
->UserIosb
= IoStatusBlock
;
661 Irp
->Tail
.Overlay
.Thread
= PsGetCurrentThread();
663 /* Set the Status Block after all is done */
671 * FUNCTION: Allocates and sets up an IRP to be sent to drivers
673 * IoControlCode = Device io control code
674 * DeviceObject = Device object to send the irp to
675 * InputBuffer = Buffer from which data will be read by the driver
676 * InputBufferLength = Length in bytes of the input buffer
677 * OutputBuffer = Buffer into which data will be written by the driver
678 * OutputBufferLength = Length in bytes of the output buffer
679 * InternalDeviceIoControl = Determines weather
680 * IRP_MJ_INTERNAL_DEVICE_CONTROL or
681 * IRP_MJ_DEVICE_CONTROL will be used
682 * Event = Event used to notify the caller of completion
683 * IoStatusBlock (OUT) = Storage for the result of the operation
684 * RETURNS: The IRP allocated on success, or
689 IoBuildDeviceIoControlRequest (ULONG IoControlCode
,
690 PDEVICE_OBJECT DeviceObject
,
692 ULONG InputBufferLength
,
694 ULONG OutputBufferLength
,
695 BOOLEAN InternalDeviceIoControl
,
697 PIO_STATUS_BLOCK IoStatusBlock
)
700 PIO_STACK_LOCATION StackPtr
;
702 LOCK_OPERATION AccessType
;
704 DPRINT("IoBuildDeviceIoRequest(IoControlCode %x, DeviceObject 0x%p, "
705 "InputBuffer 0x%p, InputBufferLength %x, OutputBuffer 0x%p, "
706 "OutputBufferLength %x, InternalDeviceIoControl %x "
707 "Event 0x%p, IoStatusBlock 0x%p\n",IoControlCode
,DeviceObject
,
708 InputBuffer
,InputBufferLength
,OutputBuffer
,OutputBufferLength
,
709 InternalDeviceIoControl
,Event
,IoStatusBlock
);
712 if (!(Irp
= IoAllocateIrp(DeviceObject
->StackSize
, FALSE
))) return Irp
;
715 StackPtr
= IoGetNextIrpStackLocation(Irp
);
717 /* Set the DevCtl Type */
718 StackPtr
->MajorFunction
= InternalDeviceIoControl
?
719 IRP_MJ_INTERNAL_DEVICE_CONTROL
: IRP_MJ_DEVICE_CONTROL
;
721 /* Set the IOCTL Data */
722 StackPtr
->Parameters
.DeviceIoControl
.IoControlCode
= IoControlCode
;
723 StackPtr
->Parameters
.DeviceIoControl
.InputBufferLength
= InputBufferLength
;
724 StackPtr
->Parameters
.DeviceIoControl
.OutputBufferLength
= OutputBufferLength
;
726 /* Handle the Methods */
727 switch (IO_METHOD_FROM_CTL_CODE(IoControlCode
))
729 case METHOD_BUFFERED
:
730 DPRINT("Using METHOD_BUFFERED!\n");
732 /* Select the right Buffer Length */
733 BufferLength
= InputBufferLength
> OutputBufferLength
? InputBufferLength
: OutputBufferLength
;
735 /* Make sure there is one */
738 /* Allocate the System Buffer */
739 Irp
->AssociatedIrp
.SystemBuffer
= ExAllocatePoolWithTag(NonPagedPool
,
743 /* Fail if we couldn't */
744 if (Irp
->AssociatedIrp
.SystemBuffer
== NULL
)
750 /* Check if we got a buffer */
753 /* Copy into the System Buffer */
754 RtlCopyMemory(Irp
->AssociatedIrp
.SystemBuffer
,
759 /* Write the flags */
760 Irp
->Flags
= IRP_BUFFERED_IO
| IRP_DEALLOCATE_BUFFER
;
761 if (OutputBuffer
) Irp
->Flags
|= IRP_INPUT_OPERATION
;
763 /* Save the Buffer */
764 Irp
->UserBuffer
= OutputBuffer
;
768 /* Clear the Flags and Buffer */
770 Irp
->UserBuffer
= NULL
;
774 case METHOD_IN_DIRECT
:
775 case METHOD_OUT_DIRECT
:
776 DPRINT("Using METHOD_IN/OUT DIRECT!\n");
778 /* Check if we got an input buffer */
781 /* Allocate the System Buffer */
782 Irp
->AssociatedIrp
.SystemBuffer
= ExAllocatePoolWithTag(NonPagedPool
,
786 /* Fail if we couldn't */
787 if (Irp
->AssociatedIrp
.SystemBuffer
== NULL
)
793 /* Copy into the System Buffer */
794 RtlCopyMemory(Irp
->AssociatedIrp
.SystemBuffer
,
798 /* Write the flags */
799 Irp
->Flags
= IRP_BUFFERED_IO
| IRP_DEALLOCATE_BUFFER
;
806 /* Check if we got an output buffer */
809 /* Allocate the System Buffer */
810 Irp
->MdlAddress
= IoAllocateMdl(OutputBuffer
,
816 /* Fail if we couldn't */
817 if (Irp
->MdlAddress
== NULL
)
826 /* Use the right Access Type */
827 if (IO_METHOD_FROM_CTL_CODE(IoControlCode
) == METHOD_IN_DIRECT
)
829 AccessType
= IoReadAccess
;
833 AccessType
= IoWriteAccess
;
837 MmProbeAndLockPages(Irp
->MdlAddress
, KernelMode
, AccessType
);
841 /* Free the MDL and IRP */
842 IoFreeMdl(Irp
->MdlAddress
);
844 /* FIXME - pass the exception to the caller? */
856 /* Just save the Buffer */
857 Irp
->UserBuffer
= OutputBuffer
;
858 StackPtr
->Parameters
.DeviceIoControl
.Type3InputBuffer
= InputBuffer
;
862 /* Now write the Event and IoSB */
863 if (!IoStatusBlock
) KEBUGCHECK(0); /* Temporary to catch illegal ROS Drivers */
864 Irp
->UserIosb
= IoStatusBlock
;
865 Irp
->UserEvent
= Event
;
867 /* Sync IRPs are queued to requestor thread's irp cancel/cleanup list */
868 Irp
->Tail
.Overlay
.Thread
= PsGetCurrentThread();
869 IoQueueThreadIrp(Irp
);
878 * FUNCTION: Allocates and builds an IRP to be sent synchronously to lower
881 * MajorFunction = Major function code, one of IRP_MJ_READ,
882 * IRP_MJ_WRITE, IRP_MJ_FLUSH_BUFFERS, IRP_MJ_SHUTDOWN
883 * DeviceObject = Target device object
884 * Buffer = Buffer containing data for a read or write
885 * Length = Length in bytes of the information to be transferred
886 * StartingOffset = Offset to begin the read/write from
887 * Event (OUT) = Will be set when the operation is complete
888 * IoStatusBlock (OUT) = Set to the status of the operation
889 * RETURNS: The IRP allocated on success, or
894 IoBuildSynchronousFsdRequest(ULONG MajorFunction
,
895 PDEVICE_OBJECT DeviceObject
,
898 PLARGE_INTEGER StartingOffset
,
900 PIO_STATUS_BLOCK IoStatusBlock
)
904 DPRINT("IoBuildSynchronousFsdRequest(MajorFunction %x, DeviceObject 0x%p, "
905 "Buffer 0x%p, Length %x, StartingOffset 0x%p, Event 0x%p, "
906 "IoStatusBlock 0x%p\n",MajorFunction
,DeviceObject
,Buffer
,Length
,
907 StartingOffset
,Event
,IoStatusBlock
);
909 /* Do the big work to set up the IRP */
910 Irp
= IoBuildAsynchronousFsdRequest(MajorFunction
,
917 /* Set the Event which makes it Syncronous */
918 Irp
->UserEvent
= Event
;
920 /* Sync IRPs are queued to requestor thread's irp cancel/cleanup list */
921 IoQueueThreadIrp(Irp
);
930 IoCancelIrp(PIRP Irp
)
933 PDRIVER_CANCEL CancelRoutine
;
935 DPRINT("IoCancelIrp(Irp 0x%p)\n",Irp
);
937 IoAcquireCancelSpinLock(&oldlvl
);
941 CancelRoutine
= IoSetCancelRoutine(Irp
, NULL
);
942 if (CancelRoutine
== NULL
)
944 IoReleaseCancelSpinLock(oldlvl
);
948 Irp
->CancelIrql
= oldlvl
;
949 CancelRoutine(IoGetCurrentIrpStackLocation(Irp
)->DeviceObject
, Irp
);
954 * @name IoCancelThreadIo
956 * Cancel all pending I/O request associated with specified thread.
959 * Thread to cancel requests for.
963 IoCancelThreadIo(PETHREAD Thread
)
967 ULONG Retries
= 3000;
968 LARGE_INTEGER Interval
;
970 /* Raise to APC to protect the IrpList */
971 OldIrql
= KfRaiseIrql(APC_LEVEL
);
973 /* Start by cancelling all the IRPs in the current thread queue. */
974 LIST_FOR_EACH(Irp
, &Thread
->IrpList
, IRP
, ThreadListEntry
)
980 /* Wait 100 milliseconds */
981 Interval
.QuadPart
= -1000000;
983 /* Wait till all the IRPs are completed or cancelled. */
984 while (!IsListEmpty(&Thread
->IrpList
))
986 /* Now we can lower */
987 KfLowerIrql(OldIrql
);
989 /* Wait a short while and then look if all our IRPs were completed. */
990 KeDelayExecutionThread(KernelMode
, FALSE
, &Interval
);
993 * Don't stay here forever if some broken driver doesn't complete
996 if (Retries
-- == 0) IopRemoveThreadIrp();
998 /* Raise the IRQL Again */
999 OldIrql
= KfRaiseIrql(APC_LEVEL
);
1002 /* We're done, lower the IRQL */
1003 KfLowerIrql(OldIrql
);
1014 IoCallDriver (PDEVICE_OBJECT DeviceObject
, PIRP Irp
)
1016 /* Call fast call */
1017 return IofCallDriver(DeviceObject
, Irp
);
1023 #undef IoCompleteRequest
1026 IoCompleteRequest(PIRP Irp
,
1027 CCHAR PriorityBoost
)
1029 /* Call the fastcall */
1030 IofCompleteRequest(Irp
, PriorityBoost
);
1038 IoEnqueueIrp(IN PIRP Irp
)
1040 IoQueueThreadIrp(Irp
);
1046 * FUNCTION: Sends an IRP to the next lower driver
1050 IofCallDriver(PDEVICE_OBJECT DeviceObject
,
1054 PDRIVER_OBJECT DriverObject
;
1055 PIO_STACK_LOCATION Param
;
1057 DPRINT("IofCallDriver(DeviceObject 0x%p, Irp 0x%p)\n",DeviceObject
,Irp
);
1059 /* Get the Driver Object */
1060 DriverObject
= DeviceObject
->DriverObject
;
1062 /* Set the Stack Location */
1063 IoSetNextIrpStackLocation(Irp
);
1065 /* Get the current one */
1066 Param
= IoGetCurrentIrpStackLocation(Irp
);
1068 DPRINT("IrpSp 0x0x%p\n", Param
);
1070 /* Get the Device Object */
1071 Param
->DeviceObject
= DeviceObject
;
1074 return DriverObject
->MajorFunction
[Param
->MajorFunction
](DeviceObject
, Irp
);
1077 #ifdef IoCompleteRequest
1078 #undef IoCompleteRequest
1083 * FUNCTION: Indicates the caller has finished all processing for a given
1084 * I/O request and is returning the given IRP to the I/O manager
1086 * Irp = Irp to be cancelled
1087 * PriorityBoost = Increment by which to boost the priority of the
1088 * thread making the request
1092 IofCompleteRequest(PIRP Irp
,
1093 CCHAR PriorityBoost
)
1095 PIO_STACK_LOCATION StackPtr
;
1096 PDEVICE_OBJECT DeviceObject
;
1097 PFILE_OBJECT FileObject
= Irp
->Tail
.Overlay
.OriginalFileObject
;
1098 PETHREAD Thread
= Irp
->Tail
.Overlay
.Thread
;
1102 DPRINT("IofCompleteRequest(Irp 0x%p, PriorityBoost %d) Event 0x%p THread 0x%p\n",
1103 Irp
,PriorityBoost
, Irp
->UserEvent
, PsGetCurrentThread());
1105 ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL
);
1106 ASSERT(!Irp
->CancelRoutine
);
1107 ASSERT(Irp
->IoStatus
.Status
!= STATUS_PENDING
);
1109 /* Get the Current Stack */
1110 StackPtr
= IoGetCurrentIrpStackLocation(Irp
);
1111 IoSkipCurrentIrpStackLocation(Irp
);
1113 /* Loop the Stacks and complete the IRPs */
1114 for (;Irp
->CurrentLocation
<= (Irp
->StackCount
+ 1); StackPtr
++)
1116 /* Set Pending Returned */
1117 Irp
->PendingReturned
= StackPtr
->Control
& SL_PENDING_RETURNED
;
1120 * Completion routines expect the current irp stack location to be the same as when
1121 * IoSetCompletionRoutine was called to set them. A side effect is that completion
1122 * routines set by highest level drivers without their own stack location will receive
1123 * an invalid current stack location (at least it should be considered as invalid).
1124 * Since the DeviceObject argument passed is taken from the current stack, this value
1125 * is also invalid (NULL).
1127 if (Irp
->CurrentLocation
== (Irp
->StackCount
+ 1))
1129 DeviceObject
= NULL
;
1133 DeviceObject
= IoGetCurrentIrpStackLocation(Irp
)->DeviceObject
;
1136 /* Check if there is a Completion Routine to Call */
1137 if ((NT_SUCCESS(Irp
->IoStatus
.Status
) &&
1138 (StackPtr
->Control
& SL_INVOKE_ON_SUCCESS
)) ||
1139 (!NT_SUCCESS(Irp
->IoStatus
.Status
) &&
1140 (StackPtr
->Control
& SL_INVOKE_ON_ERROR
)) ||
1141 (Irp
->Cancel
&& (StackPtr
->Control
& SL_INVOKE_ON_CANCEL
)))
1144 Status
= StackPtr
->CompletionRoutine(DeviceObject
,
1148 /* Don't touch the Packet if this was returned. It might be gone! */
1149 if (Status
== STATUS_MORE_PROCESSING_REQUIRED
) return;
1153 if ((Irp
->CurrentLocation
<= Irp
->StackCount
) && (Irp
->PendingReturned
))
1155 IoMarkIrpPending(Irp
);
1159 /* Move to next stack */
1160 IoSkipCurrentIrpStackLocation(Irp
);
1163 /* Windows NT File System Internals, page 165 */
1164 if (Irp
->Flags
& IRP_ASSOCIATED_IRP
)
1166 ULONG MasterIrpCount
;
1167 PIRP MasterIrp
= Irp
->AssociatedIrp
.MasterIrp
;
1169 DPRINT("Handling Associated IRP\n");
1170 /* This should never happen! */
1171 ASSERT(IsListEmpty(&Irp
->ThreadListEntry
));
1173 /* Decrement and get the old count */
1174 MasterIrpCount
= InterlockedDecrement(&MasterIrp
->AssociatedIrp
.IrpCount
);
1176 /* Free MDLs and IRP */
1177 while ((Mdl
= Irp
->MdlAddress
))
1179 Irp
->MdlAddress
= Mdl
->Next
;
1184 /* Complete the Master IRP */
1185 if (!MasterIrpCount
) IofCompleteRequest(MasterIrp
, PriorityBoost
);
1189 /* Windows NT File System Internals, page 165 */
1190 if (Irp
->Flags
& (IRP_PAGING_IO
|IRP_CLOSE_OPERATION
))
1192 DPRINT("Handling Paging or Close I/O\n");
1193 /* This should never happen! */
1194 ASSERT(IsListEmpty(&Irp
->ThreadListEntry
));
1196 /* Handle a Close Operation or Sync Paging I/O (see page 165) */
1197 if (Irp
->Flags
& (IRP_SYNCHRONOUS_PAGING_IO
| IRP_CLOSE_OPERATION
))
1199 /* Set the I/O Status and Signal the Event */
1200 DPRINT("Handling Sync Paging or Close I/O\n");
1201 *Irp
->UserIosb
= Irp
->IoStatus
;
1202 KeSetEvent(Irp
->UserEvent
, PriorityBoost
, FALSE
);
1204 /* Free the IRP for a Paging I/O Only, Close is handled by us */
1205 if (Irp
->Flags
& IRP_SYNCHRONOUS_PAGING_IO
)
1207 DPRINT("Handling Sync Paging I/O\n");
1215 KeInitializeApc(&Irp
->Tail
.Apc
1216 &Irp
->Tail
.Overlay
.Thread
->Tcb
,
1217 Irp
->ApcEnvironment
,
1218 IopCompletePageWrite
,
1223 KeInsertQueueApc(&Irp
->Tail
.Apc
,
1228 /* Not implemented yet. */
1235 /* Unlock MDL Pages, page 167. */
1236 Mdl
= Irp
->MdlAddress
;
1239 DPRINT("Unlocking MDL: 0x%p\n", Mdl
);
1244 /* Check if we should exit because of a Deferred I/O (page 168) */
1245 if (Irp
->Flags
& IRP_DEFER_IO_COMPLETION
&& !Irp
->PendingReturned
)
1247 DPRINT("Quick return\n");
1251 /* Now queue the special APC */
1254 DPRINT("KMODE APC QUEUE\n");
1255 KeInitializeApc(&Irp
->Tail
.Apc
,
1257 Irp
->ApcEnvironment
,
1260 (PKNORMAL_ROUTINE
) NULL
,
1263 KeInsertQueueApc(&Irp
->Tail
.Apc
,
1265 NULL
, /* This is used for REPARSE stuff */
1270 /* The IRP just got cancelled... does a thread still own it? */
1271 if ((Thread
= Irp
->Tail
.Overlay
.Thread
))
1273 /* Yes! There is still hope! */
1274 DPRINT("KMODE APC QUEUE\n");
1275 KeInitializeApc(&Irp
->Tail
.Apc
,
1277 Irp
->ApcEnvironment
,
1280 (PKNORMAL_ROUTINE
) NULL
,
1283 KeInsertQueueApc(&Irp
->Tail
.Apc
,
1285 NULL
, /* This is used for REPARSE stuff */
1290 /* Nothing left for us to do, kill it */
1291 IopCleanupIrp(Irp
, FileObject
);
1301 IoForwardIrpSynchronously(IN PDEVICE_OBJECT DeviceObject
,
1311 * FUNCTION: Releases a caller allocated irp
1319 PNPAGED_LOOKASIDE_LIST List
;
1320 PP_NPAGED_LOOKASIDE_NUMBER ListType
= LookasideSmallIrpList
;
1323 /* If this was a pool alloc, free it with the pool */
1324 if (!(Irp
->AllocationFlags
& IRP_ALLOCATED_FIXED_SIZE
))
1327 DPRINT("Freeing pool IRP\n");
1332 DPRINT("Freeing Lookaside IRP\n");
1334 /* Check if this was a Big IRP */
1335 if (Irp
->StackCount
!= 1)
1337 DPRINT("Large IRP\n");
1338 ListType
= LookasideLargeIrpList
;
1342 Prcb
= KeGetCurrentPrcb();
1344 /* Use the P List */
1345 List
= (PNPAGED_LOOKASIDE_LIST
)Prcb
->PPLookasideList
[ListType
].P
;
1346 List
->L
.TotalFrees
++;
1348 /* Check if the Free was within the Depth or not */
1349 if (ExQueryDepthSList(&List
->L
.ListHead
) >= List
->L
.Depth
)
1351 /* Let the balancer know */
1352 List
->L
.FreeMisses
++;
1354 /* Use the L List */
1355 List
= (PNPAGED_LOOKASIDE_LIST
)Prcb
->PPLookasideList
[ListType
].L
;
1356 List
->L
.TotalFrees
++;
1358 /* Check if the Free was within the Depth or not */
1359 if (ExQueryDepthSList(&List
->L
.ListHead
) >= List
->L
.Depth
)
1361 /* All lists failed, use the pool */
1362 List
->L
.FreeMisses
++;
1368 /* The free was within dhe Depth */
1371 InterlockedPushEntrySList(&List
->L
.ListHead
, (PSINGLE_LIST_ENTRY
)Irp
);
1375 DPRINT("Free done\n");
1382 IoGetRequestorProcess(IN PIRP Irp
)
1384 return(Irp
->Tail
.Overlay
.Thread
->ThreadsProcess
);
1392 IoGetRequestorProcessId(IN PIRP Irp
)
1394 return (ULONG
)(IoGetRequestorProcess(Irp
)->UniqueProcessId
);
1402 IoGetRequestorSessionId(IN PIRP Irp
,
1403 OUT PULONG pSessionId
)
1405 *pSessionId
= IoGetRequestorProcess(Irp
)->Session
;
1407 return STATUS_SUCCESS
;
1415 IoGetTopLevelIrp(VOID
)
1417 return (PIRP
)PsGetCurrentThread()->TopLevelIrp
;
1423 * FUNCTION: Initalizes an irp allocated by the caller
1425 * Irp = IRP to initalize
1426 * PacketSize = Size in bytes of the IRP
1427 * StackSize = Number of stack locations in the IRP
1431 IoInitializeIrp(PIRP Irp
,
1435 ASSERT(Irp
!= NULL
);
1437 DPRINT("IoInitializeIrp(StackSize %x, Irp 0x%p)\n",StackSize
, Irp
);
1440 RtlZeroMemory(Irp
, PacketSize
);
1442 /* Set the Header and other data */
1443 Irp
->Type
= IO_TYPE_IRP
;
1444 Irp
->Size
= PacketSize
;
1445 Irp
->StackCount
= StackSize
;
1446 Irp
->CurrentLocation
= StackSize
+ 1;
1447 Irp
->ApcEnvironment
= KeGetCurrentThread()->ApcStateIndex
;
1448 Irp
->Tail
.Overlay
.CurrentStackLocation
= (PIO_STACK_LOCATION
)(Irp
+ 1) + StackSize
;
1450 /* Initialize the Thread List */
1451 InitializeListHead(&Irp
->ThreadListEntry
);
1453 DPRINT("Irp->Tail.Overlay.CurrentStackLocation 0x%p\n", Irp
->Tail
.Overlay
.CurrentStackLocation
);
1458 * IoIsOperationSynchronous@4
1461 * Check if the I/O operation associated with the given IRP
1465 * Irp Packet to check.
1468 * TRUE if Irp's operation is synchronous; otherwise FALSE.
1474 IoIsOperationSynchronous(IN PIRP Irp
)
1476 /* Check the flags */
1477 if ((Irp
->Flags
& IRP_SYNCHRONOUS_PAGING_IO
) ||
1478 (Irp
->Flags
& IRP_SYNCHRONOUS_API
) ||
1479 (IoGetCurrentIrpStackLocation(Irp
)->FileObject
->Flags
&
1482 /* Synch API or Paging I/O is OK, as is Sync File I/O */
1486 /* Otherwise, it is an asynchronous operation. */
1495 IoIsValidNameGraftingBuffer(IN PIRP Irp
,
1496 IN PREPARSE_DATA_BUFFER ReparseBuffer
)
1505 * FUNCTION: Allocates and initializes an irp to associated with a master irp
1508 * StackSize = Number of stack locations to be allocated in the irp
1509 * RETURNS: The irp allocated
1510 * NOTE: The caller is responsible for incrementing
1511 * Irp->AssociatedIrp.IrpCount.
1515 IoMakeAssociatedIrp(PIRP Irp
,
1520 /* Allocate the IRP */
1521 AssocIrp
= IoAllocateIrp(StackSize
, FALSE
);
1522 if (AssocIrp
== NULL
) return NULL
;
1525 AssocIrp
->Flags
|= IRP_ASSOCIATED_IRP
;
1527 /* Set the Thread */
1528 AssocIrp
->Tail
.Overlay
.Thread
= Irp
->Tail
.Overlay
.Thread
;
1530 /* Associate them */
1531 AssocIrp
->AssociatedIrp
.MasterIrp
= Irp
;
1541 IoPageRead(PFILE_OBJECT FileObject
,
1543 PLARGE_INTEGER Offset
,
1545 PIO_STATUS_BLOCK StatusBlock
)
1548 PIO_STACK_LOCATION StackPtr
;
1549 PDEVICE_OBJECT DeviceObject
;
1551 DPRINT("IoPageRead(FileObject 0x%p, Mdl 0x%p)\n",
1554 /* Get the Device Object */
1555 DeviceObject
= IoGetRelatedDeviceObject(FileObject
);
1558 Irp
= IoAllocateIrp(DeviceObject
->StackSize
, FALSE
);
1561 StackPtr
= IoGetNextIrpStackLocation(Irp
);
1563 /* Create the IRP Settings */
1564 Irp
->MdlAddress
= Mdl
;
1565 Irp
->UserBuffer
= MmGetMdlVirtualAddress(Mdl
);
1566 Irp
->UserIosb
= StatusBlock
;
1567 Irp
->UserEvent
= Event
;
1568 Irp
->RequestorMode
= KernelMode
;
1569 Irp
->Flags
= IRP_PAGING_IO
| IRP_NOCACHE
| IRP_SYNCHRONOUS_PAGING_IO
| IRP_INPUT_OPERATION
;
1570 Irp
->Tail
.Overlay
.OriginalFileObject
= FileObject
;
1571 Irp
->Tail
.Overlay
.Thread
= PsGetCurrentThread();
1573 /* Set the Stack Settings */
1574 StackPtr
->Parameters
.Read
.Length
= MmGetMdlByteCount(Mdl
);
1575 StackPtr
->Parameters
.Read
.ByteOffset
= *Offset
;
1576 StackPtr
->MajorFunction
= IRP_MJ_READ
;
1577 StackPtr
->FileObject
= FileObject
;
1579 /* Call the Driver */
1580 return IofCallDriver(DeviceObject
, Irp
);
1588 IoQueueThreadIrp(IN PIRP Irp
)
1593 OldIrql
= KfRaiseIrql(APC_LEVEL
);
1596 * Synchronous irp's are queued to requestor thread. If they are not
1597 * completed when the thread exits, they are canceled (cleaned up).
1600 InsertTailList(&Irp
->Tail
.Overlay
.Thread
->IrpList
, &Irp
->ThreadListEntry
);
1603 KfLowerIrql(OldIrql
);
1608 * Reference: Chris Cant's "Writing WDM Device Drivers"
1612 IoReuseIrp(IN OUT PIRP Irp
,
1615 UCHAR AllocationFlags
;
1617 /* Get the old flags */
1618 AllocationFlags
= Irp
->AllocationFlags
;
1620 /* Reinitialize the IRP */
1621 IoInitializeIrp(Irp
, Irp
->Size
, Irp
->StackCount
);
1623 /* Duplicate the data */
1624 Irp
->IoStatus
.Status
= Status
;
1625 Irp
->AllocationFlags
= AllocationFlags
;
1633 IoSetTopLevelIrp(IN PIRP Irp
)
1635 PsGetCurrentThread()->TopLevelIrp
= (ULONG
)Irp
;
1643 IoSynchronousPageWrite(PFILE_OBJECT FileObject
,
1645 PLARGE_INTEGER Offset
,
1647 PIO_STATUS_BLOCK StatusBlock
)
1650 PIO_STACK_LOCATION StackPtr
;
1651 PDEVICE_OBJECT DeviceObject
;
1653 DPRINT("IoSynchronousPageWrite(FileObject 0x%p, Mdl 0x%p)\n",
1656 /* Get the Device Object */
1657 DeviceObject
= IoGetRelatedDeviceObject(FileObject
);
1660 Irp
= IoAllocateIrp(DeviceObject
->StackSize
, FALSE
);
1663 StackPtr
= IoGetNextIrpStackLocation(Irp
);
1665 /* Create the IRP Settings */
1666 Irp
->MdlAddress
= Mdl
;
1667 Irp
->UserBuffer
= MmGetMdlVirtualAddress(Mdl
);
1668 Irp
->UserIosb
= StatusBlock
;
1669 Irp
->UserEvent
= Event
;
1670 Irp
->RequestorMode
= KernelMode
;
1671 Irp
->Flags
= IRP_PAGING_IO
| IRP_NOCACHE
| IRP_SYNCHRONOUS_PAGING_IO
;
1672 Irp
->Tail
.Overlay
.OriginalFileObject
= FileObject
;
1673 Irp
->Tail
.Overlay
.Thread
= PsGetCurrentThread();
1675 /* Set the Stack Settings */
1676 StackPtr
->Parameters
.Write
.Length
= MmGetMdlByteCount(Mdl
);
1677 StackPtr
->Parameters
.Write
.ByteOffset
= *Offset
;
1678 StackPtr
->MajorFunction
= IRP_MJ_WRITE
;
1679 StackPtr
->FileObject
= FileObject
;
1681 /* Call the Driver */
1682 return IofCallDriver(DeviceObject
, Irp
);