VirtualBox

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

Last change on this file since 27978 was 27978, checked in by vboxsync, 15 years ago

Cleanup

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

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette