VDIoBackendMem.cpp revision 39cac49f62afd27b0ffdbb779c7c64211939030c
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync/** $Id$ */
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync/** @file
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync *
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync * VBox HDD container test utility, async I/O memory backend
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync */
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync/*
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync * Copyright (C) 2011 Oracle Corporation
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync *
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync * available from http://www.virtualbox.org. This file is free software;
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync * you can redistribute it and/or modify it under the terms of the GNU
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync * General Public License (GPL) as published by the Free Software
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync */
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync#define LOGGROUP LOGGROUP_DEFAULT /** @todo: Log group */
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync#include <iprt/err.h>
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync#include <iprt/log.h>
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync#include <iprt/assert.h>
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync#include <iprt/asm.h>
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync#include <iprt/mem.h>
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync#include <iprt/thread.h>
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync#include <iprt/circbuf.h>
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync#include <iprt/semaphore.h>
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync#include "VDMemDisk.h"
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync#include "VDIoBackendMem.h"
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync#define VDMEMIOBACKEND_REQS 1024
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync/**
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync * Memory I/O request.
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync */
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsynctypedef struct VDIOBACKENDREQ
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync{
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync /** I/O request direction. */
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync VDIOTXDIR enmTxDir;
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync /** Memory disk handle. */
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync PVDMEMDISK pMemDisk;
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync /** Start offset. */
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync uint64_t off;
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync /** Size of the transfer. */
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync size_t cbTransfer;
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync /** Number of segments in the array. */
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync unsigned cSegs;
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync /** Completion handler to call. */
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync PFNVDIOCOMPLETE pfnComplete;
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync /** Opaque user data. */
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync void *pvUser;
39cac49f62afd27b0ffdbb779c7c64211939030cvboxsync /** Segment array - variable in size */
39cac49f62afd27b0ffdbb779c7c64211939030cvboxsync RTSGSEG aSegs[1];
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync} VDIOBACKENDREQ, *PVDIOBACKENDREQ;
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync/**
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync * I/O memory backend
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync */
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsynctypedef struct VDIOBACKENDMEM
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync{
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync /** Thread handle for the backend. */
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync RTTHREAD hThreadIo;
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync /** Circular buffer used for submitting requests. */
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync PRTCIRCBUF pRequestRing;
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync /** Size of the buffer in request items. */
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync unsigned cReqsRing;
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync /** Event semaphore the thread waits on for more work. */
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync RTSEMEVENT EventSem;
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync /** Flag whether the the server should be still running. */
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync volatile bool fRunning;
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync} VDIOBACKENDMEM;
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsyncstatic int vdIoBackendMemThread(RTTHREAD hThread, void *pvUser);
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync/**
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync * Pokes the I/O thread that something interesting happened.
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync *
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync * @returns IPRT status code.
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync *
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync * @param pIoBackend The backend to poke.
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync */
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsyncstatic int vdIoBackendMemThreadPoke(PVDIOBACKENDMEM pIoBackend)
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync{
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync return RTSemEventSignal(pIoBackend->EventSem);
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync}
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsyncint VDIoBackendMemCreate(PPVDIOBACKENDMEM ppIoBackend)
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync{
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync int rc = VINF_SUCCESS;
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync PVDIOBACKENDMEM pIoBackend = NULL;
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync pIoBackend = (PVDIOBACKENDMEM)RTMemAllocZ(sizeof(VDIOBACKENDMEM));
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync if (pIoBackend)
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync {
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync rc = RTCircBufCreate(&pIoBackend->pRequestRing, VDMEMIOBACKEND_REQS * sizeof(VDIOBACKENDREQ));
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync if (RT_SUCCESS(rc))
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync {
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync pIoBackend->cReqsRing = VDMEMIOBACKEND_REQS * sizeof(VDIOBACKENDREQ);
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync pIoBackend->fRunning = true;
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync rc = RTSemEventCreate(&pIoBackend->EventSem);
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync if (RT_SUCCESS(rc))
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync {
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync rc = RTThreadCreate(&pIoBackend->hThreadIo, vdIoBackendMemThread, pIoBackend, 0, RTTHREADTYPE_IO,
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync RTTHREADFLAGS_WAITABLE, "MemIo");
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync if (RT_SUCCESS(rc))
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync {
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync *ppIoBackend = pIoBackend;
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync LogFlowFunc(("returns success\n"));
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync return VINF_SUCCESS;
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync }
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync RTSemEventDestroy(pIoBackend->EventSem);
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync }
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync RTCircBufDestroy(pIoBackend->pRequestRing);
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync }
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync RTMemFree(pIoBackend);
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync }
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync else
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync rc = VERR_NO_MEMORY;
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync return rc;
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync}
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsyncint VDIoBackendMemDestroy(PVDIOBACKENDMEM pIoBackend)
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync{
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync ASMAtomicXchgBool(&pIoBackend->fRunning, false);
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync vdIoBackendMemThreadPoke(pIoBackend);
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync RTThreadWait(pIoBackend->hThreadIo, RT_INDEFINITE_WAIT, NULL);
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync RTSemEventDestroy(pIoBackend->EventSem);
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync RTCircBufDestroy(pIoBackend->pRequestRing);
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync RTMemFree(pIoBackend);
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync return VINF_SUCCESS;
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync}
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsyncint VDIoBackendMemTransfer(PVDIOBACKENDMEM pIoBackend, PVDMEMDISK pMemDisk,
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync VDIOTXDIR enmTxDir, uint64_t off, size_t cbTransfer, PCRTSGSEG paSegs,
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync unsigned cSegs, PFNVDIOCOMPLETE pfnComplete, void *pvUser)
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync{
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync PVDIOBACKENDREQ pReq = NULL;
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync size_t cbData;
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync
39cac49f62afd27b0ffdbb779c7c64211939030cvboxsync RTCircBufAcquireWriteBlock(pIoBackend->pRequestRing, RT_OFFSETOF(VDIOBACKENDREQ, aSegs[cSegs]), (void **)&pReq, &cbData);
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync if (!pReq)
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync return VERR_NO_MEMORY;
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync Assert(cbData == sizeof(VDIOBACKENDREQ));
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync pReq->enmTxDir = enmTxDir;
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync pReq->cbTransfer = cbTransfer;
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync pReq->off = off;
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync pReq->pMemDisk = pMemDisk;
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync pReq->cSegs = cSegs;
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync pReq->pfnComplete = pfnComplete;
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync pReq->pvUser = pvUser;
39cac49f62afd27b0ffdbb779c7c64211939030cvboxsync for (unsigned i = 0; i < cSegs; i++)
39cac49f62afd27b0ffdbb779c7c64211939030cvboxsync {
39cac49f62afd27b0ffdbb779c7c64211939030cvboxsync pReq->aSegs[i].pvSeg = paSegs[i].pvSeg;
39cac49f62afd27b0ffdbb779c7c64211939030cvboxsync pReq->aSegs[i].cbSeg = paSegs[i].cbSeg;
39cac49f62afd27b0ffdbb779c7c64211939030cvboxsync }
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync RTCircBufReleaseWriteBlock(pIoBackend->pRequestRing, sizeof(VDIOBACKENDREQ));
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync vdIoBackendMemThreadPoke(pIoBackend);
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync return VINF_SUCCESS;
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync}
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync/**
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync * I/O thread for the memory backend.
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync *
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync * @returns IPRT status code.
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync *
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync * @param hThread The thread handle.
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync * @param pvUser Opaque user data.
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync */
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsyncstatic int vdIoBackendMemThread(RTTHREAD hThread, void *pvUser)
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync{
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync PVDIOBACKENDMEM pIoBackend = (PVDIOBACKENDMEM)pvUser;
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync while (pIoBackend->fRunning)
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync {
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync int rc = RTSemEventWait(pIoBackend->EventSem, RT_INDEFINITE_WAIT);
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync if (RT_FAILURE(rc) || !pIoBackend->fRunning)
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync break;
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync PVDIOBACKENDREQ pReq;
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync size_t cbData;
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync RTCircBufAcquireReadBlock(pIoBackend->pRequestRing, sizeof(VDIOBACKENDREQ), (void **)&pReq, &cbData);
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync Assert(!pReq || cbData == sizeof(VDIOBACKENDREQ));
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync while (pReq)
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync {
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync int rcReq = VINF_SUCCESS;
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync switch (pReq->enmTxDir)
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync {
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync case VDIOTXDIR_READ:
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync {
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync RTSGBUF SgBuf;
39cac49f62afd27b0ffdbb779c7c64211939030cvboxsync RTSgBufInit(&SgBuf, pReq->aSegs, pReq->cSegs);
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync rcReq = VDMemDiskRead(pReq->pMemDisk, pReq->off, pReq->cbTransfer, &SgBuf);
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync break;
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync }
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync case VDIOTXDIR_WRITE:
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync {
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync RTSGBUF SgBuf;
39cac49f62afd27b0ffdbb779c7c64211939030cvboxsync RTSgBufInit(&SgBuf, pReq->aSegs, pReq->cSegs);
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync rcReq = VDMemDiskWrite(pReq->pMemDisk, pReq->off, pReq->cbTransfer, &SgBuf);
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync break;
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync }
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync case VDIOTXDIR_FLUSH:
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync break;
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync default:
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync AssertMsgFailed(("Invalid TX direction!\n"));
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync }
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync /* Notify completion. */
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync pReq->pfnComplete(pReq->pvUser, rcReq);
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync RTCircBufReleaseReadBlock(pIoBackend->pRequestRing, cbData);
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync /* Do we have another request? */
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync RTCircBufAcquireReadBlock(pIoBackend->pRequestRing, sizeof(VDIOBACKENDREQ), (void **)&pReq, &cbData);
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync Assert(!pReq || cbData == sizeof(VDIOBACKENDREQ));
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync }
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync }
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync return VINF_SUCCESS;
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync}
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync