Index: trunk/src/VBox/VMM/PDMAsyncCompletionFile.cpp
===================================================================
--- trunk/src/VBox/VMM/PDMAsyncCompletionFile.cpp	(revision 34340)
+++ trunk/src/VBox/VMM/PDMAsyncCompletionFile.cpp	(revision 34344)
@@ -283,4 +283,19 @@
         if (RT_FAILURE(rc))
             ASMAtomicCmpXchgS32(&pTaskFile->rc, rc, VINF_SUCCESS);
+#ifdef DEBUG
+        else
+        {
+            PPDMASYNCCOMPLETIONENDPOINTFILE pEpFile = (PPDMASYNCCOMPLETIONENDPOINTFILE)pTaskFile->Core.pEndpoint;
+
+            /* Overwrite with injected error code. */
+            if (pTask->enmTransferType == PDMACTASKFILETRANSFER_READ)
+                rc = ASMAtomicXchgS32(&pEpFile->rcReqRead, VINF_SUCCESS);
+            else
+                rc = ASMAtomicXchgS32(&pEpFile->rcReqWrite, VINF_SUCCESS);
+
+            if (RT_FAILURE(rc))
+                ASMAtomicCmpXchgS32(&pTaskFile->rc, rc, VINF_SUCCESS);
+        }
+#endif
 
         if (!(uOld - pTask->DataSeg.cbSeg)
@@ -583,4 +598,97 @@
 }
 
+#ifdef DEBUG
+/**
+ * Error inject callback.
+ *
+ * The argument parsing is quite ugly but it is only a development tool
+ * not compiled into a release build. Will improve some day.
+ */
+static DECLCALLBACK(void) pdmacEpFileErrorInject(void *pvUser, PCDBGFINFOHLP pHlp, const char *pszArgs)
+{
+    bool fWrite;
+    int rcToInject = VINF_SUCCESS;
+    char *pszFilename = NULL;
+    PPDMASYNCCOMPLETIONEPCLASSFILE pEpClassFile = (PPDMASYNCCOMPLETIONEPCLASSFILE)pvUser;
+
+    /* Syntax is "read|write <filename> <status code>" */
+    if (!RTStrNCmp(pszArgs, "read", 4))
+        fWrite = false;
+    else if (!RTStrNCmp(pszArgs, "write", 5))
+        fWrite = true;
+    else
+        return;
+
+    pszArgs += fWrite ? 5 : 4;
+
+    /* Skip white space. */
+    while (   *pszArgs == ' '
+           && *pszArgs != '\0')
+        pszArgs++;
+
+    if (pszArgs != '\0')
+    {
+        /* Extract the filename */
+        const char *pszPos = pszArgs;
+
+        /* ASSUMPTION: No white space in the filename. */
+        while (   *pszArgs != ' '
+               && *pszArgs != '\0')
+            pszArgs++;
+
+        if (*pszArgs != '\0')
+        {
+            size_t cchFilename = pszArgs - pszPos;
+            pszFilename = RTStrDupN(pszPos, cchFilename);
+            if (pszFilename)
+            {
+                /* Skip white space. */
+                while (   *pszArgs == ' '
+                       && *pszArgs != '\0')
+                    pszArgs++;
+
+                if (*pszArgs != '\0')
+                {
+                    /* Extract error number. */
+                    rcToInject = RTStrToInt32(pszArgs);
+                    if (rcToInject != 0)
+                    {
+                        /* Search for the matching endpoint. */
+                        RTCritSectEnter(&pEpClassFile->Core.CritSect);
+                        PPDMASYNCCOMPLETIONENDPOINTFILE pEpFile = (PPDMASYNCCOMPLETIONENDPOINTFILE)pEpClassFile->Core.pEndpointsHead;
+
+                        while (pEpFile)
+                        {
+                            if (!RTStrCmp(pszFilename, RTPathFilename(pEpFile->Core.pszUri)))
+                                break;
+                            pEpFile = (PPDMASYNCCOMPLETIONENDPOINTFILE)pEpFile->Core.pNext;
+                        }
+
+                        if (pEpFile)
+                        {
+                            if (fWrite)
+                                ASMAtomicXchgS32(&pEpFile->rcReqWrite, rcToInject);
+                            else
+                                ASMAtomicXchgS32(&pEpFile->rcReqRead, rcToInject);
+
+                            pHlp->pfnPrintf(pHlp, "Injected %Rrc into '%s' for %s\n",
+                                            rcToInject, pszFilename, fWrite ? "write" : "read");
+                        }
+                        else
+                            pHlp->pfnPrintf(pHlp, "No file with name '%s' found\n", pszFilename);
+
+                        RTCritSectLeave(&pEpClassFile->Core.CritSect);
+                        RTStrFree(pszFilename);
+                        return;
+                    }
+                }
+                RTStrFree(pszFilename);
+            }
+        }
+    }
+    pHlp->pfnPrintf(pHlp, "Error parsing command line\n");
+}
+#endif
+
 static int pdmacFileInitialize(PPDMASYNCCOMPLETIONEPCLASS pClassGlobals, PCFGMNODE pCfgNode)
 {
@@ -670,4 +778,15 @@
             LogRel(("AIOMgr: Cache was globally disabled\n"));
     }
+
+#ifdef DEBUG
+    /* Install the error injection handler. */
+    if (RT_SUCCESS(rc))
+    {
+        rc = DBGFR3InfoRegisterExternal(pClassGlobals->pVM, "injecterror",
+                                        "Inject an error into the async file I/O handling",
+                                        pdmacEpFileErrorInject, pEpClassFile);
+        AssertRC(rc);
+    }
+#endif
 
     return rc;
Index: trunk/src/VBox/VMM/PDMAsyncCompletionFileInternal.h
===================================================================
--- trunk/src/VBox/VMM/PDMAsyncCompletionFileInternal.h	(revision 34340)
+++ trunk/src/VBox/VMM/PDMAsyncCompletionFileInternal.h	(revision 34344)
@@ -542,4 +542,10 @@
     /** Flag whether the host supports the async flush API. */
     bool                                   fAsyncFlushSupported;
+#ifdef DEBUG
+    /** Status code to inject for the next complete read. */
+    volatile int                           rcReqRead;
+    /** Status code to inject for the next complete write. */
+    volatile int                           rcReqWrite;
+#endif
     /** Flag whether a blocking event is pending and needs
      * processing by the I/O manager. */
