Index: /trunk/src/VBox/Devices/Storage/DrvVD.cpp
===================================================================
--- /trunk/src/VBox/Devices/Storage/DrvVD.cpp	(revision 64663)
+++ /trunk/src/VBox/Devices/Storage/DrvVD.cpp	(revision 64664)
@@ -204,6 +204,23 @@
             /** Size of the allocated I/O buffer. */
             size_t                        cbIoBuf;
-            /** I/O buffer descriptor. */
-            IOBUFDESC                     IoBuf;
+            /** Pointer to the S/G buffer. */
+            PRTSGBUF                      pSgBuf;
+            /** Flag whether the pointer is a direct buffer or
+             *  was allocated by us. */
+            bool                          fDirectBuf;
+            /** Buffer management data based on the fDirectBuf flag. */
+            union
+            {
+                /** Direct buffer. */
+                struct
+                {
+                    /** Segment for the data buffer. */
+                    RTSGSEG               Seg;
+                    /** S/G buffer structure. */
+                    RTSGBUF               SgBuf;
+                } Direct;
+                /** I/O buffer descriptor. */
+                IOBUFDESC                 IoBuf;
+            };
         } ReadWrite;
         /** Discard specific data. */
@@ -2626,19 +2643,22 @@
     Assert(pIoReq->ReadWrite.cbIoBuf > 0);
 
-    /* Make sure the buffer is reset. */
-    RTSgBufReset(&pIoReq->ReadWrite.IoBuf.SgBuf);
-
-    size_t const offSrc = pIoReq->ReadWrite.cbReq - pIoReq->ReadWrite.cbReqLeft;
-    Assert((uint32_t)offSrc == offSrc);
-    if (fToIoBuf)
-        rc = pThis->pDrvMediaExPort->pfnIoReqCopyToBuf(pThis->pDrvMediaExPort, pIoReq, &pIoReq->abAlloc[0], (uint32_t)offSrc,
-                                                       &pIoReq->ReadWrite.IoBuf.SgBuf,
-                                                       RT_MIN(pIoReq->ReadWrite.cbIoBuf, pIoReq->ReadWrite.cbReqLeft));
-    else
-        rc = pThis->pDrvMediaExPort->pfnIoReqCopyFromBuf(pThis->pDrvMediaExPort, pIoReq, &pIoReq->abAlloc[0], (uint32_t)offSrc,
-                                                         &pIoReq->ReadWrite.IoBuf.SgBuf,
-                                                         (uint32_t)RT_MIN(pIoReq->ReadWrite.cbIoBuf, pIoReq->ReadWrite.cbReqLeft));
-
-    RTSgBufReset(&pIoReq->ReadWrite.IoBuf.SgBuf);
+    if (!pIoReq->ReadWrite.fDirectBuf)
+    {
+        /* Make sure the buffer is reset. */
+        RTSgBufReset(&pIoReq->ReadWrite.IoBuf.SgBuf);
+
+        size_t const offSrc = pIoReq->ReadWrite.cbReq - pIoReq->ReadWrite.cbReqLeft;
+        Assert((uint32_t)offSrc == offSrc);
+        if (fToIoBuf)
+            rc = pThis->pDrvMediaExPort->pfnIoReqCopyToBuf(pThis->pDrvMediaExPort, pIoReq, &pIoReq->abAlloc[0], (uint32_t)offSrc,
+                                                           &pIoReq->ReadWrite.IoBuf.SgBuf,
+                                                           RT_MIN(pIoReq->ReadWrite.cbIoBuf, pIoReq->ReadWrite.cbReqLeft));
+        else
+            rc = pThis->pDrvMediaExPort->pfnIoReqCopyFromBuf(pThis->pDrvMediaExPort, pIoReq, &pIoReq->abAlloc[0], (uint32_t)offSrc,
+                                                             &pIoReq->ReadWrite.IoBuf.SgBuf,
+                                                             (uint32_t)RT_MIN(pIoReq->ReadWrite.cbIoBuf, pIoReq->ReadWrite.cbReqLeft));
+
+        RTSgBufReset(&pIoReq->ReadWrite.IoBuf.SgBuf);
+    }
     return rc;
 }
