/* * PROJECT: ReactOS Kernel * LICENSE: GPL - See COPYING in the top level directory * FILE: ntoskrnl/io/iomgr/irp.c * PURPOSE: IRP Handling Functions * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org) * Gunnar Dalsnes * Filip Navara (navaraf@reactos.org) * Pierre Schweitzer (pierre@reactos.org) */ /* INCLUDES ****************************************************************/ #include #define NDEBUG #include PIRP IopDeadIrp; RESERVE_IRP_ALLOCATOR IopReserveIrpAllocator; /* PRIVATE FUNCTIONS ********************************************************/ VOID NTAPI IopFreeIrpKernelApc(IN PKAPC Apc, IN PKNORMAL_ROUTINE *NormalRoutine, IN PVOID *NormalContext, IN PVOID *SystemArgument1, IN PVOID *SystemArgument2) { /* Free the IRP */ IoFreeIrp(CONTAINING_RECORD(Apc, IRP, Tail.Apc)); } VOID NTAPI IopAbortIrpKernelApc(IN PKAPC Apc) { /* Free the IRP */ IoFreeIrp(CONTAINING_RECORD(Apc, IRP, Tail.Apc)); } NTSTATUS NTAPI IopCleanupFailedIrp(IN PFILE_OBJECT FileObject, IN PKEVENT EventObject OPTIONAL, IN PVOID Buffer OPTIONAL) { PAGED_CODE(); /* Dereference the event */ if (EventObject) ObDereferenceObject(EventObject); /* Free a buffer, if any */ if (Buffer) ExFreePool(Buffer); /* If this was a file opened for synch I/O, then unlock it */ if (FileObject->Flags & FO_SYNCHRONOUS_IO) IopUnlockFileObject(FileObject); /* Now dereference it and return */ ObDereferenceObject(FileObject); return STATUS_INSUFFICIENT_RESOURCES; } VOID NTAPI IopAbortInterruptedIrp(IN PKEVENT EventObject, IN PIRP Irp) { KIRQL OldIrql; BOOLEAN CancelResult; LARGE_INTEGER Wait; PAGED_CODE(); /* Raise IRQL to APC */ KeRaiseIrql(APC_LEVEL, &OldIrql); /* Check if nobody completed it yet */ if (!KeReadStateEvent(EventObject)) { /* First, cancel it */ CancelResult = IoCancelIrp(Irp); KeLowerIrql(OldIrql); /* Check if we cancelled it */ if (CancelResult) { /* Wait for the IRP to be cancelled */ Wait.QuadPart = -100000; while (!KeReadStateEvent(EventObject)) { /* Delay indefintely */ KeDelayExecutionThread(KernelMode, FALSE, &Wait); } } else { /* No cancellation done, so wait for the I/O system to kill it */ KeWaitForSingleObject(EventObject, Executive, KernelMode, FALSE, NULL); } } else { /* We got preempted, so give up */ KeLowerIrql(OldIrql); } } VOID NTAPI IopDisassociateThreadIrp(VOID) { KIRQL OldIrql, LockIrql; PETHREAD IrpThread; PLIST_ENTRY IrpEntry; PIO_ERROR_LOG_PACKET ErrorLogEntry; PDEVICE_OBJECT DeviceObject = NULL; PIO_STACK_LOCATION IoStackLocation; /* First, raise to APC to protect IrpList */ KeRaiseIrql(APC_LEVEL, &OldIrql); /* Get the Thread and check the list */ IrpThread = PsGetCurrentThread(); if (IsListEmpty(&IrpThread->IrpList)) { /* It got completed now, so quit */ KeLowerIrql(OldIrql); return; } /* Ensure no one will come disturb */ LockIrql = KeAcquireQueuedSpinLock(LockQueueIoCompletionLock); /* Get the misbehaving IRP */ IrpEntry = IrpThread->IrpList.Flink; IopDeadIrp = CONTAINING_RECORD(IrpEntry, IRP, ThreadListEntry); IOTRACE(IO_IRP_DEBUG, "%s - Deassociating IRP %p for %p\n", __FUNCTION__, IopDeadIrp, IrpThread); /* Don't cancel the IRP if it's already been completed far */ if (IopDeadIrp->CurrentLocation == (IopDeadIrp->StackCount + 2)) { /* Return */ KeReleaseQueuedSpinLock(LockQueueIoCompletionLock, LockIrql); KeLowerIrql(OldIrql); return; } /* Disown the IRP! */ IopDeadIrp->Tail.Overlay.Thread = NULL; RemoveHeadList(&IrpThread->IrpList); InitializeListHead(&IopDeadIrp->ThreadListEntry); /* Get the stack location and check if it's valid */ IoStackLocation = IoGetCurrentIrpStackLocation(IopDeadIrp); if (IopDeadIrp->CurrentLocation <= IopDeadIrp->StackCount) { /* Get the device object */ DeviceObject = IoStackLocation->DeviceObject; } KeReleaseQueuedSpinLock(LockQueueIoCompletionLock, LockIrql); /* Lower IRQL now, since we have the pointers we need */ KeLowerIrql(OldIrql); /* Check if we can send an Error Log Entry*/ if (DeviceObject) { /* Allocate an entry */ ErrorLogEntry = IoAllocateErrorLogEntry(DeviceObject, sizeof(IO_ERROR_LOG_PACKET)); if (ErrorLogEntry) { /* Write the entry */ ErrorLogEntry->ErrorCode = IO_DRIVER_CANCEL_TIMEOUT; IoWriteErrorLogEntry(ErrorLogEntry); } } } VOID NTAPI IopCleanupIrp(IN PIRP Irp, IN PFILE_OBJECT FileObject) { PMDL Mdl; IOTRACE(IO_IRP_DEBUG, "%s - Cleaning IRP %p for %p\n", __FUNCTION__, Irp, FileObject); /* Check if there's an MDL */ while ((Mdl = Irp->MdlAddress)) { /* Clear all of them */ Irp->MdlAddress = Mdl->Next; IoFreeMdl(Mdl); } /* Check if the IRP has system buffer */ if (Irp->Flags & IRP_DEALLOCATE_BUFFER) { /* Free the buffer */ ExFreePoolWithTag(Irp->AssociatedIrp.SystemBuffer, TAG_SYS_BUF); } /* Check if this IRP has a user event, a file object, and is async */ if ((Irp->UserEvent) && !(Irp->Flags & IRP_SYNCHRONOUS_API) && (FileObject)) { /* Dereference the User Event */ ObDereferenceObject(Irp->UserEvent); } /* Check if we have a file object and this isn't a create operation */ if ((FileObject) && !(Irp->Flags & IRP_CREATE_OPERATION)) { /* Dereference the file object */ ObDereferenceObject(FileObject); } /* Free the IRP */ IoFreeIrp(Irp); } VOID NTAPI IopCompleteRequest(IN PKAPC Apc, IN PKNORMAL_ROUTINE* NormalRoutine, IN PVOID* NormalContext, IN PVOID* SystemArgument1, IN PVOID* SystemArgument2) { PFILE_OBJECT FileObject; PIRP Irp; PMDL Mdl, NextMdl; PVOID Port = NULL, Key = NULL; BOOLEAN SignaledCreateRequest = FALSE; /* Get data from the APC */ FileObject = (PFILE_OBJECT)*SystemArgument1; Irp = CONTAINING_RECORD(Apc, IRP, Tail.Apc); IOTRACE(IO_IRP_DEBUG, "%s - Completing IRP %p for %p\n", __FUNCTION__, Irp, FileObject); /* Sanity check */ ASSERT(Irp->IoStatus.Status != (NTSTATUS)0xFFFFFFFF); /* Check if we have a file object */ if (*SystemArgument2) { /* Check if we're reparsing */ if ((Irp->IoStatus.Status == STATUS_REPARSE) && (Irp->IoStatus.Information == IO_REPARSE_TAG_MOUNT_POINT)) { PREPARSE_DATA_BUFFER ReparseData; ReparseData = (PREPARSE_DATA_BUFFER)*SystemArgument2; ASSERT(ReparseData->ReparseTag == IO_REPARSE_TAG_MOUNT_POINT); ASSERT(ReparseData->ReparseDataLength < MAXIMUM_REPARSE_DATA_BUFFER_SIZE); ASSERT(ReparseData->Reserved < MAXIMUM_REPARSE_DATA_BUFFER_SIZE); IopDoNameTransmogrify(Irp, FileObject, ReparseData); } } /* Handle Buffered case first */ if (Irp->Flags & IRP_BUFFERED_IO) { /* Check if we have an input buffer and if we succeeded */ if ((Irp->Flags & IRP_INPUT_OPERATION) && (Irp->IoStatus.Status != STATUS_VERIFY_REQUIRED) && !(NT_ERROR(Irp->IoStatus.Status))) { _SEH2_TRY { /* Copy the buffer back to the user */ RtlCopyMemory(Irp->UserBuffer, Irp->AssociatedIrp.SystemBuffer, Irp->IoStatus.Information); } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { /* Fail the IRP */ Irp->IoStatus.Status = _SEH2_GetExceptionCode(); } _SEH2_END; } /* Also check if we should de-allocate it */ if (Irp->Flags & IRP_DEALLOCATE_BUFFER) { /* Deallocate it */ ExFreePool(Irp->AssociatedIrp.SystemBuffer); } } /* Now we got rid of these two... */ Irp->Flags &= ~(IRP_BUFFERED_IO | IRP_DEALLOCATE_BUFFER); /* Check if there's an MDL */ for (Mdl = Irp->MdlAddress; Mdl; Mdl = NextMdl) { /* Free it */ NextMdl = Mdl->Next; IoFreeMdl(Mdl); } /* No MDLs left */ Irp->MdlAddress = NULL; /* * Check if either the request was completed without any errors * (but warnings are OK!), or if it was completed with an error, but * did return from a pending I/O Operation and is not synchronous. */ if (!NT_ERROR(Irp->IoStatus.Status) || (Irp->PendingReturned && !IsIrpSynchronous(Irp, FileObject))) { /* Get any information we need from the FO before we kill it */ if ((FileObject) && (FileObject->CompletionContext)) { /* Save Completion Data */ Port = FileObject->CompletionContext->Port; Key = FileObject->CompletionContext->Key; } /* Check for UserIos */ if (Irp->UserIosb != NULL) { /* Use SEH to make sure we don't write somewhere invalid */ _SEH2_TRY { /* Save the IOSB Information */ *Irp->UserIosb = Irp->IoStatus; } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { /* Ignore any error */ } _SEH2_END; } /* Check if we have an event or a file object */ if (Irp->UserEvent) { /* At the very least, this is a PKEVENT, so signal it always */ KeSetEvent(Irp->UserEvent, 0, FALSE); /* Check if we also have a File Object */ if (FileObject) { /* Check if this is an Asynch API */ if (!(Irp->Flags & IRP_SYNCHRONOUS_API)) { /* Dereference the event */ ObDereferenceObject(Irp->UserEvent); } /* * Now, if this is a Synch I/O File Object, then this event is * NOT an actual Executive Event, so we won't dereference it, * and instead, we will signal the File Object */ if ((FileObject->Flags & FO_SYNCHRONOUS_IO) && !(Irp->Flags & IRP_OB_QUERY_NAME)) { /* Signal the file object and set the status */ KeSetEvent(&FileObject->Event, 0, FALSE); FileObject->FinalStatus = Irp->IoStatus.Status; } /* * This could also be a create operation, in which case we want * to make sure there's no APC fired. */ if (Irp->Flags & IRP_CREATE_OPERATION) { /* Clear the APC Routine and remember this */ Irp->Overlay.AsynchronousParameters.UserApcRoutine = NULL; SignaledCreateRequest = TRUE; } } } else if (FileObject) { /* Signal the file object and set the status */ KeSetEvent(&FileObject->Event, 0, FALSE); FileObject->FinalStatus = Irp->IoStatus.Status; /* * This could also be a create operation, in which case we want * to make sure there's no APC fired. */ if (Irp->Flags & IRP_CREATE_OPERATION) { /* Clear the APC Routine and remember this */ Irp->Overlay.AsynchronousParameters.UserApcRoutine = NULL; SignaledCreateRequest = TRUE; } } /* Update transfer count for everything but create operation */ if (!(Irp->Flags & IRP_CREATE_OPERATION)) { if (Irp->Flags & IRP_WRITE_OPERATION) { /* Update write transfer count */ IopUpdateTransferCount(IopWriteTransfer, (ULONG)Irp->IoStatus.Information); } else if (Irp->Flags & IRP_READ_OPERATION) { /* Update read transfer count */ IopUpdateTransferCount(IopReadTransfer, (ULONG)Irp->IoStatus.Information); } else { /* Update other transfer count */ IopUpdateTransferCount(IopOtherTransfer, (ULONG)Irp->IoStatus.Information); } } /* Now that we've signaled the events, de-associate the IRP */ IopUnQueueIrpFromThread(Irp); /* Now check if a User APC Routine was requested */ if (Irp->Overlay.AsynchronousParameters.UserApcRoutine) { /* Initialize it */ KeInitializeApc(&Irp->Tail.Apc, KeGetCurrentThread(), CurrentApcEnvironment, IopFreeIrpKernelApc, IopAbortIrpKernelApc, (PKNORMAL_ROUTINE)Irp-> Overlay.AsynchronousParameters.UserApcRoutine, Irp->RequestorMode, Irp-> Overlay.AsynchronousParameters.UserApcContext); /* Queue it */ KeInsertQueueApc(&Irp->Tail.Apc, Irp->UserIosb, NULL, 2); } else if ((Port) && (Irp->Overlay.AsynchronousParameters.UserApcContext)) { /* We have an I/O Completion setup... create the special Overlay */ Irp->Tail.CompletionKey = Key; Irp->Tail.Overlay.PacketType = IopCompletionPacketIrp; KeInsertQueue(Port, &Irp->Tail.Overlay.ListEntry); } else { /* Free the IRP since we don't need it anymore */ IoFreeIrp(Irp); } /* Check if we have a file object that wasn't part of a create */ if ((FileObject) && !(SignaledCreateRequest)) { /* Dereference it, since it's not needed anymore either */ ObDereferenceObjectDeferDelete(FileObject); } } else { /* * Either we didn't return from the request, or we did return but this * request was synchronous. */ if ((Irp->PendingReturned) && (FileObject)) { /* So we did return with a synch operation, was it the IRP? */ if (Irp->Flags & IRP_SYNCHRONOUS_API) { /* Yes, this IRP was synchronous, so return the I/O Status */ *Irp->UserIosb = Irp->IoStatus; /* Now check if the user gave an event */ if (Irp->UserEvent) { /* Signal it */ KeSetEvent(Irp->UserEvent, 0, FALSE); } else { /* No event was given, so signal the FO instead */ KeSetEvent(&FileObject->Event, 0, FALSE); } } else { /* * It's not the IRP that was synchronous, it was the FO * that was opened this way. Signal its event. */ FileObject->FinalStatus = Irp->IoStatus.Status; KeSetEvent(&FileObject->Event, 0, FALSE); } } /* Now that we got here, we do this for incomplete I/Os as well */ if ((FileObject) && !(Irp->Flags & IRP_CREATE_OPERATION)) { /* Dereference the File Object unless this was a create */ ObDereferenceObjectDeferDelete(FileObject); } /* * Check if this was an Executive Event (remember that we know this * by checking if the IRP is synchronous) */ if ((Irp->UserEvent) && (FileObject) && !(Irp->Flags & IRP_SYNCHRONOUS_API)) { /* This isn't a PKEVENT, so dereference it */ ObDereferenceObject(Irp->UserEvent); } /* Now that we've signaled the events, de-associate the IRP */ IopUnQueueIrpFromThread(Irp); /* Free the IRP as well */ IoFreeIrp(Irp); } } BOOLEAN NTAPI IopInitializeReserveIrp(IN PRESERVE_IRP_ALLOCATOR ReserveIrpAllocator) { /* Our allocated stack size */ ReserveIrpAllocator->StackSize = 20; /* Allocate the IRP now */ ReserveIrpAllocator->ReserveIrp = IoAllocateIrp(ReserveIrpAllocator->StackSize, FALSE); /* If we cannot, abort system boot */ if (ReserveIrpAllocator->ReserveIrp == NULL) { return FALSE; } /* It's not in use */ ReserveIrpAllocator->ReserveIrpInUse = 0; /* And init the event */ KeInitializeEvent(&ReserveIrpAllocator->WaitEvent, SynchronizationEvent, FALSE); /* All good, keep booting */ return TRUE; } PIRP NTAPI IopAllocateReserveIrp(IN CCHAR StackSize) { /* If we need a stack size higher than what was allocated, then fail */ if (StackSize > IopReserveIrpAllocator.StackSize) { return NULL; } /* Now, wait until the IRP becomes available and reserve it immediately */ while (InterlockedExchange(&IopReserveIrpAllocator.ReserveIrpInUse, 1) == 1) { KeWaitForSingleObject(&IopReserveIrpAllocator.WaitEvent, Executive, KernelMode, FALSE, NULL); } /* It's ours! Initialize it */ IoInitializeIrp(IopReserveIrpAllocator.ReserveIrp, IoSizeOfIrp(StackSize), StackSize); /* And return it to the caller */ return IopReserveIrpAllocator.ReserveIrp; } VOID IopFreeReserveIrp(IN CCHAR PriorityBoost) { /* Mark we don't use the IRP anymore */ InterlockedExchange(&IopReserveIrpAllocator.ReserveIrpInUse, 0); /* And set the event if someone is waiting on the IRP */ KeSetEvent(&IopReserveIrpAllocator.WaitEvent, PriorityBoost, FALSE); } /* FUNCTIONS *****************************************************************/ /* * @implemented */ PIRP NTAPI IoAllocateIrp(IN CCHAR StackSize, IN BOOLEAN ChargeQuota) { PIRP Irp = NULL; USHORT Size = IoSizeOfIrp(StackSize); PKPRCB Prcb; UCHAR Flags = 0; PNPAGED_LOOKASIDE_LIST List = NULL; PP_NPAGED_LOOKASIDE_NUMBER ListType = LookasideSmallIrpList; /* Set Charge Quota Flag */ if (ChargeQuota) Flags |= IRP_QUOTA_CHARGED; /* Get the PRCB */ Prcb = KeGetCurrentPrcb(); /* Figure out which Lookaside List to use */ if ((StackSize <= 8) && (ChargeQuota == FALSE || Prcb->LookasideIrpFloat > 0)) { /* Set Fixed Size Flag */ Flags |= IRP_ALLOCATED_FIXED_SIZE; /* See if we should use big list */ if (StackSize != 1) { Size = IoSizeOfIrp(8); ListType = LookasideLargeIrpList; } /* Get the P List First */ List = (PNPAGED_LOOKASIDE_LIST)Prcb->PPLookasideList[ListType].P; /* Attempt allocation */ List->L.TotalAllocates++; Irp = (PIRP)InterlockedPopEntrySList(&List->L.ListHead); /* Check if the P List failed */ if (!Irp) { /* Let the balancer know */ List->L.AllocateMisses++; /* Try the L List */ List = (PNPAGED_LOOKASIDE_LIST)Prcb->PPLookasideList[ListType].L; List->L.TotalAllocates++; Irp = (PIRP)InterlockedPopEntrySList(&List->L.ListHead); } } /* Check if we have to use the pool */ if (!Irp) { /* Did we try lookaside and fail? */ if (Flags & IRP_ALLOCATED_FIXED_SIZE) List->L.AllocateMisses++; /* Check if we should charge quota */ if (ChargeQuota) { Irp = ExAllocatePoolWithQuotaTag(NonPagedPool | POOL_QUOTA_FAIL_INSTEAD_OF_RAISE, Size, TAG_IRP); } else { /* Allocate the IRP with no quota charge */ Irp = ExAllocatePoolWithTag(NonPagedPool, Size, TAG_IRP); } /* Make sure it was sucessful */ if (!Irp) return NULL; } else if (Flags & IRP_QUOTA_CHARGED) { /* Decrement lookaside float */ InterlockedDecrement(&Prcb->LookasideIrpFloat); Flags |= IRP_LOOKASIDE_ALLOCATION; /* In this case there is no charge quota */ Flags &= ~IRP_QUOTA_CHARGED; } /* Now Initialize it */ IoInitializeIrp(Irp, Size, StackSize); /* Set the Allocation Flags */ Irp->AllocationFlags = Flags; /* Return it */ IOTRACE(IO_IRP_DEBUG, "%s - Allocated IRP %p with allocation flags %lx\n", __FUNCTION__, Irp, Flags); return Irp; } /* * @implemented */ PIRP NTAPI IopAllocateIrpMustSucceed(IN CCHAR StackSize) { LONG i; PIRP Irp; LARGE_INTEGER Sleep; /* Try to get an IRP */ Irp = IoAllocateIrp(StackSize, FALSE); if (Irp) return Irp; /* If we fail, start looping till we may get one */ i = LONG_MAX; do { i--; /* First, sleep for 10ms */ Sleep.QuadPart = -10 * 1000 * 10; KeDelayExecutionThread(KernelMode, FALSE, &Sleep); /* Then, retry allocation */ Irp = IoAllocateIrp(StackSize, FALSE); if (Irp) return Irp; } while (i > 0); return Irp; } /* * @implemented */ PIRP NTAPI IoBuildAsynchronousFsdRequest(IN ULONG MajorFunction, IN PDEVICE_OBJECT DeviceObject, IN PVOID Buffer, IN ULONG Length, IN PLARGE_INTEGER StartingOffset, IN PIO_STATUS_BLOCK IoStatusBlock) { PIRP Irp; PIO_STACK_LOCATION StackPtr; /* Allocate IRP */ Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE); if (!Irp) return NULL; /* Get the Stack */ StackPtr = IoGetNextIrpStackLocation(Irp); /* Write the Major function and then deal with it */ StackPtr->MajorFunction = (UCHAR)MajorFunction; /* Do not handle the following here */ if ((MajorFunction != IRP_MJ_FLUSH_BUFFERS) && (MajorFunction != IRP_MJ_SHUTDOWN) && (MajorFunction != IRP_MJ_PNP) && (MajorFunction != IRP_MJ_POWER)) { /* Check if this is Buffered IO */ if (DeviceObject->Flags & DO_BUFFERED_IO) { /* Allocate the System Buffer */ Irp->AssociatedIrp.SystemBuffer = ExAllocatePoolWithTag(NonPagedPool, Length, TAG_SYS_BUF); if (!Irp->AssociatedIrp.SystemBuffer) { /* Free the IRP and fail */ IoFreeIrp(Irp); return NULL; } /* Set flags */ Irp->Flags = IRP_BUFFERED_IO | IRP_DEALLOCATE_BUFFER; /* Handle special IRP_MJ_WRITE Case */ if (MajorFunction == IRP_MJ_WRITE) { /* Copy the buffer data */ RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer, Buffer, Length); } else { /* Set the Input Operation flag and set this as a User Buffer */ Irp->Flags |= IRP_INPUT_OPERATION; Irp->UserBuffer = Buffer; } } else if (DeviceObject->Flags & DO_DIRECT_IO) { /* Use an MDL for Direct I/O */ Irp->MdlAddress = IoAllocateMdl(Buffer, Length, FALSE, FALSE, NULL); if (!Irp->MdlAddress) { /* Free the IRP and fail */ IoFreeIrp(Irp); return NULL; } /* Probe and Lock */ _SEH2_TRY { /* Do the probe */ MmProbeAndLockPages(Irp->MdlAddress, KernelMode, MajorFunction == IRP_MJ_READ ? IoWriteAccess : IoReadAccess); } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { /* Free the IRP and its MDL */ IoFreeMdl(Irp->MdlAddress); IoFreeIrp(Irp); /* Fail */ _SEH2_YIELD(return NULL); } _SEH2_END; } else { /* Neither, use the buffer */ Irp->UserBuffer = Buffer; } /* Check if this is a read */ if (MajorFunction == IRP_MJ_READ) { /* Set the parameters for a read */ StackPtr->Parameters.Read.Length = Length; StackPtr->Parameters.Read.ByteOffset = *StartingOffset; } else if (MajorFunction == IRP_MJ_WRITE) { /* Otherwise, set write parameters */ StackPtr->Parameters.Write.Length = Length; StackPtr->Parameters.Write.ByteOffset = *StartingOffset; } } /* Set the Current Thread and IOSB */ Irp->UserIosb = IoStatusBlock; Irp->Tail.Overlay.Thread = PsGetCurrentThread(); /* Return the IRP */ IOTRACE(IO_IRP_DEBUG, "%s - Built IRP %p with Major, Buffer, DO %lx %p %p\n", __FUNCTION__, Irp, MajorFunction, Buffer, DeviceObject); return Irp; } /* * @implemented */ PIRP NTAPI IoBuildDeviceIoControlRequest(IN ULONG IoControlCode, IN PDEVICE_OBJECT DeviceObject, IN PVOID InputBuffer, IN ULONG InputBufferLength, IN PVOID OutputBuffer, IN ULONG OutputBufferLength, IN BOOLEAN InternalDeviceIoControl, IN PKEVENT Event, IN PIO_STATUS_BLOCK IoStatusBlock) { PIRP Irp; PIO_STACK_LOCATION StackPtr; ULONG BufferLength; /* Allocate IRP */ Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE); if (!Irp) return NULL; /* Get the Stack */ StackPtr = IoGetNextIrpStackLocation(Irp); /* Set the DevCtl Type */ StackPtr->MajorFunction = InternalDeviceIoControl ? IRP_MJ_INTERNAL_DEVICE_CONTROL : IRP_MJ_DEVICE_CONTROL; /* Set the IOCTL Data */ StackPtr->Parameters.DeviceIoControl.IoControlCode = IoControlCode; StackPtr->Parameters.DeviceIoControl.InputBufferLength = InputBufferLength; StackPtr->Parameters.DeviceIoControl.OutputBufferLength = OutputBufferLength; /* Handle the Methods */ switch (IO_METHOD_FROM_CTL_CODE(IoControlCode)) { /* Buffered I/O */ case METHOD_BUFFERED: /* Select the right Buffer Length */ BufferLength = InputBufferLength > OutputBufferLength ? InputBufferLength : OutputBufferLength; /* Make sure there is one */ if (BufferLength) { /* Allocate the System Buffer */ Irp->AssociatedIrp.SystemBuffer = ExAllocatePoolWithTag(NonPagedPool, BufferLength, TAG_SYS_BUF); if (!Irp->AssociatedIrp.SystemBuffer) { /* Free the IRP and fail */ IoFreeIrp(Irp); return NULL; } /* Check if we got a buffer */ if (InputBuffer) { /* Copy into the System Buffer */ RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer, InputBuffer, InputBufferLength); } /* Write the flags */ Irp->Flags = IRP_BUFFERED_IO | IRP_DEALLOCATE_BUFFER; if (OutputBuffer) Irp->Flags |= IRP_INPUT_OPERATION; /* Save the Buffer */ Irp->UserBuffer = OutputBuffer; } else { /* Clear the Flags and Buffer */ Irp->Flags = 0; Irp->UserBuffer = NULL; } break; /* Direct I/O */ case METHOD_IN_DIRECT: case METHOD_OUT_DIRECT: /* Check if we got an input buffer */ if (InputBuffer) { /* Allocate the System Buffer */ Irp->AssociatedIrp.SystemBuffer = ExAllocatePoolWithTag(NonPagedPool, InputBufferLength, TAG_SYS_BUF); if (!Irp->AssociatedIrp.SystemBuffer) { /* Free the IRP and fail */ IoFreeIrp(Irp); return NULL; } /* Copy into the System Buffer */ RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer, InputBuffer, InputBufferLength); /* Write the flags */ Irp->Flags = IRP_BUFFERED_IO | IRP_DEALLOCATE_BUFFER; } else { /* Clear the flags */ Irp->Flags = 0; } /* Check if we got an output buffer */ if (OutputBuffer) { /* Allocate the System Buffer */ Irp->MdlAddress = IoAllocateMdl(OutputBuffer, OutputBufferLength, FALSE, FALSE, Irp); if (!Irp->MdlAddress) { /* Free the IRP and fail */ IoFreeIrp(Irp); return NULL; } /* Probe and Lock */ _SEH2_TRY { /* Do the probe */ MmProbeAndLockPages(Irp->MdlAddress, KernelMode, IO_METHOD_FROM_CTL_CODE(IoControlCode) == METHOD_IN_DIRECT ? IoReadAccess : IoWriteAccess); } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { /* Free the MDL */ IoFreeMdl(Irp->MdlAddress); /* Free the input buffer and IRP */ if (InputBuffer) ExFreePool(Irp->AssociatedIrp.SystemBuffer); IoFreeIrp(Irp); /* Fail */ _SEH2_YIELD(return NULL); } _SEH2_END; } break; case METHOD_NEITHER: /* Just save the Buffer */ Irp->UserBuffer = OutputBuffer; StackPtr->Parameters.DeviceIoControl.Type3InputBuffer = InputBuffer; } /* Now write the Event and IoSB */ Irp->UserIosb = IoStatusBlock; Irp->UserEvent = Event; /* Sync IRPs are queued to requestor thread's irp cancel/cleanup list */ Irp->Tail.Overlay.Thread = PsGetCurrentThread(); IoQueueThreadIrp(Irp); /* Return the IRP */ IOTRACE(IO_IRP_DEBUG, "%s - Built IRP %p with IOCTL, Buffers, DO %lx %p %p %p\n", __FUNCTION__, Irp, IoControlCode, InputBuffer, OutputBuffer, DeviceObject); return Irp; } /* * @implemented */ PIRP NTAPI IoBuildSynchronousFsdRequest(IN ULONG MajorFunction, IN PDEVICE_OBJECT DeviceObject, IN PVOID Buffer, IN ULONG Length, IN PLARGE_INTEGER StartingOffset, IN PKEVENT Event, IN PIO_STATUS_BLOCK IoStatusBlock) { PIRP Irp; /* Do the big work to set up the IRP */ Irp = IoBuildAsynchronousFsdRequest(MajorFunction, DeviceObject, Buffer, Length, StartingOffset, IoStatusBlock ); if (!Irp) return NULL; /* Set the Event which makes it Syncronous */ Irp->UserEvent = Event; /* Sync IRPs are queued to requestor thread's irp cancel/cleanup list */ IoQueueThreadIrp(Irp); return Irp; } /* * @implemented */ BOOLEAN NTAPI IoCancelIrp(IN PIRP Irp) { KIRQL OldIrql; PDRIVER_CANCEL CancelRoutine; IOTRACE(IO_IRP_DEBUG, "%s - Canceling IRP %p\n", __FUNCTION__, Irp); ASSERT(Irp->Type == IO_TYPE_IRP); /* Acquire the cancel lock and cancel the IRP */ IoAcquireCancelSpinLock(&OldIrql); Irp->Cancel = TRUE; /* Clear the cancel routine and get the old one */ CancelRoutine = IoSetCancelRoutine(Irp, NULL); if (CancelRoutine) { /* We had a routine, make sure the IRP isn't completed */ if (Irp->CurrentLocation > (Irp->StackCount + 1)) { /* It is, bugcheck */ KeBugCheckEx(CANCEL_STATE_IN_COMPLETED_IRP, (ULONG_PTR)Irp, (ULONG_PTR)CancelRoutine, 0, 0); } /* Set the cancel IRQL And call the routine */ Irp->CancelIrql = OldIrql; CancelRoutine(IoGetCurrentIrpStackLocation(Irp)->DeviceObject, Irp); return TRUE; } /* Otherwise, release the cancel lock and fail */ IoReleaseCancelSpinLock(OldIrql); return FALSE; } /* * @implemented */ VOID NTAPI IoCancelThreadIo(IN PETHREAD Thread) { KIRQL OldIrql; ULONG Retries = 3000; LARGE_INTEGER Interval; PLIST_ENTRY ListHead, NextEntry; PIRP Irp; PAGED_CODE(); /* Windows isn't using given thread, but using current. */ Thread = PsGetCurrentThread(); IOTRACE(IO_IRP_DEBUG, "%s - Canceling IRPs for Thread %p\n", __FUNCTION__, Thread); /* Raise to APC to protect the IrpList */ KeRaiseIrql(APC_LEVEL, &OldIrql); /* Start by cancelling all the IRPs in the current thread queue. */ ListHead = &Thread->IrpList; NextEntry = ListHead->Flink; while (ListHead != NextEntry) { /* Get the IRP */ Irp = CONTAINING_RECORD(NextEntry, IRP, ThreadListEntry); /* Cancel it */ IoCancelIrp(Irp); /* Move to the next entry */ NextEntry = NextEntry->Flink; } /* Wait 100 milliseconds */ Interval.QuadPart = -1000000; /* Wait till all the IRPs are completed or cancelled. */ while (!IsListEmpty(&Thread->IrpList)) { /* Now we can lower */ KeLowerIrql(OldIrql); /* Wait a short while and then look if all our IRPs were completed. */ KeDelayExecutionThread(KernelMode, FALSE, &Interval); /* * Don't stay here forever if some broken driver doesn't complete * the IRP. */ if (!(Retries--)) { /* Print out a message and remove the IRP */ DPRINT1("Broken driver did not complete!\n"); IopDisassociateThreadIrp(); } /* Raise the IRQL Again */ KeRaiseIrql(APC_LEVEL, &OldIrql); } /* We're done, lower the IRQL */ KeLowerIrql(OldIrql); } /* * @implemented */ #undef IoCallDriver NTSTATUS NTAPI IoCallDriver(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) { /* Call fastcall */ return IofCallDriver(DeviceObject, Irp); } #define IoCallDriver IofCallDriver /* * @implemented */ #undef IoCompleteRequest VOID NTAPI IoCompleteRequest(IN PIRP Irp, IN CCHAR PriorityBoost) { /* Call the fastcall */ IofCompleteRequest(Irp, PriorityBoost); } #define IoCompleteRequest IofCompleteRequest /* * @implemented */ VOID NTAPI IoEnqueueIrp(IN PIRP Irp) { /* This is the same as calling IoQueueThreadIrp */ IoQueueThreadIrp(Irp); } /* * @implemented */ NTSTATUS FASTCALL IofCallDriver(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) { PDRIVER_OBJECT DriverObject; PIO_STACK_LOCATION StackPtr; /* Make sure this is a valid IRP */ ASSERT(Irp->Type == IO_TYPE_IRP); /* Get the Driver Object */ DriverObject = DeviceObject->DriverObject; /* Decrease the current location and check if */ Irp->CurrentLocation--; if (Irp->CurrentLocation <= 0) { /* This IRP ran out of stack, bugcheck */ KeBugCheckEx(NO_MORE_IRP_STACK_LOCATIONS, (ULONG_PTR)Irp, 0, 0, 0); } /* Now update the stack location */ StackPtr = IoGetNextIrpStackLocation(Irp); Irp->Tail.Overlay.CurrentStackLocation = StackPtr; /* Get the Device Object */ StackPtr->DeviceObject = DeviceObject; /* Call it */ return DriverObject->MajorFunction[StackPtr->MajorFunction](DeviceObject, Irp); } FORCEINLINE VOID IopClearStackLocation(IN PIO_STACK_LOCATION IoStackLocation) { IoStackLocation->MinorFunction = 0; IoStackLocation->Flags = 0; IoStackLocation->Control &= SL_ERROR_RETURNED; IoStackLocation->Parameters.Others.Argument1 = 0; IoStackLocation->Parameters.Others.Argument2 = 0; IoStackLocation->Parameters.Others.Argument3 = 0; IoStackLocation->FileObject = NULL; } /* * @implemented */ VOID FASTCALL IofCompleteRequest(IN PIRP Irp, IN CCHAR PriorityBoost) { PIO_STACK_LOCATION StackPtr, LastStackPtr; PDEVICE_OBJECT DeviceObject; PFILE_OBJECT FileObject; PETHREAD Thread; NTSTATUS Status; PMDL Mdl, NextMdl; ULONG MasterCount; PIRP MasterIrp; ULONG Flags; NTSTATUS ErrorCode = STATUS_SUCCESS; PREPARSE_DATA_BUFFER DataBuffer = NULL; IOTRACE(IO_IRP_DEBUG, "%s - Completing IRP %p\n", __FUNCTION__, Irp); /* Make sure this IRP isn't getting completed twice or is invalid */ if ((Irp->CurrentLocation) > (Irp->StackCount + 1)) { /* Bugcheck */ KeBugCheckEx(MULTIPLE_IRP_COMPLETE_REQUESTS, (ULONG_PTR)Irp, 0, 0, 0); } /* Some sanity checks */ ASSERT(Irp->Type == IO_TYPE_IRP); ASSERT(!Irp->CancelRoutine); ASSERT(Irp->IoStatus.Status != STATUS_PENDING); ASSERT(Irp->IoStatus.Status != (NTSTATUS)0xFFFFFFFF); /* Get the last stack */ LastStackPtr = (PIO_STACK_LOCATION)(Irp + 1); if (LastStackPtr->Control & SL_ERROR_RETURNED) { /* Get the error code */ ErrorCode = PtrToUlong(LastStackPtr->Parameters.Others.Argument4); } /* * Start the loop with the current stack and point the IRP to the next stack * and then keep incrementing the stack as we loop through. The IRP should * always point to the next stack location w.r.t the one currently being * analyzed, so completion routine code will see the appropriate value. * Because of this, we must loop until the current stack location is +1 of * the stack count, because when StackPtr is at the end, CurrentLocation is +1. */ for (StackPtr = IoGetCurrentIrpStackLocation(Irp), Irp->CurrentLocation++, Irp->Tail.Overlay.CurrentStackLocation++; Irp->CurrentLocation <= (Irp->StackCount + 1); StackPtr++, Irp->CurrentLocation++, Irp->Tail.Overlay.CurrentStackLocation++) { /* Set Pending Returned */ Irp->PendingReturned = StackPtr->Control & SL_PENDING_RETURNED; /* Check if we failed */ if (!NT_SUCCESS(Irp->IoStatus.Status)) { /* Check if it was changed by a completion routine */ if (Irp->IoStatus.Status != ErrorCode) { /* Update the error for the current stack */ ErrorCode = Irp->IoStatus.Status; StackPtr->Control |= SL_ERROR_RETURNED; LastStackPtr->Parameters.Others.Argument4 = UlongToPtr(ErrorCode); LastStackPtr->Control |= SL_ERROR_RETURNED; } } /* Check if there is a Completion Routine to Call */ if ((NT_SUCCESS(Irp->IoStatus.Status) && (StackPtr->Control & SL_INVOKE_ON_SUCCESS)) || (!NT_SUCCESS(Irp->IoStatus.Status) && (StackPtr->Control & SL_INVOKE_ON_ERROR)) || (Irp->Cancel && (StackPtr->Control & SL_INVOKE_ON_CANCEL))) { /* Clear the stack location */ IopClearStackLocation(StackPtr); /* Check for highest-level device completion routines */ if (Irp->CurrentLocation == (Irp->StackCount + 1)) { /* Clear the DO, since the current stack location is invalid */ DeviceObject = NULL; } else { /* Otherwise, return the real one */ DeviceObject = IoGetCurrentIrpStackLocation(Irp)->DeviceObject; } /* Call the completion routine */ Status = StackPtr->CompletionRoutine(DeviceObject, Irp, StackPtr->Context); /* Don't touch the Packet in this case, since it might be gone! */ if (Status == STATUS_MORE_PROCESSING_REQUIRED) return; } else { /* Otherwise, check if this is a completed IRP */ if ((Irp->CurrentLocation <= Irp->StackCount) && (Irp->PendingReturned)) { /* Mark it as pending */ IoMarkIrpPending(Irp); } /* Clear the stack location */ IopClearStackLocation(StackPtr); } } /* Check if the IRP is an associated IRP */ if (Irp->Flags & IRP_ASSOCIATED_IRP) { /* Get the master IRP and count */ MasterIrp = Irp->AssociatedIrp.MasterIrp; MasterCount = InterlockedDecrement(&MasterIrp->AssociatedIrp.IrpCount); /* Free the MDLs */ for (Mdl = Irp->MdlAddress; Mdl; Mdl = NextMdl) { /* Go to the next one */ NextMdl = Mdl->Next; IoFreeMdl(Mdl); } /* Free the IRP itself */ IoFreeIrp(Irp); /* Complete the Master IRP */ if (!MasterCount) IofCompleteRequest(MasterIrp, PriorityBoost); return; } /* Check whether we have to reparse */ if (Irp->IoStatus.Status == STATUS_REPARSE) { if (Irp->IoStatus.Information > IO_REMOUNT) { /* If that's a reparse tag we understand, save the buffer from deletion */ if (Irp->IoStatus.Information == IO_REPARSE_TAG_MOUNT_POINT) { ASSERT(Irp->Tail.Overlay.AuxiliaryBuffer != NULL); DataBuffer = (PREPARSE_DATA_BUFFER)Irp->Tail.Overlay.AuxiliaryBuffer; Irp->Tail.Overlay.AuxiliaryBuffer = NULL; } else { Irp->IoStatus.Status = STATUS_IO_REPARSE_TAG_NOT_HANDLED; } } } /* Check if we have an auxiliary buffer */ if (Irp->Tail.Overlay.AuxiliaryBuffer) { /* Free it */ ExFreePool(Irp->Tail.Overlay.AuxiliaryBuffer); Irp->Tail.Overlay.AuxiliaryBuffer = NULL; } /* Check if this is a Paging I/O or Close Operation */ if (Irp->Flags & (IRP_PAGING_IO | IRP_CLOSE_OPERATION)) { /* Handle a Close Operation or Sync Paging I/O */ if (Irp->Flags & (IRP_SYNCHRONOUS_PAGING_IO | IRP_CLOSE_OPERATION)) { /* Set the I/O Status and Signal the Event */ Flags = Irp->Flags & (IRP_SYNCHRONOUS_PAGING_IO | IRP_PAGING_IO); *Irp->UserIosb = Irp->IoStatus; KeSetEvent(Irp->UserEvent, PriorityBoost, FALSE); /* Free the IRP for a Paging I/O Only, Close is handled by us */ if (Flags) { /* If we were using the reserve IRP, then call the appropriate * free function (to make the IRP available again) */ if (Irp == IopReserveIrpAllocator.ReserveIrp) { IopFreeReserveIrp(PriorityBoost); } /* Otherwise, free for real! */ else { IoFreeIrp(Irp); } } } else { #if 0 /* Page 166 */ KeInitializeApc(&Irp->Tail.Apc &Irp->Tail.Overlay.Thread->Tcb, Irp->ApcEnvironment, IopCompletePageWrite, NULL, NULL, KernelMode, NULL); KeInsertQueueApc(&Irp->Tail.Apc, NULL, NULL, PriorityBoost); #else /* Not implemented yet. */ UNIMPLEMENTED_DBGBREAK("Not supported!\n"); #endif } /* Get out of here */ return; } /* Unlock MDL Pages, page 167. */ Mdl = Irp->MdlAddress; while (Mdl) { MmUnlockPages(Mdl); Mdl = Mdl->Next; } /* Check if we should exit because of a Deferred I/O (page 168) */ if ((Irp->Flags & IRP_DEFER_IO_COMPLETION) && !(Irp->PendingReturned)) { /* Restore the saved reparse buffer for the caller */ if (Irp->IoStatus.Status == STATUS_REPARSE && Irp->IoStatus.Information == IO_REPARSE_TAG_MOUNT_POINT) { Irp->Tail.Overlay.AuxiliaryBuffer = (PCHAR)DataBuffer; } /* * Return without queuing the completion APC, since the caller will * take care of doing its own optimized completion at PASSIVE_LEVEL. */ return; } /* Get the thread and file object */ Thread = Irp->Tail.Overlay.Thread; FileObject = Irp->Tail.Overlay.OriginalFileObject; /* Make sure the IRP isn't canceled */ if (!Irp->Cancel) { /* Initialize the APC */ KeInitializeApc(&Irp->Tail.Apc, &Thread->Tcb, Irp->ApcEnvironment, IopCompleteRequest, NULL, NULL, KernelMode, NULL); /* Queue it */ KeInsertQueueApc(&Irp->Tail.Apc, FileObject, DataBuffer, PriorityBoost); } else { /* The IRP just got canceled... does a thread still own it? */ if (Thread) { /* Yes! There is still hope! Initialize the APC */ KeInitializeApc(&Irp->Tail.Apc, &Thread->Tcb, Irp->ApcEnvironment, IopCompleteRequest, NULL, NULL, KernelMode, NULL); /* Queue it */ KeInsertQueueApc(&Irp->Tail.Apc, FileObject, DataBuffer, PriorityBoost); } else { /* Nothing left for us to do, kill it */ ASSERT(Irp->Cancel); IopCleanupIrp(Irp, FileObject); } } } NTSTATUS NTAPI IopSynchronousCompletion(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID Context) { if (Irp->PendingReturned) KeSetEvent((PKEVENT)Context, IO_NO_INCREMENT, FALSE); return STATUS_MORE_PROCESSING_REQUIRED; } /* * @implemented */ BOOLEAN NTAPI IoForwardIrpSynchronously(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) { KEVENT Event; NTSTATUS Status; /* Check if next stack location is available */ if (Irp->CurrentLocation < Irp->StackCount) { /* No more stack location */ return FALSE; } /* Initialize event */ KeInitializeEvent(&Event, NotificationEvent, FALSE); /* Copy stack location for next driver */ IoCopyCurrentIrpStackLocationToNext(Irp); /* Set a completion routine, which will signal the event */ IoSetCompletionRoutine(Irp, IopSynchronousCompletion, &Event, TRUE, TRUE, TRUE); /* Call next driver */ Status = IoCallDriver(DeviceObject, Irp); /* Check if irp is pending */ if (Status == STATUS_PENDING) { /* Yes, wait for its completion */ KeWaitForSingleObject(&Event, Suspended, KernelMode, FALSE, NULL); } /* Return success */ return TRUE; } /* * @implemented */ VOID NTAPI IoFreeIrp(IN PIRP Irp) { PNPAGED_LOOKASIDE_LIST List; PP_NPAGED_LOOKASIDE_NUMBER ListType = LookasideSmallIrpList; PKPRCB Prcb; IOTRACE(IO_IRP_DEBUG, "%s - Freeing IRPs %p\n", __FUNCTION__, Irp); /* Make sure the Thread IRP list is empty and that it OK to free it */ ASSERT(Irp->Type == IO_TYPE_IRP); ASSERT(IsListEmpty(&Irp->ThreadListEntry)); ASSERT(Irp->CurrentLocation >= Irp->StackCount); /* Get the PRCB */ Prcb = KeGetCurrentPrcb(); /* If this was a lookaside alloc, increment lookaside float */ if (Irp->AllocationFlags & IRP_LOOKASIDE_ALLOCATION) { Irp->AllocationFlags &= ~IRP_LOOKASIDE_ALLOCATION; InterlockedIncrement(&Prcb->LookasideIrpFloat); } /* If this was a pool alloc, free it with the pool */ if (!(Irp->AllocationFlags & IRP_ALLOCATED_FIXED_SIZE)) { /* Free it */ ExFreePoolWithTag(Irp, TAG_IRP); } else { /* Check if this was a Big IRP */ if (Irp->StackCount != 1) ListType = LookasideLargeIrpList; /* Use the P List */ List = (PNPAGED_LOOKASIDE_LIST)Prcb->PPLookasideList[ListType].P; List->L.TotalFrees++; /* Check if the Free was within the Depth or not */ if (ExQueryDepthSList(&List->L.ListHead) >= List->L.Depth) { /* Let the balancer know */ List->L.FreeMisses++; /* Use the L List */ List = (PNPAGED_LOOKASIDE_LIST)Prcb->PPLookasideList[ListType].L; List->L.TotalFrees++; /* Check if the Free was within the Depth or not */ if (ExQueryDepthSList(&List->L.ListHead) >= List->L.Depth) { /* All lists failed, use the pool */ List->L.FreeMisses++; ExFreePoolWithTag(Irp, TAG_IRP); Irp = NULL; } } /* The free was within the Depth */ if (Irp) { /* Remove the association with the process */ if (Irp->AllocationFlags & IRP_QUOTA_CHARGED) { ExReturnPoolQuota(Irp); Irp->AllocationFlags &= ~IRP_QUOTA_CHARGED; } /* Add it to the lookaside list */ InterlockedPushEntrySList(&List->L.ListHead, (PSLIST_ENTRY)Irp); } } } /* * @implemented */ IO_PAGING_PRIORITY FASTCALL IoGetPagingIoPriority(IN PIRP Irp) { IO_PAGING_PRIORITY Priority; ULONG Flags; /* Get the flags */ Flags = Irp->Flags; /* Check what priority it has */ if (Flags & IRP_CLASS_CACHE_OPERATION) { /* High priority */ Priority = IoPagingPriorityHigh; } else if (Flags & IRP_PAGING_IO) { /* Normal priority */ Priority = IoPagingPriorityNormal; } else { /* Invalid -- not a paging IRP */ Priority = IoPagingPriorityInvalid; } /* Return the priority */ return Priority; } /* * @implemented */ PEPROCESS NTAPI IoGetRequestorProcess(IN PIRP Irp) { /* Return the requestor process */ if (Irp->Tail.Overlay.Thread) { if (Irp->ApcEnvironment == OriginalApcEnvironment) { return Irp->Tail.Overlay.Thread->ThreadsProcess; } else if (Irp->ApcEnvironment == AttachedApcEnvironment) { return (PEPROCESS)Irp->Tail.Overlay.Thread->Tcb.ApcState.Process; } } return NULL; } /* * @implemented */ ULONG NTAPI IoGetRequestorProcessId(IN PIRP Irp) { PEPROCESS Process; /* Return the requestor process' id */ Process = IoGetRequestorProcess(Irp); if (Process) return PtrToUlong(Process->UniqueProcessId); return 0; } /* * @implemented */ NTSTATUS NTAPI IoGetRequestorSessionId(IN PIRP Irp, OUT PULONG pSessionId) { PEPROCESS Process; /* Return the session */ if (Irp->Tail.Overlay.Thread) { Process = Irp->Tail.Overlay.Thread->ThreadsProcess; *pSessionId = MmGetSessionId(Process); return STATUS_SUCCESS; } *pSessionId = (ULONG)-1; return STATUS_UNSUCCESSFUL; } /* * @implemented */ PIRP NTAPI IoGetTopLevelIrp(VOID) { /* Return the IRP */ return (PIRP)PsGetCurrentThread()->TopLevelIrp; } /* * @implemented */ VOID NTAPI IoInitializeIrp(IN PIRP Irp, IN USHORT PacketSize, IN CCHAR StackSize) { /* Clear it */ IOTRACE(IO_IRP_DEBUG, "%s - Initializing IRP %p\n", __FUNCTION__, Irp); RtlZeroMemory(Irp, PacketSize); /* Set the Header and other data */ Irp->Type = IO_TYPE_IRP; Irp->Size = PacketSize; Irp->StackCount = StackSize; Irp->CurrentLocation = StackSize + 1; Irp->ApcEnvironment = KeGetCurrentThread()->ApcStateIndex; Irp->Tail.Overlay.CurrentStackLocation = (PIO_STACK_LOCATION)(Irp + 1) + StackSize; /* Initialize the Thread List */ InitializeListHead(&Irp->ThreadListEntry); } /* * @implemented */ BOOLEAN NTAPI IoIsOperationSynchronous(IN PIRP Irp) { BOOLEAN SynchIO; BOOLEAN ForceAsync; /* If the IRP requests synchronous paging I/O, if the file object was opened for synchronous I/O, if the IRP_SYNCHRONOUS_API flag is set in the IRP the operation is synchronous */ SynchIO = (IoGetCurrentIrpStackLocation(Irp)->FileObject->Flags & FO_SYNCHRONOUS_IO) || (Irp->Flags & IRP_SYNCHRONOUS_API) || (Irp->Flags & IRP_SYNCHRONOUS_PAGING_IO); /* If the IRP requests asynchronous paging I/O, the operation is asynchronous, even if one of the above conditions is true */ ForceAsync = (Irp->Flags & IRP_PAGING_IO) && !(Irp->Flags & IRP_SYNCHRONOUS_PAGING_IO); /* Check the flags */ if (SynchIO && !ForceAsync) { /* Synch API or Paging I/O is OK, as is Sync File I/O */ return TRUE; } /* Otherwise, it is an asynchronous operation. */ return FALSE; } /* * @unimplemented */ BOOLEAN NTAPI IoIsValidNameGraftingBuffer(IN PIRP Irp, IN PREPARSE_DATA_BUFFER ReparseBuffer) { UNIMPLEMENTED; return FALSE; } /* * @implemented */ PIRP NTAPI IoMakeAssociatedIrp(IN PIRP Irp, IN CCHAR StackSize) { PIRP AssocIrp; IOTRACE(IO_IRP_DEBUG, "%s - Associating IRP %p\n", __FUNCTION__, Irp); /* Allocate the IRP */ AssocIrp = IoAllocateIrp(StackSize, FALSE); if (!AssocIrp) return NULL; /* Set the Flags */ AssocIrp->Flags |= IRP_ASSOCIATED_IRP; /* Set the Thread */ AssocIrp->Tail.Overlay.Thread = Irp->Tail.Overlay.Thread; /* Associate them */ AssocIrp->AssociatedIrp.MasterIrp = Irp; return AssocIrp; } /* * @implemented */ VOID NTAPI IoQueueThreadIrp(IN PIRP Irp) { IOTRACE(IO_IRP_DEBUG, "%s - Queueing IRP %p\n", __FUNCTION__, Irp); /* Use our inlined routine */ IopQueueIrpToThread(Irp); } /* * @implemented * Reference: Chris Cant's "Writing WDM Device Drivers" */ VOID NTAPI IoReuseIrp(IN OUT PIRP Irp, IN NTSTATUS Status) { UCHAR AllocationFlags; IOTRACE(IO_IRP_DEBUG, "%s - Reusing IRP %p\n", __FUNCTION__, Irp); /* Make sure it's OK to reuse it */ ASSERT(!Irp->CancelRoutine); ASSERT(IsListEmpty(&Irp->ThreadListEntry)); /* Get the old flags */ AllocationFlags = Irp->AllocationFlags; /* Reinitialize the IRP */ IoInitializeIrp(Irp, Irp->Size, Irp->StackCount); /* Duplicate the data */ Irp->IoStatus.Status = Status; Irp->AllocationFlags = AllocationFlags; } /* * @implemented */ VOID NTAPI IoSetTopLevelIrp(IN PIRP Irp) { /* Set the IRP */ PsGetCurrentThread()->TopLevelIrp = (ULONG_PTR)Irp; } #if defined (_WIN64) BOOLEAN NTAPI IoIs32bitProcess( IN PIRP Irp OPTIONAL) { UNIMPLEMENTED; return FALSE; } #endif