[NTOSKRNL]
[reactos.git] / reactos / ntoskrnl / io / iomgr / iofunc.c
index 885a60c..61ff138 100644 (file)
@@ -1,11 +1,12 @@
 /*
  * PROJECT:         ReactOS Kernel
  * LICENSE:         GPL - See COPYING in the top level directory
- * FILE:            ntoskrnl/io/iofunc.c
+ * FILE:            ntoskrnl/io/iomgr/iofunc.c
  * PURPOSE:         Generic I/O Functions that build IRPs for various operations
  * PROGRAMMERS:     Alex Ionescu (alex.ionescu@reactos.org)
  *                  Gunnar Dalsnes
  *                  Filip Navara (navaraf@reactos.org)
+ *                  Pierre Schweitzer (pierre@reactos.org)
  */
 
 /* INCLUDES *****************************************************************/
@@ -341,12 +342,119 @@ IopDeviceFsIoControl(IN HANDLE DeviceHandle,
         DeviceObject = IoGetRelatedDeviceObject(FileObject);
     }
 
+    /* If that's FS I/O, try to do it with FastIO path */
+    if (!IsDevIoCtl)
+    {
+        PFAST_IO_DISPATCH FastIoDispatch = DeviceObject->DriverObject->FastIoDispatch;
+
+        /* Check whether FSD is FastIO aware and provide an appropriate routine */
+        if (FastIoDispatch != NULL && FastIoDispatch->FastIoDeviceControl != NULL)
+        {
+            IO_STATUS_BLOCK KernelIosb;
+
+            /* If we have an output buffer coming from usermode */
+            if (PreviousMode != KernelMode && OutputBuffer != NULL)
+            {
+                /* Probe it according to its usage */
+                _SEH2_TRY
+                {
+                    if (AccessType == METHOD_IN_DIRECT)
+                    {
+                        ProbeForRead(OutputBuffer, OutputBufferLength, sizeof(CHAR));
+                    }
+                    else if (AccessType == METHOD_OUT_DIRECT)
+                    {
+                        ProbeForWrite(OutputBuffer, OutputBufferLength, sizeof(CHAR));
+                    }
+                }
+                _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+                {
+                    /* Cleanup after exception and return */
+                    IopCleanupAfterException(FileObject, NULL, EventObject, NULL);
+
+                    /* Return the exception code */
+                    _SEH2_YIELD(return _SEH2_GetExceptionCode());
+                }
+                _SEH2_END;
+            }
+
+            /* If we're to dismount a volume, increaase the dismount count */
+            if (IoControlCode == FSCTL_DISMOUNT_VOLUME)
+            {
+                InterlockedExchangeAdd((PLONG)&SharedUserData->DismountCount, 1);
+            }
+
+            /* Call the FSD */
+            if (FastIoDispatch->FastIoDeviceControl(FileObject,
+                                                    TRUE,
+                                                    InputBuffer,
+                                                    InputBufferLength,
+                                                    OutputBuffer,
+                                                    OutputBufferLength,
+                                                    IoControlCode,
+                                                    &KernelIosb,
+                                                    DeviceObject))
+            {
+                IO_COMPLETION_CONTEXT CompletionInfo = { NULL, NULL };
+
+                /* Write the IOSB back */
+                _SEH2_TRY
+                {
+                    *IoStatusBlock = KernelIosb;
+
+                }
+                _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+                {
+                    KernelIosb.Status = _SEH2_GetExceptionCode();
+                }
+                _SEH2_END;
+
+                /* Backup our complete context in case it exists */
+                if (FileObject->CompletionContext)
+                {
+                     CompletionInfo = *(FileObject->CompletionContext);
+                }
+
+                /* If we had an event, signal it */
+                if (Event)
+                {
+                    KeSetEvent(EventObject, IO_NO_INCREMENT, FALSE);
+                    ObDereferenceObject(EventObject);
+                }
+
+                /* If FO was locked, unlock it */
+                if (LockedForSynch)
+                {
+                    IopUnlockFileObject(FileObject);
+                }
+
+                /* Set completion if required */
+                if (CompletionInfo.Port != NULL && UserApcContext != NULL)
+                {
+                    if (!NT_SUCCESS(IoSetIoCompletion(CompletionInfo.Port,
+                                                      CompletionInfo.Key,
+                                                      UserApcContext,
+                                                      KernelIosb.Status,
+                                                      KernelIosb.Information,
+                                                      TRUE)))
+                    {
+                        KernelIosb.Status = STATUS_INSUFFICIENT_RESOURCES;
+                    }
+                }
+
+                /* We're done with FastIO! */
+                ObDereferenceObject(FileObject);
+                return KernelIosb.Status;
+            }
+        }
+    }
+
     /* Clear the event */
     KeClearEvent(&FileObject->Event);
 
     /* Allocate IRP */
     Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
