summaryrefslogtreecommitdiff
path: root/src/VBox/Additions/WINNT/SharedFolders/driver/file.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/VBox/Additions/WINNT/SharedFolders/driver/file.c')
-rw-r--r--src/VBox/Additions/WINNT/SharedFolders/driver/file.c248
1 files changed, 240 insertions, 8 deletions
diff --git a/src/VBox/Additions/WINNT/SharedFolders/driver/file.c b/src/VBox/Additions/WINNT/SharedFolders/driver/file.c
index f8101cb5..ba39cb3f 100644
--- a/src/VBox/Additions/WINNT/SharedFolders/driver/file.c
+++ b/src/VBox/Additions/WINNT/SharedFolders/driver/file.c
@@ -6,7 +6,7 @@
*/
/*
- * Copyright (C) 2012 Oracle Corporation
+ * Copyright (C) 2012-2013 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -19,10 +19,219 @@
#include "vbsf.h"
#include <iprt/fs.h>
+#include <iprt/mem.h>
+
+
+/* How much data to transfer in one HGCM request. */
+#define VBSF_MAX_READ_WRITE_PAGES 256
+
+
+typedef int FNVBSFTRANSFERBUFFER(PVBSFCLIENT pClient, PVBSFMAP pMap, SHFLHANDLE hFile,
+ uint64_t offset, uint32_t *pcbBuffer,
+ uint8_t *pBuffer, bool fLocked);
+typedef FNVBSFTRANSFERBUFFER *PFNVBSFTRANSFERBUFFER;
+
+typedef int FNVBSFTRANSFERPAGES(PVBSFCLIENT pClient, PVBSFMAP pMap, SHFLHANDLE hFile,
+ uint64_t offset, uint32_t *pcbBuffer,
+ uint16_t offFirstPage, uint16_t cPages, RTGCPHYS64 *paPages);
+typedef FNVBSFTRANSFERPAGES *PFNVBSFTRANSFERPAGES;
+
+
+static int vbsfTransferBufferRead(PVBSFCLIENT pClient, PVBSFMAP pMap, SHFLHANDLE hFile,
+ uint64_t offset, uint32_t *pcbBuffer,
+ uint8_t *pBuffer, bool fLocked)
+{
+ return vboxCallRead(pClient, pMap, hFile, offset, pcbBuffer, pBuffer, fLocked);
+}
+
+static int vbsfTransferBufferWrite(PVBSFCLIENT pClient, PVBSFMAP pMap, SHFLHANDLE hFile,
+ uint64_t offset, uint32_t *pcbBuffer,
+ uint8_t *pBuffer, bool fLocked)
+{
+ return vboxCallWrite(pClient, pMap, hFile, offset, pcbBuffer, pBuffer, fLocked);
+}
+
+static int vbsfTransferPagesRead(PVBSFCLIENT pClient, PVBSFMAP pMap, SHFLHANDLE hFile,
+ uint64_t offset, uint32_t *pcbBuffer,
+ uint16_t offFirstPage, uint16_t cPages, RTGCPHYS64 *paPages)
+{
+ return VbglR0SharedFolderReadPageList(pClient, pMap, hFile, offset, pcbBuffer, offFirstPage, cPages, paPages);
+}
+
+static int vbsfTransferPagesWrite(PVBSFCLIENT pClient, PVBSFMAP pMap, SHFLHANDLE hFile,
+ uint64_t offset, uint32_t *pcbBuffer,
+ uint16_t offFirstPage, uint16_t cPages, RTGCPHYS64 *paPages)
+{
+ return VbglR0SharedFolderWritePageList(pClient, pMap, hFile, offset, pcbBuffer, offFirstPage, cPages, paPages);
+}
+
+
+typedef struct VBSFTRANSFERCTX
+{
+ PVBSFCLIENT pClient;
+ PVBSFMAP pMap;
+ SHFLHANDLE hFile;
+ uint64_t offset;
+ uint32_t cbData;
+
+ PMDL pMdl;
+ uint8_t *pBuffer;
+ bool fLocked;
+
+ PFNVBSFTRANSFERBUFFER pfnTransferBuffer;
+ PFNVBSFTRANSFERPAGES pfnTransferPages;
+} VBSFTRANSFERCTX;
+
+
+static int vbsfTransferCommon(VBSFTRANSFERCTX *pCtx)
+{
+ int rc = VINF_SUCCESS;
+ BOOLEAN fProcessed = FALSE;
+
+ uint32_t cbTransferred = 0;
+
+ uint32_t cbToTransfer;
+ uint32_t cbIO;
+
+ if (VbglR0CanUsePhysPageList())
+ {
+ ULONG offFirstPage = MmGetMdlByteOffset(pCtx->pMdl);
+ ULONG cPages = ADDRESS_AND_SIZE_TO_SPAN_PAGES(MmGetMdlVirtualAddress(pCtx->pMdl), pCtx->cbData);
+ ULONG cPagesToTransfer = RT_MIN(cPages, VBSF_MAX_READ_WRITE_PAGES);
+ RTGCPHYS64 *paPages = (RTGCPHYS64 *)RTMemTmpAlloc(cPagesToTransfer * sizeof(RTGCPHYS64));
+
+ Log(("VBOXSF: vbsfTransferCommon: using page list: %d pages, offset 0x%03X\n", cPages, offFirstPage));
+
+ if (paPages)
+ {
+ PPFN_NUMBER paPfns = MmGetMdlPfnArray(pCtx->pMdl);
+ ULONG cPagesTransferred = 0;
+ cbTransferred = 0;
+
+ while (cPagesToTransfer != 0)
+ {
+ ULONG iPage;
+ cbToTransfer = cPagesToTransfer * PAGE_SIZE - offFirstPage;
+
+ if (cbToTransfer > pCtx->cbData - cbTransferred)
+ {
+ cbToTransfer = pCtx->cbData - cbTransferred;
+ }
+
+ if (cbToTransfer == 0)
+ {
+ /* Nothing to transfer. */
+ break;
+ }
+
+ cbIO = cbToTransfer;
+
+ Log(("VBOXSF: vbsfTransferCommon: transferring %d pages at %d; %d bytes at %d\n",
+ cPagesToTransfer, cPagesTransferred, cbToTransfer, cbTransferred));
+
+ for (iPage = 0; iPage < cPagesToTransfer; iPage++)
+ {
+ paPages[iPage] = (RTGCPHYS64)paPfns[iPage + cPagesTransferred] << PAGE_SHIFT;
+ }
+
+ rc = pCtx->pfnTransferPages(pCtx->pClient, pCtx->pMap, pCtx->hFile,
+ pCtx->offset + cbTransferred, &cbIO,
+ (uint16_t)offFirstPage, (uint16_t)cPagesToTransfer, paPages);
+ if (RT_FAILURE(rc))
+ {
+ Log(("VBOXSF: vbsfTransferCommon: pfnTransferPages %Rrc, cbTransferred %d\n", rc, cbTransferred));
+
+ /* If some data was transferred, then it is no error. */
+ if (cbTransferred > 0)
+ {
+ rc = VINF_SUCCESS;
+ }
+
+ break;
+ }
+
+ cbTransferred += cbIO;
+
+ if (cbToTransfer < cbIO)
+ {
+ /* Transferred less than requested, do not continue with the possibly remaining data. */
+ break;
+ }
+
+ cPagesTransferred += cPagesToTransfer;
+ offFirstPage = 0;
+
+ cPagesToTransfer = cPages - cPagesTransferred;
+ if (cPagesToTransfer > VBSF_MAX_READ_WRITE_PAGES)
+ {
+ cPagesToTransfer = VBSF_MAX_READ_WRITE_PAGES;
+ }
+ }
+
+ RTMemTmpFree(paPages);
+
+ fProcessed = TRUE;
+ }
+ }
+
+ if (fProcessed != TRUE)
+ {
+ /* Split large transfers. */
+ cbTransferred = 0;
+ cbToTransfer = RT_MIN(pCtx->cbData, VBSF_MAX_READ_WRITE_PAGES * PAGE_SIZE);
+
+ /* Page list not supported or a fallback. */
+ Log(("VBOXSF: vbsfTransferCommon: using linear address\n"));
+
+ while (cbToTransfer != 0)
+ {
+ cbIO = cbToTransfer;
+
+ Log(("VBOXSF: vbsfTransferCommon: transferring %d bytes at %d\n",
+ cbToTransfer, cbTransferred));
+
+ rc = pCtx->pfnTransferBuffer(pCtx->pClient, pCtx->pMap, pCtx->hFile,
+ pCtx->offset + cbTransferred, &cbIO,
+ pCtx->pBuffer + cbTransferred, true /* locked */);
+
+ if (RT_FAILURE(rc))
+ {
+ Log(("VBOXSF: vbsfTransferCommon: pfnTransferBuffer %Rrc, cbTransferred %d\n", rc, cbTransferred));
+
+ /* If some data was transferred, then it is no error. */
+ if (cbTransferred > 0)
+ {
+ rc = VINF_SUCCESS;
+ }
+
+ break;
+ }
+
+ cbTransferred += cbIO;
+
+ if (cbToTransfer < cbIO)
+ {
+ /* Transferred less than requested, do not continue with the possibly remaining data. */
+ break;
+ }
+
+ cbToTransfer = pCtx->cbData - cbTransferred;
+ if (cbToTransfer > VBSF_MAX_READ_WRITE_PAGES * PAGE_SIZE)
+ {
+ cbToTransfer = VBSF_MAX_READ_WRITE_PAGES * PAGE_SIZE;
+ }
+ }
+ }
+
+ pCtx->cbData = cbTransferred;
+
+ return rc;
+}
static NTSTATUS vbsfReadInternal(IN PRX_CONTEXT RxContext)
{
NTSTATUS Status = STATUS_SUCCESS;
+ VBSFTRANSFERCTX ctx;
RxCaptureFcb;
RxCaptureFobx;
@@ -80,9 +289,20 @@ static NTSTATUS vbsfReadInternal(IN PRX_CONTEXT RxContext)
return STATUS_INVALID_PARAMETER;
}
- /* @todo Split large reads. */
- vboxRC = vboxCallRead(&pDeviceExtension->hgcmClient, &pNetRootExtension->map, pVBoxFobx->hFile,
- ByteOffset, &ByteCount, (uint8_t *)pbUserBuffer, true /* locked */);
+ ctx.pClient = &pDeviceExtension->hgcmClient;
+ ctx.pMap = &pNetRootExtension->map;
+ ctx.hFile = pVBoxFobx->hFile;
+ ctx.offset = (uint64_t)ByteOffset;
+ ctx.cbData = ByteCount;
+ ctx.pMdl = BufferMdl;
+ ctx.pBuffer = (uint8_t *)pbUserBuffer;
+ ctx.fLocked = true;
+ ctx.pfnTransferBuffer = vbsfTransferBufferRead;
+ ctx.pfnTransferPages = vbsfTransferPagesRead;
+
+ vboxRC = vbsfTransferCommon(&ctx);
+
+ ByteCount = ctx.cbData;
Status = VBoxErrorToNTStatus(vboxRC);
@@ -136,6 +356,7 @@ NTSTATUS VBoxMRxRead(IN PRX_CONTEXT RxContext)
static NTSTATUS vbsfWriteInternal(IN PRX_CONTEXT RxContext)
{
NTSTATUS Status = STATUS_SUCCESS;
+ VBSFTRANSFERCTX ctx;
RxCaptureFcb;
RxCaptureFobx;
@@ -174,9 +395,20 @@ static NTSTATUS vbsfWriteInternal(IN PRX_CONTEXT RxContext)
return STATUS_INVALID_PARAMETER;
}
- /* @todo Split large writes. */
- vboxRC = vboxCallWrite(&pDeviceExtension->hgcmClient, &pNetRootExtension->map, pVBoxFobx->hFile,
- ByteOffset, &ByteCount, (uint8_t *)pbUserBuffer, true /* locked */);
+ ctx.pClient = &pDeviceExtension->hgcmClient;
+ ctx.pMap = &pNetRootExtension->map;
+ ctx.hFile = pVBoxFobx->hFile;
+ ctx.offset = (uint64_t)ByteOffset;
+ ctx.cbData = ByteCount;
+ ctx.pMdl = BufferMdl;
+ ctx.pBuffer = (uint8_t *)pbUserBuffer;
+ ctx.fLocked = true;
+ ctx.pfnTransferBuffer = vbsfTransferBufferWrite;
+ ctx.pfnTransferPages = vbsfTransferPagesWrite;
+
+ vboxRC = vbsfTransferCommon(&ctx);
+
+ ByteCount = ctx.cbData;
Status = VBoxErrorToNTStatus(vboxRC);
@@ -318,7 +550,7 @@ NTSTATUS VBoxMRxFlush (IN PRX_CONTEXT RxContext)
Status = VBoxErrorToNTStatus(vboxRC);
- Log(("VBOXSF: MRxFlush: Returned 0x%08X\n",
+ Log(("VBOXSF: MRxFlush: Returned 0x%08X\n",
Status));
return Status;
}