[RDBSS]
authorPierre Schweitzer <pierre@reactos.org>
Wed, 26 Jul 2017 09:28:41 +0000 (09:28 +0000)
committerPierre Schweitzer <pierre@reactos.org>
Wed, 26 Jul 2017 09:28:41 +0000 (09:28 +0000)
- Implement RxFastIoWrite()
- Finish implementation of RxFastIoCheckIfPossible()

[COPYSUP]
- Implement FsRtlCopyWrite2()

This brings (in link with r75398 fast IO writes to RDBSS, and thus NFS!

CORE-8204
CORE-11327

svn path=/trunk/; revision=75409

reactos/sdk/include/ddk/mrxfcb.h
reactos/sdk/lib/drivers/copysup/copysup.c
reactos/sdk/lib/drivers/copysup/copysup.h
reactos/sdk/lib/drivers/rdbsslib/rdbss.c

index 9aadec3..93a6320 100644 (file)
@@ -179,6 +179,7 @@ typedef struct _MRX_SRV_OPEN_
 } MRX_SRV_OPEN, *PMRX_SRV_OPEN;
 
 #define FOBX_FLAG_DFS_OPEN 0x0001
 } MRX_SRV_OPEN, *PMRX_SRV_OPEN;
 
 #define FOBX_FLAG_DFS_OPEN 0x0001
+#define FOBX_FLAG_BAD_HANDLE 0x0002
 #define FOBX_FLAG_BACKUP_INTENT 0x0004
 
 typedef struct _MRX_PIPE_HANDLE_INFORMATION
 #define FOBX_FLAG_BACKUP_INTENT 0x0004
 
 typedef struct _MRX_PIPE_HANDLE_INFORMATION
index 05d2cc4..d7f7051 100644 (file)
@@ -28,6 +28,8 @@
 
 #include "copysup.h"
 #include <pseh/pseh2.h>
 
 #include "copysup.h"
 #include <pseh/pseh2.h>
+#define NDEBUG
+#include <debug.h>
 
 /* FUNCTIONS ****************************************************************/
 
 
 /* FUNCTIONS ****************************************************************/
 
@@ -180,3 +182,513 @@ CriticalSection:
 
     return Ret;
 }
 
     return Ret;
 }