-    if (!Irp) return IopCleanupFailedIrp(FileObject, Event, NULL);
+    if (!Irp) return IopCleanupFailedIrp(FileObject, EventObject, NULL);
 
     /* Setup the IRP */
     Irp->UserIosb = IoStatusBlock;
@@ -1491,6 +1599,7 @@ NtLockFile(IN HANDLE FileHandle,
     LARGE_INTEGER CapturedByteOffset, CapturedLength;
     NTSTATUS Status;
     OBJECT_HANDLE_INFORMATION HandleInformation;
+    PFAST_IO_DISPATCH FastIoDispatch;
     PAGED_CODE();
     CapturedByteOffset.QuadPart = 0;
     CapturedLength.QuadPart = 0;
@@ -1558,6 +1667,62 @@ NtLockFile(IN HANDLE FileHandle,
     /* Get the device object */
     DeviceObject = IoGetRelatedDeviceObject(FileObject);
 
+    /* Try to do it the FastIO way if possible */
+    FastIoDispatch = DeviceObject->DriverObject->FastIoDispatch;
+    if (FastIoDispatch != NULL && FastIoDispatch->FastIoLock != NULL)
+    {
+        IO_STATUS_BLOCK KernelIosb;
+
+        if (FastIoDispatch->FastIoLock(FileObject,
+                                       &CapturedByteOffset,
+                                       &CapturedLength,
+                                       PsGetCurrentProcess(),
+                                       Key,
+                                       FailImmediately,
+                                       ExclusiveLock,
+                                       &KernelIosb,
+                                       DeviceObject))
+        {
+            /* Write the IOSB back */
+            _SEH2_TRY
+            {
+                *IoStatusBlock = KernelIosb;
+            }
+            _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+            {
+                KernelIosb.Status = _SEH2_GetExceptionCode();
+            }
+            _SEH2_END;
+
+            /* If we had an event, signal it */
+            if (EventHandle)
+            {
+                KeSetEvent(Event, IO_NO_INCREMENT, FALSE);
+                ObDereferenceObject(Event);
+            }
+
+            /* Set completion if required */
+            if (FileObject->CompletionContext != NULL && ApcContext != NULL)
+            {
+                if (!NT_SUCCESS(IoSetIoCompletion(FileObject->CompletionContext->Port,
+                                                  FileObject->CompletionContext->Key,
+                                                  ApcContext,
+                                                  KernelIosb.Status,
+                                                  KernelIosb.Information,
+                                                  TRUE)))
+                {
+                    KernelIosb.Status = STATUS_INSUFFICIENT_RESOURCES;
+                }
+            }
+
+            FileObject->LockOperation = TRUE;
+
+            /* We're done with FastIO! */
+            ObDereferenceObject(FileObject);
+            return KernelIosb.Status;
+        }
+    }
+
     /* Check if we should use Sync IO or not */
     if (FileObject->Flags & FO_SYNCHRONOUS_IO)
     {
@@ -1897,6 +2062,7 @@ NtQueryInformationFile(IN HANDLE FileHandle,
     PFILE_MODE_INFORMATION ModeBuffer;
     PFILE_ALIGNMENT_INFORMATION AlignmentBuffer;
     PFILE_ALL_INFORMATION AllBuffer;
+    PFAST_IO_DISPATCH FastIoDispatch;
     PAGED_CODE();
     IOTRACE(IO_API_DEBUG, "FileHandle: %p\n", FileHandle);
 
@@ -2020,6 +2186,52 @@ NtQueryInformationFile(IN HANDLE FileHandle,
         LocalEvent = TRUE;
     }
 
+    /* Check if FastIO is possible for the two available information classes */
+    FastIoDispatch = DeviceObject->DriverObject->FastIoDispatch;
+    if (FastIoDispatch != NULL &&
+        ((FileInformationClass == FileBasicInformation && FastIoDispatch->FastIoQueryBasicInfo != NULL) ||
+         (FileInformationClass == FileStandardInformation && FastIoDispatch->FastIoQueryStandardInfo != NULL)))
+    {
+        BOOLEAN Success = FALSE;
+
+        if (FileInformationClass == FileBasicInformation)
+        {
+            Success = FastIoDispatch->FastIoQueryBasicInfo(FileObject, TRUE,
+                                                           FileInformation,
+                                                           &KernelIosb,
+                                                           DeviceObject);
+        }
+        else
+        {
+            Success = FastIoDispatch->FastIoQueryStandardInfo(FileObject, TRUE,
+                                                              FileInformation,
+                                                              &KernelIosb,
+                                                              DeviceObject);
+        }
+
+        /* If call succeed */
+        if (Success)
+        {
+            /* Write the IOSB back */
+            _SEH2_TRY
+            {
+                *IoStatusBlock = KernelIosb;
+            }
+            _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+            {
+                KernelIosb.Status = _SEH2_GetExceptionCode();
+            }
+            _SEH2_END;
+
+            /* Unlock FO */
+            IopUnlockFileObject(FileObject);
+
+            /* We're done with FastIO! */
+            ObDereferenceObject(FileObject);
+            return KernelIosb.Status;
+        }
+    }
+
     /* Clear the File Object event */
     KeClearEvent(&FileObject->Event);
 
@@ -2255,6 +2467,10 @@ NtReadFile(IN HANDLE FileHandle,
     ULONG CapturedKey = 0;
     BOOLEAN Synchronous = FALSE;
     PMDL Mdl;
+    PFAST_IO_DISPATCH FastIoDispatch;
+    IO_STATUS_BLOCK KernelIosb;
+    BOOLEAN Success;
+
     PAGED_CODE();
     CapturedByteOffset.QuadPart = 0;
     IOTRACE(IO_API_DEBUG, "FileHandle: %p\n", FileHandle);
@@ -2324,13 +2540,16 @@ NtReadFile(IN HANDLE FileHandle,
         KeClearEvent(EventObject);
     }
 
+    /* Get the device object */
+    DeviceObject = IoGetRelatedDeviceObject(FileObject);
+
     /* Check if we should use Sync IO or not */
     if (FileObject->Flags & FO_SYNCHRONOUS_IO)
     {
         /* Lock the file object */
         IopLockFileObject(FileObject);
 
-        /* Check if we don't have a byte offset avilable */
+        /* Check if we don't have a byte offset available */
         if (!(ByteOffset) ||
             ((CapturedByteOffset.u.LowPart == FILE_USE_FILE_POINTER_POSITION) &&
              (CapturedByteOffset.u.HighPart == -1)))
@@ -2339,6 +2558,64 @@ NtReadFile(IN HANDLE FileHandle,
             CapturedByteOffset = FileObject->CurrentByteOffset;
         }
 
+        /* If the file is cached, try fast I/O */
+        if (FileObject->PrivateCacheMap)
+        {
+            /* Perform fast read */
+            FastIoDispatch = DeviceObject->DriverObject->FastIoDispatch;
+            if (FastIoDispatch != NULL && FastIoDispatch->FastIoRead != NULL)
+            {
+                Success = FastIoDispatch->FastIoRead(FileObject,
+                                                     &CapturedByteOffset,
+                                                     Length,
+                                                     TRUE,
+                                                     CapturedKey,
+                                                     Buffer,
+                                                     &KernelIosb,
+                                                     DeviceObject);
+
+                /* Only accept the result if we got a straightforward status */
+                if (Success &&
+                    (KernelIosb.Status == STATUS_SUCCESS ||
+                     KernelIosb.Status == STATUS_BUFFER_OVERFLOW ||
+                     KernelIosb.Status == STATUS_END_OF_FILE))
+                {
+                    /* Fast path -- update transfer & operation counts */
+                    IopUpdateOperationCount(IopReadTransfer);
+                    IopUpdateTransferCount(IopReadTransfer,
+                                           (ULONG)KernelIosb.Information);
+
+                    /* Enter SEH to write the IOSB back */
+                    _SEH2_TRY
+                    {
+                        /* Write it back to the caller */
+                        *IoStatusBlock = KernelIosb;
+                    }
+                    _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+                    {
+                        /* The caller's IOSB was invalid, so fail */
+                        if (EventObject) ObDereferenceObject(EventObject);
+                        IopUnlockFileObject(FileObject);
+                        ObDereferenceObject(FileObject);
+                        _SEH2_YIELD(return _SEH2_GetExceptionCode());
+                    }
+                    _SEH2_END;
+
+                    /* Signal the completion event */
+                    if (EventObject)
+                    {
+                        KeSetEvent(EventObject, 0, FALSE);
+                        ObDereferenceObject(EventObject);
+                    }
+
+                    /* Clean up */
+                    IopUnlockFileObject(FileObject);
+                    ObDereferenceObject(FileObject);
+                    return KernelIosb.Status;
+                }
+            }
+        }
+
         /* Remember we are sync */
         Synchronous = TRUE;
     }
@@ -2351,15 +2628,12 @@ NtReadFile(IN HANDLE FileHandle,
         return STATUS_INVALID_PARAMETER;
     }
 
-    /* Get the device object */
-    DeviceObject = IoGetRelatedDeviceObject(FileObject);
-
     /* Clear the File Object's event */
     KeClearEvent(&FileObject->Event);
 
     /* Allocate the IRP */
     Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
-    if (!Irp) return IopCleanupFailedIrp(FileObject, NULL, NULL);
+    if (!Irp) return IopCleanupFailedIrp(FileObject, EventObject, NULL);
 
     /* Set the IRP */
     Irp->Tail.Overlay.OriginalFileObject = FileObject;
@@ -2609,6 +2883,9 @@ NtSetInformationFile(IN HANDLE FileHandle,
         DeviceObject = IoGetRelatedDeviceObject(FileObject);
     }
 
+    DPRINT("Will call: %p\n", DeviceObject);
+    DPRINT("Associated driver: %p (%wZ)\n", DeviceObject->DriverObject, &DeviceObject->DriverObject->DriverName);
+
     /* Check if this is a file that was opened for Synch I/O */
     if (FileObject->Flags & FO_SYNCHRONOUS_IO)
     {
@@ -2969,6 +3246,7 @@ NtUnlockFile(IN HANDLE FileHandle,
     NTSTATUS Status;
     OBJECT_HANDLE_INFORMATION HandleInformation;
     IO_STATUS_BLOCK KernelIosb;
+    PFAST_IO_DISPATCH FastIoDispatch;
     PAGED_CODE();
     CapturedByteOffset.QuadPart = 0;
     CapturedLength.QuadPart = 0;
@@ -3029,6 +3307,35 @@ NtUnlockFile(IN HANDLE FileHandle,
         DeviceObject = IoGetRelatedDeviceObject(FileObject);
     }
 
+    /* Try to do it the FastIO way if possible */
+    FastIoDispatch = DeviceObject->DriverObject->FastIoDispatch;
+    if (FastIoDispatch != NULL && FastIoDispatch->FastIoUnlockSingle != NULL)
+    {
+        if (FastIoDispatch->FastIoUnlockSingle(FileObject,
+                                               &CapturedByteOffset,
+                                               &CapturedLength,
+                                               PsGetCurrentProcess(),
+                                               Key,
+                                               &KernelIosb,
+                                               DeviceObject))
+        {
+            /* Write the IOSB back */
+            _SEH2_TRY
+            {
+                *IoStatusBlock = KernelIosb;
+            }
+            _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+            {
+                KernelIosb.Status = _SEH2_GetExceptionCode();
+            }
+            _SEH2_END;
+
+            /* We're done with FastIO! */
+            ObDereferenceObject(FileObject);
+            return KernelIosb.Status;
+        }
+    }
+
     /* Check if we should use Sync IO or not */
     if (FileObject->Flags & FO_SYNCHRONOUS_IO)
     {
@@ -3150,6 +3457,10 @@ NtWriteFile(IN HANDLE FileHandle,
     BOOLEAN Synchronous = FALSE;
     PMDL Mdl;
     OBJECT_HANDLE_INFORMATION ObjectHandleInfo;
+    PFAST_IO_DISPATCH FastIoDispatch;
+    IO_STATUS_BLOCK KernelIosb;
+    BOOLEAN Success;
+
     PAGED_CODE();
     CapturedByteOffset.QuadPart = 0;
     IOTRACE(IO_API_DEBUG, "FileHandle: %p\n", FileHandle);
@@ -3201,7 +3512,8 @@ NtWriteFile(IN HANDLE FileHandle,
         }
         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
         {
-            /* Return the exception code */
+            /* Release the file object and return the exception code */
+            ObDereferenceObject(FileObject);
             _SEH2_YIELD(return _SEH2_GetExceptionCode());
         }
         _SEH2_END;
@@ -3243,13 +3555,16 @@ NtWriteFile(IN HANDLE FileHandle,
         KeClearEvent(EventObject);
     }
 
+    /* Get the device object */
+    DeviceObject = IoGetRelatedDeviceObject(FileObject);
+
     /* Check if we should use Sync IO or not */
     if (FileObject->Flags & FO_SYNCHRONOUS_IO)
     {
         /* Lock the file object */
         IopLockFileObject(FileObject);
 
-        /* Check if we don't have a byte offset avilable */
+        /* Check if we don't have a byte offset available */
         if (!(ByteOffset) ||
             ((CapturedByteOffset.u.LowPart == FILE_USE_FILE_POINTER_POSITION) &&
              (CapturedByteOffset.u.HighPart == -1)))
@@ -3258,6 +3573,62 @@ NtWriteFile(IN HANDLE FileHandle,
             CapturedByteOffset = FileObject->CurrentByteOffset;
         }
 
+        /* If the file is cached, try fast I/O */
+        if (FileObject->PrivateCacheMap)
+        {
+            /* Perform fast write */
+            FastIoDispatch = DeviceObject->DriverObject->FastIoDispatch;
+            if (FastIoDispatch != NULL && FastIoDispatch->FastIoWrite != NULL)
+            {
+                Success = FastIoDispatch->FastIoWrite(FileObject,
+                                                      &CapturedByteOffset,
+                                                      Length,
+                                                      TRUE,
+                                                      CapturedKey,
+                                                      Buffer,
+                                                      &KernelIosb,
+                                                      DeviceObject);
+
+                /* Only accept the result if it was successful */
+                if (Success &&
+                    KernelIosb.Status == STATUS_SUCCESS)
+                {
+                    /* Fast path -- update transfer & operation counts */
+                    IopUpdateOperationCount(IopWriteTransfer);
+                    IopUpdateTransferCount(IopWriteTransfer,
+                                           (ULONG)KernelIosb.Information);
+
+                    /* Enter SEH to write the IOSB back */
+                    _SEH2_TRY
+                    {
+                        /* Write it back to the caller */
+                        *IoStatusBlock = KernelIosb;
+                    }
+                    _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+                    {
+                        /* The caller's IOSB was invalid, so fail */
+                        if (EventObject) ObDereferenceObject(EventObject);
+                        IopUnlockFileObject(FileObject);
+                        ObDereferenceObject(FileObject);
+                        _SEH2_YIELD(return _SEH2_GetExceptionCode());
+                    }
+                    _SEH2_END;
+
+                    /* Signal the completion event */
+                    if (EventObject)
+                    {
+                        KeSetEvent(EventObject, 0, FALSE);
+                        ObDereferenceObject(EventObject);
+                    }
+
+                    /* Clean up */
+                    IopUnlockFileObject(FileObject);
+                    ObDereferenceObject(FileObject);
+                    return KernelIosb.Status;
+                }
+            }
+        }
+
         /* Remember we are sync */
         Synchronous = TRUE;
     }
@@ -3270,15 +3641,12 @@ NtWriteFile(IN HANDLE FileHandle,
         return STATUS_INVALID_PARAMETER;
     }
 
-    /* Get the device object */
-    DeviceObject = IoGetRelatedDeviceObject(FileObject);
-
     /* Clear the File Object's event */
     KeClearEvent(&FileObject->Event);
 
     /* Allocate the IRP */
     Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
-    if (!Irp) return IopCleanupFailedIrp(FileObject, NULL, NULL);
+    if (!Irp) return IopCleanupFailedIrp(FileObject, EventObject, NULL);
 
     /* Set the IRP */
     Irp->Tail.Overlay.OriginalFileObject = FileObject;