/* $Id: VDIoBackend.cpp 77232 2019-02-09 01:55:37Z vboxsync $ */ /** @file * VBox HDD container test utility, I/O backend API */ /* * Copyright (C) 2013-2019 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; * you can redistribute it and/or modify it under the terms of the GNU * General Public License (GPL) as published by the Free Software * Foundation, in version 2 as it comes in the "COPYING" file of the * VirtualBox OSE distribution. VirtualBox OSE is distributed in the * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. */ #define LOGGROUP LOGGROUP_DEFAULT /** @todo Log group */ #include #include #include #include #include #include #include #include #include "VDIoBackend.h" #include "VDMemDisk.h" #include "VDIoBackendMem.h" typedef struct VDIOBACKEND { /** Memory I/O backend handle. */ PVDIOBACKENDMEM pIoMem; /** Async I/O manager. */ RTAIOMGR hAioMgr; /** Users of the memory backend. */ volatile uint32_t cRefsIoMem; /** Users of the file backend. */ volatile uint32_t cRefsFile; } VDIOBACKEND; typedef struct VDIOSTORAGE { /** Pointer to the I/O backend parent. */ PVDIOBACKEND pIoBackend; /** Completion callback. */ PFNVDIOCOMPLETE pfnComplete; /** Flag whether this storage is backed by a file or memory.disk. */ bool fMemory; /** Type dependent data. */ union { /** Memory disk handle. */ PVDMEMDISK pMemDisk; struct { /** file handle. */ RTFILE hFile; /** I/O manager file handle. */ RTAIOMGRFILE hAioMgrFile; } File; } u; } VDIOSTORAGE; static DECLCALLBACK(void) vdIoBackendFileIoComplete(RTAIOMGRFILE hAioMgrFile, int rcReq, void *pvUser) { PVDIOSTORAGE pIoStorage = (PVDIOSTORAGE)RTAioMgrFileGetUser(hAioMgrFile); pIoStorage->pfnComplete(pvUser, rcReq); } int VDIoBackendCreate(PPVDIOBACKEND ppIoBackend) { int rc = VINF_SUCCESS; PVDIOBACKEND pIoBackend; pIoBackend = (PVDIOBACKEND)RTMemAllocZ(sizeof(VDIOBACKEND)); if (pIoBackend) { pIoBackend->hAioMgr = NIL_RTAIOMGR; *ppIoBackend = pIoBackend; } else rc = VERR_NO_MEMORY; return rc; } void VDIoBackendDestroy(PVDIOBACKEND pIoBackend) { if (pIoBackend->pIoMem) VDIoBackendMemDestroy(pIoBackend->pIoMem); if (pIoBackend->hAioMgr) RTAioMgrRelease(pIoBackend->hAioMgr); RTMemFree(pIoBackend); } int VDIoBackendStorageCreate(PVDIOBACKEND pIoBackend, const char *pszBackend, const char *pszName, PFNVDIOCOMPLETE pfnComplete, PPVDIOSTORAGE ppIoStorage) { int rc = VINF_SUCCESS; PVDIOSTORAGE pIoStorage = (PVDIOSTORAGE)RTMemAllocZ(sizeof(VDIOSTORAGE)); if (pIoStorage) { pIoStorage->pIoBackend = pIoBackend; pIoStorage->pfnComplete = pfnComplete; if (!strcmp(pszBackend, "memory")) { pIoStorage->fMemory = true; rc = VDMemDiskCreate(&pIoStorage->u.pMemDisk, 0 /* Growing */); if (RT_SUCCESS(rc)) { uint32_t cRefs = ASMAtomicIncU32(&pIoBackend->cRefsIoMem); if ( cRefs == 1 && !pIoBackend->pIoMem) { rc = VDIoBackendMemCreate(&pIoBackend->pIoMem); if (RT_FAILURE(rc)) VDMemDiskDestroy(pIoStorage->u.pMemDisk); } } } else if (!strcmp(pszBackend, "file")) { pIoStorage->fMemory = false; uint32_t cRefs = ASMAtomicIncU32(&pIoBackend->cRefsFile); if ( cRefs == 1 && pIoBackend->hAioMgr == NIL_RTAIOMGR) rc = RTAioMgrCreate(&pIoBackend->hAioMgr, 1024); if (RT_SUCCESS(rc)) { /* Create file. */ rc = RTFileOpen(&pIoStorage->u.File.hFile, pszName, RTFILE_O_READWRITE | RTFILE_O_CREATE | RTFILE_O_ASYNC_IO | RTFILE_O_NO_CACHE | RTFILE_O_DENY_NONE); if (RT_SUCCESS(rc)) { /* Create file handle for I/O manager. */ rc = RTAioMgrFileCreate(pIoBackend->hAioMgr, pIoStorage->u.File.hFile, vdIoBackendFileIoComplete, pIoStorage, &pIoStorage->u.File.hAioMgrFile); if (RT_FAILURE(rc)) RTFileClose(pIoStorage->u.File.hFile); } } if (RT_FAILURE(rc)) ASMAtomicDecU32(&pIoBackend->cRefsFile); } else rc = VERR_NOT_SUPPORTED; if (RT_FAILURE(rc)) RTMemFree(pIoStorage); else *ppIoStorage = pIoStorage; } else rc = VERR_NO_MEMORY; return rc; } void VDIoBackendStorageDestroy(PVDIOSTORAGE pIoStorage) { if (pIoStorage->fMemory) { VDMemDiskDestroy(pIoStorage->u.pMemDisk); ASMAtomicDecU32(&pIoStorage->pIoBackend->cRefsIoMem); } else { RTAioMgrFileRelease(pIoStorage->u.File.hAioMgrFile); RTFileClose(pIoStorage->u.File.hFile); ASMAtomicDecU32(&pIoStorage->pIoBackend->cRefsFile); } RTMemFree(pIoStorage); } int VDIoBackendTransfer(PVDIOSTORAGE pIoStorage, VDIOTXDIR enmTxDir, uint64_t off, size_t cbTransfer, PRTSGBUF pSgBuf, void *pvUser, bool fSync) { int rc = VINF_SUCCESS; if (pIoStorage->fMemory) { if (!fSync) { rc = VDIoBackendMemTransfer(pIoStorage->pIoBackend->pIoMem, pIoStorage->u.pMemDisk, enmTxDir, off, cbTransfer, pSgBuf, pIoStorage->pfnComplete, pvUser); } else { switch (enmTxDir) { case VDIOTXDIR_READ: rc = VDMemDiskRead(pIoStorage->u.pMemDisk, off, cbTransfer, pSgBuf); break; case VDIOTXDIR_WRITE: rc = VDMemDiskWrite(pIoStorage->u.pMemDisk, off, cbTransfer, pSgBuf); break; case VDIOTXDIR_FLUSH: break; default: AssertMsgFailed(("Invalid transfer type %d\n", enmTxDir)); } } } else { if (!fSync) { switch (enmTxDir) { case VDIOTXDIR_READ: rc = RTAioMgrFileRead(pIoStorage->u.File.hAioMgrFile, off, pSgBuf, cbTransfer, pvUser); break; case VDIOTXDIR_WRITE: rc = RTAioMgrFileWrite(pIoStorage->u.File.hAioMgrFile, off, pSgBuf, cbTransfer, pvUser); break; case VDIOTXDIR_FLUSH: rc = RTAioMgrFileFlush(pIoStorage->u.File.hAioMgrFile, pvUser); break; default: AssertMsgFailed(("Invalid transfer type %d\n", enmTxDir)); } if (rc == VERR_FILE_AIO_IN_PROGRESS) rc = VINF_SUCCESS; } else { switch (enmTxDir) { case VDIOTXDIR_READ: rc = RTFileSgReadAt(pIoStorage->u.File.hFile, off, pSgBuf, cbTransfer, NULL); break; case VDIOTXDIR_WRITE: rc = RTFileSgWriteAt(pIoStorage->u.File.hFile, off, pSgBuf, cbTransfer, NULL); break; case VDIOTXDIR_FLUSH: rc = RTFileFlush(pIoStorage->u.File.hFile); break; default: AssertMsgFailed(("Invalid transfer type %d\n", enmTxDir)); } } } return rc; } int VDIoBackendStorageSetSize(PVDIOSTORAGE pIoStorage, uint64_t cbSize) { int rc = VINF_SUCCESS; if (pIoStorage->fMemory) { rc = VDMemDiskSetSize(pIoStorage->u.pMemDisk, cbSize); } else rc = RTFileSetSize(pIoStorage->u.File.hFile, cbSize); return rc; } int VDIoBackendStorageGetSize(PVDIOSTORAGE pIoStorage, uint64_t *pcbSize) { int rc = VINF_SUCCESS; if (pIoStorage->fMemory) { rc = VDMemDiskGetSize(pIoStorage->u.pMemDisk, pcbSize); } else rc = RTFileGetSize(pIoStorage->u.File.hFile, pcbSize); return rc; } DECLHIDDEN(int) VDIoBackendDumpToFile(PVDIOSTORAGE pIoStorage, const char *pszPath) { int rc = VINF_SUCCESS; if (pIoStorage->fMemory) rc = VDMemDiskWriteToFile(pIoStorage->u.pMemDisk, pszPath); else rc = VERR_NOT_IMPLEMENTED; return rc; }