+
+/*
+ * @implemented
+ */
+BOOLEAN
+FsRtlCopyWrite2(
+    IN PFILE_OBJECT FileObject,
+    IN PLARGE_INTEGER FileOffset,
+    IN ULONG Length,
+    IN BOOLEAN Wait,
+    IN ULONG LockKey,
+    IN PVOID Buffer,
+    OUT PIO_STATUS_BLOCK IoStatus,
+    IN PDEVICE_OBJECT DeviceObject,
+    IN PVOID TopLevelContext)
+{
+    IO_STATUS_BLOCK LocalIoStatus;
+    PFSRTL_ADVANCED_FCB_HEADER Fcb;
+    BOOLEAN WriteToEof, AcquiredShared, FileSizeChanged, Ret;
+    LARGE_INTEGER WriteOffset, LastOffset, InitialFileSize, InitialValidDataLength;
+
+    PAGED_CODE();
+
+    /* First, check whether we're writing to EOF */
+    WriteToEof = ((FileOffset->LowPart == FILE_WRITE_TO_END_OF_FILE) &&
+                  (FileOffset->HighPart == -1));
+
+    /* If Cc says we cannot write, fail now */
+    if (!CcCanIWrite(FileObject, Length, Wait, FALSE))
+    {
+        return FALSE;
+    }
+
+    /* Write through means no cache */
+    if (BooleanFlagOn(FileObject->Flags, FO_WRITE_THROUGH))
+    {
+        return FALSE;
+    }
+
+    /* If write is > 64Kb, don't use FastIO */
+    if (!CcCopyWriteWontFlush(FileObject, FileOffset, Length))
+    {
+        return FALSE;
+    }
+
+    /* Initialize the IO_STATUS_BLOCK */
+    IoStatus->Status = STATUS_SUCCESS;
+    IoStatus->Information = Length;
+
+    /* No length, it's already written! */
+    if (Length == 0)
+    {
+        return TRUE;
+    }
+
+    AcquiredShared = FALSE;
+    FileSizeChanged = FALSE;
+    Fcb = FileObject->FsContext;
+
+    FsRtlEnterFileSystem();
+
+    /* If we cannot wait, or deal with files bigger then 4GB */
+    if (!Wait || (Fcb->AllocationSize.HighPart != 0))
+    {
+        /* If we're to extend the file, then, acquire exclusively */
+        if (WriteToEof || FileOffset->QuadPart + Length > Fcb->ValidDataLength.QuadPart)
+        {
+            if (!ExAcquireResourceExclusiveLite(Fcb->Resource, Wait))
+            {
+                FsRtlExitFileSystem();
+                return FALSE;
+            }
+        }
+        /* Otherwise, a shared lock is enough */
+        else
+        {
+            if (!ExAcquireResourceSharedLite(Fcb->Resource, Wait))
+            {
+                FsRtlExitFileSystem();
+                return FALSE;
+            }
+
+            AcquiredShared = TRUE;
+        }
+
+        /* Get first write offset, and last */
+        if (WriteToEof)
+        {
+            WriteOffset.QuadPart = Fcb->FileSize.QuadPart;
+            LastOffset.QuadPart = WriteOffset.QuadPart + Length;
+        }
+        else
+        {
+            WriteOffset.QuadPart = FileOffset->QuadPart;
+            LastOffset.QuadPart = WriteOffset.QuadPart + Length;
+        }
+
+        /* If cache wasn't initialized, fail */
+        if (FileObject->PrivateCacheMap == NULL ||
+            Fcb->IsFastIoPossible == FastIoIsNotPossible)
+        {
+            ExReleaseResourceLite(Fcb->Resource);
+            FsRtlExitFileSystem();
+
+            return FALSE;
+        }
+
+        /* If we're to write beyond allocation size, it's no go,
+         * same is we create a hole bigger than 8kb
+         */
+        if ((Fcb->ValidDataLength.QuadPart + 0x2000 <= WriteOffset.QuadPart) ||
+            (Length > MAXLONGLONG - WriteOffset.QuadPart) ||
+            (Fcb->AllocationSize.QuadPart < LastOffset.QuadPart))
+        {
+            ExReleaseResourceLite(Fcb->Resource);
+            FsRtlExitFileSystem();
+
+            return FALSE;
+        }
+
+        /* If we have to extend the VDL, shared lock isn't enough */
+        if (AcquiredShared && LastOffset.QuadPart > Fcb->ValidDataLength.QuadPart)
+        {
+            /* So release, and attempt to acquire exclusively */
+            ExReleaseResourceLite(Fcb->Resource);
+            if (!ExAcquireResourceExclusiveLite(Fcb->Resource, Wait))
+            {
+                FsRtlExitFileSystem();
+                return FALSE;
+            }
+
+            /* Get again EOF, in case file size changed in between */
+            if (WriteToEof)
+            {
+                WriteOffset.QuadPart = Fcb->FileSize.QuadPart;
+                LastOffset.QuadPart = WriteOffset.QuadPart + Length;
+            }
+
+            /* Make sure caching is still enabled */
+            if (FileObject->PrivateCacheMap == NULL ||
+                Fcb->IsFastIoPossible == FastIoIsNotPossible)
+            {
+                ExReleaseResourceLite(Fcb->Resource);
+                FsRtlExitFileSystem();
+
+                return FALSE;
+            }
+
+            /* And that we're not writting beyond allocation size */
+            if (Fcb->AllocationSize.QuadPart < LastOffset.QuadPart)
+            {
+                ExReleaseResourceLite(Fcb->Resource);
+                FsRtlExitFileSystem();
+
+                return FALSE;
+            }
+        }
+
+        /* If FastIO is questionable, then question */
+        if (Fcb->IsFastIoPossible == FastIoIsQuestionable)
+        {
+            PFAST_IO_DISPATCH FastIoDispatch;
+            PDEVICE_OBJECT RelatedDeviceObject;
+
+            RelatedDeviceObject = IoGetRelatedDeviceObject(FileObject);
+            FastIoDispatch = RelatedDeviceObject->DriverObject->FastIoDispatch;
+            ASSERT(FastIoDispatch != NULL);
+            ASSERT(FastIoDispatch->FastIoCheckIfPossible != NULL);
+
+            if (!FastIoDispatch->FastIoCheckIfPossible(FileObject,
+                                                       &WriteOffset,
+                                                       Length, Wait, LockKey,
+                                                       FALSE, &LocalIoStatus,
+                                                       RelatedDeviceObject))
+            {
+                ExReleaseResourceLite(Fcb->Resource);
+                FsRtlExitFileSystem();
+
+                return FALSE;
+            }
+        }
+
+        /* If we write beyond EOF, then, save previous sizes (in case of failure)
+         * and update file size, to allow writing
+         */
+        if (LastOffset.QuadPart > Fcb->FileSize.QuadPart)
+        {
+            FileSizeChanged = TRUE;
+            InitialFileSize.QuadPart = Fcb->FileSize.QuadPart;
+            InitialValidDataLength.QuadPart = Fcb->ValidDataLength.QuadPart;
+
+            if (LastOffset.HighPart != Fcb->FileSize.HighPart &&
+                Fcb->PagingIoResource != NULL)
+            {
+                ExAcquireResourceExclusiveLite(Fcb->PagingIoResource, TRUE);
+                Fcb->FileSize.QuadPart = LastOffset.QuadPart;
+                ExReleaseResourceLite(Fcb->PagingIoResource);
+            }
+            else
+            {
+                Fcb->FileSize.QuadPart = LastOffset.QuadPart;
+            }
+        }
+
+        /* Set caller provided context as top level IRP */
+        IoSetTopLevelIrp(TopLevelContext);
+
+        Ret = TRUE;
+
+        /* And perform the writing */
+        _SEH2_TRY
+        {
+            /* Check whether we've to create a hole first */
+            if (LastOffset.QuadPart > Fcb->ValidDataLength.QuadPart)
+            {
+                Ret = CcZeroData(FileObject, &Fcb->ValidDataLength,
+                                 &WriteOffset, Wait);
+            }
+
+            /* If not needed, or if it worked, write data */
+            if (Ret)
+            {
+                Ret = CcCopyWrite(FileObject, &WriteOffset,
+                                  Length, Wait, Buffer);
+            }
+        }
+        _SEH2_EXCEPT(FsRtlIsNtstatusExpected(_SEH2_GetExceptionCode()) ?
+                                             EXCEPTION_EXECUTE_HANDLER :
+                                             EXCEPTION_CONTINUE_SEARCH)
+        {
+            Ret = FALSE;
+        }
+        _SEH2_END;
+
+        /* Restore top level IRP */
+        IoSetTopLevelIrp(NULL);
+
+        /* If writing succeed */
+        if (Ret)
+        {
+            /* If we wrote beyond VDL, update it */
+            if (LastOffset.QuadPart > Fcb->ValidDataLength.QuadPart)
+            {
+                if (LastOffset.HighPart != Fcb->ValidDataLength.HighPart &&
+                    Fcb->PagingIoResource != NULL)
+                {
+                    ExAcquireResourceExclusiveLite(Fcb->PagingIoResource, TRUE);
+                    Fcb->ValidDataLength.QuadPart = LastOffset.QuadPart;
+                    ExReleaseResourceLite(Fcb->PagingIoResource);
+                }
+                else
+                {
+                    Fcb->ValidDataLength.QuadPart = LastOffset.QuadPart;
+                }
+            }
+
+            /* File was obviously modified */
+            SetFlag(FileObject->Flags, FO_FILE_MODIFIED);
+
+            /* And if we increased it, modify size in Cc and update FO */
+            if (FileSizeChanged)
+            {
+                (*CcGetFileSizePointer(FileObject)).QuadPart = LastOffset.QuadPart;
+                SetFlag(FileObject->Flags, FO_FILE_SIZE_CHANGED);
+            }
+
+            /* Update offset */
+            FileObject->CurrentByteOffset.QuadPart = WriteOffset.QuadPart + Length;
+        }
+        else
+        {
+            /* We failed, we need to restore previous sizes */
+            if (FileSizeChanged)
+            {
+                if (Fcb->PagingIoResource != NULL)
+                {
+                    ExAcquireResourceExclusiveLite(Fcb->PagingIoResource, TRUE);
+                    Fcb->FileSize.QuadPart = InitialFileSize.QuadPart;
+                    Fcb->ValidDataLength.QuadPart = InitialValidDataLength.QuadPart;
+                    ExReleaseResourceLite(Fcb->PagingIoResource);
+                }
+                else
+                {
+                    Fcb->FileSize.QuadPart = InitialFileSize.QuadPart;
+                    Fcb->ValidDataLength.QuadPart = InitialValidDataLength.QuadPart;
+                }
+            }
+        }
+    }
+    else
+    {
+        BOOLEAN AboveFour;
+
+        WriteOffset.HighPart = 0;
+        LastOffset.HighPart = 0;
+
+        /* If we're to extend the file, then, acquire exclusively
+         * Here, easy stuff, we know we can wait, no return to check!
+         */
+        if (WriteToEof || FileOffset->QuadPart + Length > Fcb->ValidDataLength.QuadPart)
+        {
+            ExAcquireResourceExclusiveLite(Fcb->Resource, TRUE);
+        }
+        /* Otherwise, a shared lock is enough */
+        else
+        {
+            ExAcquireResourceSharedLite(Fcb->Resource, TRUE);
+            AcquiredShared = TRUE;
+        }
+
+        /* Get first write offset, and last
+         * Also check whether our writing will bring us
+         * beyond the 4GB
+         */
+        if (WriteToEof)
+        {
+            WriteOffset.LowPart = Fcb->FileSize.LowPart;
+            LastOffset.LowPart = WriteOffset.LowPart + Length;
+            AboveFour = (LastOffset.LowPart < Fcb->FileSize.LowPart);
+        }
+        else
+        {
+            WriteOffset.LowPart = FileOffset->LowPart;
+            LastOffset.LowPart = WriteOffset.LowPart + Length;
+            AboveFour = (LastOffset.LowPart < FileOffset->LowPart) ||
+                         (FileOffset->HighPart != 0);
+        }
+
+        /* If cache wasn't initialized, fail */
+        if (FileObject->PrivateCacheMap == NULL ||
+            Fcb->IsFastIoPossible == FastIoIsNotPossible)
+        {
+            ExReleaseResourceLite(Fcb->Resource);
+            FsRtlExitFileSystem();
+
+            return FALSE;
+        }
+
+        /* If we're to write beyond allocation size, it's no go,
+         * same is we create a hole bigger than 8kb
+         * same if we end writing beyond 4GB
+         */
+        if ((Fcb->AllocationSize.LowPart < LastOffset.LowPart) ||
+            (WriteOffset.LowPart >= Fcb->ValidDataLength.LowPart + 0x2000) ||
+            AboveFour)
+        {
+            ExReleaseResourceLite(Fcb->Resource);
+            FsRtlExitFileSystem();
+
+            return FALSE;
+        }
+
+        /* If we have to extend the VDL, shared lock isn't enough */
+        if (AcquiredShared && LastOffset.LowPart > Fcb->ValidDataLength.LowPart)
+        {
+            /* So release, and acquire exclusively */
+            ExReleaseResourceLite(Fcb->Resource);
+            ExAcquireResourceExclusiveLite(Fcb->Resource, TRUE);
+
+            /* Get again EOF, in case file size changed in between and
+             * recheck we won't go beyond 4GB
+             */
+            if (WriteToEof)
+            {
+                WriteOffset.LowPart = Fcb->FileSize.LowPart;
+                LastOffset.LowPart = WriteOffset.LowPart + Length;
+                AboveFour = (((LARGE_INTEGER)LastOffset).LowPart <
+                             Fcb->FileSize.LowPart);
+            }
+
+            /* Make sure caching is still enabled */
+            if (FileObject->PrivateCacheMap == NULL ||
+                Fcb->IsFastIoPossible == FastIoIsNotPossible)
+            {
+                ExReleaseResourceLite(Fcb->Resource);
+                FsRtlExitFileSystem();
+
+                return FALSE;
+            }
+
+            /* And that we're not writting beyond allocation size
+             * and that we're not going above 4GB
+             */
+            if ((Fcb->AllocationSize.LowPart < LastOffset.LowPart) ||
+                (Fcb->AllocationSize.HighPart != 0) || AboveFour)
+            {
+                ExReleaseResourceLite(Fcb->Resource);
+                FsRtlExitFileSystem();
+
+                return FALSE;
+            }
+        }
+
+        /* If FastIO is questionable, then question */
+        if (Fcb->IsFastIoPossible == FastIoIsQuestionable)
+        {
+            PFAST_IO_DISPATCH FastIoDispatch;
+            PDEVICE_OBJECT RelatedDeviceObject;
+            C_ASSERT(sizeof(LARGE_INTEGER) == sizeof(LONGLONG));
+
+            RelatedDeviceObject = IoGetRelatedDeviceObject(FileObject);
+            FastIoDispatch = RelatedDeviceObject->DriverObject->FastIoDispatch;
+            ASSERT(FastIoDispatch != NULL);
+            ASSERT(FastIoDispatch->FastIoCheckIfPossible != NULL);
+
+            if (!FastIoDispatch->FastIoCheckIfPossible(FileObject,
+                                                       &WriteOffset,
+                                                       Length, Wait, LockKey,
+                                                       FALSE, &LocalIoStatus,
+                                                       RelatedDeviceObject))
+            {
+                ExReleaseResourceLite(Fcb->Resource);
+                FsRtlExitFileSystem();
+
+                return FALSE;
+            }
+        }
+
+        /* If we write beyond EOF, then, save previous sizes (in case of failure)
+         * and update file size, to allow writing
+         */
+        if (LastOffset.LowPart > Fcb->FileSize.LowPart)
+        {
+            FileSizeChanged = TRUE;
+            InitialFileSize.LowPart = Fcb->FileSize.LowPart;
+            InitialValidDataLength.LowPart = Fcb->ValidDataLength.LowPart;
+            Fcb->FileSize.LowPart = LastOffset.LowPart;
+        }
+
+        /* Set caller provided context as top level IRP */
+        IoSetTopLevelIrp(TopLevelContext);
+
+        Ret = TRUE;
+
+        /* And perform the writing */
+        _SEH2_TRY
+        {
+            /* Check whether we've to create a hole first -
+             * it cannot fail, we can wait
+             */
+            if (LastOffset.LowPart > Fcb->ValidDataLength.LowPart)
+            {
+                CcZeroData(FileObject, &Fcb->ValidDataLength, &WriteOffset, TRUE);
+            }
+
+            /* Write data */
+            CcFastCopyWrite(FileObject, WriteOffset.LowPart, Length, Buffer);
+        }
+        _SEH2_EXCEPT(FsRtlIsNtstatusExpected(_SEH2_GetExceptionCode()) ?
+                                             EXCEPTION_EXECUTE_HANDLER :
+                                             EXCEPTION_CONTINUE_SEARCH)
+        {
+            Ret = FALSE;
+        }
+        _SEH2_END;
+
+        /* Restore top level IRP */
+        IoSetTopLevelIrp(NULL);
+
+        /* If writing succeed */
+        if (Ret)
+        {
+            /* If we wrote beyond VDL, update it */
+            if (LastOffset.LowPart > Fcb->ValidDataLength.LowPart)
+            {
+                Fcb->ValidDataLength.LowPart = LastOffset.LowPart;
+            }
+
+            /* File was obviously modified */
+            SetFlag(FileObject->Flags, FO_FILE_MODIFIED);
+
+            /* And if we increased it, modify size in Cc and update FO */
+            if (FileSizeChanged)
+            {
+                (*CcGetFileSizePointer(FileObject)).LowPart = LastOffset.LowPart;
+                SetFlag(FileObject->Flags, FO_FILE_SIZE_CHANGED);
+            }
+
+            /* Update offset - we're still below 4GB, so high part must be 0 */
+            FileObject->CurrentByteOffset.LowPart = WriteOffset.LowPart + Length;
+            FileObject->CurrentByteOffset.HighPart = 0;
+        }
+        else
+        {
+            /* We failed, we need to restore previous sizes */
+            if (FileSizeChanged)
+            {
+                if (Fcb->PagingIoResource != NULL)
+                {
+                    ExAcquireResourceExclusiveLite(Fcb->PagingIoResource, TRUE);
+                    Fcb->FileSize.LowPart = InitialFileSize.LowPart;
+                    Fcb->ValidDataLength.LowPart = InitialValidDataLength.LowPart;
+                    ExReleaseResourceLite(Fcb->PagingIoResource);
+                }
+                else
+                {
+                    Fcb->FileSize.LowPart = InitialFileSize.LowPart;
+                    Fcb->ValidDataLength.LowPart = InitialValidDataLength.LowPart;
+                }
+            }
+        }
+    }
+
+    /* Release our resource and leave */
+    ExReleaseResourceLite(Fcb->Resource);
+
+    FsRtlExitFileSystem();
+
+    return Ret;
+}
index 40cf924..8b78ec3 100644 (file)
@@ -15,4 +15,16 @@ FsRtlCopyRead2(
     _In_ PDEVICE_OBJECT DeviceObject,
     _In_ PVOID TopLevelContext);
 
     _In_ PDEVICE_OBJECT DeviceObject,
     _In_ PVOID TopLevelContext);
 
