Author: ion
Date: Sun Jul 2 20:20:10 2006
New Revision: 22769
URL:
http://svn.reactos.org/svn/reactos?rev=22769&view=rev
Log:
- Start of heavy work on iofunc.c:
- Created our new friends: IopCleanupFailedIrp, IopAbortInterruptedIrp,
IopPerformSynchronousRequest, IopLockFileObject, IopUnlockFileObject, IopQueueIrpToThread,
IopUpdateOperationCount.
- What does this mean: We actually queue IRPs to their thread! We actually respect I/O
transfers being interrupted/alerted! We actually respect I/O operation counts! We actually
LOCK FILE OBJECTS instead of randomly using them! We now support Deferred (read: MUCH
faster) I/O completion.
- First function blessed: IopDeviceFsIoControl.
- Also simplified access rights check and fixedup some formatting.
Added:
trunk/reactos/ntoskrnl/include/internal/io_x.h
Modified:
trunk/reactos/ntoskrnl/include/internal/io.h
trunk/reactos/ntoskrnl/include/internal/ob.h
trunk/reactos/ntoskrnl/io/iomgr/iofunc.c
trunk/reactos/ntoskrnl/io/iomgr/iomgr.c
trunk/reactos/ntoskrnl/io/iomgr/irp.c
Modified: trunk/reactos/ntoskrnl/include/internal/io.h
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/include/internal/…
==============================================================================
--- trunk/reactos/ntoskrnl/include/internal/io.h (original)
+++ trunk/reactos/ntoskrnl/include/internal/io.h Sun Jul 2 20:20:10 2006
@@ -5,7 +5,6 @@
* PURPOSE: Internal header for the I/O Manager
* PROGRAMMERS: Alex Ionescu (alex.ionescu(a)reactos.org)
*/
-//#include "io_x.h"
#include "ntdddisk.h"
//
@@ -192,6 +191,16 @@
IopRemove,
IopAdd
} IOP_DEVICE_LIST_OPERATION, *PIOP_DEVICE_LIST_OPERATION;
+
+//
+// Transfer statistics
+//
+typedef enum _IOP_TRANSFER_TYPE
+{
+ IopReadTransfer,
+ IopWriteTransfer,
+ IopOtherTransfer
+} IOP_TRANSFER_TYPE, *PIOP_TRANSFER_TYPE;
//
// Special version of the IRP Overlay used to optimize I/O completion
@@ -674,6 +683,19 @@
);
//
+// I/O Completion
+//
+VOID
+NTAPI
+IopCompleteRequest(
+ IN PKAPC Apc,
+ IN PKNORMAL_ROUTINE* NormalRoutine,
+ IN PVOID* NormalContext,
+ IN PVOID* SystemArgument1,
+ IN PVOID* SystemArgument2
+);
+
+//
// Error Logging Routines
//
VOID
@@ -949,3 +971,8 @@
extern PDEVICE_NODE IopRootDeviceNode;
extern ULONG IopTraceLevel;
extern NPAGED_LOOKASIDE_LIST IopMdlLookasideList;
+
+//
+// Inlined Functions
+//
+#include "io_x.h"
Added: trunk/reactos/ntoskrnl/include/internal/io_x.h
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/include/internal/…
==============================================================================
--- trunk/reactos/ntoskrnl/include/internal/io_x.h (added)
+++ trunk/reactos/ntoskrnl/include/internal/io_x.h Sun Jul 2 20:20:10 2006
@@ -1,0 +1,78 @@
+/*
+* PROJECT: ReactOS Kernel
+* LICENSE: GPL - See COPYING in the top level directory
+* FILE: ntoskrnl/include/io_x.h
+* PURPOSE: Internal Inlined Functions for the I/O Manager
+* PROGRAMMERS: Alex Ionescu (alex.ionescu(a)reactos.org)
+*/
+
+VOID
+static __inline
+IopLockFileObject(IN PFILE_OBJECT FileObject)
+{
+ /* Lock the FO and check for contention */
+ if (InterlockedExchange(&FileObject->Busy, TRUE))
+ {
+ /* FIXME: Implement contention case */
+ KEBUGCHECK(0);
+ }
+}
+
+VOID
+static __inline
+IopUnlockFileObject(IN PFILE_OBJECT FileObject)
+{
+ /* Unlock the FO and wake any waiters up */
+ InterlockedExchange(&FileObject->Busy, FALSE);
+ if (FileObject->Waiters) KeSetEvent(&FileObject->Lock, 0, FALSE);
+}
+
+VOID
+static __inline
+IopQueueIrpToThread(IN PIRP Irp)
+{
+ KIRQL OldIrql;
+
+ /* Raise to APC Level */
+ KeRaiseIrql(APC_LEVEL, &OldIrql);
+
+ /* Insert it into the list */
+ InsertHeadList(&Irp->Tail.Overlay.Thread->IrpList,
&Irp->ThreadListEntry);
+
+ /* Lower irql */
+ KeLowerIrql(OldIrql);
+}
+
+VOID
+static __inline
+IopUpdateOperationCount(IN IOP_TRANSFER_TYPE Type)
+{
+ PLARGE_INTEGER CountToChange;
+
+ /* Make sure I/O operations are being counted */
+ if (IoCountOperations)
+ {
+ if (Type == IopReadTransfer)
+ {
+ /* Increase read count */
+ IoReadOperationCount++;
+ CountToChange = &PsGetCurrentProcess()->ReadOperationCount;
+ }
+ else if (Type == IopWriteTransfer)
+ {
+ /* Increase write count */
+ IoWriteOperationCount++;
+ CountToChange = &PsGetCurrentProcess()->ReadOperationCount;
+ }
+ else
+ {
+ /* Increase other count */
+ IoOtherOperationCount++;
+ CountToChange = &PsGetCurrentProcess()->ReadOperationCount;
+ }
+
+ /* Increase the process-wide count */
+ ExInterlockedAddLargeStatistic(CountToChange, 1);
+ }
+}
+
Modified: trunk/reactos/ntoskrnl/include/internal/ob.h
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/include/internal/…
==============================================================================
--- trunk/reactos/ntoskrnl/include/internal/ob.h (original)
+++ trunk/reactos/ntoskrnl/include/internal/ob.h Sun Jul 2 20:20:10 2006
@@ -5,8 +5,6 @@
* PURPOSE: Internal header for the Object Manager
* PROGRAMMERS: Alex Ionescu (alex.ionescu(a)reactos.org)
*/
-#include "ob_x.h"
-
//
// Define this if you want debugging support
//
@@ -323,3 +321,9 @@
extern WORK_QUEUE_ITEM ObpReaperWorkItem;
extern volatile PVOID ObpReaperList;
extern NPAGED_LOOKASIDE_LIST ObpNmLookasideList, ObpCiLookasideList;
+extern BOOLEAN IoCountOperations;
+
+//
+// Inlined Functions
+//
+#include "ob_x.h"
Modified: trunk/reactos/ntoskrnl/io/iomgr/iofunc.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/io/iomgr/iofunc.c…
==============================================================================
--- trunk/reactos/ntoskrnl/io/iomgr/iofunc.c (original)
+++ trunk/reactos/ntoskrnl/io/iomgr/iofunc.c Sun Jul 2 20:20:10 2006
@@ -23,14 +23,145 @@
/* PRIVATE FUNCTIONS *********************************************************/
+/* DON'T inline this: it's a failure case */
NTSTATUS
NTAPI
-IopQueryDirectoryFileCompletion(IN PDEVICE_OBJECT DeviceObject,
- IN PIRP Irp,
- IN PVOID Context)
-{
- ExFreePool(Context);
- return STATUS_SUCCESS;
+IopCleanupFailedIrp(IN PFILE_OBJECT FileObject,
+ IN PKEVENT EventObject)
+{
+ PAGED_CODE();
+
+ /* Dereference the event */
+ if (EventObject) ObDereferenceObject(EventObject);
+
+ /* 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;
+}
+
+/* DON'T inline this: it's a failure case */
+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);
+ }
+}
+
+NTSTATUS
+NTAPI
+IopPerformSynchronousRequest(IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp,
+ IN PFILE_OBJECT FileObject,
+ IN BOOLEAN Deferred,
+ IN KPROCESSOR_MODE PreviousMode,
+ IN BOOLEAN SynchIo,
+ IN IOP_TRANSFER_TYPE TransferType)
+{
+ NTSTATUS Status;
+ PKNORMAL_ROUTINE NormalRoutine;
+ PVOID NormalContext;
+ KIRQL OldIrql;
+ PAGED_CODE();
+
+ /* Queue the IRP */
+ IopQueueIrpToThread(Irp);
+
+ /* Update operation counts */
+ IopUpdateOperationCount(TransferType);
+
+ /* Call the driver */
+ Status = IoCallDriver(DeviceObject, Irp);
+
+ /* Check if we're optimizing this case */
+ if (Deferred)
+ {
+ /* We are! Check if the IRP wasn't completed */
+ if (Status != STATUS_PENDING)
+ {
+ /* Complete it ourselves */
+ ASSERT(!Irp->PendingReturned);
+ KeRaiseIrql(APC_LEVEL, &OldIrql);
+ IopCompleteRequest(&Irp->Tail.Apc,
+ &NormalRoutine,
+ &NormalContext,
+ (PVOID*)&FileObject,
+ &NormalContext);
+ KeLowerIrql(OldIrql);
+ }
+ }
+
+ /* Check if this was synch I/O */
+ if (SynchIo)
+ {
+ /* Make sure the IRP was completed, but returned pending */
+ if (Status == STATUS_PENDING)
+ {
+ /* Wait for the IRP */
+ Status = KeWaitForSingleObject(&FileObject->Event,
+ Executive,
+ PreviousMode,
+ (FileObject->Flags & FO_ALERTABLE_IO),
+ NULL);
+ if ((Status == STATUS_ALERTED) || (Status == STATUS_USER_APC))
+ {
+ /* Abort the request */
+ IopAbortInterruptedIrp(&FileObject->Event, Irp);
+ }
+
+ /* Set the final status */
+ Status = FileObject->FinalStatus;
+ }
+
+ /* Release the file lock */
+ IopUnlockFileObject(FileObject);
+ }
+
+ /* Return status */
+ return Status;
}
NTSTATUS
@@ -45,7 +176,7 @@
IN ULONG InputBufferLength OPTIONAL,
OUT PVOID OutputBuffer,
IN ULONG OutputBufferLength OPTIONAL,
- BOOLEAN IsDevIoCtl)
+ IN BOOLEAN IsDevIoCtl)
{
NTSTATUS Status = STATUS_SUCCESS;
PFILE_OBJECT FileObject;
@@ -53,54 +184,65 @@
PIRP Irp;
PIO_STACK_LOCATION StackPtr;
PKEVENT EventObject = NULL;
- BOOLEAN LocalEvent = FALSE;
+ BOOLEAN LockedForSynch = FALSE;
ULONG AccessType;
OBJECT_HANDLE_INFORMATION HandleInformation;
+ ACCESS_MASK DesiredAccess;
KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
+ /* Get the access type */
AccessType = IO_METHOD_FROM_CTL_CODE(IoControlCode);
+ /* Check if we came from user mode */
if (PreviousMode != KernelMode)
{
_SEH_TRY
{
+ /* Probe the status block */
ProbeForWrite(IoStatusBlock,
sizeof(IO_STATUS_BLOCK),
sizeof(ULONG));
- /* probe the input and output buffers if needed */
+ /* Check if this is buffered I/O */
if (AccessType == METHOD_BUFFERED)
{
- if (OutputBuffer != NULL)
+ /* Check if we have an output buffer */
+ if (OutputBuffer)
{
+ /* Probe the output buffer */
ProbeForWrite(OutputBuffer, OutputBufferLength, 1);
}
else
{
- /* make sure the caller can't fake this as we depend on this */
+ /* Make sure the caller can't fake this as we depend on this */
OutputBufferLength = 0;
}
}
+ /* Check if we we have an input buffer I/O */
if (AccessType != METHOD_NEITHER)
{
- if (InputBuffer != NULL)
+ /* Check if we have an input buffer */
+ if (InputBuffer)
{
+ /* Probe the input buffer */
ProbeForRead(InputBuffer, InputBufferLength, 1);
}
else
{
- /* make sure the caller can't fake this as we depend on this */
+ /* Make sure the caller can't fake this as we depend on this */
InputBufferLength = 0;
}
}
}
_SEH_HANDLE
{
+ /* Get the exception code */
Status = _SEH_GetExceptionCode();
}
_SEH_END;
+ /* Fail if we got an access violation */
if (!NT_SUCCESS(Status)) return Status;
}
@@ -113,15 +255,18 @@
&HandleInformation);
if (!NT_SUCCESS(Status)) return Status;
- /* Check for sufficient access rights */
+ /* Check if we from user mode */
if (PreviousMode != KernelMode)
{
- ACCESS_MASK DesiredAccess = (ACCESS_MASK)((IoControlCode >> 14) & 3);
- if (DesiredAccess != FILE_ANY_ACCESS &&
- !RtlAreAllAccessesGranted(HandleInformation.GrantedAccess,
- (ACCESS_MASK)((IoControlCode >> 14) &
3)))
- {
- ObDereferenceObject (FileObject);
+ /* Get the access mask */
+ DesiredAccess = (ACCESS_MASK)((IoControlCode >> 14) & 3);
+
+ /* Check if we can open it */
+ if ((DesiredAccess != FILE_ANY_ACCESS) &&
+ (HandleInformation.GrantedAccess & DesiredAccess) != DesiredAccess)
+ {
+ /* Dereference the file object and fail */
+ ObDereferenceObject(FileObject);
return STATUS_ACCESS_DENIED;
}
}
@@ -138,7 +283,8 @@
NULL);
if (!NT_SUCCESS(Status))
{
- ObDereferenceObject (FileObject);
+ /* Dereference the file object and fail */
+ ObDereferenceObject(FileObject);
return Status;
}
@@ -146,27 +292,30 @@
KeClearEvent(EventObject);
}
+ /* Check if this is a file that was opened for Synch I/O */
+ if (FileObject->Flags & FO_SYNCHRONOUS_IO)
+ {
+ /* Lock it */
+ IopLockFileObject(FileObject);
+
+ /* Remember to unlock later */
+ LockedForSynch = TRUE;
+ }
+
/* Check if this is a direct open or not */
if (FileObject->Flags & FO_DIRECT_DEVICE_OPEN)
{
+ /* It's a direct open, get the attached device */
DeviceObject = IoGetAttachedDevice(FileObject->DeviceObject);
}
else
{
+ /* Otherwise get the related device */
DeviceObject = IoGetRelatedDeviceObject(FileObject);
}
- /* Check if we should use Sync IO or not */
- if (FileObject->Flags & FO_SYNCHRONOUS_IO)
- {
- /* Use File Object event */
- KeClearEvent(&FileObject->Event);
- }
- else
- {
- /* Use local event */
- LocalEvent = TRUE;
- }
+ /* Clear the event */
+ KeClearEvent(&FileObject->Event);
/* Build the IRP */
Irp = IoBuildDeviceIoControlRequest(IoControlCode,
@@ -178,14 +327,10 @@
FALSE,
EventObject,
IoStatusBlock);
- if (!Irp)
- {
- if (EventObject) ObDereferenceObject(EventObject);
- ObDereferenceObject(FileObject);
- return STATUS_INSUFFICIENT_RESOURCES;
- }
+ if (!Irp) return IopCleanupFailedIrp(FileObject, Event);
/* Set some extra settings */
+ Irp->Tail.Overlay.AuxiliaryBuffer = (PVOID) NULL;
Irp->Tail.Overlay.OriginalFileObject = FileObject;
Irp->RequestorMode = PreviousMode;
Irp->Overlay.AsynchronousParameters.UserApcRoutine = UserApcRoutine;
@@ -196,23 +341,27 @@
IRP_MJ_DEVICE_CONTROL :
IRP_MJ_FILE_SYSTEM_CONTROL;
- /* Call the Driver */
- Status = IoCallDriver(DeviceObject, Irp);
- if (Status == STATUS_PENDING)
- {
- if (!LocalEvent)
- {
- KeWaitForSingleObject(&FileObject->Event,
- Executive,
- PreviousMode,
- FileObject->Flags & FO_ALERTABLE_IO,
- NULL);
- Status = FileObject->FinalStatus;
- }
- }
-
- /* Return the Status */
- return Status;
+ /* Use deferred completion for FS I/O */
+ Irp->Flags |= (!IsDevIoCtl) ? IRP_DEFER_IO_COMPLETION : 0;
+
+ /* Perform the call */
+ return IopPerformSynchronousRequest(DeviceObject,
+ Irp,
+ FileObject,
+ !IsDevIoCtl,
+ PreviousMode,
+ LockedForSynch,
+ IopOtherTransfer);
+}
+
+NTSTATUS
+NTAPI
+IopQueryDirectoryFileCompletion(IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp,
+ IN PVOID Context)
+{
+ ExFreePool(Context);
+ return STATUS_SUCCESS;
}
/* PUBLIC FUNCTIONS **********************************************************/
Modified: trunk/reactos/ntoskrnl/io/iomgr/iomgr.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/io/iomgr/iomgr.c?…
==============================================================================
--- trunk/reactos/ntoskrnl/io/iomgr/iomgr.c (original)
+++ trunk/reactos/ntoskrnl/io/iomgr/iomgr.c Sun Jul 2 20:20:10 2006
@@ -20,6 +20,7 @@
POBJECT_TYPE IoDeviceObjectType = NULL;
POBJECT_TYPE IoFileObjectType = NULL;
extern POBJECT_TYPE IoControllerObjectType;
+BOOLEAN IoCountOperations;
ULONG IoReadOperationCount = 0;
LARGE_INTEGER IoReadTransferCount = {{0, 0}};
ULONG IoWriteOperationCount = 0;
Modified: trunk/reactos/ntoskrnl/io/iomgr/irp.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/io/iomgr/irp.c?re…
==============================================================================
--- trunk/reactos/ntoskrnl/io/iomgr/irp.c (original)
+++ trunk/reactos/ntoskrnl/io/iomgr/irp.c Sun Jul 2 20:20:10 2006
@@ -849,13 +849,13 @@
{
KIRQL OldIrql;
PDRIVER_CANCEL CancelRoutine;
-
- /* Acquire the cancel lock and cancel the IRP */
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;
@@ -892,10 +892,11 @@
NTAPI
IoCancelThreadIo(IN PETHREAD Thread)
{
- PIRP Irp;
KIRQL OldIrql;
ULONG Retries = 3000;
LARGE_INTEGER Interval;
+ //PLIST_ENTRY ListHead, NextEntry;
+ //PIRP Irp;
IOTRACE(IO_IRP_DEBUG,
"%s - Canceling IRPs for Thread %p\n",
__FUNCTION__,
@@ -905,11 +906,21 @@
OldIrql = KfRaiseIrql(APC_LEVEL);
/* Start by cancelling all the IRPs in the current thread queue. */
- LIST_FOR_EACH(Irp, &Thread->IrpList, IRP, ThreadListEntry)
- {
+#if 0
+ 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;
+ }
+#endif
/* Wait 100 milliseconds */
Interval.QuadPart = -1000000;
@@ -1462,24 +1473,13 @@
NTAPI
IoQueueThreadIrp(IN PIRP Irp)
{
- KIRQL OldIrql;
IOTRACE(IO_IRP_DEBUG,
"%s - Queueing IRP %p\n",
__FUNCTION__,
Irp);
- /* Raise to APC */
- OldIrql = KfRaiseIrql(APC_LEVEL);
-
- /*
- * Synchronous irp's are queued to requestor thread. If they are not
- * completed when the thread exits, they are canceled (cleaned up).
- * - Gunnar
- */
- InsertTailList(&Irp->Tail.Overlay.Thread->IrpList,
&Irp->ThreadListEntry);
-
- /* Lower back */
- KfLowerIrql(OldIrql);
+ /* Use our inlined routine */
+ IopQueueIrpToThread(Irp);
}
/*