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: %x\n", Apc
);
147 /* Get data from the APC */
148 FileObject
= (PFILE_OBJECT
)(*SystemArgument1
);
149 Irp
= CONTAINING_RECORD(Apc
, IRP
, Tail
.Apc
);
150 DPRINT("IoSecondStageCompletition, %x\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 %x, "
564 "Buffer %x, Length %x, StartingOffset %x, "
565 "IoStatusBlock %x\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 %x, "
705 "InputBuffer %x, InputBufferLength %x, OutputBuffer %x, "
706 "OutputBufferLength %x, InternalDeviceIoControl %x "
707 "Event %x, IoStatusBlock %x\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 %x, "
905 "Buffer %x, Length %x, StartingOffset %x, Event %x, "
906 "IoStatusBlock %x\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 %x)\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
)
965 PLIST_ENTRY IrpEntry
;
968 ULONG Retries
= 3000;
969 LARGE_INTEGER Interval
;
971 /* Raise to APC to protect the IrpList */
972 OldIrql
= KfRaiseIrql(APC_LEVEL
);
974 /* Start by cancelling all the IRPs in the current thread queue. */
975 for (IrpEntry
= Thread
->IrpList
.Flink
;
976 IrpEntry
!= &Thread
->IrpList
;
977 IrpEntry
= IrpEntry
->Flink
)
980 Irp
= CONTAINING_RECORD(IrpEntry
, IRP
, ThreadListEntry
);
986 /* Wait 100 milliseconds */
987 Interval
.QuadPart
= -1000000;
989 /* Wait till all the IRPs are completed or cancelled. */
990 while (!IsListEmpty(&Thread
->IrpList
))
992 /* Now we can lower */
993 KfLowerIrql(OldIrql
);
995 /* Wait a short while and then look if all our IRPs were completed. */
996 KeDelayExecutionThread(KernelMode
, FALSE
, &Interval
);
999 * Don't stay here forever if some broken driver doesn't complete
1002 if (Retries
-- == 0) IopRemoveThreadIrp();
1004 /* Raise the IRQL Again */
1005 OldIrql
= KfRaiseIrql(APC_LEVEL
);
1008 /* We're done, lower the IRQL */
1009 KfLowerIrql(OldIrql
);
1020 IoCallDriver (PDEVICE_OBJECT DeviceObject
, PIRP Irp
)
1022 /* Call fast call */
1023 return IofCallDriver(DeviceObject
, Irp
);
1029 #undef IoCompleteRequest
1032 IoCompleteRequest(PIRP Irp
,
1033 CCHAR PriorityBoost
)
1035 /* Call the fastcall */
1036 IofCompleteRequest(Irp
, PriorityBoost
);
1044 IoEnqueueIrp(IN PIRP Irp
)
1046 IoQueueThreadIrp(Irp
);
1052 * FUNCTION: Sends an IRP to the next lower driver
1056 IofCallDriver(PDEVICE_OBJECT DeviceObject
,
1060 PDRIVER_OBJECT DriverObject
;
1061 PIO_STACK_LOCATION Param
;
1063 DPRINT("IofCallDriver(DeviceObject %x, Irp %x)\n",DeviceObject
,Irp
);
1065 /* Get the Driver Object */
1066 DriverObject
= DeviceObject
->DriverObject
;
1068 /* Set the Stack Location */
1069 IoSetNextIrpStackLocation(Irp
);
1071 /* Get the current one */
1072 Param
= IoGetCurrentIrpStackLocation(Irp
);
1074 DPRINT("IrpSp 0x%X\n", Param
);
1076 /* Get the Device Object */
1077 Param
->DeviceObject
= DeviceObject
;
1080 return DriverObject
->MajorFunction
[Param
->MajorFunction
](DeviceObject
, Irp
);
1083 #ifdef IoCompleteRequest
1084 #undef IoCompleteRequest
1089 * FUNCTION: Indicates the caller has finished all processing for a given
1090 * I/O request and is returning the given IRP to the I/O manager
1092 * Irp = Irp to be cancelled
1093 * PriorityBoost = Increment by which to boost the priority of the
1094 * thread making the request
1098 IofCompleteRequest(PIRP Irp
,
1099 CCHAR PriorityBoost
)
1101 PIO_STACK_LOCATION StackPtr
;
1102 PDEVICE_OBJECT DeviceObject
;
1103 PFILE_OBJECT FileObject
= Irp
->Tail
.Overlay
.OriginalFileObject
;
1104 PETHREAD Thread
= Irp
->Tail
.Overlay
.Thread
;
1108 DPRINT("IofCompleteRequest(Irp %x, PriorityBoost %d) Event %x THread %x\n",
1109 Irp
,PriorityBoost
, Irp
->UserEvent
, PsGetCurrentThread());
1111 ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL
);
1112 ASSERT(!Irp
->CancelRoutine
);
1113 ASSERT(Irp
->IoStatus
.Status
!= STATUS_PENDING
);
1115 /* Get the Current Stack */
1116 StackPtr
= IoGetCurrentIrpStackLocation(Irp
);
1117 IoSkipCurrentIrpStackLocation(Irp
);
1119 /* Loop the Stacks and complete the IRPs */
1120 for (;Irp
->CurrentLocation
<= (Irp
->StackCount
+ 1); StackPtr
++)
1122 /* Set Pending Returned */
1123 Irp
->PendingReturned
= StackPtr
->Control
& SL_PENDING_RETURNED
;
1126 * Completion routines expect the current irp stack location to be the same as when
1127 * IoSetCompletionRoutine was called to set them. A side effect is that completion
1128 * routines set by highest level drivers without their own stack location will receive
1129 * an invalid current stack location (at least it should be considered as invalid).
1130 * Since the DeviceObject argument passed is taken from the current stack, this value
1131 * is also invalid (NULL).
1133 if (Irp
->CurrentLocation
== (Irp
->StackCount
+ 1))
1135 DeviceObject
= NULL
;
1139 DeviceObject
= IoGetCurrentIrpStackLocation(Irp
)->DeviceObject
;
1142 /* Check if there is a Completion Routine to Call */
1143 if ((NT_SUCCESS(Irp
->IoStatus
.Status
) &&
1144 (StackPtr
->Control
& SL_INVOKE_ON_SUCCESS
)) ||
1145 (!NT_SUCCESS(Irp
->IoStatus
.Status
) &&
1146 (StackPtr
->Control
& SL_INVOKE_ON_ERROR
)) ||
1147 (Irp
->Cancel
&& (StackPtr
->Control
& SL_INVOKE_ON_CANCEL
)))
1150 Status
= StackPtr
->CompletionRoutine(DeviceObject
,
1154 /* Don't touch the Packet if this was returned. It might be gone! */
1155 if (Status
== STATUS_MORE_PROCESSING_REQUIRED
) return;
1159 if ((Irp
->CurrentLocation
<= Irp
->StackCount
) && (Irp
->PendingReturned
))
1161 if (IoGetCurrentIrpStackLocation(Irp
)->Control
& SL_PENDING_RETURNED
)
1163 Irp
->PendingReturned
= TRUE
;
1168 /* Move to next stack */
1169 IoSkipCurrentIrpStackLocation(Irp
);
1172 /* Windows NT File System Internals, page 165 */
1173 if (Irp
->Flags
& IRP_ASSOCIATED_IRP
)
1175 ULONG MasterIrpCount
;
1176 PIRP MasterIrp
= Irp
->AssociatedIrp
.MasterIrp
;
1178 DPRINT("Handling Associated IRP\n");
1179 /* This should never happen! */
1180 ASSERT(IsListEmpty(&Irp
->ThreadListEntry
));
1182 /* Decrement and get the old count */
1183 MasterIrpCount
= InterlockedDecrement(&MasterIrp
->AssociatedIrp
.IrpCount
);
1185 /* Free MDLs and IRP */
1186 while ((Mdl
= Irp
->MdlAddress
))
1188 Irp
->MdlAddress
= Mdl
->Next
;
1193 /* Complete the Master IRP */
1194 if (!MasterIrpCount
) IofCompleteRequest(MasterIrp
, IO_NO_INCREMENT
);
1198 /* Windows NT File System Internals, page 165 */
1199 if (Irp
->Flags
& (IRP_PAGING_IO
|IRP_CLOSE_OPERATION
))
1201 DPRINT("Handling Paging or Close I/O\n");
1202 /* This should never happen! */
1203 ASSERT(IsListEmpty(&Irp
->ThreadListEntry
));
1205 /* Handle a Close Operation or Sync Paging I/O (see page 165) */
1206 if (Irp
->Flags
& (IRP_SYNCHRONOUS_PAGING_IO
| IRP_CLOSE_OPERATION
))
1208 /* Set the I/O Status and Signal the Event */
1209 DPRINT("Handling Sync Paging or Close I/O\n");
1210 *Irp
->UserIosb
= Irp
->IoStatus
;
1211 KeSetEvent(Irp
->UserEvent
, PriorityBoost
, FALSE
);
1213 /* Free the IRP for a Paging I/O Only, Close is handled by us */
1214 if (Irp
->Flags
& IRP_SYNCHRONOUS_PAGING_IO
)
1216 DPRINT("Handling Sync Paging I/O\n");
1222 DPRINT1("BUG BUG, YOU SHOULDNT BE HERE\n");
1225 /* When we'll actually support Async Paging I/O Properly... */
1226 KeInitializeApc(&Irp
->Tail
.Apc
1227 &Irp
->tail
.Overlay
.Thread
->Tcb
,
1228 Irp
->ApcEnvironment
,
1229 IopCompletePageWrite
,
1234 KeInsertQueueApc(&Irp
->Tail
.Apc
,
1243 /* Unlock MDL Pages, page 167. */
1244 Mdl
= Irp
->MdlAddress
;
1247 DPRINT("Unlocking MDL: %x\n", Mdl
);
1252 /* Check if we should exit because of a Deferred I/O (page 168) */
1253 if (Irp
->Flags
& IRP_DEFER_IO_COMPLETION
&& !Irp
->PendingReturned
)
1255 DPRINT("Quick return\n");
1259 /* Now queue the special APC */
1262 DPRINT("KMODE APC QUEUE\n");
1263 KeInitializeApc(&Irp
->Tail
.Apc
,
1265 Irp
->ApcEnvironment
,
1268 (PKNORMAL_ROUTINE
) NULL
,
1271 KeInsertQueueApc(&Irp
->Tail
.Apc
,
1273 NULL
, /* This is used for REPARSE stuff */
1278 /* The IRP just got cancelled... does a thread still own it? */
1279 if ((Thread
= Irp
->Tail
.Overlay
.Thread
))
1281 /* Yes! There is still hope! */
1282 DPRINT("KMODE APC QUEUE\n");
1283 KeInitializeApc(&Irp
->Tail
.Apc
,
1285 Irp
->ApcEnvironment
,
1288 (PKNORMAL_ROUTINE
) NULL
,
1291 KeInsertQueueApc(&Irp
->Tail
.Apc
,
1293 NULL
, /* This is used for REPARSE stuff */
1298 /* Nothing left for us to do, kill it */
1299 IopCleanupIrp(Irp
, FileObject
);
1309 IoForwardIrpSynchronously(IN PDEVICE_OBJECT DeviceObject
,
1319 * FUNCTION: Releases a caller allocated irp
1327 PNPAGED_LOOKASIDE_LIST List
;
1328 PP_NPAGED_LOOKASIDE_NUMBER ListType
= LookasideSmallIrpList
;
1331 /* If this was a pool alloc, free it with the pool */
1332 if (!(Irp
->AllocationFlags
& IRP_ALLOCATED_FIXED_SIZE
))
1335 DPRINT("Freeing pool IRP\n");
1340 DPRINT("Freeing Lookaside IRP\n");
1342 /* Check if this was a Big IRP */
1343 if (Irp
->StackCount
!= 1)
1345 DPRINT("Large IRP\n");
1346 ListType
= LookasideLargeIrpList
;
1350 Prcb
= KeGetCurrentPrcb();
1352 /* Use the P List */
1353 List
= (PNPAGED_LOOKASIDE_LIST
)Prcb
->PPLookasideList
[ListType
].P
;
1354 List
->L
.TotalFrees
++;
1356 /* Check if the Free was within the Depth or not */
1357 if (ExQueryDepthSList(&List
->L
.ListHead
) >= List
->L
.Depth
)
1359 /* Let the balancer know */
1360 List
->L
.FreeMisses
++;
1362 /* Use the L List */
1363 List
= (PNPAGED_LOOKASIDE_LIST
)Prcb
->PPLookasideList
[ListType
].L
;
1364 List
->L
.TotalFrees
++;
1366 /* Check if the Free was within the Depth or not */
1367 if (ExQueryDepthSList(&List
->L
.ListHead
) >= List
->L
.Depth
)
1369 /* All lists failed, use the pool */
1370 List
->L
.FreeMisses
++;
1376 /* The free was within dhe Depth */
1379 InterlockedPushEntrySList(&List
->L
.ListHead
, (PSINGLE_LIST_ENTRY
)Irp
);
1383 DPRINT("Free done\n");
1390 IoGetRequestorProcess(IN PIRP Irp
)
1392 return(Irp
->Tail
.Overlay
.Thread
->ThreadsProcess
);
1400 IoGetRequestorProcessId(IN PIRP Irp
)
1402 return (ULONG
)(IoGetRequestorProcess(Irp
)->UniqueProcessId
);
1410 IoGetRequestorSessionId(IN PIRP Irp
,
1411 OUT PULONG pSessionId
)
1413 *pSessionId
= IoGetRequestorProcess(Irp
)->Session
;
1415 return STATUS_SUCCESS
;
1423 IoGetTopLevelIrp(VOID
)
1425 return (PIRP
)PsGetCurrentThread()->TopLevelIrp
;
1431 * FUNCTION: Initalizes an irp allocated by the caller
1433 * Irp = IRP to initalize
1434 * PacketSize = Size in bytes of the IRP
1435 * StackSize = Number of stack locations in the IRP
1439 IoInitializeIrp(PIRP Irp
,
1443 ASSERT(Irp
!= NULL
);
1445 DPRINT("IoInitializeIrp(StackSize %x, Irp %x)\n",StackSize
, Irp
);
1448 RtlZeroMemory(Irp
, PacketSize
);
1450 /* Set the Header and other data */
1451 Irp
->Type
= IO_TYPE_IRP
;
1452 Irp
->Size
= PacketSize
;
1453 Irp
->StackCount
= StackSize
;
1454 Irp
->CurrentLocation
= StackSize
+ 1;
1455 Irp
->ApcEnvironment
= KeGetCurrentThread()->ApcStateIndex
;
1456 Irp
->Tail
.Overlay
.CurrentStackLocation
= (PIO_STACK_LOCATION
)(Irp
+ 1) + StackSize
;
1458 /* Initialize the Thread List */
1459 InitializeListHead(&Irp
->ThreadListEntry
);
1461 DPRINT("Irp->Tail.Overlay.CurrentStackLocation %x\n", Irp
->Tail
.Overlay
.CurrentStackLocation
);
1466 * IoIsOperationSynchronous@4
1469 * Check if the I/O operation associated with the given IRP
1473 * Irp Packet to check.
1476 * TRUE if Irp's operation is synchronous; otherwise FALSE.
1482 IoIsOperationSynchronous(IN PIRP Irp
)
1484 /* Check the flags */
1485 if ((Irp
->Flags
& IRP_SYNCHRONOUS_PAGING_IO
) ||
1486 (Irp
->Flags
& IRP_SYNCHRONOUS_API
) ||
1487 (IoGetCurrentIrpStackLocation(Irp
)->FileObject
->Flags
&
1490 /* Synch API or Paging I/O is OK, as is Sync File I/O */
1494 /* Otherwise, it is an asynchronous operation. */
1503 IoIsValidNameGraftingBuffer(IN PIRP Irp
,
1504 IN PREPARSE_DATA_BUFFER ReparseBuffer
)
1513 * FUNCTION: Allocates and initializes an irp to associated with a master irp
1516 * StackSize = Number of stack locations to be allocated in the irp
1517 * RETURNS: The irp allocated
1518 * NOTE: The caller is responsible for incrementing
1519 * Irp->AssociatedIrp.IrpCount.
1523 IoMakeAssociatedIrp(PIRP Irp
,
1528 /* Allocate the IRP */
1529 AssocIrp
= IoAllocateIrp(StackSize
, FALSE
);
1530 if (AssocIrp
== NULL
) return NULL
;
1533 AssocIrp
->Flags
|= IRP_ASSOCIATED_IRP
;
1535 /* Set the Thread */
1536 AssocIrp
->Tail
.Overlay
.Thread
= Irp
->Tail
.Overlay
.Thread
;
1538 /* Associate them */
1539 AssocIrp
->AssociatedIrp
.MasterIrp
= Irp
;
1549 IoPageRead(PFILE_OBJECT FileObject
,
1551 PLARGE_INTEGER Offset
,
1553 PIO_STATUS_BLOCK StatusBlock
)
1556 PIO_STACK_LOCATION StackPtr
;
1557 PDEVICE_OBJECT DeviceObject
;
1559 DPRINT("IoPageRead(FileObject %x, Mdl %x)\n",
1562 /* Get the Device Object */
1563 DeviceObject
= IoGetRelatedDeviceObject(FileObject
);
1566 Irp
= IoAllocateIrp(DeviceObject
->StackSize
, FALSE
);
1569 StackPtr
= IoGetNextIrpStackLocation(Irp
);
1571 /* Create the IRP Settings */
1572 Irp
->MdlAddress
= Mdl
;
1573 Irp
->UserBuffer
= MmGetMdlVirtualAddress(Mdl
);
1574 Irp
->UserIosb
= StatusBlock
;
1575 Irp
->UserEvent
= Event
;
1576 Irp
->RequestorMode
= KernelMode
;
1577 Irp
->Flags
= IRP_PAGING_IO
| IRP_NOCACHE
| IRP_SYNCHRONOUS_PAGING_IO
| IRP_INPUT_OPERATION
;
1578 Irp
->Tail
.Overlay
.OriginalFileObject
= FileObject
;
1579 Irp
->Tail
.Overlay
.Thread
= PsGetCurrentThread();
1581 /* Set the Stack Settings */
1582 StackPtr
->Parameters
.Read
.Length
= MmGetMdlByteCount(Mdl
);
1583 StackPtr
->Parameters
.Read
.ByteOffset
= *Offset
;
1584 StackPtr
->MajorFunction
= IRP_MJ_READ
;
1585 StackPtr
->FileObject
= FileObject
;
1587 /* Call the Driver */
1588 return IofCallDriver(DeviceObject
, Irp
);
1596 IoQueueThreadIrp(IN PIRP Irp
)
1601 OldIrql
= KfRaiseIrql(APC_LEVEL
);
1604 * Synchronous irp's are queued to requestor thread. If they are not
1605 * completed when the thread exits, they are canceled (cleaned up).
1608 InsertTailList(&Irp
->Tail
.Overlay
.Thread
->IrpList
, &Irp
->ThreadListEntry
);
1611 KfLowerIrql(OldIrql
);
1616 * Reference: Chris Cant's "Writing WDM Device Drivers"
1620 IoReuseIrp(IN OUT PIRP Irp
,
1623 UCHAR AllocationFlags
;
1625 /* Get the old flags */
1626 AllocationFlags
= Irp
->AllocationFlags
;
1628 /* Reinitialize the IRP */
1629 IoInitializeIrp(Irp
, Irp
->Size
, Irp
->StackCount
);
1631 /* Duplicate the data */
1632 Irp
->IoStatus
.Status
= Status
;
1633 Irp
->AllocationFlags
= AllocationFlags
;
1641 IoSetTopLevelIrp(IN PIRP Irp
)
1643 PsGetCurrentThread()->TopLevelIrp
= (ULONG
)Irp
;
1651 IoSynchronousPageWrite(PFILE_OBJECT FileObject
,
1653 PLARGE_INTEGER Offset
,
1655 PIO_STATUS_BLOCK StatusBlock
)
1658 PIO_STACK_LOCATION StackPtr
;
1659 PDEVICE_OBJECT DeviceObject
;
1661 DPRINT("IoSynchronousPageWrite(FileObject %x, Mdl %x)\n",
1664 /* Get the Device Object */
1665 DeviceObject
= IoGetRelatedDeviceObject(FileObject
);
1668 Irp
= IoAllocateIrp(DeviceObject
->StackSize
, FALSE
);
1671 StackPtr
= IoGetNextIrpStackLocation(Irp
);
1673 /* Create the IRP Settings */
1674 Irp
->MdlAddress
= Mdl
;
1675 Irp
->UserBuffer
= MmGetMdlVirtualAddress(Mdl
);
1676 Irp
->UserIosb
= StatusBlock
;
1677 Irp
->UserEvent
= Event
;
1678 Irp
->RequestorMode
= KernelMode
;
1679 Irp
->Flags
= IRP_PAGING_IO
| IRP_NOCACHE
| IRP_SYNCHRONOUS_PAGING_IO
;
1680 Irp
->Tail
.Overlay
.OriginalFileObject
= FileObject
;
1681 Irp
->Tail
.Overlay
.Thread
= PsGetCurrentThread();
1683 /* Set the Stack Settings */
1684 StackPtr
->Parameters
.Write
.Length
= MmGetMdlByteCount(Mdl
);
1685 StackPtr
->Parameters
.Write
.ByteOffset
= *Offset
;
1686 StackPtr
->MajorFunction
= IRP_MJ_WRITE
;
1687 StackPtr
->FileObject
= FileObject
;
1689 /* Call the Driver */
1690 return IofCallDriver(DeviceObject
, Irp
);