Sync with trunk r63502.
[reactos.git] / ntoskrnl / fsrtl / fastio.c
index 56f2925..174c8bc 100644 (file)
@@ -3,7 +3,9 @@
  * LICENSE:         GPL - See COPYING in the top level directory
  * FILE:            ntoskrnl/fsrtl/fastio.c
  * PURPOSE:         Provides Fast I/O entrypoints to the Cache Manager
- * PROGRAMMERS:     buzdelabuz2@gmail.com,alex.ionescu@reactos.org
+ * PROGRAMMERS:     Dominique Cote (buzdelabuz2@gmail.com)
+ *                  Alex Ionescu (alex.ionescu@reactos.org)
+ *                  Aleksey Bragin (aleksey@reactos.org)
  */
 
 /* INCLUDES ******************************************************************/
@@ -227,7 +229,7 @@ FsRtlCopyRead(IN PFILE_OBJECT FileObject,
         /* Update the current file offset */
         if (Result == TRUE)
         {
-            FileObject->CurrentByteOffset.QuadPart += IoStatus->Information;
+            FileObject->CurrentByteOffset.QuadPart = FileOffset->QuadPart + IoStatus->Information;
         }
     }
     _SEH2_EXCEPT(FsRtlIsNtstatusExpected(_SEH2_GetExceptionCode()) ?
@@ -280,7 +282,7 @@ FsRtlCopyWrite(IN PFILE_OBJECT FileObject,
     BOOLEAN FileOffsetAppend = (FileOffset->HighPart == (LONG)0xffffffff) &&
                                (FileOffset->LowPart == 0xffffffff);
 
-    BOOLEAN ResourceAquiredShared = FALSE;
+    BOOLEAN ResourceAcquiredShared = FALSE;
     BOOLEAN b_4GB = FALSE;
     BOOLEAN FileSizeModified = FALSE;
     LARGE_INTEGER OldFileSize;
@@ -293,11 +295,6 @@ FsRtlCopyWrite(IN PFILE_OBJECT FileObject,
     ASSERT(FileObject);
     ASSERT(FileObject->FsContext);
 
-#if defined(__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__ == 405)
-    /* Silence incorrect GCC 4.5.x warning */
-    OldFileSize.LowPart = 0;
-#endif
-
     /* Initialize some of the vars and pointers */
     NewSize.QuadPart = 0;
     Offset.QuadPart = FileOffset->QuadPart + Length;
@@ -335,7 +332,7 @@ FsRtlCopyWrite(IN PFILE_OBJECT FileObject,
             (Offset.LowPart <= FcbHeader->ValidDataLength.LowPart))
         {
             ExAcquireResourceSharedLite(FcbHeader->Resource, TRUE);
-            ResourceAquiredShared = TRUE;
+            ResourceAcquiredShared = TRUE;
         }
         else
         {
@@ -378,7 +375,7 @@ FsRtlCopyWrite(IN PFILE_OBJECT FileObject,
              * release the lock and acquire it exclusively, because
              * we are going to need to update the FcbHeader.
              */
-            if (ResourceAquiredShared &&
+            if (ResourceAcquiredShared &&
                 (NewSize.LowPart > FcbHeader->ValidDataLength.LowPart + 0x2000))
             {
                 /* Then we need to acquire the resource exclusive */
@@ -545,11 +542,6 @@ FsRtlCopyWrite(IN PFILE_OBJECT FileObject,
     {
         LARGE_INTEGER OldFileSize;
 
-#if defined(__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__ == 405)
-        /* Silence incorrect GCC 4.5.x warning */
-        OldFileSize.QuadPart = 0;
-#endif
-
         /* Sanity check */
         ASSERT(!KeIsExecutingDpc());
 
@@ -564,7 +556,7 @@ FsRtlCopyWrite(IN PFILE_OBJECT FileObject,
             {
                 goto LeaveCriticalAndFail;
             }
-            ResourceAquiredShared = TRUE;
+            ResourceAcquiredShared = TRUE;
         }
         else
         {
@@ -600,7 +592,7 @@ FsRtlCopyWrite(IN PFILE_OBJECT FileObject,
             (FcbHeader->AllocationSize.QuadPart >= NewSize.QuadPart))
         {
             /* Check if we can keep the lock shared */
-            if (ResourceAquiredShared &&
+            if (ResourceAcquiredShared &&
                 (NewSize.QuadPart > FcbHeader->ValidDataLength.QuadPart))
             {
                 ExReleaseResourceLite(FcbHeader->Resource);
@@ -651,7 +643,7 @@ FsRtlCopyWrite(IN PFILE_OBJECT FileObject,
                                                             &FcbHeader->FileSize :
                                                             FileOffset,
                                                            Length,
-                                                           TRUE,
+                                                           Wait,
                                                            LockKey,
                                                            FALSE,
                                                            &FastIoCheckIfPossibleStatus,
@@ -706,8 +698,8 @@ FsRtlCopyWrite(IN PFILE_OBJECT FileObject,
                                               &Offset,
                                               Wait)))
                     {
-                        /* If this operation fails, then we have to exit. We can jump
-                         * outside the SEH, so I a using a variable to exit normally.
+                        /* If this operation fails, then we have to exit. We can't jump
+                         * outside the SEH, so I am using a variable to exit normally.
                          */
                         CallCc = FALSE;
                     }
@@ -880,7 +872,7 @@ FsRtlGetFileSize(IN PFILE_OBJECT FileObject,
         IoStackLocation->FileObject = FileObject;
         IoStackLocation->DeviceObject = DeviceObject;
         IoStackLocation->Parameters.QueryFile.Length =
-            ALIGN_UP(sizeof(FILE_INFORMATION_CLASS), ULONG);
+            sizeof(FILE_STANDARD_INFORMATION);
         IoStackLocation->Parameters.QueryFile.FileInformationClass =
             FileStandardInformation;
 
@@ -1019,7 +1011,7 @@ FsRtlMdlReadCompleteDev(IN PFILE_OBJECT FileObject,
                         IN PDEVICE_OBJECT DeviceObject)
 {
     /* Call the Cache Manager */
-    CcMdlReadComplete2(MemoryDescriptorList, FileObject);
+    CcMdlReadComplete2(FileObject, MemoryDescriptorList);
     return TRUE;
 }
 
@@ -1301,7 +1293,7 @@ FsRtlPrepareMdlWriteDev(IN PFILE_OBJECT FileObject,
                                (FileOffset->LowPart == 0xffffffff);
 
     BOOLEAN FileSizeModified = FALSE;
-    BOOLEAN ResourceAquiredShared = FALSE;
+    BOOLEAN ResourceAcquiredShared = FALSE;
 
     /* Initialize some of the vars and pointers */
     OldFileSize.QuadPart = 0;
@@ -1337,7 +1329,7 @@ FsRtlPrepareMdlWriteDev(IN PFILE_OBJECT FileObject,
     {
         /* Acquire the resource shared */
         ExAcquireResourceSharedLite(FcbHeader->Resource, TRUE);
-        ResourceAquiredShared = TRUE;
+        ResourceAcquiredShared = TRUE;
     }
     else
     {
@@ -1363,7 +1355,7 @@ FsRtlPrepareMdlWriteDev(IN PFILE_OBJECT FileObject,
         (NewSize.QuadPart <= FcbHeader->AllocationSize.QuadPart))
     {
         /* Check if we can keep the lock shared */
-        if (ResourceAquiredShared &&
+        if (ResourceAcquiredShared &&
             (NewSize.QuadPart > FcbHeader->ValidDataLength.QuadPart))
         {
             ExReleaseResourceLite(FcbHeader->Resource);
@@ -1558,6 +1550,40 @@ Cleanup:
     return Result;
 }
 
+NTSTATUS
+NTAPI
+FsRtlAcquireFileExclusiveCommon(IN PFILE_OBJECT FileObject,
+                                IN FS_FILTER_SECTION_SYNC_TYPE SyncType,
+                                IN ULONG Reserved)
+{
+    PFSRTL_COMMON_FCB_HEADER FcbHeader;
+    PDEVICE_OBJECT DeviceObject;
+    PFAST_IO_DISPATCH FastDispatch;
+
+    /* Get Device Object and Fast Calls */
+    FcbHeader = (PFSRTL_COMMON_FCB_HEADER)FileObject->FsContext;
+    DeviceObject = IoGetRelatedDeviceObject(FileObject);
+    FastDispatch = DeviceObject->DriverObject->FastIoDispatch;
+
+    /* Get master FsRtl lock */
+    FsRtlEnterFileSystem();
+
+    /* Check if Fast Calls are supported, and check AcquireFileForNtCreateSection */
+    if (FastDispatch &&
+        FastDispatch->AcquireFileForNtCreateSection)
+    {
+        /* Call the AcquireFileForNtCreateSection FastIo handler */
+        FastDispatch->AcquireFileForNtCreateSection(FileObject);
+    }
+    else
+    {
+        /* No FastIo handler, acquire file's resource exclusively */
+        if (FcbHeader && FcbHeader->Resource) ExAcquireResourceExclusiveLite(FcbHeader->Resource, TRUE);
+    }
+
+    return STATUS_SUCCESS;
+}
+
 /*
 * @implemented
 */
@@ -1565,9 +1591,10 @@ VOID
 NTAPI
 FsRtlAcquireFileExclusive(IN PFILE_OBJECT FileObject)
 {
-    /* PAGED_CODE(); */
-    /* FsRtlAcquireFileExclusiveCommon(FileObject, 0, 0); */
-    KeBugCheck(FILE_SYSTEM);
+    PAGED_CODE();
+
+    /* Call the common routine. Don't care about the result */
+    (VOID)FsRtlAcquireFileExclusiveCommon(FileObject, SyncTypeOther, 0);
 }
 
 /*
@@ -1577,9 +1604,325 @@ VOID
 NTAPI
 FsRtlReleaseFile(IN PFILE_OBJECT FileObject)
 {
-    KeBugCheck(FILE_SYSTEM);
+    PFSRTL_COMMON_FCB_HEADER FcbHeader;
+    PDEVICE_OBJECT DeviceObject;
+    PFAST_IO_DISPATCH FastDispatch;
+
+    /* Get Device Object and Fast Calls */
+    FcbHeader = (PFSRTL_COMMON_FCB_HEADER)FileObject->FsContext;
+    DeviceObject = IoGetRelatedDeviceObject(FileObject);
+    FastDispatch = DeviceObject->DriverObject->FastIoDispatch;
+
+    /* Check if Fast Calls are supported and check ReleaseFileForNtCreateSection */
+    if (FastDispatch &&
+        FastDispatch->ReleaseFileForNtCreateSection)
+    {
+        /* Call the ReleaseFileForNtCreateSection FastIo handler */
+        FastDispatch->ReleaseFileForNtCreateSection(FileObject);
+    }
+    else
+    {
+        /* No FastIo handler, release file's resource */
+        if (FcbHeader && FcbHeader->Resource) ExReleaseResourceLite(FcbHeader->Resource);
+    }
+
+    /* Release master FsRtl lock */
+    FsRtlExitFileSystem();
+}
+
+/*
+* @implemented
+*/
+NTSTATUS
+NTAPI
+FsRtlAcquireFileForCcFlushEx(IN PFILE_OBJECT FileObject)
+{
+    PFSRTL_COMMON_FCB_HEADER FcbHeader;
+    PDEVICE_OBJECT DeviceObject, BaseDeviceObject;
+    PFAST_IO_DISPATCH FastDispatch;
+    NTSTATUS Status;
+
+    /* Get the Base File System (Volume) and Fast Calls */
+    FcbHeader = (PFSRTL_COMMON_FCB_HEADER)FileObject->FsContext;
+    DeviceObject = IoGetRelatedDeviceObject(FileObject);
+    BaseDeviceObject = IoGetBaseFileSystemDeviceObject(FileObject);
+    FastDispatch = DeviceObject->DriverObject->FastIoDispatch;
+
+    /* Get master FsRtl lock */
+    FsRtlEnterFileSystem();
+
+    /* Check if Fast Calls are supported, and check AcquireForCcFlush */
+    if (FastDispatch &&
+        FastDispatch->AcquireForCcFlush)
+    {
+        /* Call the AcquireForCcFlush FastIo handler */
+        Status = FastDispatch->AcquireForCcFlush(FileObject, BaseDeviceObject);
+
+        /* Return either success or inability to wait.
+           In case of other failure - fall through */
+        if (Status == STATUS_SUCCESS ||
+            Status == STATUS_CANT_WAIT)
+        {
+            return Status;
+        }
+    }
+
+    /* No FastIo handler (or it failed). Acquire Main resource */
+    if (FcbHeader->Resource)
+    {
+        /* Acquire it - either shared if it's already acquired
+            or exclusively if we are the first */
+        if (ExIsResourceAcquiredSharedLite(FcbHeader->Resource))
+            ExAcquireResourceSharedLite(FcbHeader->Resource, TRUE);
+        else
+            ExAcquireResourceExclusiveLite(FcbHeader->Resource, TRUE);
+    }
+
+    /* Also acquire its PagingIO resource */
+    if (FcbHeader->PagingIoResource)
+        ExAcquireResourceSharedLite(FcbHeader->PagingIoResource, TRUE);
+
+    return STATUS_SUCCESS;
+}
+
+/*
+* @implemented
+*/
+VOID
+NTAPI
+FsRtlAcquireFileForCcFlush(IN PFILE_OBJECT FileObject)
+{
+    PAGED_CODE();
+
+    /* Call the common routine. Don't care about the result */
+    (VOID)FsRtlAcquireFileForCcFlushEx(FileObject);
+}
+
+
+/*
+* @implemented
+*/
+VOID
+NTAPI
+FsRtlReleaseFileForCcFlush(IN PFILE_OBJECT FileObject)
+{
+    PFSRTL_COMMON_FCB_HEADER FcbHeader;
+    PDEVICE_OBJECT DeviceObject, BaseDeviceObject;
+    PFAST_IO_DISPATCH FastDispatch;
+    NTSTATUS Status = STATUS_INVALID_DEVICE_REQUEST;
+
+    /* Get Device Object and Fast Calls */
+    FcbHeader = (PFSRTL_COMMON_FCB_HEADER)FileObject->FsContext;
+    DeviceObject = IoGetRelatedDeviceObject(FileObject);
+    BaseDeviceObject = IoGetBaseFileSystemDeviceObject(FileObject);
+    FastDispatch = DeviceObject->DriverObject->FastIoDispatch;
+
+    /* Check if Fast Calls are supported, and check ReleaseForCcFlush */
+    if (FastDispatch &&
+        FastDispatch->ReleaseForCcFlush)
+    {
+        /* Call the ReleaseForCcFlush FastIo handler */
+        Status = FastDispatch->ReleaseForCcFlush(FileObject, BaseDeviceObject);
+    }
+
+    if (!NT_SUCCESS(Status))
+    {
+        /* No FastIo handler (or it failed). Release PagingIO resource and
+           then Main resource */
+        if (FcbHeader->PagingIoResource) ExReleaseResourceLite(FcbHeader->PagingIoResource);
+        if (FcbHeader->Resource) ExReleaseResourceLite(FcbHeader->Resource);
+    }
+
+    /* Release master FsRtl lock */
+    FsRtlExitFileSystem();
+}
+
+/*
+* @implemented
+*/
+NTSTATUS
+NTAPI
+FsRtlAcquireFileForModWriteEx(IN PFILE_OBJECT FileObject,
+                              IN PLARGE_INTEGER EndingOffset,
+                              IN PERESOURCE *ResourceToRelease)
+{
+    PFSRTL_COMMON_FCB_HEADER FcbHeader;
+    PDEVICE_OBJECT DeviceObject, BaseDeviceObject;
+    PFAST_IO_DISPATCH FastDispatch;
+    PERESOURCE ResourceToAcquire = NULL;
+    BOOLEAN Exclusive = FALSE;
+    BOOLEAN Result;
+    NTSTATUS Status = STATUS_SUCCESS;
+
+    /* Get Device Object and Fast Calls */
+    FcbHeader = (PFSRTL_COMMON_FCB_HEADER)FileObject->FsContext;
+    DeviceObject = IoGetRelatedDeviceObject(FileObject);
+    BaseDeviceObject = IoGetBaseFileSystemDeviceObject(FileObject);
+    FastDispatch = DeviceObject->DriverObject->FastIoDispatch;
+
+    /* Check if Fast Calls are supported, and check AcquireForModWrite */
+    if (FastDispatch &&
+        FastDispatch->AcquireForModWrite)
+    {
+        /* Call the AcquireForModWrite FastIo handler */
+        Status = FastDispatch->AcquireForModWrite(FileObject,
+                                                  EndingOffset,
+                                                  ResourceToRelease,
+                                                  BaseDeviceObject);
+
+        /* Return either success or inability to wait.
+           In case of other failure - fall through */
+        if (Status == STATUS_SUCCESS ||
+            Status == STATUS_CANT_WAIT)
+        {
+            return Status;
+        }
+    }
+
+    Status = STATUS_SUCCESS;
+
+    /* No FastIo handler, use algorithm from Nagar p.550. */
+    if (!FcbHeader->Resource)
+    {
+        *ResourceToRelease = NULL;
+        return STATUS_SUCCESS;
+    }
+
+    /* Default condition - shared acquiring of Paging IO Resource */
+    ResourceToAcquire = FcbHeader->PagingIoResource;
+
+    /* Decide on type of locking and type of resource based on historical magic
+       well explain by Nagar in p. 550-551 */
+    if ((EndingOffset->QuadPart > FcbHeader->ValidDataLength.QuadPart &&
+         FcbHeader->FileSize.QuadPart != FcbHeader->ValidDataLength.QuadPart) ||
+         (FcbHeader->Flags & FSRTL_FLAG_ACQUIRE_MAIN_RSRC_EX))
+    {
+        /* Either exclusive flag is set or write operation is extending
+           the valid data length. Prefer exclusive acquire then */
+        Exclusive = TRUE;
+        ResourceToAcquire = FcbHeader->Resource;
+    }
+    else if (!FcbHeader->PagingIoResource ||
+             (FcbHeader->Flags & FSRTL_FLAG_ACQUIRE_MAIN_RSRC_SH))
+    {
+        /* Acquire main resource shared if flag is specified or
+           if PagingIo resource is missing */
+        Exclusive = FALSE;
+        ResourceToAcquire = FcbHeader->Resource;
+    }
+
+    /* Acquire the resource in the loop, since the above code is unsafe */
+    while (TRUE)
+    {
+        Result = FALSE;
+
+        if (Exclusive)
+            Result = ExAcquireResourceExclusiveLite(ResourceToAcquire, FALSE);
+        else
+            Result = ExAcquireSharedWaitForExclusive(ResourceToAcquire, FALSE);
+
+        if (!Result) {
+            Status = STATUS_CANT_WAIT;
+            break;
+        }
+
+        /* Do the magic ifs again */
+        if ((EndingOffset->QuadPart > FcbHeader->ValidDataLength.QuadPart) ||
+             (FcbHeader->Flags & FSRTL_FLAG_ACQUIRE_MAIN_RSRC_EX))
+        {
+            /* Check what we have */
+            if (Exclusive)
+            {
+                /* Asked for exclusive, got exclusive! */
+                break;
+            }
+            else
+            {
+                /* Asked for exclusive, got shared. Release it and retry. */
+                ExReleaseResourceLite(ResourceToAcquire);
+                Exclusive = TRUE;
+                ResourceToAcquire = FcbHeader->Resource;
+            }
+        }
+        else if (FcbHeader->Flags & FSRTL_FLAG_ACQUIRE_MAIN_RSRC_SH)
+        {
+            if (Exclusive)
+            {
+                /* Asked for shared, got exclusive - convert */
+                ExConvertExclusiveToSharedLite(ResourceToAcquire);
+                break;
+            }
+            else if (ResourceToAcquire != FcbHeader->Resource)
+            {
+                /* Asked for main resource, got something else */
+                ExReleaseResourceLite(ResourceToAcquire);
+                ResourceToAcquire = FcbHeader->Resource;
+                Exclusive = TRUE;
+            }
+        }
+        else if (FcbHeader->PagingIoResource &&
+                 ResourceToAcquire != FcbHeader->PagingIoResource)
+        {
+            /* There is PagingIo resource, but other resource was acquired */
+            ResourceToAcquire = FcbHeader->PagingIoResource;
+            if (!ExAcquireSharedWaitForExclusive(ResourceToAcquire, FALSE))
+            {
+                Status = STATUS_CANT_WAIT;
+                ExReleaseResourceLite(FcbHeader->Resource);
+            }
+
+            break;
+        }
+        else if (Exclusive)
+        {
+            /* Asked for shared got exclusive - convert */
+            ExConvertExclusiveToSharedLite(ResourceToAcquire);
+            break;
+        }
+    }
+
+    /* If the resource was acquired successfully - pass it to the caller */
+    if (NT_SUCCESS(Status))
+        *ResourceToRelease = ResourceToAcquire;
+
+    return Status;
 }
 
+/*
+* @implemented
+*/
+VOID
+NTAPI
+FsRtlReleaseFileForModWrite(IN PFILE_OBJECT FileObject,
+                            IN PERESOURCE ResourceToRelease)
+{
+    PDEVICE_OBJECT DeviceObject, BaseDeviceObject;
+    PFAST_IO_DISPATCH FastDispatch;
+    NTSTATUS Status = STATUS_SUCCESS;
+
+    /* Get Device Object and Fast Calls */
+    DeviceObject = IoGetRelatedDeviceObject(FileObject);
+    BaseDeviceObject = IoGetBaseFileSystemDeviceObject(FileObject);
+    FastDispatch = DeviceObject->DriverObject->FastIoDispatch;
+
+    /* Check if Fast Calls are supported and check ReleaseFileForNtCreateSection */
+    if (FastDispatch &&
+        FastDispatch->ReleaseForModWrite)
+    {
+        /* Call the ReleaseForModWrite FastIo handler */
+        Status = FastDispatch->ReleaseForModWrite(FileObject,
+                                                  ResourceToRelease,
+                                                  BaseDeviceObject);
+    }
+
+    /* Just release the resource if previous op failed */
+    if (!NT_SUCCESS(Status))
+    {
+        ExReleaseResourceLite(ResourceToRelease);
+    }
+}
+
+
 /*++
  * @name FsRtlRegisterFileSystemFilterCallbacks
  * @unimplemented
@@ -1599,9 +1942,35 @@ FsRtlReleaseFile(IN PFILE_OBJECT FileObject)
  *--*/
 NTSTATUS
 NTAPI
-FsRtlRegisterFileSystemFilterCallbacks(IN PDRIVER_OBJECT FilterDriverObject,
-                                       IN PFS_FILTER_CALLBACKS Callbacks)
+FsRtlRegisterFileSystemFilterCallbacks(
+    PDRIVER_OBJECT FilterDriverObject,
+    PFS_FILTER_CALLBACKS Callbacks)
 {
-    UNIMPLEMENTED;
-    return STATUS_NOT_IMPLEMENTED;
+    PFS_FILTER_CALLBACKS NewCallbacks;
+    PEXTENDED_DRIVER_EXTENSION DriverExtension;
+    PAGED_CODE();
+
+    /* Verify parameters */
+    if ((FilterDriverObject == NULL) || (Callbacks == NULL))
+    {
+        return STATUS_INVALID_PARAMETER;
+    }
+
+    /* Allocate a buffer for a copy of the callbacks */
+    NewCallbacks = ExAllocatePoolWithTag(NonPagedPool,
+                                         Callbacks->SizeOfFsFilterCallbacks,
+                                         'gmSF');
+    if (NewCallbacks == NULL)
+    {
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
+
+    /* Copy the callbacks */
+    RtlCopyMemory(NewCallbacks, Callbacks, Callbacks->SizeOfFsFilterCallbacks);
+
+    /* Set the callbacks in the driver extension */
+    DriverExtension = (PEXTENDED_DRIVER_EXTENSION)FilterDriverObject->DriverExtension;
+    DriverExtension->FsFilterCallbacks = NewCallbacks;
+
+    return STATUS_SUCCESS;
 }