VirtualBox

source: vbox/trunk/src/VBox/VMM/PDMAsyncCompletionFile.cpp@ 28800

Last change on this file since 28800 was 28800, checked in by vboxsync, 14 years ago

Automated rebranding to Oracle copyright/license strings via filemuncher

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 37.3 KB
Line 
1/* $Id: PDMAsyncCompletionFile.cpp 28800 2010-04-27 08:22:32Z vboxsync $ */
2/** @file
3 * PDM Async I/O - Transport data asynchronous in R3 using EMT.
4 */
5
6/*
7 * Copyright (C) 2006-2009 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18
19/*******************************************************************************
20* Header Files *
21*******************************************************************************/
22#define LOG_GROUP LOG_GROUP_PDM_ASYNC_COMPLETION
23//#define DEBUG
24#include "PDMInternal.h"
25#include <VBox/pdm.h>
26#include <VBox/mm.h>
27#include <VBox/vm.h>
28#include <VBox/err.h>
29#include <VBox/log.h>
30
31#include <iprt/asm.h>
32#include <iprt/assert.h>
33#include <iprt/critsect.h>
34#include <iprt/env.h>
35#include <iprt/file.h>
36#include <iprt/mem.h>
37#include <iprt/semaphore.h>
38#include <iprt/string.h>
39#include <iprt/thread.h>
40#include <iprt/path.h>
41
42#include "PDMAsyncCompletionFileInternal.h"
43
44/**
45 * Frees a task.
46 *
47 * @returns nothing.
48 * @param pEndpoint Pointer to the endpoint the segment was for.
49 * @param pTask The task to free.
50 */
51void pdmacFileTaskFree(PPDMASYNCCOMPLETIONENDPOINTFILE pEndpoint,
52 PPDMACTASKFILE pTask)
53{
54 PPDMASYNCCOMPLETIONEPCLASSFILE pEpClass = (PPDMASYNCCOMPLETIONEPCLASSFILE)pEndpoint->Core.pEpClass;
55
56 LogFlowFunc((": pEndpoint=%p pTask=%p\n", pEndpoint, pTask));
57
58 /* Try the per endpoint cache first. */
59 if (pEndpoint->cTasksCached < pEpClass->cTasksCacheMax)
60 {
61 /* Add it to the list. */
62 pEndpoint->pTasksFreeTail->pNext = pTask;
63 pEndpoint->pTasksFreeTail = pTask;
64 ASMAtomicIncU32(&pEndpoint->cTasksCached);
65 }
66 else
67 {
68 Log(("Freeing task %p because all caches are full\n", pTask));
69 MMR3HeapFree(pTask);
70 }
71}
72
73/**
74 * Allocates a task segment
75 *
76 * @returns Pointer to the new task segment or NULL
77 * @param pEndpoint Pointer to the endpoint
78 */
79PPDMACTASKFILE pdmacFileTaskAlloc(PPDMASYNCCOMPLETIONENDPOINTFILE pEndpoint)
80{
81 PPDMACTASKFILE pTask = NULL;
82
83 /* Try the small per endpoint cache first. */
84 if (pEndpoint->pTasksFreeHead == pEndpoint->pTasksFreeTail)
85 {
86 /* Try the bigger endpoint class cache. */
87 PPDMASYNCCOMPLETIONEPCLASSFILE pEndpointClass = (PPDMASYNCCOMPLETIONEPCLASSFILE)pEndpoint->Core.pEpClass;
88
89 /*
90 * Allocate completely new.
91 * If this fails we return NULL.
92 */
93 int rc = MMR3HeapAllocZEx(pEndpointClass->Core.pVM, MM_TAG_PDM_ASYNC_COMPLETION,
94 sizeof(PDMACTASKFILE),
95 (void **)&pTask);
96 if (RT_FAILURE(rc))
97 pTask = NULL;
98
99 LogFlow(("Allocated task %p\n", pTask));
100 }
101 else
102 {
103 /* Grab a free task from the head. */
104 AssertMsg(pEndpoint->cTasksCached > 0, ("No tasks cached but list contains more than one element\n"));
105
106 pTask = pEndpoint->pTasksFreeHead;
107 pEndpoint->pTasksFreeHead = pTask->pNext;
108 ASMAtomicDecU32(&pEndpoint->cTasksCached);
109 }
110
111 pTask->pNext = NULL;
112
113 return pTask;
114}
115
116PPDMACTASKFILE pdmacFileEpGetNewTasks(PPDMASYNCCOMPLETIONENDPOINTFILE pEndpoint)
117{
118 PPDMACTASKFILE pTasks = NULL;
119
120 /*
121 * Get pending tasks.
122 */
123 pTasks = (PPDMACTASKFILE)ASMAtomicXchgPtr((void * volatile *)&pEndpoint->pTasksNewHead, NULL);
124
125 /* Reverse the list to process in FIFO order. */
126 if (pTasks)
127 {
128 PPDMACTASKFILE pTask = pTasks;
129
130 pTasks = NULL;
131
132 while (pTask)
133 {
134 PPDMACTASKFILE pCur = pTask;
135 pTask = pTask->pNext;
136 pCur->pNext = pTasks;
137 pTasks = pCur;
138 }
139 }
140
141 return pTasks;
142}
143
144static void pdmacFileAioMgrWakeup(PPDMACEPFILEMGR pAioMgr)
145{
146 bool fWokenUp = ASMAtomicXchgBool(&pAioMgr->fWokenUp, true);
147
148 if (!fWokenUp)
149 {
150 int rc = VINF_SUCCESS;
151 bool fWaitingEventSem = ASMAtomicReadBool(&pAioMgr->fWaitingEventSem);
152
153 if (fWaitingEventSem)
154 rc = RTSemEventSignal(pAioMgr->EventSem);
155
156 AssertRC(rc);
157 }
158}
159
160static int pdmacFileAioMgrWaitForBlockingEvent(PPDMACEPFILEMGR pAioMgr, PDMACEPFILEAIOMGRBLOCKINGEVENT enmEvent)
161{
162 int rc = VINF_SUCCESS;
163
164 ASMAtomicWriteU32((volatile uint32_t *)&pAioMgr->enmBlockingEvent, enmEvent);
165 Assert(!pAioMgr->fBlockingEventPending);
166 ASMAtomicXchgBool(&pAioMgr->fBlockingEventPending, true);
167
168 /* Wakeup the async I/O manager */
169 pdmacFileAioMgrWakeup(pAioMgr);
170
171 /* Wait for completion. */
172 rc = RTSemEventWait(pAioMgr->EventSemBlock, RT_INDEFINITE_WAIT);
173 AssertRC(rc);
174
175 ASMAtomicXchgBool(&pAioMgr->fBlockingEventPending, false);
176 ASMAtomicWriteU32((volatile uint32_t *)&pAioMgr->enmBlockingEvent, PDMACEPFILEAIOMGRBLOCKINGEVENT_INVALID);
177
178 return rc;
179}
180
181int pdmacFileAioMgrAddEndpoint(PPDMACEPFILEMGR pAioMgr, PPDMASYNCCOMPLETIONENDPOINTFILE pEndpoint)
182{
183 int rc;
184
185 rc = RTCritSectEnter(&pAioMgr->CritSectBlockingEvent);
186 AssertRCReturn(rc, rc);
187
188 ASMAtomicWritePtr((void * volatile *)&pAioMgr->BlockingEventData.AddEndpoint.pEndpoint, pEndpoint);
189 rc = pdmacFileAioMgrWaitForBlockingEvent(pAioMgr, PDMACEPFILEAIOMGRBLOCKINGEVENT_ADD_ENDPOINT);
190
191 RTCritSectLeave(&pAioMgr->CritSectBlockingEvent);
192
193 if (RT_SUCCESS(rc))
194 ASMAtomicWritePtr((void * volatile *)&pEndpoint->pAioMgr, pAioMgr);
195
196 return rc;
197}
198
199static int pdmacFileAioMgrRemoveEndpoint(PPDMACEPFILEMGR pAioMgr, PPDMASYNCCOMPLETIONENDPOINTFILE pEndpoint)
200{
201 int rc;
202
203 rc = RTCritSectEnter(&pAioMgr->CritSectBlockingEvent);
204 AssertRCReturn(rc, rc);
205
206 ASMAtomicWritePtr((void * volatile *)&pAioMgr->BlockingEventData.RemoveEndpoint.pEndpoint, pEndpoint);
207 rc = pdmacFileAioMgrWaitForBlockingEvent(pAioMgr, PDMACEPFILEAIOMGRBLOCKINGEVENT_REMOVE_ENDPOINT);
208
209 RTCritSectLeave(&pAioMgr->CritSectBlockingEvent);
210
211 return rc;
212}
213
214static int pdmacFileAioMgrCloseEndpoint(PPDMACEPFILEMGR pAioMgr, PPDMASYNCCOMPLETIONENDPOINTFILE pEndpoint)
215{
216 int rc;
217
218 rc = RTCritSectEnter(&pAioMgr->CritSectBlockingEvent);
219 AssertRCReturn(rc, rc);
220
221 ASMAtomicWritePtr((void * volatile *)&pAioMgr->BlockingEventData.CloseEndpoint.pEndpoint, pEndpoint);
222 rc = pdmacFileAioMgrWaitForBlockingEvent(pAioMgr, PDMACEPFILEAIOMGRBLOCKINGEVENT_CLOSE_ENDPOINT);
223
224 RTCritSectLeave(&pAioMgr->CritSectBlockingEvent);
225
226 return rc;
227}
228
229static int pdmacFileAioMgrShutdown(PPDMACEPFILEMGR pAioMgr)
230{
231 int rc;
232
233 rc = RTCritSectEnter(&pAioMgr->CritSectBlockingEvent);
234 AssertRCReturn(rc, rc);
235
236 rc = pdmacFileAioMgrWaitForBlockingEvent(pAioMgr, PDMACEPFILEAIOMGRBLOCKINGEVENT_SHUTDOWN);
237
238 RTCritSectLeave(&pAioMgr->CritSectBlockingEvent);
239
240 return rc;
241}
242
243int pdmacFileEpAddTask(PPDMASYNCCOMPLETIONENDPOINTFILE pEndpoint, PPDMACTASKFILE pTask)
244{
245 PPDMACTASKFILE pNext;
246 do
247 {
248 pNext = pEndpoint->pTasksNewHead;
249 pTask->pNext = pNext;
250 } while (!ASMAtomicCmpXchgPtr((void * volatile *)&pEndpoint->pTasksNewHead, (void *)pTask, (void *)pNext));
251
252 pdmacFileAioMgrWakeup((PPDMACEPFILEMGR)ASMAtomicReadPtr((void * volatile *)&pEndpoint->pAioMgr));
253
254 return VINF_SUCCESS;
255}
256
257void pdmacFileEpTaskCompleted(PPDMACTASKFILE pTask, void *pvUser, int rc)
258{
259 PPDMASYNCCOMPLETIONTASKFILE pTaskFile = (PPDMASYNCCOMPLETIONTASKFILE)pvUser;
260
261 if (pTask->enmTransferType == PDMACTASKFILETRANSFER_FLUSH)
262 {
263 pdmR3AsyncCompletionCompleteTask(&pTaskFile->Core, rc, true);
264 }
265 else
266 {
267 Assert((uint32_t)pTask->DataSeg.cbSeg == pTask->DataSeg.cbSeg && (int32_t)pTask->DataSeg.cbSeg >= 0);
268 uint32_t uOld = ASMAtomicSubS32(&pTaskFile->cbTransferLeft, (int32_t)pTask->DataSeg.cbSeg);
269
270 /* The first error will be returned. */
271 if (RT_FAILURE(rc))
272 ASMAtomicCmpXchgS32(&pTaskFile->rc, rc, VINF_SUCCESS);
273
274 if (!(uOld - pTask->DataSeg.cbSeg)
275 && !ASMAtomicXchgBool(&pTaskFile->fCompleted, true))
276 pdmR3AsyncCompletionCompleteTask(&pTaskFile->Core, pTaskFile->rc, true);
277 }
278}
279
280int pdmacFileEpTaskInitiate(PPDMASYNCCOMPLETIONTASK pTask,
281 PPDMASYNCCOMPLETIONENDPOINT pEndpoint, RTFOFF off,
282 PCRTSGSEG paSegments, size_t cSegments,
283 size_t cbTransfer, PDMACTASKFILETRANSFER enmTransfer)
284{
285 int rc = VINF_SUCCESS;
286 PPDMASYNCCOMPLETIONENDPOINTFILE pEpFile = (PPDMASYNCCOMPLETIONENDPOINTFILE)pEndpoint;
287 PPDMASYNCCOMPLETIONTASKFILE pTaskFile = (PPDMASYNCCOMPLETIONTASKFILE)pTask;
288 PPDMACEPFILEMGR pAioMgr = pEpFile->pAioMgr;
289
290 Assert( (enmTransfer == PDMACTASKFILETRANSFER_READ)
291 || (enmTransfer == PDMACTASKFILETRANSFER_WRITE));
292
293 Assert((uint32_t)cbTransfer == cbTransfer && (int32_t)cbTransfer >= 0);
294 ASMAtomicWriteS32(&pTaskFile->cbTransferLeft, (int32_t)cbTransfer);
295 ASMAtomicWriteBool(&pTaskFile->fCompleted, false);
296 ASMAtomicWriteS32(&pTaskFile->rc, VINF_SUCCESS);
297
298 for (unsigned i = 0; i < cSegments; i++)
299 {
300 PPDMACTASKFILE pIoTask = pdmacFileTaskAlloc(pEpFile);
301 AssertPtr(pIoTask);
302
303 pIoTask->pEndpoint = pEpFile;
304 pIoTask->enmTransferType = enmTransfer;
305 pIoTask->Off = off;
306 pIoTask->DataSeg.cbSeg = paSegments[i].cbSeg;
307 pIoTask->DataSeg.pvSeg = paSegments[i].pvSeg;
308 pIoTask->pvUser = pTaskFile;
309 pIoTask->pfnCompleted = pdmacFileEpTaskCompleted;
310
311 /* Send it off to the I/O manager. */
312 pdmacFileEpAddTask(pEpFile, pIoTask);
313 off += paSegments[i].cbSeg;
314 cbTransfer -= paSegments[i].cbSeg;
315 }
316
317 AssertMsg(!cbTransfer, ("Incomplete transfer %u bytes left\n", cbTransfer));
318
319 if (ASMAtomicReadS32(&pTaskFile->cbTransferLeft) == 0
320 && !ASMAtomicXchgBool(&pTaskFile->fCompleted, true))
321 pdmR3AsyncCompletionCompleteTask(pTask, pTaskFile->rc, false);
322 else
323 rc = VINF_AIO_TASK_PENDING;
324
325 return rc;
326}
327
328/**
329 * Creates a new async I/O manager.
330 *
331 * @returns VBox status code.
332 * @param pEpClass Pointer to the endpoint class data.
333 * @param ppAioMgr Where to store the pointer to the new async I/O manager on success.
334 * @param enmMgrType Wanted manager type - can be overwritten by the global override.
335 */
336int pdmacFileAioMgrCreate(PPDMASYNCCOMPLETIONEPCLASSFILE pEpClass, PPPDMACEPFILEMGR ppAioMgr,
337 PDMACEPFILEMGRTYPE enmMgrType)
338{
339 int rc = VINF_SUCCESS;
340 PPDMACEPFILEMGR pAioMgrNew;
341
342 LogFlowFunc((": Entered\n"));
343
344 rc = MMR3HeapAllocZEx(pEpClass->Core.pVM, MM_TAG_PDM_ASYNC_COMPLETION, sizeof(PDMACEPFILEMGR), (void **)&pAioMgrNew);
345 if (RT_SUCCESS(rc))
346 {
347 if (enmMgrType < pEpClass->enmMgrTypeOverride)
348 pAioMgrNew->enmMgrType = enmMgrType;
349 else
350 pAioMgrNew->enmMgrType = pEpClass->enmMgrTypeOverride;
351
352 rc = RTSemEventCreate(&pAioMgrNew->EventSem);
353 if (RT_SUCCESS(rc))
354 {
355 rc = RTSemEventCreate(&pAioMgrNew->EventSemBlock);
356 if (RT_SUCCESS(rc))
357 {
358 rc = RTCritSectInit(&pAioMgrNew->CritSectBlockingEvent);
359 if (RT_SUCCESS(rc))
360 {
361 /* Init the rest of the manager. */
362 if (pAioMgrNew->enmMgrType != PDMACEPFILEMGRTYPE_SIMPLE)
363 rc = pdmacFileAioMgrNormalInit(pAioMgrNew);
364
365 if (RT_SUCCESS(rc))
366 {
367 pAioMgrNew->enmState = PDMACEPFILEMGRSTATE_RUNNING;
368
369 rc = RTThreadCreateF(&pAioMgrNew->Thread,
370 pAioMgrNew->enmMgrType == PDMACEPFILEMGRTYPE_SIMPLE
371 ? pdmacFileAioMgrFailsafe
372 : pdmacFileAioMgrNormal,
373 pAioMgrNew,
374 0,
375 RTTHREADTYPE_IO,
376 0,
377 "AioMgr%d-%s", pEpClass->cAioMgrs,
378 pAioMgrNew->enmMgrType == PDMACEPFILEMGRTYPE_SIMPLE
379 ? "F"
380 : "N");
381 if (RT_SUCCESS(rc))
382 {
383 /* Link it into the list. */
384 RTCritSectEnter(&pEpClass->CritSect);
385 pAioMgrNew->pNext = pEpClass->pAioMgrHead;
386 if (pEpClass->pAioMgrHead)
387 pEpClass->pAioMgrHead->pPrev = pAioMgrNew;
388 pEpClass->pAioMgrHead = pAioMgrNew;
389 pEpClass->cAioMgrs++;
390 RTCritSectLeave(&pEpClass->CritSect);
391
392 *ppAioMgr = pAioMgrNew;
393
394 Log(("PDMAC: Successfully created new file AIO Mgr {%s}\n", RTThreadGetName(pAioMgrNew->Thread)));
395 return VINF_SUCCESS;
396 }
397 pdmacFileAioMgrNormalDestroy(pAioMgrNew);
398 }
399 RTCritSectDelete(&pAioMgrNew->CritSectBlockingEvent);
400 }
401 RTSemEventDestroy(pAioMgrNew->EventSem);
402 }
403 RTSemEventDestroy(pAioMgrNew->EventSemBlock);
404 }
405 MMR3HeapFree(pAioMgrNew);
406 }
407
408 LogFlowFunc((": Leave rc=%Rrc\n", rc));
409
410 return rc;
411}
412
413/**
414 * Destroys a async I/O manager.
415 *
416 * @returns nothing.
417 * @param pAioMgr The async I/O manager to destroy.
418 */
419static void pdmacFileAioMgrDestroy(PPDMASYNCCOMPLETIONEPCLASSFILE pEpClassFile, PPDMACEPFILEMGR pAioMgr)
420{
421 int rc = pdmacFileAioMgrShutdown(pAioMgr);
422 AssertRC(rc);
423
424 /* Unlink from the list. */
425 rc = RTCritSectEnter(&pEpClassFile->CritSect);
426 AssertRC(rc);
427
428 PPDMACEPFILEMGR pPrev = pAioMgr->pPrev;
429 PPDMACEPFILEMGR pNext = pAioMgr->pNext;
430
431 if (pPrev)
432 pPrev->pNext = pNext;
433 else
434 pEpClassFile->pAioMgrHead = pNext;
435
436 if (pNext)
437 pNext->pPrev = pPrev;
438
439 pEpClassFile->cAioMgrs--;
440 rc = RTCritSectLeave(&pEpClassFile->CritSect);
441 AssertRC(rc);
442
443 /* Free the ressources. */
444 RTCritSectDelete(&pAioMgr->CritSectBlockingEvent);
445 RTSemEventDestroy(pAioMgr->EventSem);
446 if (pAioMgr->enmMgrType != PDMACEPFILEMGRTYPE_SIMPLE)
447 pdmacFileAioMgrNormalDestroy(pAioMgr);
448
449 MMR3HeapFree(pAioMgr);
450}
451
452static int pdmacFileBwMgrInitialize(PPDMASYNCCOMPLETIONEPCLASSFILE pEpClassFile,
453 PCFGMNODE pCfgNode, PPPDMACFILEBWMGR ppBwMgr)
454{
455 int rc = VINF_SUCCESS;
456 PPDMACFILEBWMGR pBwMgr = NULL;
457
458 rc = MMR3HeapAllocZEx(pEpClassFile->Core.pVM, MM_TAG_PDM_ASYNC_COMPLETION,
459 sizeof(PDMACFILEBWMGR),
460 (void **)&pBwMgr);
461 if (RT_SUCCESS(rc))
462 {
463 /* Init I/O flow control. */
464 rc = CFGMR3QueryU32Def(pCfgNode, "VMTransferPerSecMax", &pBwMgr->cbVMTransferPerSecMax, UINT32_MAX);
465 AssertLogRelRCReturn(rc, rc);
466 rc = CFGMR3QueryU32Def(pCfgNode, "VMTransferPerSecStart", &pBwMgr->cbVMTransferPerSecStart, UINT32_MAX /*5 * _1M*/);
467 AssertLogRelRCReturn(rc, rc);
468 rc = CFGMR3QueryU32Def(pCfgNode, "VMTransferPerSecStep", &pBwMgr->cbVMTransferPerSecStep, _1M);
469 AssertLogRelRCReturn(rc, rc);
470
471 pBwMgr->cbVMTransferAllowed = pBwMgr->cbVMTransferPerSecStart;
472 pBwMgr->tsUpdatedLast = RTTimeSystemNanoTS();
473
474 if (pBwMgr->cbVMTransferPerSecMax != UINT32_MAX)
475 LogRel(("AIOMgr: I/O bandwidth limited to %u bytes/sec\n", pBwMgr->cbVMTransferPerSecMax));
476 else
477 LogRel(("AIOMgr: I/O bandwidth not limited\n"));
478
479 *ppBwMgr = pBwMgr;
480 }
481
482 return rc;
483}
484
485static void pdmacFileBwMgrDestroy(PPDMACFILEBWMGR pBwMgr)
486{
487 MMR3HeapFree(pBwMgr);
488}
489
490static void pdmacFileBwRef(PPDMACFILEBWMGR pBwMgr)
491{
492 pBwMgr->cRefs++;
493}
494
495static void pdmacFileBwUnref(PPDMACFILEBWMGR pBwMgr)
496{
497 Assert(pBwMgr->cRefs > 0);
498 pBwMgr->cRefs--;
499}
500
501bool pdmacFileBwMgrIsTransferAllowed(PPDMACFILEBWMGR pBwMgr, uint32_t cbTransfer)
502{
503 bool fAllowed = false;
504
505 LogFlowFunc(("pBwMgr=%p cbTransfer=%u\n", pBwMgr, cbTransfer));
506
507 uint32_t cbOld = ASMAtomicSubU32(&pBwMgr->cbVMTransferAllowed, cbTransfer);
508 if (RT_LIKELY(cbOld >= cbTransfer))
509 fAllowed = true;
510 else
511 {
512 /* We are out of ressources Check if we can update again. */
513 uint64_t tsNow = RTTimeSystemNanoTS();
514 uint64_t tsUpdatedLast = ASMAtomicUoReadU64(&pBwMgr->tsUpdatedLast);
515
516 if (tsNow - tsUpdatedLast >= (1000*1000*1000))
517 {
518 if (ASMAtomicCmpXchgU64(&pBwMgr->tsUpdatedLast, tsNow, tsUpdatedLast))
519 {
520 if (pBwMgr->cbVMTransferPerSecStart < pBwMgr->cbVMTransferPerSecMax)
521 {
522 pBwMgr->cbVMTransferPerSecStart = RT_MIN(pBwMgr->cbVMTransferPerSecMax, pBwMgr->cbVMTransferPerSecStart + pBwMgr->cbVMTransferPerSecStep);
523 LogFlow(("AIOMgr: Increasing maximum bandwidth to %u bytes/sec\n", pBwMgr->cbVMTransferPerSecStart));
524 }
525
526 /* Update */
527 ASMAtomicWriteU32(&pBwMgr->cbVMTransferAllowed, pBwMgr->cbVMTransferPerSecStart - cbTransfer);
528 fAllowed = true;
529 LogFlow(("AIOMgr: Refreshed bandwidth\n"));
530 }
531 }
532 else
533 ASMAtomicAddU32(&pBwMgr->cbVMTransferAllowed, cbTransfer);
534 }
535
536 LogFlowFunc(("fAllowed=%RTbool\n", fAllowed));
537
538 return fAllowed;
539}
540
541static int pdmacFileMgrTypeFromName(const char *pszVal, PPDMACEPFILEMGRTYPE penmMgrType)
542{
543 int rc = VINF_SUCCESS;
544
545 if (!RTStrCmp(pszVal, "Simple"))
546 *penmMgrType = PDMACEPFILEMGRTYPE_SIMPLE;
547 else if (!RTStrCmp(pszVal, "Async"))
548 *penmMgrType = PDMACEPFILEMGRTYPE_ASYNC;
549 else
550 rc = VERR_CFGM_CONFIG_UNKNOWN_VALUE;
551
552 return rc;
553}
554
555static const char *pdmacFileMgrTypeToName(PDMACEPFILEMGRTYPE enmMgrType)
556{
557 if (enmMgrType == PDMACEPFILEMGRTYPE_SIMPLE)
558 return "Simple";
559 if (enmMgrType == PDMACEPFILEMGRTYPE_ASYNC)
560 return "Async";
561
562 return NULL;
563}
564
565static int pdmacFileBackendTypeFromName(const char *pszVal, PPDMACFILEEPBACKEND penmBackendType)
566{
567 int rc = VINF_SUCCESS;
568
569 if (!RTStrCmp(pszVal, "Buffered"))
570 *penmBackendType = PDMACFILEEPBACKEND_BUFFERED;
571 else if (!RTStrCmp(pszVal, "NonBuffered"))
572 *penmBackendType = PDMACFILEEPBACKEND_NON_BUFFERED;
573 else
574 rc = VERR_CFGM_CONFIG_UNKNOWN_VALUE;
575
576 return rc;
577}
578
579static const char *pdmacFileBackendTypeToName(PDMACFILEEPBACKEND enmBackendType)
580{
581 if (enmBackendType == PDMACFILEEPBACKEND_BUFFERED)
582 return "Buffered";
583 if (enmBackendType == PDMACFILEEPBACKEND_NON_BUFFERED)
584 return "NonBuffered";
585
586 return NULL;
587}
588
589static int pdmacFileInitialize(PPDMASYNCCOMPLETIONEPCLASS pClassGlobals, PCFGMNODE pCfgNode)
590{
591 int rc = VINF_SUCCESS;
592 RTFILEAIOLIMITS AioLimits; /** < Async I/O limitations. */
593
594 PPDMASYNCCOMPLETIONEPCLASSFILE pEpClassFile = (PPDMASYNCCOMPLETIONEPCLASSFILE)pClassGlobals;
595
596 rc = RTFileAioGetLimits(&AioLimits);
597#ifdef DEBUG
598 if (RT_SUCCESS(rc) && RTEnvExist("VBOX_ASYNC_IO_FAILBACK"))
599 rc = VERR_ENV_VAR_NOT_FOUND;
600#endif
601 if (RT_FAILURE(rc))
602 {
603 LogRel(("AIO: Async I/O manager not supported (rc=%Rrc). Falling back to simple manager\n",
604 rc));
605 pEpClassFile->enmMgrTypeOverride = PDMACEPFILEMGRTYPE_SIMPLE;
606 pEpClassFile->enmEpBackendDefault = PDMACFILEEPBACKEND_BUFFERED;
607 }
608 else
609 {
610 pEpClassFile->uBitmaskAlignment = AioLimits.cbBufferAlignment ? ~((RTR3UINTPTR)AioLimits.cbBufferAlignment - 1) : RTR3UINTPTR_MAX;
611 pEpClassFile->cReqsOutstandingMax = AioLimits.cReqsOutstandingMax;
612
613 if (pCfgNode)
614 {
615 /* Query the default manager type */
616 char *pszVal = NULL;
617 rc = CFGMR3QueryStringAllocDef(pCfgNode, "IoMgr", &pszVal, "Async");
618 AssertLogRelRCReturn(rc, rc);
619
620 rc = pdmacFileMgrTypeFromName(pszVal, &pEpClassFile->enmMgrTypeOverride);
621 MMR3HeapFree(pszVal);
622 if (RT_FAILURE(rc))
623 return rc;
624
625 LogRel(("AIOMgr: Default manager type is \"%s\"\n", pdmacFileMgrTypeToName(pEpClassFile->enmMgrTypeOverride)));
626
627 /* Query default backend type */
628#ifndef RT_OS_LINUX
629 rc = CFGMR3QueryStringAllocDef(pCfgNode, "FileBackend", &pszVal, "Buffered");
630#else /* Linux can't use buffered with async */
631 rc = CFGMR3QueryStringAllocDef(pCfgNode, "FileBackend", &pszVal, "NonBuffered");
632#endif
633 AssertLogRelRCReturn(rc, rc);
634
635 rc = pdmacFileBackendTypeFromName(pszVal, &pEpClassFile->enmEpBackendDefault);
636 MMR3HeapFree(pszVal);
637 if (RT_FAILURE(rc))
638 return rc;
639
640 LogRel(("AIOMgr: Default file backend is \"%s\"\n", pdmacFileBackendTypeToName(pEpClassFile->enmEpBackendDefault)));
641
642#ifdef RT_OS_LINUX
643 if ( pEpClassFile->enmMgrTypeOverride == PDMACEPFILEMGRTYPE_ASYNC
644 && pEpClassFile->enmEpBackendDefault == PDMACFILEEPBACKEND_BUFFERED)
645 {
646 LogRel(("AIOMgr: Linux does not support buffered async I/O, changing to non buffered\n"));
647 pEpClassFile->enmEpBackendDefault = PDMACFILEEPBACKEND_NON_BUFFERED;
648 }
649#endif
650 }
651 else
652 {
653 /* No configuration supplied, set defaults */
654 pEpClassFile->enmMgrTypeOverride = PDMACEPFILEMGRTYPE_ASYNC;
655#ifdef RT_OS_LINUX
656 pEpClassFile->enmEpBackendDefault = PDMACFILEEPBACKEND_NON_BUFFERED;
657#else
658 pEpClassFile->enmEpBackendDefault = PDMACFILEEPBACKEND_BUFFERED;
659#endif
660 }
661 }
662
663 /* Init critical section. */
664 rc = RTCritSectInit(&pEpClassFile->CritSect);
665 if (RT_SUCCESS(rc))
666 {
667 /* Check if the cache was disabled by the user. */
668 rc = CFGMR3QueryBoolDef(pCfgNode, "CacheEnabled", &pEpClassFile->fCacheEnabled, true);
669 AssertLogRelRCReturn(rc, rc);
670
671 if (pEpClassFile->fCacheEnabled)
672 {
673 /* Init cache structure */
674 rc = pdmacFileCacheInit(pEpClassFile, pCfgNode);
675 if (RT_FAILURE(rc))
676 {
677 pEpClassFile->fCacheEnabled = false;
678 LogRel(("AIOMgr: Failed to initialise the cache (rc=%Rrc), disabled caching\n"));
679 }
680 }
681 else
682 LogRel(("AIOMgr: Cache was globally disabled\n"));
683
684 rc = pdmacFileBwMgrInitialize(pEpClassFile, pCfgNode, &pEpClassFile->pBwMgr);
685 if (RT_FAILURE(rc))
686 RTCritSectDelete(&pEpClassFile->CritSect);
687 }
688
689 return rc;
690}
691
692static void pdmacFileTerminate(PPDMASYNCCOMPLETIONEPCLASS pClassGlobals)
693{
694 PPDMASYNCCOMPLETIONEPCLASSFILE pEpClassFile = (PPDMASYNCCOMPLETIONEPCLASSFILE)pClassGlobals;
695
696 /* All endpoints should be closed at this point. */
697 AssertMsg(!pEpClassFile->Core.pEndpointsHead, ("There are still endpoints left\n"));
698
699 /* Destroy all left async I/O managers. */
700 while (pEpClassFile->pAioMgrHead)
701 pdmacFileAioMgrDestroy(pEpClassFile, pEpClassFile->pAioMgrHead);
702
703 /* Destroy the cache. */
704 if (pEpClassFile->fCacheEnabled)
705 pdmacFileCacheDestroy(pEpClassFile);
706
707 RTCritSectDelete(&pEpClassFile->CritSect);
708 pdmacFileBwMgrDestroy(pEpClassFile->pBwMgr);
709}
710
711static int pdmacFileEpInitialize(PPDMASYNCCOMPLETIONENDPOINT pEndpoint,
712 const char *pszUri, uint32_t fFlags)
713{
714 int rc = VINF_SUCCESS;
715 PPDMASYNCCOMPLETIONENDPOINTFILE pEpFile = (PPDMASYNCCOMPLETIONENDPOINTFILE)pEndpoint;
716 PPDMASYNCCOMPLETIONEPCLASSFILE pEpClassFile = (PPDMASYNCCOMPLETIONEPCLASSFILE)pEndpoint->pEpClass;
717 PDMACEPFILEMGRTYPE enmMgrType = pEpClassFile->enmMgrTypeOverride;
718 PDMACFILEEPBACKEND enmEpBackend = pEpClassFile->enmEpBackendDefault;
719
720 AssertMsgReturn((fFlags & ~(PDMACEP_FILE_FLAGS_READ_ONLY | PDMACEP_FILE_FLAGS_CACHING)) == 0,
721 ("PDMAsyncCompletion: Invalid flag specified\n"), VERR_INVALID_PARAMETER);
722
723 unsigned fFileFlags = fFlags & PDMACEP_FILE_FLAGS_READ_ONLY
724 ? RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_NONE
725 : RTFILE_O_READWRITE | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE;
726
727 if (enmMgrType == PDMACEPFILEMGRTYPE_ASYNC)
728 fFileFlags |= RTFILE_O_ASYNC_IO;
729
730 if (enmEpBackend == PDMACFILEEPBACKEND_NON_BUFFERED)
731 {
732 /*
733 * We only disable the cache if the size of the file is a multiple of 512.
734 * Certain hosts like Windows, Linux and Solaris require that transfer sizes
735 * are aligned to the volume sector size.
736 * If not we just make sure that the data is written to disk with RTFILE_O_WRITE_THROUGH
737 * which will trash the host cache but ensures that the host cache will not
738 * contain dirty buffers.
739 */
740 RTFILE File = NIL_RTFILE;
741
742 rc = RTFileOpen(&File, pszUri, RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_NONE);
743 if (RT_SUCCESS(rc))
744 {
745 uint64_t cbSize;
746
747 rc = RTFileGetSize(File, &cbSize);
748 if (RT_SUCCESS(rc) && ((cbSize % 512) == 0))
749 fFileFlags |= RTFILE_O_NO_CACHE;
750 else
751 {
752 /* Downgrade to the buffered backend */
753 enmEpBackend = PDMACFILEEPBACKEND_BUFFERED;
754
755#ifdef RT_OS_LINUX
756 fFileFlags &= ~RTFILE_O_ASYNC_IO;
757 enmMgrType = PDMACEPFILEMGRTYPE_SIMPLE;
758#endif
759 }
760 RTFileClose(File);
761 }
762 }
763
764 /* Open with final flags. */
765 rc = RTFileOpen(&pEpFile->File, pszUri, fFileFlags);
766 if ((rc == VERR_INVALID_FUNCTION) || (rc == VERR_INVALID_PARAMETER))
767 {
768 LogRel(("pdmacFileEpInitialize: RTFileOpen %s / %08x failed with %Rrc\n",
769 pszUri, fFileFlags, rc));
770 /*
771 * Solaris doesn't support directio on ZFS so far. :-\
772 * Trying to enable it returns VERR_INVALID_FUNCTION
773 * (ENOTTY). Remove it and hope for the best.
774 * ZFS supports write throttling in case applications
775 * write more data than can be synced to the disk
776 * without blocking the whole application.
777 *
778 * On Linux we have the same problem with cifs.
779 * Have to disable async I/O here too because it requires O_DIRECT.
780 */
781 fFileFlags &= ~RTFILE_O_NO_CACHE;
782 enmEpBackend = PDMACFILEEPBACKEND_BUFFERED;
783
784#ifdef RT_OS_LINUX
785 fFileFlags &= ~RTFILE_O_ASYNC_IO;
786 enmMgrType = PDMACEPFILEMGRTYPE_SIMPLE;
787#endif
788
789 /* Open again. */
790 rc = RTFileOpen(&pEpFile->File, pszUri, fFileFlags);
791
792 if (RT_FAILURE(rc))
793 {
794 LogRel(("pdmacFileEpInitialize: RTFileOpen %s / %08x failed AGAIN(!) with %Rrc\n",
795 pszUri, fFileFlags, rc));
796 }
797 }
798
799 if (RT_SUCCESS(rc))
800 {
801 pEpFile->fFlags = fFileFlags;
802
803 rc = RTFileGetSize(pEpFile->File, (uint64_t *)&pEpFile->cbFile);
804 if (RT_SUCCESS(rc) && (pEpFile->cbFile == 0))
805 {
806 /* Could be a block device */
807 rc = RTFileSeek(pEpFile->File, 0, RTFILE_SEEK_END, (uint64_t *)&pEpFile->cbFile);
808 }
809
810 if (RT_SUCCESS(rc))
811 {
812 /* Initialize the segment cache */
813 rc = MMR3HeapAllocZEx(pEpClassFile->Core.pVM, MM_TAG_PDM_ASYNC_COMPLETION,
814 sizeof(PDMACTASKFILE),
815 (void **)&pEpFile->pTasksFreeHead);
816 if (RT_SUCCESS(rc))
817 {
818 PPDMACEPFILEMGR pAioMgr = NULL;
819
820 pEpFile->cbEndpoint = pEpFile->cbFile;
821 pEpFile->pTasksFreeTail = pEpFile->pTasksFreeHead;
822 pEpFile->cTasksCached = 0;
823 pEpFile->pBwMgr = pEpClassFile->pBwMgr;
824 pEpFile->enmBackendType = enmEpBackend;
825 pdmacFileBwRef(pEpFile->pBwMgr);
826
827 if (enmMgrType == PDMACEPFILEMGRTYPE_SIMPLE)
828 {
829 /* Simple mode. Every file has its own async I/O manager. */
830 rc = pdmacFileAioMgrCreate(pEpClassFile, &pAioMgr, PDMACEPFILEMGRTYPE_SIMPLE);
831 AssertRC(rc);
832 }
833 else
834 {
835 if ( (fFlags & PDMACEP_FILE_FLAGS_CACHING)
836 && (pEpClassFile->fCacheEnabled))
837 {
838 pEpFile->fCaching = true;
839 rc = pdmacFileEpCacheInit(pEpFile, pEpClassFile);
840 if (RT_FAILURE(rc))
841 {
842 LogRel(("AIOMgr: Endpoint for \"%s\" was opened with caching but initializing cache failed. Disabled caching\n", pszUri));
843 pEpFile->fCaching = false;
844 }
845 }
846
847 pAioMgr = pEpClassFile->pAioMgrHead;
848
849 /* Check for an idling manager of the same type */
850 while (pAioMgr)
851 {
852 if (pAioMgr->enmMgrType == enmMgrType)
853 break;
854 pAioMgr = pAioMgr->pNext;
855 }
856
857 if (!pAioMgr)
858 {
859 rc = pdmacFileAioMgrCreate(pEpClassFile, &pAioMgr, enmMgrType);
860 AssertRC(rc);
861 }
862 }
863
864 pEpFile->AioMgr.pTreeRangesLocked = (PAVLRFOFFTREE)RTMemAllocZ(sizeof(AVLRFOFFTREE));
865 if (!pEpFile->AioMgr.pTreeRangesLocked)
866 rc = VERR_NO_MEMORY;
867 else
868 {
869 pEpFile->enmState = PDMASYNCCOMPLETIONENDPOINTFILESTATE_ACTIVE;
870
871 /* Assign the endpoint to the thread. */
872 rc = pdmacFileAioMgrAddEndpoint(pAioMgr, pEpFile);
873 if (RT_FAILURE(rc))
874 {
875 RTMemFree(pEpFile->AioMgr.pTreeRangesLocked);
876 MMR3HeapFree(pEpFile->pTasksFreeHead);
877 pdmacFileBwUnref(pEpFile->pBwMgr);
878 }
879 }
880 }
881 }
882
883 if (RT_FAILURE(rc))
884 RTFileClose(pEpFile->File);
885 }
886
887#ifdef VBOX_WITH_STATISTICS
888 if (RT_SUCCESS(rc))
889 {
890 STAMR3RegisterF(pEpClassFile->Core.pVM, &pEpFile->StatRead,
891 STAMTYPE_PROFILE_ADV, STAMVISIBILITY_ALWAYS,
892 STAMUNIT_TICKS_PER_CALL, "Time taken to read from the endpoint",
893 "/PDM/AsyncCompletion/File/%s/Read", RTPathFilename(pEpFile->Core.pszUri));
894
895 STAMR3RegisterF(pEpClassFile->Core.pVM, &pEpFile->StatWrite,
896 STAMTYPE_PROFILE_ADV, STAMVISIBILITY_ALWAYS,
897 STAMUNIT_TICKS_PER_CALL, "Time taken to write to the endpoint",
898 "/PDM/AsyncCompletion/File/%s/Write", RTPathFilename(pEpFile->Core.pszUri));
899 }
900#endif
901
902 if (RT_SUCCESS(rc))
903 LogRel(("AIOMgr: Endpoint for file '%s' (flags %08x) created successfully\n", pszUri, pEpFile->fFlags));
904
905 return rc;
906}
907
908static int pdmacFileEpRangesLockedDestroy(PAVLRFOFFNODECORE pNode, void *pvUser)
909{
910 AssertMsgFailed(("The locked ranges tree should be empty at that point\n"));
911 return VINF_SUCCESS;
912}
913
914static int pdmacFileEpClose(PPDMASYNCCOMPLETIONENDPOINT pEndpoint)
915{
916 PPDMASYNCCOMPLETIONENDPOINTFILE pEpFile = (PPDMASYNCCOMPLETIONENDPOINTFILE)pEndpoint;
917 PPDMASYNCCOMPLETIONEPCLASSFILE pEpClassFile = (PPDMASYNCCOMPLETIONEPCLASSFILE)pEndpoint->pEpClass;
918
919 /* Make sure that all tasks finished for this endpoint. */
920 int rc = pdmacFileAioMgrCloseEndpoint(pEpFile->pAioMgr, pEpFile);
921 AssertRC(rc);
922
923 /* endpoint and real file size should better be equal now. */
924 AssertMsg(pEpFile->cbFile == pEpFile->cbEndpoint,
925 ("Endpoint and real file size should match now!\n"));
926
927 /*
928 * If the async I/O manager is in failsafe mode this is the only endpoint
929 * he processes and thus can be destroyed now.
930 */
931 if (pEpFile->pAioMgr->enmMgrType == PDMACEPFILEMGRTYPE_SIMPLE)
932 pdmacFileAioMgrDestroy(pEpClassFile, pEpFile->pAioMgr);
933
934 /* Free cached tasks. */
935 PPDMACTASKFILE pTask = pEpFile->pTasksFreeHead;
936
937 while (pTask)
938 {
939 PPDMACTASKFILE pTaskFree = pTask;
940 pTask = pTask->pNext;
941 MMR3HeapFree(pTaskFree);
942 }
943
944 /* Free the cached data. */
945 if (pEpFile->fCaching)
946 pdmacFileEpCacheDestroy(pEpFile);
947
948 /* Remove from the bandwidth manager */
949 pdmacFileBwUnref(pEpFile->pBwMgr);
950
951 /* Destroy the locked ranges tree now. */
952 RTAvlrFileOffsetDestroy(pEpFile->AioMgr.pTreeRangesLocked, pdmacFileEpRangesLockedDestroy, NULL);
953
954 RTFileClose(pEpFile->File);
955
956#ifdef VBOX_WITH_STATISTICS
957 STAMR3Deregister(pEpClassFile->Core.pVM, &pEpFile->StatRead);
958 STAMR3Deregister(pEpClassFile->Core.pVM, &pEpFile->StatWrite);
959#endif
960
961 return VINF_SUCCESS;
962}
963
964static int pdmacFileEpRead(PPDMASYNCCOMPLETIONTASK pTask,
965 PPDMASYNCCOMPLETIONENDPOINT pEndpoint, RTFOFF off,
966 PCRTSGSEG paSegments, size_t cSegments,
967 size_t cbRead)
968{
969 int rc = VINF_SUCCESS;
970 PPDMASYNCCOMPLETIONENDPOINTFILE pEpFile = (PPDMASYNCCOMPLETIONENDPOINTFILE)pEndpoint;
971
972 STAM_PROFILE_ADV_START(&pEpFile->StatRead, Read);
973
974 if (pEpFile->fCaching)
975 rc = pdmacFileEpCacheRead(pEpFile, (PPDMASYNCCOMPLETIONTASKFILE)pTask,
976 off, paSegments, cSegments, cbRead);
977 else
978 rc = pdmacFileEpTaskInitiate(pTask, pEndpoint, off, paSegments, cSegments, cbRead,
979 PDMACTASKFILETRANSFER_READ);
980
981 STAM_PROFILE_ADV_STOP(&pEpFile->StatRead, Read);
982
983 return rc;
984}
985
986static int pdmacFileEpWrite(PPDMASYNCCOMPLETIONTASK pTask,
987 PPDMASYNCCOMPLETIONENDPOINT pEndpoint, RTFOFF off,
988 PCRTSGSEG paSegments, size_t cSegments,
989 size_t cbWrite)
990{
991 int rc = VINF_SUCCESS;
992 PPDMASYNCCOMPLETIONENDPOINTFILE pEpFile = (PPDMASYNCCOMPLETIONENDPOINTFILE)pEndpoint;
993
994 if (RT_UNLIKELY(pEpFile->fReadonly))
995 return VERR_NOT_SUPPORTED;
996
997 STAM_PROFILE_ADV_START(&pEpFile->StatWrite, Write);
998
999 if (pEpFile->fCaching)
1000 rc = pdmacFileEpCacheWrite(pEpFile, (PPDMASYNCCOMPLETIONTASKFILE)pTask,
1001 off, paSegments, cSegments, cbWrite);
1002 else
1003 rc = pdmacFileEpTaskInitiate(pTask, pEndpoint, off, paSegments, cSegments, cbWrite,
1004 PDMACTASKFILETRANSFER_WRITE);
1005
1006 STAM_PROFILE_ADV_STOP(&pEpFile->StatWrite, Write);
1007
1008 /* Increase endpoint size. */
1009 if ( RT_SUCCESS(rc)
1010 && ((uint64_t)off + cbWrite) > pEpFile->cbEndpoint)
1011 ASMAtomicWriteU64(&pEpFile->cbEndpoint, (uint64_t)off + cbWrite);
1012
1013 return rc;
1014}
1015
1016static int pdmacFileEpFlush(PPDMASYNCCOMPLETIONTASK pTask,
1017 PPDMASYNCCOMPLETIONENDPOINT pEndpoint)
1018{
1019 int rc = VINF_SUCCESS;
1020 PPDMASYNCCOMPLETIONENDPOINTFILE pEpFile = (PPDMASYNCCOMPLETIONENDPOINTFILE)pEndpoint;
1021 PPDMASYNCCOMPLETIONTASKFILE pTaskFile = (PPDMASYNCCOMPLETIONTASKFILE)pTask;
1022
1023 if (RT_UNLIKELY(pEpFile->fReadonly))
1024 return VERR_NOT_SUPPORTED;
1025
1026 pTaskFile->cbTransferLeft = 0;
1027 pTaskFile->rc = VINF_SUCCESS;
1028
1029 if (pEpFile->fCaching)
1030 rc = pdmacFileEpCacheFlush(pEpFile, pTaskFile);
1031 else
1032 {
1033 PPDMACTASKFILE pIoTask = pdmacFileTaskAlloc(pEpFile);
1034 AssertPtr(pIoTask);
1035
1036 pIoTask->pEndpoint = pEpFile;
1037 pIoTask->enmTransferType = PDMACTASKFILETRANSFER_FLUSH;
1038 pIoTask->pvUser = pTaskFile;
1039 pIoTask->pfnCompleted = pdmacFileEpTaskCompleted;
1040 pdmacFileEpAddTask(pEpFile, pIoTask);
1041 rc = VINF_AIO_TASK_PENDING;
1042 }
1043
1044 return rc;
1045}
1046
1047static int pdmacFileEpGetSize(PPDMASYNCCOMPLETIONENDPOINT pEndpoint, uint64_t *pcbSize)
1048{
1049 PPDMASYNCCOMPLETIONENDPOINTFILE pEpFile = (PPDMASYNCCOMPLETIONENDPOINTFILE)pEndpoint;
1050
1051 *pcbSize = ASMAtomicReadU64(&pEpFile->cbEndpoint);
1052
1053 return VINF_SUCCESS;
1054}
1055
1056static int pdmacFileEpSetSize(PPDMASYNCCOMPLETIONENDPOINT pEndpoint, uint64_t cbSize)
1057{
1058 PPDMASYNCCOMPLETIONENDPOINTFILE pEpFile = (PPDMASYNCCOMPLETIONENDPOINTFILE)pEndpoint;
1059
1060 ASMAtomicWriteU64(&pEpFile->cbEndpoint, cbSize);
1061 return RTFileSetSize(pEpFile->File, cbSize);
1062}
1063
1064const PDMASYNCCOMPLETIONEPCLASSOPS g_PDMAsyncCompletionEndpointClassFile =
1065{
1066 /* u32Version */
1067 PDMAC_EPCLASS_OPS_VERSION,
1068 /* pcszName */
1069 "File",
1070 /* enmClassType */
1071 PDMASYNCCOMPLETIONEPCLASSTYPE_FILE,
1072 /* cbEndpointClassGlobal */
1073 sizeof(PDMASYNCCOMPLETIONEPCLASSFILE),
1074 /* cbEndpoint */
1075 sizeof(PDMASYNCCOMPLETIONENDPOINTFILE),
1076 /* cbTask */
1077 sizeof(PDMASYNCCOMPLETIONTASKFILE),
1078 /* pfnInitialize */
1079 pdmacFileInitialize,
1080 /* pfnTerminate */
1081 pdmacFileTerminate,
1082 /* pfnEpInitialize. */
1083 pdmacFileEpInitialize,
1084 /* pfnEpClose */
1085 pdmacFileEpClose,
1086 /* pfnEpRead */
1087 pdmacFileEpRead,
1088 /* pfnEpWrite */
1089 pdmacFileEpWrite,
1090 /* pfnEpFlush */
1091 pdmacFileEpFlush,
1092 /* pfnEpGetSize */
1093 pdmacFileEpGetSize,
1094 /* pfnEpSetSize */
1095 pdmacFileEpSetSize,
1096 /* u32VersionEnd */
1097 PDMAC_EPCLASS_OPS_VERSION
1098};
1099
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use