VirtualBox

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

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

*: spelling fixes, thanks Timeless!

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