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
) &&
163 (Irp
->IoStatus
.Status
!= STATUS_VERIFY_REQUIRED
) &&
164 !(NT_ERROR(Irp
->IoStatus
.Status
)))
166 /* Copy the buffer back to the user */
167 RtlCopyMemory(Irp
->UserBuffer
,
168 Irp
->AssociatedIrp
.SystemBuffer
,
169 Irp
->IoStatus
.Information
);
172 /* Also check if we should de-allocate it */
173 if (Irp
->Flags
& IRP_DEALLOCATE_BUFFER
)
175 ExFreePoolWithTag(Irp
->AssociatedIrp
.SystemBuffer
, TAG_SYS_BUF
);
179 /* Now we got rid of these two... */
180 Irp
->Flags
&= ~(IRP_BUFFERED_IO
| IRP_DEALLOCATE_BUFFER
);
182 /* Check if there's an MDL */
183 while ((Mdl
= Irp
->MdlAddress
))
185 /* Clear all of them */
186 Irp
->MdlAddress
= Mdl
->Next
;
190 /* Remove the IRP from the list of Thread Pending IRPs */
191 RemoveEntryList(&Irp
->ThreadListEntry
);
192 InitializeListHead(&Irp
->ThreadListEntry
);
195 /* Check for Success but allow failure for Async IRPs */
196 if (!(NT_ERROR(Irp
->IoStatus
.Status
)) ||
197 ((NT_ERROR(Irp
->IoStatus
.Status
)) &&
198 (Irp
->PendingReturned
) && !(SyncIrp
) &&
199 ((FileObject
== NULL
) || (FileObject
->Flags
& FO_SYNCHRONOUS_IO
))))
203 /* Save the IOSB Information */
204 *Irp
->UserIosb
= Irp
->IoStatus
;
208 /* Ignore any error */
212 /* Check if there's an event */
215 /* Check if we should signal the File Object Event as well */
218 /* If the File Object is SYNC, then we need to signal its event too */
219 if (FileObject
->Flags
& FO_SYNCHRONOUS_IO
)
222 FileObject
->FinalStatus
= Irp
->IoStatus
.Status
;
225 KeSetEvent(&FileObject
->Event
, 0, FALSE
);
228 /* Signal the Event */
229 KeSetEvent(UserEvent
, 0, FALSE
);
231 /* Dereference the Event if this is an ASYNC IRP */
232 if (FileObject
&& !SyncIrp
&& UserEvent
!= &FileObject
->Event
)
234 ObDereferenceObject(UserEvent
);
240 FileObject
->FinalStatus
= Irp
->IoStatus
.Status
;
242 /* Signal the File Object Instead */
243 KeSetEvent(&FileObject
->Event
, 0, FALSE
);
247 /* Now call the User APC if one was requested */
248 if (Irp
->Overlay
.AsynchronousParameters
.UserApcRoutine
!= NULL
)
250 KeInitializeApc(&Irp
->Tail
.Apc
,
251 KeGetCurrentThread(),
252 CurrentApcEnvironment
,
254 IopAbortIrpKernelApc
,
255 (PKNORMAL_ROUTINE
)Irp
->Overlay
.AsynchronousParameters
.UserApcRoutine
,
257 Irp
->Overlay
.AsynchronousParameters
.UserApcContext
);
259 KeInsertQueueApc(&Irp
->Tail
.Apc
,
265 else if (FileObject
&& FileObject
->CompletionContext
)
267 /* Call the IO Completion Port if we have one, instead */
268 Irp
->Tail
.CompletionKey
= FileObject
->CompletionContext
->Key
;
269 Irp
->Tail
.Overlay
.PacketType
= IrpCompletionPacket
;
270 KeInsertQueue(FileObject
->CompletionContext
->Port
,
271 &Irp
->Tail
.Overlay
.ListEntry
);
277 /* Signal the Events only if PendingReturned and we have a File Object */
278 if (FileObject
&& Irp
->PendingReturned
)
280 /* Check for SYNC IRP */
283 /* Set the status in this case only */
286 *Irp
->UserIosb
= Irp
->IoStatus
;
290 /* Ignore any error */
294 /* Signal our event if we have one */
297 KeSetEvent(UserEvent
, 0, FALSE
);
301 /* Signal the File's Event instead */
302 KeSetEvent(&FileObject
->Event
, 0, FALSE
);
308 /* FIXME: This is necessary to fix bug #609 */
311 *Irp
->UserIosb
= Irp
->IoStatus
;
315 /* Ignore any error */
319 /* We'll report the Status to the File Object, not the IRP */
320 FileObject
->FinalStatus
= Irp
->IoStatus
.Status
;
322 /* Signal the File Object ONLY if this was Async */
323 KeSetEvent(&FileObject
->Event
, 0, FALSE
);
327 /* Dereference the Event if it's an ASYNC IRP on a File Object */
328 if (UserEvent
&& !SyncIrp
&& FileObject
)
330 if (UserEvent
!= &FileObject
->Event
)
332 ObDereferenceObject(UserEvent
);
337 /* Dereference the File Object */
338 if (FileObject
) ObDereferenceObject(FileObject
);
341 if (Irp
) IoFreeIrp(Irp
);
345 if (NT_SUCCESS(Irp
->IoStatus
.Status
) || Irp
->PendingReturned
)
349 /* Save the IOSB Information */
350 *Irp
->UserIosb
= Irp
->IoStatus
;
354 /* Ignore any error */
360 if (FileObject
->Flags
& FO_SYNCHRONOUS_IO
)
363 FileObject
->FinalStatus
= Irp
->IoStatus
.Status
;
365 /* FIXME: Remove this check when I/O code is fixed */
366 if (UserEvent
!= &FileObject
->Event
)
369 KeSetEvent(&FileObject
->Event
, 0, FALSE
);
374 /* Signal the user event, if one exist */
377 KeSetEvent(UserEvent
, 0, FALSE
);
380 /* Now call the User APC if one was requested */
381 if (Irp
->Overlay
.AsynchronousParameters
.UserApcRoutine
)
383 KeInitializeApc(&Irp
->Tail
.Apc
,
384 KeGetCurrentThread(),
385 CurrentApcEnvironment
,
387 IopAbortIrpKernelApc
,
388 (PKNORMAL_ROUTINE
)Irp
->Overlay
.AsynchronousParameters
.UserApcRoutine
,
390 Irp
->Overlay
.AsynchronousParameters
.UserApcContext
);
392 KeInsertQueueApc(&Irp
->Tail
.Apc
,
398 else if (FileObject
&& FileObject
->CompletionContext
)
400 /* Call the IO Completion Port if we have one, instead */
401 IoSetIoCompletion(FileObject
->CompletionContext
->Port
,
402 FileObject
->CompletionContext
->Key
,
403 Irp
->Overlay
.AsynchronousParameters
.UserApcContext
,
404 Irp
->IoStatus
.Status
,
405 Irp
->IoStatus
.Information
,
411 /* Free the Irp if it hasn't already */
412 if (Irp
) IoFreeIrp(Irp
);
416 /* Dereference the user event, if it is an event object */
417 /* FIXME: Remove last check when I/O code is fixed */
418 if (UserEvent
&& !SyncIrp
&& UserEvent
!= &FileObject
->Event
)
420 ObDereferenceObject(UserEvent
);
423 /* Dereference the File Object */
424 ObDereferenceObject(FileObject
);
429 /* FUNCTIONS *****************************************************************/
434 * FUNCTION: Allocates an IRP
436 * StackSize = the size of the stack required for the irp
437 * ChargeQuota = Charge allocation to current threads quota
438 * RETURNS: Irp allocated
442 IoAllocateIrp(CCHAR StackSize
,
446 USHORT Size
= IoSizeOfIrp(StackSize
);
449 PNPAGED_LOOKASIDE_LIST List
= NULL
;
450 PP_NPAGED_LOOKASIDE_NUMBER ListType
= LookasideSmallIrpList
;
452 /* Figure out which Lookaside List to use */
453 if ((StackSize
<= 8) && (ChargeQuota
== FALSE
))
455 DPRINT("Using lookaside, %d\n", StackSize
);
456 /* Set Fixed Size Flag */
457 Flags
= IRP_ALLOCATED_FIXED_SIZE
;
459 /* See if we should use big list */
462 DPRINT("Using large lookaside\n");
463 Size
= IoSizeOfIrp(8);
464 ListType
= LookasideLargeIrpList
;
468 Prcb
= KeGetCurrentPrcb();
470 /* Get the P List First */
471 List
= (PNPAGED_LOOKASIDE_LIST
)Prcb
->PPLookasideList
[ListType
].P
;
473 /* Attempt allocation */
474 List
->L
.TotalAllocates
++;
475 DPRINT("Total allocates: %d\n", List
->L
.TotalAllocates
);
476 Irp
= (PIRP
)InterlockedPopEntrySList(&List
->L
.ListHead
);
477 DPRINT("Alloc attempt on CPU list: %p\n", Irp
);
479 /* Check if the P List failed */
482 /* Let the balancer know */
483 List
->L
.AllocateMisses
++;
484 DPRINT("Total misses: %d\n", List
->L
.AllocateMisses
);
487 List
= (PNPAGED_LOOKASIDE_LIST
)Prcb
->PPLookasideList
[ListType
].L
;
488 List
->L
.TotalAllocates
++;
489 Irp
= (PIRP
)InterlockedPopEntrySList(&List
->L
.ListHead
);
490 DPRINT("Alloc attempt on SYS list: %p\n", Irp
);
494 /* Check if we have to use the pool */
497 DPRINT("Using pool\n");
498 /* Did we try lookaside and fail? */
499 if (Flags
& IRP_ALLOCATED_FIXED_SIZE
) List
->L
.AllocateMisses
++;
501 /* Check if we shoudl charge quota */
504 /* Irp = ExAllocatePoolWithQuotaTag(NonPagedPool, Size, TAG_IRP); */
506 Irp
= ExAllocatePoolWithTag(NonPagedPool
, Size
, TAG_IRP
);
510 /* Allocate the IRP With no Quota charge */
511 Irp
= ExAllocatePoolWithTag(NonPagedPool
, Size
, TAG_IRP
);
514 /* Make sure it was sucessful */
515 if (!Irp
) return(NULL
);
519 /* We have an IRP from Lookaside */
520 Flags
|= IRP_LOOKASIDE_ALLOCATION
;
524 if (ChargeQuota
) Flags
|= IRP_QUOTA_CHARGED
;
526 /* Now Initialize it */
527 DPRINT("irp allocated\n");
528 IoInitializeIrp(Irp
, Size
, StackSize
);
530 /* Set the Allocation Flags */
531 Irp
->AllocationFlags
= Flags
;
540 * FUNCTION: Allocates and sets up an IRP to be sent to lower level drivers
542 * MajorFunction = One of IRP_MJ_READ, IRP_MJ_WRITE,
543 * IRP_MJ_FLUSH_BUFFERS or IRP_MJ_SHUTDOWN
544 * DeviceObject = Device object to send the irp to
545 * Buffer = Buffer into which data will be read or written
546 * Length = Length in bytes of the irp to be allocated
547 * StartingOffset = Starting offset on the device
548 * IoStatusBlock (OUT) = Storage for the result of the operation
549 * RETURNS: The IRP allocated on success, or
554 IoBuildAsynchronousFsdRequest(ULONG MajorFunction
,
555 PDEVICE_OBJECT DeviceObject
,
558 PLARGE_INTEGER StartingOffset
,
559 PIO_STATUS_BLOCK IoStatusBlock
)
562 PIO_STACK_LOCATION StackPtr
;
563 LOCK_OPERATION AccessType
;
565 DPRINT("IoBuildAsynchronousFsdRequest(MajorFunction %x, DeviceObject 0x%p, "
566 "Buffer 0x%p, Length %x, StartingOffset 0x%p, "
567 "IoStatusBlock 0x%p\n",MajorFunction
,DeviceObject
,Buffer
,Length
,
568 StartingOffset
,IoStatusBlock
);
571 if (!(Irp
= IoAllocateIrp(DeviceObject
->StackSize
, FALSE
))) return Irp
;
574 StackPtr
= IoGetNextIrpStackLocation(Irp
);
576 /* Write the Major function and then deal with it */
577 StackPtr
->MajorFunction
= (UCHAR
)MajorFunction
;
579 /* Do not handle the following here */
580 if (MajorFunction
!= IRP_MJ_FLUSH_BUFFERS
&&
581 MajorFunction
!= IRP_MJ_SHUTDOWN
&&
582 MajorFunction
!= IRP_MJ_PNP
)
584 /* Check if this is Buffered IO */
585 if (DeviceObject
->Flags
& DO_BUFFERED_IO
)
587 /* Allocate the System Buffer */
588 Irp
->AssociatedIrp
.SystemBuffer
= ExAllocatePoolWithTag(NonPagedPool
,
593 Irp
->Flags
= IRP_BUFFERED_IO
| IRP_DEALLOCATE_BUFFER
;
595 /* Handle special IRP_MJ_WRITE Case */
596 if (MajorFunction
== IRP_MJ_WRITE
)
598 /* Copy the buffer data */
599 RtlCopyMemory(Irp
->AssociatedIrp
.SystemBuffer
, Buffer
, Length
);
603 /* Set the Input Operation flag and set this as a User Buffer */
604 Irp
->Flags
|= IRP_INPUT_OPERATION
;
605 Irp
->UserBuffer
= Buffer
;
608 else if (DeviceObject
->Flags
& DO_DIRECT_IO
)
610 /* Use an MDL for Direct I/O */
611 Irp
->MdlAddress
= MmCreateMdl(NULL
, Buffer
, Length
);
614 if (MajorFunction
== IRP_MJ_READ
)
616 AccessType
= IoWriteAccess
;
620 AccessType
= IoReadAccess
;
627 MmProbeAndLockPages(Irp
->MdlAddress
, KernelMode
, AccessType
);
631 /* Free the IRP and its MDL */
632 IoFreeMdl(Irp
->MdlAddress
);
634 /* FIXME - pass the exception to the caller? */
644 /* Neither, use the buffer */
645 Irp
->UserBuffer
= Buffer
;
648 if (MajorFunction
== IRP_MJ_READ
)
650 StackPtr
->Parameters
.Read
.Length
= Length
;
651 StackPtr
->Parameters
.Read
.ByteOffset
= *StartingOffset
;
653 else if (MajorFunction
== IRP_MJ_WRITE
)
655 StackPtr
->Parameters
.Write
.Length
= Length
;
656 StackPtr
->Parameters
.Write
.ByteOffset
= *StartingOffset
;
660 /* Set the Current Thread and IOSB */
661 if (!IoStatusBlock
) KEBUGCHECK(0); /* Temporary to catch illegal ROS Drivers */
662 Irp
->UserIosb
= IoStatusBlock
;
663 Irp
->Tail
.Overlay
.Thread
= PsGetCurrentThread();
665 /* Set the Status Block after all is done */
673 * FUNCTION: Allocates and sets up an IRP to be sent to drivers
675 * IoControlCode = Device io control code
676 * DeviceObject = Device object to send the irp to
677 * InputBuffer = Buffer from which data will be read by the driver
678 * InputBufferLength = Length in bytes of the input buffer
679 * OutputBuffer = Buffer into which data will be written by the driver
680 * OutputBufferLength = Length in bytes of the output buffer
681 * InternalDeviceIoControl = Determines weather
682 * IRP_MJ_INTERNAL_DEVICE_CONTROL or
683 * IRP_MJ_DEVICE_CONTROL will be used
684 * Event = Event used to notify the caller of completion
685 * IoStatusBlock (OUT) = Storage for the result of the operation
686 * RETURNS: The IRP allocated on success, or
691 IoBuildDeviceIoControlRequest (ULONG IoControlCode
,
692 PDEVICE_OBJECT DeviceObject
,
694 ULONG InputBufferLength
,
696 ULONG OutputBufferLength
,
697 BOOLEAN InternalDeviceIoControl
,
699 PIO_STATUS_BLOCK IoStatusBlock
)
702 PIO_STACK_LOCATION StackPtr
;
704 LOCK_OPERATION AccessType
;
706 DPRINT("IoBuildDeviceIoRequest(IoControlCode %x, DeviceObject 0x%p, "
707 "InputBuffer 0x%p, InputBufferLength %x, OutputBuffer 0x%p, "
708 "OutputBufferLength %x, InternalDeviceIoControl %x "
709 "Event 0x%p, IoStatusBlock 0x%p\n",IoControlCode
,DeviceObject
,
710 InputBuffer
,InputBufferLength
,OutputBuffer
,OutputBufferLength
,
711 InternalDeviceIoControl
,Event
,IoStatusBlock
);
714 if (!(Irp
= IoAllocateIrp(DeviceObject
->StackSize
, FALSE
))) return Irp
;
717 StackPtr
= IoGetNextIrpStackLocation(Irp
);
719 /* Set the DevCtl Type */
720 StackPtr
->MajorFunction
= InternalDeviceIoControl
?
721 IRP_MJ_INTERNAL_DEVICE_CONTROL
: IRP_MJ_DEVICE_CONTROL
;
723 /* Set the IOCTL Data */
724 StackPtr
->Parameters
.DeviceIoControl
.IoControlCode
= IoControlCode
;
725 StackPtr
->Parameters
.DeviceIoControl
.InputBufferLength
= InputBufferLength
;
726 StackPtr
->Parameters
.DeviceIoControl
.OutputBufferLength
= OutputBufferLength
;
728 /* Handle the Methods */
729 switch (IO_METHOD_FROM_CTL_CODE(IoControlCode
))
731 case METHOD_BUFFERED
:
732 DPRINT("Using METHOD_BUFFERED!\n");
734 /* Select the right Buffer Length */
735 BufferLength
= InputBufferLength
> OutputBufferLength
? InputBufferLength
: OutputBufferLength
;
737 /* Make sure there is one */
740 /* Allocate the System Buffer */
741 Irp
->AssociatedIrp
.SystemBuffer
= ExAllocatePoolWithTag(NonPagedPool
,
745 /* Fail if we couldn't */
746 if (Irp
->AssociatedIrp
.SystemBuffer
== NULL
)
752 /* Check if we got a buffer */
755 /* Copy into the System Buffer */
756 RtlCopyMemory(Irp
->AssociatedIrp
.SystemBuffer
,
761 /* Write the flags */
762 Irp
->Flags
= IRP_BUFFERED_IO
| IRP_DEALLOCATE_BUFFER
;
763 if (OutputBuffer
) Irp
->Flags
|= IRP_INPUT_OPERATION
;
765 /* Save the Buffer */
766 Irp
->UserBuffer
= OutputBuffer
;
770 /* Clear the Flags and Buffer */
772 Irp
->UserBuffer
= NULL
;
776 case METHOD_IN_DIRECT
:
777 case METHOD_OUT_DIRECT
:
778 DPRINT("Using METHOD_IN/OUT DIRECT!\n");
780 /* Check if we got an input buffer */
783 /* Allocate the System Buffer */
784 Irp
->AssociatedIrp
.SystemBuffer
= ExAllocatePoolWithTag(NonPagedPool
,
788 /* Fail if we couldn't */
789 if (Irp
->AssociatedIrp
.SystemBuffer
== NULL
)
795 /* Copy into the System Buffer */
796 RtlCopyMemory(Irp
->AssociatedIrp
.SystemBuffer
,
800 /* Write the flags */
801 Irp
->Flags
= IRP_BUFFERED_IO
| IRP_DEALLOCATE_BUFFER
;
808 /* Check if we got an output buffer */
811 /* Allocate the System Buffer */
812 Irp
->MdlAddress
= IoAllocateMdl(OutputBuffer
,
818 /* Fail if we couldn't */
819 if (Irp
->MdlAddress
== NULL
)
828 /* Use the right Access Type */
829 if (IO_METHOD_FROM_CTL_CODE(IoControlCode
) == METHOD_IN_DIRECT
)
831 AccessType
= IoReadAccess
;
835 AccessType
= IoWriteAccess
;
839 MmProbeAndLockPages(Irp
->MdlAddress
, KernelMode
, AccessType
);
843 /* Free the MDL and IRP */
844 IoFreeMdl(Irp
->MdlAddress
);
846 /* FIXME - pass the exception to the caller? */
858 /* Just save the Buffer */
859 Irp
->UserBuffer
= OutputBuffer
;
860 StackPtr
->Parameters
.DeviceIoControl
.Type3InputBuffer
= InputBuffer
;
864 /* Now write the Event and IoSB */
865 if (!IoStatusBlock
) KEBUGCHECK(0); /* Temporary to catch illegal ROS Drivers */
866 Irp
->UserIosb
= IoStatusBlock
;
867 Irp
->UserEvent
= Event
;
869 /* Sync IRPs are queued to requestor thread's irp cancel/cleanup list */
870 Irp
->Tail
.Overlay
.Thread
= PsGetCurrentThread();
871 IoQueueThreadIrp(Irp
);
880 * FUNCTION: Allocates and builds an IRP to be sent synchronously to lower
883 * MajorFunction = Major function code, one of IRP_MJ_READ,
884 * IRP_MJ_WRITE, IRP_MJ_FLUSH_BUFFERS, IRP_MJ_SHUTDOWN
885 * DeviceObject = Target device object
886 * Buffer = Buffer containing data for a read or write
887 * Length = Length in bytes of the information to be transferred
888 * StartingOffset = Offset to begin the read/write from
889 * Event (OUT) = Will be set when the operation is complete
890 * IoStatusBlock (OUT) = Set to the status of the operation
891 * RETURNS: The IRP allocated on success, or
896 IoBuildSynchronousFsdRequest(ULONG MajorFunction
,
897 PDEVICE_OBJECT DeviceObject
,
900 PLARGE_INTEGER StartingOffset
,
902 PIO_STATUS_BLOCK IoStatusBlock
)
906 DPRINT("IoBuildSynchronousFsdRequest(MajorFunction %x, DeviceObject 0x%p, "
907 "Buffer 0x%p, Length %x, StartingOffset 0x%p, Event 0x%p, "
908 "IoStatusBlock 0x%p\n",MajorFunction
,DeviceObject
,Buffer
,Length
,
909 StartingOffset
,Event
,IoStatusBlock
);
911 /* Do the big work to set up the IRP */
912 Irp
= IoBuildAsynchronousFsdRequest(MajorFunction
,
919 /* Set the Event which makes it Syncronous */
920 Irp
->UserEvent
= Event
;
922 /* Sync IRPs are queued to requestor thread's irp cancel/cleanup list */
923 IoQueueThreadIrp(Irp
);
932 IoCancelIrp(PIRP Irp
)
935 PDRIVER_CANCEL CancelRoutine
;
937 DPRINT("IoCancelIrp(Irp 0x%p)\n",Irp
);
939 IoAcquireCancelSpinLock(&oldlvl
);
943 CancelRoutine
= IoSetCancelRoutine(Irp
, NULL
);
944 if (CancelRoutine
== NULL
)
946 IoReleaseCancelSpinLock(oldlvl
);
950 Irp
->CancelIrql
= oldlvl
;
951 CancelRoutine(IoGetCurrentIrpStackLocation(Irp
)->DeviceObject
, Irp
);
956 * @name IoCancelThreadIo
958 * Cancel all pending I/O request associated with specified thread.
961 * Thread to cancel requests for.
965 IoCancelThreadIo(PETHREAD Thread
)
969 ULONG Retries
= 3000;
970 LARGE_INTEGER Interval
;
972 /* Raise to APC to protect the IrpList */
973 OldIrql
= KfRaiseIrql(APC_LEVEL
);
975 /* Start by cancelling all the IRPs in the current thread queue. */
976 LIST_FOR_EACH(Irp
, &Thread
->IrpList
, IRP
, ThreadListEntry
)
982 /* Wait 100 milliseconds */
983 Interval
.QuadPart
= -1000000;
985 /* Wait till all the IRPs are completed or cancelled. */
986 while (!IsListEmpty(&Thread
->IrpList
))
988 /* Now we can lower */
989 KfLowerIrql(OldIrql
);
991 /* Wait a short while and then look if all our IRPs were completed. */
992 KeDelayExecutionThread(KernelMode
, FALSE
, &Interval
);
995 * Don't stay here forever if some broken driver doesn't complete
998 if (Retries
-- == 0) IopRemoveThreadIrp();
1000 /* Raise the IRQL Again */
1001 OldIrql
= KfRaiseIrql(APC_LEVEL
);
1004 /* We're done, lower the IRQL */
1005 KfLowerIrql(OldIrql
);
1016 IoCallDriver (PDEVICE_OBJECT DeviceObject
, PIRP Irp
)
1018 /* Call fast call */
1019 return IofCallDriver(DeviceObject
, Irp
);
1025 #undef IoCompleteRequest
1028 IoCompleteRequest(PIRP Irp
,
1029 CCHAR PriorityBoost
)
1031 /* Call the fastcall */
1032 IofCompleteRequest(Irp
, PriorityBoost
);
1040 IoEnqueueIrp(IN PIRP Irp
)
1042 IoQueueThreadIrp(Irp
);
1048 * FUNCTION: Sends an IRP to the next lower driver
1052 IofCallDriver(PDEVICE_OBJECT DeviceObject
,
1056 PDRIVER_OBJECT DriverObject
;
1057 PIO_STACK_LOCATION Param
;
1059 DPRINT("IofCallDriver(DeviceObject 0x%p, Irp 0x%p)\n",DeviceObject
,Irp
);
1061 /* Get the Driver Object */
1062 DriverObject
= DeviceObject
->DriverObject
;
1064 /* Set the Stack Location */
1065 IoSetNextIrpStackLocation(Irp
);
1067 /* Get the current one */
1068 Param
= IoGetCurrentIrpStackLocation(Irp
);
1070 DPRINT("IrpSp 0x0x%p\n", Param
);
1072 /* Get the Device Object */
1073 Param
->DeviceObject
= DeviceObject
;
1076 return DriverObject
->MajorFunction
[Param
->MajorFunction
](DeviceObject
, Irp
);
1079 #ifdef IoCompleteRequest
1080 #undef IoCompleteRequest
1085 * FUNCTION: Indicates the caller has finished all processing for a given
1086 * I/O request and is returning the given IRP to the I/O manager
1088 * Irp = Irp to be cancelled
1089 * PriorityBoost = Increment by which to boost the priority of the
1090 * thread making the request
1094 IofCompleteRequest(PIRP Irp
,
1095 CCHAR PriorityBoost
)
1097 PIO_STACK_LOCATION StackPtr
;
1098 PDEVICE_OBJECT DeviceObject
;
1099 PFILE_OBJECT FileObject
= Irp
->Tail
.Overlay
.OriginalFileObject
;
1100 PETHREAD Thread
= Irp
->Tail
.Overlay
.Thread
;
1104 DPRINT("IofCompleteRequest(Irp 0x%p, PriorityBoost %d) Event 0x%p THread 0x%p\n",
1105 Irp
,PriorityBoost
, Irp
->UserEvent
, PsGetCurrentThread());
1107 ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL
);
1108 ASSERT(!Irp
->CancelRoutine
);
1109 ASSERT(Irp
->IoStatus
.Status
!= STATUS_PENDING
);
1111 /* Get the Current Stack */
1112 StackPtr
= IoGetCurrentIrpStackLocation(Irp
);
1113 IoSkipCurrentIrpStackLocation(Irp
);
1115 /* Loop the Stacks and complete the IRPs */
1116 for (;Irp
->CurrentLocation
<= (Irp
->StackCount
+ 1); StackPtr
++)
1118 /* Set Pending Returned */
1119 Irp
->PendingReturned
= StackPtr
->Control
& SL_PENDING_RETURNED
;
1122 * Completion routines expect the current irp stack location to be the same as when
1123 * IoSetCompletionRoutine was called to set them. A side effect is that completion
1124 * routines set by highest level drivers without their own stack location will receive
1125 * an invalid current stack location (at least it should be considered as invalid).
1126 * Since the DeviceObject argument passed is taken from the current stack, this value
1127 * is also invalid (NULL).
1129 if (Irp
->CurrentLocation
== (Irp
->StackCount
+ 1))
1131 DeviceObject
= NULL
;
1135 DeviceObject
= IoGetCurrentIrpStackLocation(Irp
)->DeviceObject
;
1138 /* Check if there is a Completion Routine to Call */
1139 if ((NT_SUCCESS(Irp
->IoStatus
.Status
) &&
1140 (StackPtr
->Control
& SL_INVOKE_ON_SUCCESS
)) ||
1141 (!NT_SUCCESS(Irp
->IoStatus
.Status
) &&
1142 (StackPtr
->Control
& SL_INVOKE_ON_ERROR
)) ||
1143 (Irp
->Cancel
&& (StackPtr
->Control
& SL_INVOKE_ON_CANCEL
)))
1146 Status
= StackPtr
->CompletionRoutine(DeviceObject
,
1150 /* Don't touch the Packet if this was returned. It might be gone! */
1151 if (Status
== STATUS_MORE_PROCESSING_REQUIRED
) return;
1155 if ((Irp
->CurrentLocation
<= Irp
->StackCount
) && (Irp
->PendingReturned
))
1157 IoMarkIrpPending(Irp
);
1161 /* Move to next stack */
1162 IoSkipCurrentIrpStackLocation(Irp
);
1165 /* Windows NT File System Internals, page 165 */
1166 if (Irp
->Flags
& IRP_ASSOCIATED_IRP
)
1168 ULONG MasterIrpCount
;
1169 PIRP MasterIrp
= Irp
->AssociatedIrp
.MasterIrp
;
1171 DPRINT("Handling Associated IRP\n");
1172 /* This should never happen! */
1173 ASSERT(IsListEmpty(&Irp
->ThreadListEntry
));
1175 /* Decrement and get the old count */
1176 MasterIrpCount
= InterlockedDecrement(&MasterIrp
->AssociatedIrp
.IrpCount
);
1178 /* Free MDLs and IRP */
1179 while ((Mdl
= Irp
->MdlAddress
))
1181 Irp
->MdlAddress
= Mdl
->Next
;
1186 /* Complete the Master IRP */
1187 if (!MasterIrpCount
) IofCompleteRequest(MasterIrp
, PriorityBoost
);
1191 /* Windows NT File System Internals, page 165 */
1192 if (Irp
->Flags
& (IRP_PAGING_IO
|IRP_CLOSE_OPERATION
))
1194 DPRINT("Handling Paging or Close I/O\n");
1195 /* This should never happen! */
1196 ASSERT(IsListEmpty(&Irp
->ThreadListEntry
));
1198 /* Handle a Close Operation or Sync Paging I/O (see page 165) */
1199 if (Irp
->Flags
& (IRP_SYNCHRONOUS_PAGING_IO
| IRP_CLOSE_OPERATION
))
1201 /* Set the I/O Status and Signal the Event */
1202 DPRINT("Handling Sync Paging or Close I/O\n");
1203 *Irp
->UserIosb
= Irp
->IoStatus
;
1204 KeSetEvent(Irp
->UserEvent
, PriorityBoost
, FALSE
);
1206 /* Free the IRP for a Paging I/O Only, Close is handled by us */
1207 if (Irp
->Flags
& IRP_SYNCHRONOUS_PAGING_IO
)
1209 DPRINT("Handling Sync Paging I/O\n");
1217 KeInitializeApc(&Irp
->Tail
.Apc
1218 &Irp
->Tail
.Overlay
.Thread
->Tcb
,
1219 Irp
->ApcEnvironment
,
1220 IopCompletePageWrite
,
1225 KeInsertQueueApc(&Irp
->Tail
.Apc
,
1230 /* Not implemented yet. */
1237 /* Unlock MDL Pages, page 167. */
1238 Mdl
= Irp
->MdlAddress
;
1241 DPRINT("Unlocking MDL: 0x%p\n", Mdl
);
1246 /* Check if we should exit because of a Deferred I/O (page 168) */
1247 if (Irp
->Flags
& IRP_DEFER_IO_COMPLETION
&& !Irp
->PendingReturned
)
1249 DPRINT("Quick return\n");
1253 /* Now queue the special APC */
1256 DPRINT("KMODE APC QUEUE\n");
1257 KeInitializeApc(&Irp
->Tail
.Apc
,
1259 Irp
->ApcEnvironment
,
1262 (PKNORMAL_ROUTINE
) NULL
,
1265 KeInsertQueueApc(&Irp
->Tail
.Apc
,
1267 NULL
, /* This is used for REPARSE stuff */
1272 /* The IRP just got cancelled... does a thread still own it? */
1273 if ((Thread
= Irp
->Tail
.Overlay
.Thread
))
1275 /* Yes! There is still hope! */
1276 DPRINT("KMODE APC QUEUE\n");
1277 KeInitializeApc(&Irp
->Tail
.Apc
,
1279 Irp
->ApcEnvironment
,
1282 (PKNORMAL_ROUTINE
) NULL
,
1285 KeInsertQueueApc(&Irp
->Tail
.Apc
,
1287 NULL
, /* This is used for REPARSE stuff */
1292 /* Nothing left for us to do, kill it */
1293 IopCleanupIrp(Irp
, FileObject
);
1303 IoForwardIrpSynchronously(IN PDEVICE_OBJECT DeviceObject
,
1313 * FUNCTION: Releases a caller allocated irp
1321 PNPAGED_LOOKASIDE_LIST List
;
1322 PP_NPAGED_LOOKASIDE_NUMBER ListType
= LookasideSmallIrpList
;
1325 /* If this was a pool alloc, free it with the pool */
1326 if (!(Irp
->AllocationFlags
& IRP_ALLOCATED_FIXED_SIZE
))
1329 DPRINT("Freeing pool IRP\n");
1334 DPRINT("Freeing Lookaside IRP\n");
1336 /* Check if this was a Big IRP */
1337 if (Irp
->StackCount
!= 1)
1339 DPRINT("Large IRP\n");
1340 ListType
= LookasideLargeIrpList
;
1344 Prcb
= KeGetCurrentPrcb();
1346 /* Use the P List */
1347 List
= (PNPAGED_LOOKASIDE_LIST
)Prcb
->PPLookasideList
[ListType
].P
;
1348 List
->L
.TotalFrees
++;
1350 /* Check if the Free was within the Depth or not */
1351 if (ExQueryDepthSList(&List
->L
.ListHead
) >= List
->L
.Depth
)
1353 /* Let the balancer know */
1354 List
->L
.FreeMisses
++;
1356 /* Use the L List */
1357 List
= (PNPAGED_LOOKASIDE_LIST
)Prcb
->PPLookasideList
[ListType
].L
;
1358 List
->L
.TotalFrees
++;
1360 /* Check if the Free was within the Depth or not */
1361 if (ExQueryDepthSList(&List
->L
.ListHead
) >= List
->L
.Depth
)
1363 /* All lists failed, use the pool */
1364 List
->L
.FreeMisses
++;
1370 /* The free was within dhe Depth */
1373 InterlockedPushEntrySList(&List
->L
.ListHead
, (PSINGLE_LIST_ENTRY
)Irp
);
1377 DPRINT("Free done\n");
1384 IoGetRequestorProcess(IN PIRP Irp
)
1386 return(Irp
->Tail
.Overlay
.Thread
->ThreadsProcess
);
1394 IoGetRequestorProcessId(IN PIRP Irp
)
1396 return (ULONG
)(IoGetRequestorProcess(Irp
)->UniqueProcessId
);
1404 IoGetRequestorSessionId(IN PIRP Irp
,
1405 OUT PULONG pSessionId
)
1407 *pSessionId
= IoGetRequestorProcess(Irp
)->Session
;
1409 return STATUS_SUCCESS
;
1417 IoGetTopLevelIrp(VOID
)
1419 return (PIRP
)PsGetCurrentThread()->TopLevelIrp
;
1425 * FUNCTION: Initalizes an irp allocated by the caller
1427 * Irp = IRP to initalize
1428 * PacketSize = Size in bytes of the IRP
1429 * StackSize = Number of stack locations in the IRP
1433 IoInitializeIrp(PIRP Irp
,
1437 ASSERT(Irp
!= NULL
);
1439 DPRINT("IoInitializeIrp(StackSize %x, Irp 0x%p)\n",StackSize
, Irp
);
1442 RtlZeroMemory(Irp
, PacketSize
);
1444 /* Set the Header and other data */
1445 Irp
->Type
= IO_TYPE_IRP
;
1446 Irp
->Size
= PacketSize
;
1447 Irp
->StackCount
= StackSize
;
1448 Irp
->CurrentLocation
= StackSize
+ 1;
1449 Irp
->ApcEnvironment
= KeGetCurrentThread()->ApcStateIndex
;
1450 Irp
->Tail
.Overlay
.CurrentStackLocation
= (PIO_STACK_LOCATION
)(Irp
+ 1) + StackSize
;
1452 /* Initialize the Thread List */
1453 InitializeListHead(&Irp
->ThreadListEntry
);
1455 DPRINT("Irp->Tail.Overlay.CurrentStackLocation 0x%p\n", Irp
->Tail
.Overlay
.CurrentStackLocation
);
1460 * IoIsOperationSynchronous@4
1463 * Check if the I/O operation associated with the given IRP
1467 * Irp Packet to check.
1470 * TRUE if Irp's operation is synchronous; otherwise FALSE.
1476 IoIsOperationSynchronous(IN PIRP Irp
)
1478 /* Check the flags */
1479 if ((Irp
->Flags
& IRP_SYNCHRONOUS_PAGING_IO
) ||
1480 (Irp
->Flags
& IRP_SYNCHRONOUS_API
) ||
1481 (IoGetCurrentIrpStackLocation(Irp
)->FileObject
->Flags
&
1484 /* Synch API or Paging I/O is OK, as is Sync File I/O */
1488 /* Otherwise, it is an asynchronous operation. */
1497 IoIsValidNameGraftingBuffer(IN PIRP Irp
,
1498 IN PREPARSE_DATA_BUFFER ReparseBuffer
)
1507 * FUNCTION: Allocates and initializes an irp to associated with a master irp
1510 * StackSize = Number of stack locations to be allocated in the irp
1511 * RETURNS: The irp allocated
1512 * NOTE: The caller is responsible for incrementing
1513 * Irp->AssociatedIrp.IrpCount.
1517 IoMakeAssociatedIrp(PIRP Irp
,
1522 /* Allocate the IRP */
1523 AssocIrp
= IoAllocateIrp(StackSize
, FALSE
);
1524 if (AssocIrp
== NULL
) return NULL
;
1527 AssocIrp
->Flags
|= IRP_ASSOCIATED_IRP
;
1529 /* Set the Thread */
1530 AssocIrp
->Tail
.Overlay
.Thread
= Irp
->Tail
.Overlay
.Thread
;
1532 /* Associate them */
1533 AssocIrp
->AssociatedIrp
.MasterIrp
= Irp
;
1543 IoPageRead(PFILE_OBJECT FileObject
,
1545 PLARGE_INTEGER Offset
,
1547 PIO_STATUS_BLOCK StatusBlock
)
1550 PIO_STACK_LOCATION StackPtr
;
1551 PDEVICE_OBJECT DeviceObject
;
1553 DPRINT("IoPageRead(FileObject 0x%p, Mdl 0x%p)\n",
1556 /* Get the Device Object */
1557 DeviceObject
= IoGetRelatedDeviceObject(FileObject
);
1560 Irp
= IoAllocateIrp(DeviceObject
->StackSize
, FALSE
);
1563 StackPtr
= IoGetNextIrpStackLocation(Irp
);
1565 /* Create the IRP Settings */
1566 Irp
->MdlAddress
= Mdl
;
1567 Irp
->UserBuffer
= MmGetMdlVirtualAddress(Mdl
);
1568 Irp
->UserIosb
= StatusBlock
;
1569 Irp
->UserEvent
= Event
;
1570 Irp
->RequestorMode
= KernelMode
;
1571 Irp
->Flags
= IRP_PAGING_IO
| IRP_NOCACHE
| IRP_SYNCHRONOUS_PAGING_IO
| IRP_INPUT_OPERATION
;
1572 Irp
->Tail
.Overlay
.OriginalFileObject
= FileObject
;
1573 Irp
->Tail
.Overlay
.Thread
= PsGetCurrentThread();
1575 /* Set the Stack Settings */
1576 StackPtr
->Parameters
.Read
.Length
= MmGetMdlByteCount(Mdl
);
1577 StackPtr
->Parameters
.Read
.ByteOffset
= *Offset
;
1578 StackPtr
->MajorFunction
= IRP_MJ_READ
;
1579 StackPtr
->FileObject
= FileObject
;
1581 /* Call the Driver */
1582 return IofCallDriver(DeviceObject
, Irp
);
1590 IoQueueThreadIrp(IN PIRP Irp
)
1595 OldIrql
= KfRaiseIrql(APC_LEVEL
);
1598 * Synchronous irp's are queued to requestor thread. If they are not
1599 * completed when the thread exits, they are canceled (cleaned up).
1602 InsertTailList(&Irp
->Tail
.Overlay
.Thread
->IrpList
, &Irp
->ThreadListEntry
);
1605 KfLowerIrql(OldIrql
);
1610 * Reference: Chris Cant's "Writing WDM Device Drivers"
1614 IoReuseIrp(IN OUT PIRP Irp
,
1617 UCHAR AllocationFlags
;
1619 /* Get the old flags */
1620 AllocationFlags
= Irp
->AllocationFlags
;
1622 /* Reinitialize the IRP */
1623 IoInitializeIrp(Irp
, Irp
->Size
, Irp
->StackCount
);
1625 /* Duplicate the data */
1626 Irp
->IoStatus
.Status
= Status
;
1627 Irp
->AllocationFlags
= AllocationFlags
;
1635 IoSetTopLevelIrp(IN PIRP Irp
)
1637 PsGetCurrentThread()->TopLevelIrp
= (ULONG
)Irp
;
1645 IoSynchronousPageWrite(PFILE_OBJECT FileObject
,
1647 PLARGE_INTEGER Offset
,
1649 PIO_STATUS_BLOCK StatusBlock
)
1652 PIO_STACK_LOCATION StackPtr
;
1653 PDEVICE_OBJECT DeviceObject
;
1655 DPRINT("IoSynchronousPageWrite(FileObject 0x%p, Mdl 0x%p)\n",
1658 /* Get the Device Object */
1659 DeviceObject
= IoGetRelatedDeviceObject(FileObject
);
1662 Irp
= IoAllocateIrp(DeviceObject
->StackSize
, FALSE
);
1665 StackPtr
= IoGetNextIrpStackLocation(Irp
);
1667 /* Create the IRP Settings */
1668 Irp
->MdlAddress
= Mdl
;
1669 Irp
->UserBuffer
= MmGetMdlVirtualAddress(Mdl
);
1670 Irp
->UserIosb
= StatusBlock
;
1671 Irp
->UserEvent
= Event
;
1672 Irp
->RequestorMode
= KernelMode
;
1673 Irp
->Flags
= IRP_PAGING_IO
| IRP_NOCACHE
| IRP_SYNCHRONOUS_PAGING_IO
;
1674 Irp
->Tail
.Overlay
.OriginalFileObject
= FileObject
;
1675 Irp
->Tail
.Overlay
.Thread
= PsGetCurrentThread();
1677 /* Set the Stack Settings */
1678 StackPtr
->Parameters
.Write
.Length
= MmGetMdlByteCount(Mdl
);
1679 StackPtr
->Parameters
.Write
.ByteOffset
= *Offset
;
1680 StackPtr
->MajorFunction
= IRP_MJ_WRITE
;
1681 StackPtr
->FileObject
= FileObject
;
1683 /* Call the Driver */
1684 return IofCallDriver(DeviceObject
, Irp
);