Changeset 74822 in vbox for trunk/src/VBox/Main/src-server
- Timestamp:
- Oct 12, 2018 6:40:09 PM (7 years ago)
- svn:sync-xref-src-repo-rev:
- 125775
- Location:
- trunk/src/VBox/Main/src-server
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Main/src-server/MediumIOImpl.cpp
r74763 r74822 24 24 #include "MediumImpl.h" 25 25 #include "MediumLock.h" 26 #include "DataStreamImpl.h" 26 27 #include "Global.h" 28 #include "ProgressImpl.h" 29 #include "VirtualBoxImpl.h" 27 30 28 31 #include "AutoCaller.h" 29 32 #include "Logging.h" 33 #include "ThreadTask.h" 30 34 31 35 #include <iprt/fsvfs.h> 32 36 #include <iprt/dvm.h> 37 #include <iprt/zero.h> 33 38 #include <iprt/cpp/utils.h> 34 39 … … 42 47 struct MediumIO::Data 43 48 { 44 Data(Medium * const a_pMedium, bool a_fWritable, uint32_t a_cbSector = 512)49 Data(Medium * const a_pMedium, VirtualBox * const a_pVirtualBox, bool a_fWritable, uint32_t a_cbSector = 512) 45 50 : ptrMedium(a_pMedium) 51 , ptrVirtualBox(a_pVirtualBox) 46 52 , fWritable(a_fWritable) 47 53 , cbSector(a_cbSector) … … 54 60 /** Reference to the medium we're accessing. */ 55 61 ComPtr<Medium> ptrMedium; 62 /** Reference to the VirtualBox object the medium is part of. */ 63 ComPtr<VirtualBox> ptrVirtualBox; 56 64 /** Set if writable, clear if readonly. */ 57 65 bool fWritable; … … 74 82 75 83 84 /** 85 * MediumIO::StreamTask class for asynchronous convert to stream operation. 86 * 87 * @note Instances of this class must be created using new() because the 88 * task thread function will delete them when the task is complete. 89 * 90 * @note The constructor of this class adds a caller on the managed Medium 91 * object which is automatically released upon destruction. 92 */ 93 class MediumIO::StreamTask : public ThreadTask 94 { 95 public: 96 StreamTask(MediumIO *pMediumIO, DataStream *pDataStream, Progress *pProgress, const char *pszFormat, 97 MediumVariant_T fMediumVariant) 98 : ThreadTask("StreamTask"), 99 mVDOperationIfaces(NULL), 100 mMediumIO(pMediumIO), 101 mMediumCaller(pMediumIO->m->ptrMedium), 102 m_pDataStream(pDataStream), 103 m_fMediumVariant(fMediumVariant), 104 m_strFormat(pszFormat), 105 mProgress(pProgress), 106 mVirtualBoxCaller(NULL) 107 { 108 AssertReturnVoidStmt(pMediumIO, mRC = E_FAIL); 109 AssertReturnVoidStmt(pDataStream, mRC = E_FAIL); 110 mRC = mMediumCaller.rc(); 111 if (FAILED(mRC)) 112 return; 113 114 /* Get strong VirtualBox reference, see below. */ 115 VirtualBox *pVirtualBox = pMediumIO->m->ptrVirtualBox; 116 mVirtualBox = pVirtualBox; 117 mVirtualBoxCaller.attach(pVirtualBox); 118 mRC = mVirtualBoxCaller.rc(); 119 if (FAILED(mRC)) 120 return; 121 122 /* Set up a per-operation progress interface, can be used freely (for 123 * binary operations you can use it either on the source or target). */ 124 if (mProgress) 125 { 126 mVDIfProgress.pfnProgress = pProgress->i_vdProgressCallback; 127 int vrc = VDInterfaceAdd(&mVDIfProgress.Core, 128 "Medium::Task::vdInterfaceProgress", 129 VDINTERFACETYPE_PROGRESS, 130 mProgress, 131 sizeof(mVDIfProgress), 132 &mVDOperationIfaces); 133 AssertRC(vrc); 134 if (RT_FAILURE(vrc)) 135 mRC = E_FAIL; 136 } 137 } 138 139 // Make all destructors virtual. Just in case. 140 virtual ~StreamTask() 141 { 142 /* send the notification of completion.*/ 143 if ( isAsync() 144 && !mProgress.isNull()) 145 mProgress->i_notifyComplete(mRC); 146 } 147 148 HRESULT rc() const { return mRC; } 149 bool isOk() const { return SUCCEEDED(rc()); } 150 151 const ComPtr<Progress>& GetProgressObject() const {return mProgress;} 152 153 /** 154 * Implementation code for the "create base" task. 155 * Used as function for execution from a standalone thread. 156 */ 157 void handler() 158 { 159 LogFlowFuncEnter(); 160 try 161 { 162 mRC = executeTask(); /* (destructor picks up mRC, see above) */ 163 LogFlowFunc(("rc=%Rhrc\n", mRC)); 164 } 165 catch (...) 166 { 167 LogRel(("Some exception in the function MediumIO::StreamTask:handler()\n")); 168 } 169 170 LogFlowFuncLeave(); 171 } 172 173 PVDINTERFACE mVDOperationIfaces; 174 175 const ComObjPtr<MediumIO> mMediumIO; 176 AutoCaller mMediumCaller; 177 178 protected: 179 HRESULT mRC; 180 181 DataStream *m_pDataStream; 182 MediumVariant_T m_fMediumVariant; 183 Utf8Str m_strFormat; 184 185 private: 186 HRESULT executeTask(); 187 188 const ComObjPtr<Progress> mProgress; 189 190 VDINTERFACEPROGRESS mVDIfProgress; 191 192 /* Must have a strong VirtualBox reference during a task otherwise the 193 * reference count might drop to 0 while a task is still running. This 194 * would result in weird behavior, including deadlocks due to uninit and 195 * locking order issues. The deadlock often is not detectable because the 196 * uninit uses event semaphores which sabotages deadlock detection. */ 197 ComObjPtr<VirtualBox> mVirtualBox; 198 AutoCaller mVirtualBoxCaller; 199 200 static DECLCALLBACK(int) i_vdStreamOpen(void *pvUser, const char *pszLocation, uint32_t fOpen, 201 PFNVDCOMPLETED pfnCompleted, void **ppStorage); 202 static DECLCALLBACK(int) i_vdStreamClose(void *pvUser, void *pStorage); 203 static DECLCALLBACK(int) i_vdStreamDelete(void *pvUser, const char *pcszFilename); 204 static DECLCALLBACK(int) i_vdStreamMove(void *pvUser, const char *pcszSrc, const char *pcszDst, unsigned fMove); 205 static DECLCALLBACK(int) i_vdStreamGetFreeSpace(void *pvUser, const char *pcszFilename, int64_t *pcbFreeSpace); 206 static DECLCALLBACK(int) i_vdStreamGetModificationTime(void *pvUser, const char *pcszFilename, PRTTIMESPEC pModificationTime); 207 static DECLCALLBACK(int) i_vdStreamGetSize(void *pvUser, void *pStorage, uint64_t *pcbSize); 208 static DECLCALLBACK(int) i_vdStreamSetSize(void *pvUser, void *pStorage, uint64_t cbSize); 209 static DECLCALLBACK(int) i_vdStreamRead(void *pvUser, void *pStorage, uint64_t uOffset, void *pvBuffer, size_t cbBuffer, 210 size_t *pcbRead); 211 static DECLCALLBACK(int) i_vdStreamWrite(void *pvUser, void *pStorage, uint64_t uOffset, 212 const void *pvBuffer, size_t cbBuffer, size_t *pcbWritten); 213 static DECLCALLBACK(int) i_vdStreamFlush(void *pvUser, void *pStorage); 214 }; 215 216 217 /** 218 * State of a streamed file. 219 */ 220 typedef struct STREAMFILE 221 { 222 /** The data stream for this file state. */ 223 DataStream *pDataStream; 224 /** The last seen offset used to stream zeroes for non consecutive writes. */ 225 uint64_t uOffsetLast; 226 /** Set file size. */ 227 uint64_t cbFile; 228 } STREAMFILE; 229 /** Pointer to the stream file state. */ 230 typedef STREAMFILE *PSTREAMFILE; 231 232 233 234 DECLCALLBACK(int) MediumIO::StreamTask::i_vdStreamOpen(void *pvUser, const char *pszLocation, uint32_t fOpen, PFNVDCOMPLETED pfnCompleted, 235 void **ppStorage) 236 { 237 RT_NOREF2(pvUser, pszLocation); 238 239 /* Validate input. */ 240 AssertPtrReturn(ppStorage, VERR_INVALID_POINTER); 241 AssertPtrNullReturn(pfnCompleted, VERR_INVALID_PARAMETER); 242 AssertReturn((fOpen & RTFILE_O_ACCESS_MASK) == RTFILE_O_WRITE, VERR_INVALID_PARAMETER); 243 244 int rc = VINF_SUCCESS; 245 PSTREAMFILE pStreamFile = (PSTREAMFILE)RTMemAllocZ(sizeof(*pStreamFile)); 246 if (RT_LIKELY(pStreamFile)) 247 { 248 pStreamFile->pDataStream = (DataStream *)pvUser; 249 pStreamFile->uOffsetLast = 0; 250 pStreamFile->cbFile = 0; 251 *ppStorage = pStreamFile; 252 } 253 else 254 rc = VERR_NO_MEMORY; 255 256 return rc; 257 } 258 259 DECLCALLBACK(int) MediumIO::StreamTask::i_vdStreamClose(void *pvUser, void *pStorage) 260 { 261 RT_NOREF(pvUser); 262 PSTREAMFILE pStreamFile = (PSTREAMFILE)pStorage; 263 int rc = VINF_SUCCESS; 264 265 /* Fill up to the configured file size. */ 266 if (pStreamFile->uOffsetLast < pStreamFile->cbFile) 267 { 268 do 269 { 270 size_t cbThisWrite = RT_MIN(pStreamFile->cbFile - pStreamFile->uOffsetLast, sizeof(g_abRTZero64K)); 271 size_t cbWritten = 0; 272 273 rc = pStreamFile->pDataStream->i_write(&g_abRTZero64K[0], cbThisWrite, &cbWritten); 274 if (RT_SUCCESS(rc)) 275 pStreamFile->uOffsetLast += cbWritten; 276 277 } while ( RT_SUCCESS(rc) 278 && pStreamFile->uOffsetLast < pStreamFile->cbFile); 279 } 280 281 int rc2 = pStreamFile->pDataStream->i_close(); 282 if (RT_SUCCESS(rc)) 283 rc = rc2; 284 285 RTMemFree(pStreamFile); 286 return rc; 287 } 288 289 DECLCALLBACK(int) MediumIO::StreamTask::i_vdStreamDelete(void *pvUser, const char *pcszFilename) 290 { 291 NOREF(pvUser); 292 NOREF(pcszFilename); 293 AssertFailedReturn(VERR_NOT_SUPPORTED); 294 } 295 296 DECLCALLBACK(int) MediumIO::StreamTask::i_vdStreamMove(void *pvUser, const char *pcszSrc, const char *pcszDst, unsigned fMove) 297 { 298 NOREF(pvUser); 299 NOREF(pcszSrc); 300 NOREF(pcszDst); 301 NOREF(fMove); 302 AssertFailedReturn(VERR_NOT_SUPPORTED); 303 } 304 305 DECLCALLBACK(int) MediumIO::StreamTask::i_vdStreamGetFreeSpace(void *pvUser, const char *pcszFilename, int64_t *pcbFreeSpace) 306 { 307 NOREF(pvUser); 308 NOREF(pcszFilename); 309 AssertPtrReturn(pcbFreeSpace, VERR_INVALID_POINTER); 310 *pcbFreeSpace = INT64_MAX; 311 return VINF_SUCCESS; 312 } 313 314 DECLCALLBACK(int) MediumIO::StreamTask::i_vdStreamGetModificationTime(void *pvUser, const char *pcszFilename, PRTTIMESPEC pModificationTime) 315 { 316 NOREF(pvUser); 317 NOREF(pcszFilename); 318 AssertPtrReturn(pModificationTime, VERR_INVALID_POINTER); 319 AssertFailedReturn(VERR_NOT_SUPPORTED); 320 } 321 322 DECLCALLBACK(int) MediumIO::StreamTask::i_vdStreamGetSize(void *pvUser, void *pStorage, uint64_t *pcbSize) 323 { 324 NOREF(pvUser); 325 PSTREAMFILE pStreamFile = (PSTREAMFILE)pStorage; 326 AssertPtrReturn(pcbSize, VERR_INVALID_POINTER); 327 328 *pcbSize = pStreamFile->cbFile; 329 return VINF_SUCCESS; 330 } 331 332 DECLCALLBACK(int) MediumIO::StreamTask::i_vdStreamSetSize(void *pvUser, void *pStorage, uint64_t cbSize) 333 { 334 RT_NOREF(pvUser); 335 PSTREAMFILE pStreamFile = (PSTREAMFILE)pStorage; 336 337 /* Reducing the size is not supported. */ 338 int rc = VINF_SUCCESS; 339 if (pStreamFile->cbFile < cbSize) 340 pStreamFile->cbFile = cbSize; 341 else 342 rc = VERR_NOT_SUPPORTED; 343 344 return rc; 345 } 346 347 DECLCALLBACK(int) MediumIO::StreamTask::i_vdStreamRead(void *pvUser, void *pStorage, uint64_t uOffset, void *pvBuffer, size_t cbBuffer, 348 size_t *pcbRead) 349 { 350 NOREF(pvUser); 351 NOREF(pStorage); 352 NOREF(uOffset); 353 NOREF(cbBuffer); 354 NOREF(pcbRead); 355 AssertPtrReturn(pvBuffer, VERR_INVALID_POINTER); 356 AssertFailedReturn(VERR_NOT_SUPPORTED); 357 } 358 359 DECLCALLBACK(int) MediumIO::StreamTask::i_vdStreamWrite(void *pvUser, void *pStorage, uint64_t uOffset, const void *pvBuffer, size_t cbBuffer, 360 size_t *pcbWritten) 361 { 362 RT_NOREF(pvUser); 363 PSTREAMFILE pStreamFile = (PSTREAMFILE)pStorage; 364 int rc = VINF_SUCCESS; 365 366 /* Fill up to the new offset if there is non consecutive access. */ 367 if (pStreamFile->uOffsetLast < uOffset) 368 { 369 do 370 { 371 size_t cbThisWrite = RT_MIN(uOffset - pStreamFile->uOffsetLast, sizeof(g_abRTZero64K)); 372 size_t cbWritten = 0; 373 374 rc = pStreamFile->pDataStream->i_write(&g_abRTZero64K[0], cbThisWrite, &cbWritten); 375 if (RT_SUCCESS(rc)) 376 pStreamFile->uOffsetLast += cbWritten; 377 378 } while ( RT_SUCCESS(rc) 379 && pStreamFile->uOffsetLast < uOffset); 380 } 381 382 if (RT_SUCCESS(rc)) 383 { 384 if (pcbWritten) 385 rc = pStreamFile->pDataStream->i_write(pvBuffer, cbBuffer, pcbWritten); 386 else 387 { 388 const uint8_t *pbBuf = (const uint8_t *)pvBuffer; 389 size_t cbLeft = cbBuffer; 390 size_t cbWritten = 0; 391 while ( cbLeft > 0 392 && RT_SUCCESS(rc)) 393 { 394 rc = pStreamFile->pDataStream->i_write(pbBuf, cbLeft, &cbWritten); 395 if (RT_SUCCESS(rc)) 396 { 397 pbBuf += cbWritten; 398 cbLeft -= cbWritten; 399 } 400 } 401 } 402 403 if (RT_SUCCESS(rc)) 404 { 405 size_t cbWritten = pcbWritten ? *pcbWritten : cbBuffer; 406 407 /* Adjust file size. */ 408 if (uOffset + cbWritten > pStreamFile->cbFile) 409 pStreamFile->cbFile = uOffset + cbWritten; 410 411 pStreamFile->uOffsetLast = uOffset + cbWritten; 412 } 413 } 414 415 return rc; 416 } 417 418 DECLCALLBACK(int) MediumIO::StreamTask::i_vdStreamFlush(void *pvUser, void *pStorage) 419 { 420 NOREF(pvUser); 421 NOREF(pStorage); 422 return VINF_SUCCESS; 423 } 424 425 /** 426 * Implementation code for the "stream" task. 427 */ 428 HRESULT MediumIO::StreamTask::executeTask() 429 { 430 HRESULT hrc = S_OK; 431 VDINTERFACEIO IfsOutputIO; 432 PVDINTERFACE pIfsOp = NULL; 433 PVDISK pDstDisk; 434 435 IfsOutputIO.pfnOpen = i_vdStreamOpen; 436 IfsOutputIO.pfnClose = i_vdStreamClose; 437 IfsOutputIO.pfnDelete = i_vdStreamDelete; 438 IfsOutputIO.pfnMove = i_vdStreamMove; 439 IfsOutputIO.pfnGetFreeSpace = i_vdStreamGetFreeSpace; 440 IfsOutputIO.pfnGetModificationTime = i_vdStreamGetModificationTime; 441 IfsOutputIO.pfnGetSize = i_vdStreamGetSize; 442 IfsOutputIO.pfnSetSize = i_vdStreamSetSize; 443 IfsOutputIO.pfnReadSync = i_vdStreamRead; 444 IfsOutputIO.pfnWriteSync = i_vdStreamWrite; 445 IfsOutputIO.pfnFlushSync = i_vdStreamFlush; 446 VDInterfaceAdd(&IfsOutputIO.Core, "stream", VDINTERFACETYPE_IO, 447 m_pDataStream, sizeof(VDINTERFACEIO), &pIfsOp); 448 449 int vrc = VDCreate(NULL, VDTYPE_HDD, &pDstDisk); 450 if (RT_SUCCESS(vrc)) 451 { 452 /* Create the output image */ 453 vrc = VDCopy(mMediumIO->m->pHdd, VD_LAST_IMAGE, pDstDisk, m_strFormat.c_str(), 454 "stream", false, 0, m_fMediumVariant, NULL, 455 VD_OPEN_FLAGS_NORMAL | VD_OPEN_FLAGS_SEQUENTIAL, NULL, 456 pIfsOp, NULL); 457 if (RT_FAILURE(vrc)) 458 hrc = mMediumIO->setErrorBoth(VBOX_E_FILE_ERROR, vrc, 459 tr("Failed to convert and stream disk image")); 460 461 VDDestroy(pDstDisk); 462 } 463 else 464 hrc = mMediumIO->setErrorBoth(VBOX_E_FILE_ERROR, vrc, 465 tr("Failed to create destination disk container")); 466 467 return hrc; 468 } 469 470 76 471 /********************************************************************************************************************************* 77 472 * Boilerplate constructor & destructor * … … 103 498 * 104 499 * @param pMedium Pointer to the medium to access. 500 * @param pMedium Pointer to the VirtualBox object the medium is part of. 105 501 * @param fWritable Read-write (true) or readonly (false) access. 106 502 * @param rStrKeyId The key ID for an encrypted medium. Empty if not … … 110 506 * 111 507 */ 112 HRESULT MediumIO::initForMedium(Medium *pMedium, bool fWritable, com::Utf8Str const &rStrKeyId, com::Utf8Str const &rStrPassword) 113 { 114 LogFlowThisFunc(("pMedium=%p fWritable=%RTbool\n", pMedium, fWritable)); 508 HRESULT MediumIO::initForMedium(Medium *pMedium, VirtualBox *pVirtualBox, bool fWritable, 509 com::Utf8Str const &rStrKeyId, com::Utf8Str const &rStrPassword) 510 { 511 LogFlowThisFunc(("pMedium=%p pVirtualBox=%p fWritable=%RTbool\n", pMedium, pVirtualBox, fWritable)); 115 512 CheckComArgExpr(rStrPassword, rStrPassword.isEmpty() == rStrKeyId.isEmpty()); /* checked by caller */ 116 513 … … 125 522 */ 126 523 HRESULT hrc = S_OK; 127 m = new(std::nothrow) Data(pMedium, fWritable);524 m = new(std::nothrow) Data(pMedium, pVirtualBox, fWritable); 128 525 if (m) 129 526 { … … 400 797 ComPtr<IProgress> &aProgress) 401 798 { 402 RT_NOREF(aFormat, aVariant, aBufferSize, aStream, aProgress); 403 return E_NOTIMPL; 799 HRESULT rc = S_OK; 800 ComObjPtr<Progress> pProgress; 801 ComObjPtr<DataStream> pDataStream; 802 MediumIO::StreamTask *pTask = NULL; 803 804 pProgress.createObject(); 805 pDataStream.createObject(); 806 807 try 808 { 809 rc = pDataStream->init(aBufferSize); 810 if (FAILED(rc)) 811 throw rc; 812 813 ULONG mediumVariantFlags = 0; 814 815 if (aVariant.size()) 816 { 817 for (size_t i = 0; i < aVariant.size(); i++) 818 mediumVariantFlags |= (ULONG)aVariant[i]; 819 } 820 821 /* setup task object to carry out the operation asynchronously */ 822 pTask = new MediumIO::StreamTask(this, pDataStream, pProgress, 823 aFormat.c_str(), (MediumVariant_T)mediumVariantFlags); 824 rc = pTask->rc(); 825 AssertComRC(rc); 826 if (FAILED(rc)) 827 throw rc; 828 } 829 catch (HRESULT aRC) { rc = aRC; } 830 831 if (SUCCEEDED(rc)) 832 { 833 rc = pTask->createThread(); 834 835 if (SUCCEEDED(rc)) 836 { 837 pDataStream.queryInterfaceTo(aStream.asOutParam()); 838 pProgress.queryInterfaceTo(aProgress.asOutParam()); 839 } 840 } 841 else if (pTask != NULL) 842 delete pTask; 843 844 return rc; 404 845 } 405 846 -
trunk/src/VBox/Main/src-server/MediumImpl.cpp
r74353 r74822 3840 3840 if (SUCCEEDED(hrc)) 3841 3841 { 3842 hrc = ptrIO->initForMedium(this, aWritable != FALSE, strKeyId, aPassword);3842 hrc = ptrIO->initForMedium(this, m->pVirtualBox, aWritable != FALSE, strKeyId, aPassword); 3843 3843 if (SUCCEEDED(hrc)) 3844 3844 ptrIO.queryInterfaceTo(aMediumIO.asOutParam());
Note:
See TracChangeset
for help on using the changeset viewer.