@@ -2900,20 +2920,45 @@
 DECLINLINE(int) drvvdMediaExIoReqBufAlloc(PVBOXDISK pThis, PPDMMEDIAEXIOREQINT pIoReq, size_t cb)
 {
+    int rc = VERR_NOT_SUPPORTED;
     LogFlowFunc(("pThis=%#p pIoReq=%#p cb=%zu\n", pThis, pIoReq, cb));
 
-    int rc = IOBUFMgrAllocBuf(pThis->hIoBufMgr, &pIoReq->ReadWrite.IoBuf, cb, &pIoReq->ReadWrite.cbIoBuf);
-    if (rc == VERR_NO_MEMORY)
-    {
-        LogFlowFunc(("Could not allocate memory for request, deferring\n"));
-        RTCritSectEnter(&pThis->CritSectIoReqsIoBufWait);
-        RTListAppend(&pThis->LstIoReqIoBufWait, &pIoReq->NdLstWait);
-        RTCritSectLeave(&pThis->CritSectIoReqsIoBufWait);
-        ASMAtomicIncU32(&pThis->cIoReqsWaiting);
-        rc = VINF_PDM_MEDIAEX_IOREQ_IN_PROGRESS;
-    }
-    else
-    {
-        LogFlowFunc(("Allocated %zu bytes of memory\n", pIoReq->ReadWrite.cbIoBuf));
-        Assert(pIoReq->ReadWrite.cbIoBuf > 0);
+    if (   cb == _4K
+        && pThis->pDrvMediaExPort->pfnIoReqQueryBuf)
+    {
+        /* Try to get a direct pointer to the buffer first. */
+        void *pvBuf = NULL;
+        size_t cbBuf = 0;
+        rc = pThis->pDrvMediaExPort->pfnIoReqQueryBuf(pThis->pDrvMediaExPort, pIoReq, &pIoReq->abAlloc[0],
+                                                      &pvBuf, &cbBuf);
+        if (RT_SUCCESS(rc))
+        {
+            pIoReq->ReadWrite.cbIoBuf           = cbBuf;
+            pIoReq->ReadWrite.fDirectBuf        = true;
+            pIoReq->ReadWrite.Direct.Seg.pvSeg  = pvBuf;
+            pIoReq->ReadWrite.Direct.Seg.cbSeg  = cbBuf;
+            RTSgBufInit(&pIoReq->ReadWrite.Direct.SgBuf, &pIoReq->ReadWrite.Direct.Seg, 1);
+            pIoReq->ReadWrite.pSgBuf = &pIoReq->ReadWrite.Direct.SgBuf;
+        }
+    }
+
+    if (RT_FAILURE(rc))
+    {
+        rc = IOBUFMgrAllocBuf(pThis->hIoBufMgr, &pIoReq->ReadWrite.IoBuf, cb, &pIoReq->ReadWrite.cbIoBuf);
+        if (rc == VERR_NO_MEMORY)
+        {
+            LogFlowFunc(("Could not allocate memory for request, deferring\n"));
+            RTCritSectEnter(&pThis->CritSectIoReqsIoBufWait);
+            RTListAppend(&pThis->LstIoReqIoBufWait, &pIoReq->NdLstWait);
+            RTCritSectLeave(&pThis->CritSectIoReqsIoBufWait);
+            ASMAtomicIncU32(&pThis->cIoReqsWaiting);
+            rc = VINF_PDM_MEDIAEX_IOREQ_IN_PROGRESS;
+        }
+        else
+        {
+            LogFlowFunc(("Allocated %zu bytes of memory\n", pIoReq->ReadWrite.cbIoBuf));
+            Assert(pIoReq->ReadWrite.cbIoBuf > 0);
+            pIoReq->ReadWrite.fDirectBuf = false;
+            pIoReq->ReadWrite.pSgBuf = &pIoReq->ReadWrite.IoBuf.SgBuf;
+        }
     }
 
@@ -2945,5 +2990,5 @@
         {
             rc = PDMR3BlkCacheRead(pThis->pBlkCache, pIoReq->ReadWrite.offStart,
-                                   &pIoReq->ReadWrite.IoBuf.SgBuf, cbReqIo, pIoReq);
+                                   pIoReq->ReadWrite.pSgBuf, cbReqIo, pIoReq);
             if (rc == VINF_SUCCESS)
                 rc = VINF_VD_ASYNC_IO_FINISHED;
@@ -2952,10 +2997,10 @@
         }
         else
-            rc = VDAsyncRead(pThis->pDisk, pIoReq->ReadWrite.offStart, cbReqIo, &pIoReq->ReadWrite.IoBuf.SgBuf,
+            rc = VDAsyncRead(pThis->pDisk, pIoReq->ReadWrite.offStart, cbReqIo, pIoReq->ReadWrite.pSgBuf,
                              drvvdMediaExIoReqComplete, pThis, pIoReq);
     }
     else
     {
-        void *pvBuf = RTSgBufGetNextSegment(&pIoReq->ReadWrite.IoBuf.SgBuf, &cbReqIo);
+        void *pvBuf = RTSgBufGetNextSegment(pIoReq->ReadWrite.pSgBuf, &cbReqIo);
 
         Assert(cbReqIo > 0 && VALID_PTR(pvBuf));
@@ -2994,5 +3039,5 @@
         {
             rc = PDMR3BlkCacheWrite(pThis->pBlkCache, pIoReq->ReadWrite.offStart,
-                                    &pIoReq->ReadWrite.IoBuf.SgBuf, cbReqIo, pIoReq);
+                                    pIoReq->ReadWrite.pSgBuf, cbReqIo, pIoReq);
             if (rc == VINF_SUCCESS)
                 rc = VINF_VD_ASYNC_IO_FINISHED;
@@ -3001,10 +3046,10 @@
         }
         else
-            rc = VDAsyncWrite(pThis->pDisk, pIoReq->ReadWrite.offStart, cbReqIo, &pIoReq->ReadWrite.IoBuf.SgBuf,
+            rc = VDAsyncWrite(pThis->pDisk, pIoReq->ReadWrite.offStart, cbReqIo, pIoReq->ReadWrite.pSgBuf,
                               drvvdMediaExIoReqComplete, pThis, pIoReq);
     }
     else
     {
-        void *pvBuf = RTSgBufGetNextSegment(&pIoReq->ReadWrite.IoBuf.SgBuf, &cbReqIo);
+        void *pvBuf = RTSgBufGetNextSegment(pIoReq->ReadWrite.pSgBuf, &cbReqIo);
 
         Assert(cbReqIo > 0 && VALID_PTR(pvBuf));
@@ -3167,6 +3212,7 @@
     LogFlowFunc(("pThis=%#p pIoReq=%#p{.cbIoBuf=%zu}\n", pThis, pIoReq, pIoReq->ReadWrite.cbIoBuf));
 
-    if (   pIoReq->enmType == PDMMEDIAEXIOREQTYPE_READ
-        || pIoReq->enmType == PDMMEDIAEXIOREQTYPE_WRITE)
+    if (   (   pIoReq->enmType == PDMMEDIAEXIOREQTYPE_READ
+            || pIoReq->enmType == PDMMEDIAEXIOREQTYPE_WRITE)
+        && !pIoReq->ReadWrite.fDirectBuf)
     {
         IOBUFMgrFreeBuf(&pIoReq->ReadWrite.IoBuf);
@@ -3189,8 +3235,11 @@
                 if (rc == VINF_SUCCESS)
                 {
-                    Assert(pIoReq->ReadWrite.cbIoBuf > 0);
+                    Assert(pIoReqCur->ReadWrite.cbIoBuf > 0);
 
                     cIoReqsWaiting--;
                     RTListNodeRemove(&pIoReqCur->NdLstWait);
+
+                    pIoReqCur->ReadWrite.fDirectBuf = false;
+                    pIoReqCur->ReadWrite.pSgBuf     = &pIoReqCur->ReadWrite.IoBuf.SgBuf;
 
                     bool fXchg = ASMAtomicCmpXchgU32((volatile uint32_t *)&pIoReqCur->enmState, VDIOREQSTATE_ACTIVE, VDIOREQSTATE_ALLOCATED);
@@ -3198,5 +3247,5 @@
                     {
                         /* Must have been canceled inbetween. */
-                        Assert(pIoReq->enmState == VDIOREQSTATE_CANCELED);
+                        Assert(pIoReqCur->enmState == VDIOREQSTATE_CANCELED);
                         drvvdMediaExIoReqCompleteWorker(pThis, pIoReqCur, VERR_PDM_MEDIAEX_IOREQ_CANCELED, true /* fUpNotify */);
                     }
@@ -3831,5 +3880,5 @@
             /*
              * Try to allocate enough I/O buffer, if this fails for some reason put it onto the
-             * waitign list instead of the redo list.
+             * waiting list instead of the redo list.
              */
             pIoReq->ReadWrite.cbIoBuf = 0;
@@ -3843,4 +3892,9 @@
                 fPlaceOnRedoList = false;
                 rc = VINF_SUCCESS;
+            }
+            else
+            {
+                pIoReq->ReadWrite.fDirectBuf = false;
+                pIoReq->ReadWrite.pSgBuf     = &pIoReq->ReadWrite.IoBuf.SgBuf;
             }
         }
