diff options
Diffstat (limited to 'src/VBox/Additions/WINNT/SharedFolders/driver/file.c')
-rw-r--r-- | src/VBox/Additions/WINNT/SharedFolders/driver/file.c | 248 |
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; } |