+BOOLEAN
+FsRtlCopyWrite2(
+    _In_ PFILE_OBJECT FileObject,
+    _In_ PLARGE_INTEGER FileOffset,
+    _In_ ULONG Length,
+    _In_ BOOLEAN Wait,
+    _In_ ULONG LockKey,
+    _In_ PVOID Buffer,
+    _Out_ PIO_STATUS_BLOCK IoStatus,
+    _In_ PDEVICE_OBJECT DeviceObject,
+    _In_ PVOID TopLevelContext);
+
 #endif
 #endif
index 43c89c6..f63943a 100644 (file)
@@ -5364,6 +5364,9 @@ RxDumpWantedAccess(
     PAGED_CODE();
 }
 
     PAGED_CODE();
 }
 
+/*
+ * @implemented
+ */
 BOOLEAN
 NTAPI
 RxFastIoCheckIfPossible(
 BOOLEAN
 NTAPI
 RxFastIoCheckIfPossible(
@@ -5376,6 +5379,7 @@ RxFastIoCheckIfPossible(
 {
     PFCB Fcb;
     PSRV_OPEN SrvOpen;
 {
     PFCB Fcb;
     PSRV_OPEN SrvOpen;
+    LARGE_INTEGER LargeLength;
 
     PAGED_CODE();
 
 
     PAGED_CODE();
 
@@ -5436,11 +5440,11 @@ RxFastIoCheckIfPossible(
     RxProcessChangeBufferingStateRequestsForSrvOpen(SrvOpen);
     FsRtlExitFileSystem();
 
     RxProcessChangeBufferingStateRequestsForSrvOpen(SrvOpen);
     FsRtlExitFileSystem();
 
+    LargeLength.QuadPart = Length;
+
     /* If operation to come is a read operation */
     if (CheckForReadOperation)
     {
     /* If operation to come is a read operation */
     if (CheckForReadOperation)
     {
-        LARGE_INTEGER LargeLength;
-
         /* Check that read cache is enabled */
         if (!BooleanFlagOn(Fcb->FcbState, FCB_STATE_READCACHING_ENABLED))
         {
         /* Check that read cache is enabled */
         if (!BooleanFlagOn(Fcb->FcbState, FCB_STATE_READCACHING_ENABLED))
         {
@@ -5449,7 +5453,6 @@ RxFastIoCheckIfPossible(
         }
 
         /* Check whether there's a lock conflict */
         }
 
         /* Check whether there's a lock conflict */
-        LargeLength.QuadPart = Length;
         if (!FsRtlFastCheckLockForRead(&Fcb->Specific.Fcb.FileLock,
                                        FileOffset,
                                        &LargeLength,
         if (!FsRtlFastCheckLockForRead(&Fcb->Specific.Fcb.FileLock,
                                        FileOffset,
                                        &LargeLength,
@@ -5464,8 +5467,26 @@ RxFastIoCheckIfPossible(
         return TRUE;
     }
 
         return TRUE;
     }
 
-    UNIMPLEMENTED;
-    return FALSE;
+    /* Check that write cache is enabled */
+    if (!BooleanFlagOn(Fcb->FcbState, FCB_STATE_WRITECACHING_ENABLED))
+    {
+        DPRINT1("Write caching disabled\n");
+        return FALSE;
+    }
+
+    /* Check whether there's a lock conflict */
+    if (!FsRtlFastCheckLockForWrite(&Fcb->Specific.Fcb.FileLock,
+                                    FileOffset,
+                                    &LargeLength,
+                                    LockKey,
+                                    FileObject,
+                                    PsGetCurrentProcess()))
+    {
+        DPRINT1("FsRtlFastCheckLockForWrite failed\n");
+        return FALSE;
+    }
+
+    return TRUE;
 }
 
 BOOLEAN
 }
 
 BOOLEAN
@@ -5536,6 +5557,9 @@ RxFastIoRead(
     return Ret;
 }
 
     return Ret;
 }
 
+/*
+ * @implemented
+ */
 BOOLEAN
 NTAPI
 RxFastIoWrite(
 BOOLEAN
 NTAPI
 RxFastIoWrite(
@@ -5548,8 +5572,39 @@ RxFastIoWrite(
     PIO_STATUS_BLOCK IoStatus,
     PDEVICE_OBJECT DeviceObject)
 {
     PIO_STATUS_BLOCK IoStatus,
     PDEVICE_OBJECT DeviceObject)
 {
-    UNIMPLEMENTED;
-    return FALSE;
+    PFOBX Fobx;
+    BOOLEAN Ret;
+    RX_TOPLEVELIRP_CONTEXT TopLevelContext;
+
+    PAGED_CODE();
+
+    Fobx = (PFOBX)FileObject->FsContext2;
+    if (BooleanFlagOn(Fobx->Flags, FOBX_FLAG_BAD_HANDLE))
+    {
+        return FALSE;
+    }
+
+    DPRINT("RxFastIoWrite: %p (%p, %p)\n", FileObject, FileObject->FsContext,
+                                           FileObject->FsContext2);
+    DPRINT("Writing %ld at %I64x\n", Length, FileOffset->QuadPart);
+
+    /* Prepare a TLI context */
+    ASSERT(RxIsThisTheTopLevelIrp(NULL));
+    RxInitializeTopLevelIrpContext(&TopLevelContext, (PIRP)FSRTL_FAST_IO_TOP_LEVEL_IRP,
+                                   (PRDBSS_DEVICE_OBJECT)DeviceObject);
+
+    Ret = FsRtlCopyWrite2(FileObject, FileOffset, Length, Wait, LockKey, Buffer,
+                          IoStatus, DeviceObject, &TopLevelContext);
+    if (Ret)
+    {
+        DPRINT("Write OK\n");
+    }
+    else
+    {
+        DPRINT1("Write failed!\n");
+    }
+
+    return Ret;
 }
 
 NTSTATUS
 }
 
 NTSTATUS