VirtualBox

Changeset 16708 in vbox


Ignore:
Timestamp:
Feb 12, 2009 1:23:10 PM (16 years ago)
Author:
vboxsync
Message:

Storage/ATA: fix 2 deadlocks when suspending the VM due to disk problems. The error message setting and the suspending must be done when not holding the controller critsect, otherwise EMT can be waiting for it, and ATA would wait for EMT to make progress.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Devices/Storage/DevATA.cpp

    r16114 r16708  
    13521352
    13531353
    1354 static int ataReadSectors(ATADevState *s, uint64_t u64Sector, void *pvBuf, uint32_t cSectors)
     1354static void ataWarningDiskFull(PPDMDEVINS pDevIns)
     1355{
     1356    int rc;
     1357    LogRel(("PIIX3 ATA: Host disk full\n"));
     1358    rc = VMSetRuntimeError(PDMDevHlpGetVM(pDevIns),
     1359                           false, "DevATA_DISKFULL",
     1360                           N_("Host system reported disk full. VM execution is suspended. You can resume after freeing some space"));
     1361    AssertRC(rc);
     1362}
     1363
     1364static void ataWarningFileTooBig(PPDMDEVINS pDevIns)
     1365{
     1366    int rc;
     1367    LogRel(("PIIX3 ATA: File too big\n"));
     1368    rc = VMSetRuntimeError(PDMDevHlpGetVM(pDevIns),
     1369                           false, "DevATA_FILETOOBIG",
     1370                           N_("Host system reported that the file size limit of the host file system has been exceeded. VM execution is suspended. You need to move your virtual hard disk to a filesystem which allows bigger files"));
     1371    AssertRC(rc);
     1372}
     1373
     1374static void ataWarningISCSI(PPDMDEVINS pDevIns)
     1375{
     1376    int rc;
     1377    LogRel(("PIIX3 ATA: iSCSI target unavailable\n"));
     1378    rc = VMSetRuntimeError(PDMDevHlpGetVM(pDevIns),
     1379                           false, "DevATA_ISCSIDOWN",
     1380                           N_("The iSCSI target has stopped responding. VM execution is suspended. You can resume when it is available again"));
     1381    AssertRC(rc);
     1382}
     1383
     1384/**
     1385 * Suspend I/O operations on a controller. Also suspends EMT, because it's
     1386 * waiting for I/O to make progress. The next attempt to perform an I/O
     1387 * operation will be made when EMT is resumed up again (as the resume
     1388 * callback below restarts I/O).
     1389 *
     1390 * @param pCtl      Controller for which to suspend I/O.
     1391 */
     1392static void ataSuspendRedo(PATACONTROLLER pCtl)
     1393{
     1394    PPDMDEVINS  pDevIns = CONTROLLER_2_DEVINS(pCtl);
     1395    PVMREQ      pReq;
     1396    int         rc;
     1397
     1398    pCtl->fRedoIdle = true;
     1399    rc = VMR3ReqCall(PDMDevHlpGetVM(pDevIns), VMREQDEST_ANY, &pReq, RT_INDEFINITE_WAIT,
     1400                     (PFNRT)PDMDevHlpVMSuspend, 1, pDevIns);
     1401    AssertReleaseRC(rc);
     1402    VMR3ReqFree(pReq);
     1403}
     1404
     1405bool ataIsRedoSetWarning(ATADevState *s, int rc)
     1406{
     1407    PATACONTROLLER pCtl = ATADEVSTATE_2_CONTROLLER(s);
     1408    Assert(!PDMCritSectIsOwner(&pCtl->lock));
     1409    if (rc == VERR_DISK_FULL)
     1410    {
     1411        ataWarningDiskFull(ATADEVSTATE_2_DEVINS(s));
     1412        ataSuspendRedo(pCtl);
     1413        return true;
     1414    }
     1415    if (rc == VERR_FILE_TOO_BIG)
     1416    {
     1417        ataWarningFileTooBig(ATADEVSTATE_2_DEVINS(s));
     1418        ataSuspendRedo(pCtl);
     1419        return true;
     1420    }
     1421    if (rc == VERR_BROKEN_PIPE || rc == VERR_NET_CONNECTION_REFUSED)
     1422    {
     1423        /* iSCSI connection abort (first error) or failure to reestablish
     1424         * connection (second error). Pause VM. On resume we'll retry. */
     1425        ataWarningISCSI(ATADEVSTATE_2_DEVINS(s));
     1426        ataSuspendRedo(pCtl);
     1427        return true;
     1428    }
     1429    return false;
     1430}
     1431
     1432
     1433static int ataReadSectors(ATADevState *s, uint64_t u64Sector, void *pvBuf, uint32_t cSectors, bool *fRedo)
    13551434{
    13561435    PATACONTROLLER pCtl = ATADEVSTATE_2_CONTROLLER(s);
     
    13671446    STAM_REL_COUNTER_ADD(&s->StatBytesRead, cSectors * 512);
    13681447
     1448    if (RT_SUCCESS(rc))
     1449        *fRedo = false;
     1450    else
     1451        *fRedo = ataIsRedoSetWarning(s, rc);
     1452
    13691453    STAM_PROFILE_START(&pCtl->StatLockWait, a);
    13701454    PDMCritSectEnter(&pCtl->lock, VINF_SUCCESS);
     
    13741458
    13751459
    1376 static int ataWriteSectors(ATADevState *s, uint64_t u64Sector, const void *pvBuf, uint32_t cSectors)
     1460static int ataWriteSectors(ATADevState *s, uint64_t u64Sector, const void *pvBuf, uint32_t cSectors, bool *fRedo)
    13771461{
    13781462    PATACONTROLLER pCtl = ATADEVSTATE_2_CONTROLLER(s);
     
    13971481    STAM_REL_COUNTER_ADD(&s->StatBytesWritten, cSectors * 512);
    13981482
     1483    if (RT_SUCCESS(rc))
     1484        *fRedo = false;
     1485    else
     1486        *fRedo = ataIsRedoSetWarning(s, rc);
     1487
    13991488    STAM_PROFILE_START(&pCtl->StatLockWait, a);
    14001489    PDMCritSectEnter(&pCtl->lock, VINF_SUCCESS);
     
    14181507
    14191508
    1420 static void ataWarningDiskFull(PPDMDEVINS pDevIns)
    1421 {
    1422     int rc;
    1423     LogRel(("PIIX3 ATA: Host disk full\n"));
    1424     rc = VMSetRuntimeError(PDMDevHlpGetVM(pDevIns),
    1425                            false, "DevATA_DISKFULL",
    1426                            N_("Host system reported disk full. VM execution is suspended. You can resume after freeing some space"));
    1427     AssertRC(rc);
    1428 }
    1429 
    1430 
    1431 static void ataWarningFileTooBig(PPDMDEVINS pDevIns)
    1432 {
    1433     int rc;
    1434     LogRel(("PIIX3 ATA: File too big\n"));
    1435     rc = VMSetRuntimeError(PDMDevHlpGetVM(pDevIns),
    1436                            false, "DevATA_FILETOOBIG",
    1437                            N_("Host system reported that the file size limit of the host file system has been exceeded. VM execution is suspended. You need to move your virtual hard disk to a filesystem which allows bigger files"));
    1438     AssertRC(rc);
    1439 }
    1440 
    1441 
    1442 static void ataWarningISCSI(PPDMDEVINS pDevIns)
    1443 {
    1444     int rc;
    1445     LogRel(("PIIX3 ATA: iSCSI target unavailable\n"));
    1446     rc = VMSetRuntimeError(PDMDevHlpGetVM(pDevIns),
    1447                            false, "DevATA_ISCSIDOWN",
    1448                            N_("The iSCSI target has stopped responding. VM execution is suspended. You can resume when it is available again"));
    1449     AssertRC(rc);
    1450 }
    1451 
    1452 
    14531509static bool ataReadSectorsSS(ATADevState *s)
    14541510{
     
    14561512    uint32_t cSectors;
    14571513    uint64_t iLBA;
     1514    bool fRedo;
    14581515
    14591516    cSectors = s->cbElementaryTransfer / 512;
     
    14611518    iLBA = ataGetSector(s);
    14621519    Log(("%s: %d sectors at LBA %d\n", __FUNCTION__, cSectors, iLBA));
    1463     rc = ataReadSectors(s, iLBA, s->CTX_SUFF(pbIOBuffer), cSectors);
     1520    rc = ataReadSectors(s, iLBA, s->CTX_SUFF(pbIOBuffer), cSectors, &fRedo);
    14641521    if (RT_SUCCESS(rc))
    14651522    {
     
    14711528    else
    14721529    {
    1473         if (rc == VERR_DISK_FULL)
    1474         {
    1475             ataWarningDiskFull(ATADEVSTATE_2_DEVINS(s));
    1476             return true;
    1477         }
    1478         if (rc == VERR_FILE_TOO_BIG)
    1479         {
    1480             ataWarningFileTooBig(ATADEVSTATE_2_DEVINS(s));
    1481             return true;
    1482         }
    1483         if (rc == VERR_BROKEN_PIPE || rc == VERR_NET_CONNECTION_REFUSED)
    1484         {
    1485             /* iSCSI connection abort (first error) or failure to reestablish
    1486              * connection (second error). Pause VM. On resume we'll retry. */
    1487             ataWarningISCSI(ATADEVSTATE_2_DEVINS(s));
    1488             return true;
    1489         }
     1530        if (fRedo)
     1531            return fRedo;
    14901532        if (s->cErrors++ < MAX_LOG_REL_ERRORS)
    14911533            LogRel(("PIIX3 ATA: LUN#%d: disk read error (rc=%Rrc iSector=%#RX64 cSectors=%#RX32)\n",
     
    14991541            ataCmdError(s, ID_ERR);
    15001542    }
    1501     /** @todo implement redo for iSCSI */
    15021543    return false;
    15031544}
     
    15091550    uint32_t cSectors;
    15101551    uint64_t iLBA;
     1552    bool fRedo;
    15111553
    15121554    cSectors = s->cbElementaryTransfer / 512;
     
    15141556    iLBA = ataGetSector(s);
    15151557    Log(("%s: %d sectors at LBA %d\n", __FUNCTION__, cSectors, iLBA));
    1516     rc = ataWriteSectors(s, iLBA, s->CTX_SUFF(pbIOBuffer), cSectors);
     1558    rc = ataWriteSectors(s, iLBA, s->CTX_SUFF(pbIOBuffer), cSectors, &fRedo);
    15171559    if (RT_SUCCESS(rc))
    15181560    {
     
    15241566    else
    15251567    {
    1526         if (rc == VERR_DISK_FULL)
    1527         {
    1528             ataWarningDiskFull(ATADEVSTATE_2_DEVINS(s));
    1529             return true;
    1530         }
    1531         if (rc == VERR_FILE_TOO_BIG)
    1532         {
    1533             ataWarningFileTooBig(ATADEVSTATE_2_DEVINS(s));
    1534             return true;
    1535         }
    1536         if (rc == VERR_BROKEN_PIPE || rc == VERR_NET_CONNECTION_REFUSED)
    1537         {
    1538             /* iSCSI connection abort (first error) or failure to reestablish
    1539              * connection (second error). Pause VM. On resume we'll retry. */
    1540             ataWarningISCSI(ATADEVSTATE_2_DEVINS(s));
    1541             return true;
    1542         }
     1568        if (fRedo)
     1569            return fRedo;
    15431570        if (s->cErrors++ < MAX_LOG_REL_ERRORS)
    15441571            LogRel(("PIIX3 ATA: LUN#%d: disk write error (rc=%Rrc iSector=%#RX64 cSectors=%#RX32)\n",
     
    15521579            ataCmdError(s, ID_ERR);
    15531580    }
    1554     /** @todo implement redo for iSCSI */
    15551581    return false;
    15561582}
     
    42784304
    42794305
    4280 /**
    4281  * Suspend I/O operations on a controller. Also suspends EMT, because it's
    4282  * waiting for I/O to make progress. The next attempt to perform an I/O
    4283  * operation will be made when EMT is resumed up again (as the resume
    4284  * callback below restarts I/O).
    4285  *
    4286  * @param pCtl      Controller for which to suspend I/O.
    4287  */
    4288 static void ataSuspendRedo(PATACONTROLLER pCtl)
    4289 {
    4290     PPDMDEVINS  pDevIns = CONTROLLER_2_DEVINS(pCtl);
    4291     PVMREQ      pReq;
    4292     int         rc;
    4293 
    4294     pCtl->fRedoIdle = true;
    4295     rc = VMR3ReqCall(PDMDevHlpGetVM(pDevIns), VMREQDEST_ANY, &pReq, RT_INDEFINITE_WAIT,
    4296                      (PFNRT)PDMDevHlpVMSuspend, 1, pDevIns);
    4297     AssertReleaseRC(rc);
    4298     VMR3ReqFree(pReq);
    4299 }
    4300 
    43014306/** Asynch I/O thread for an interface. Once upon a time this was readable
    43024307 * code with several loops and a different semaphore for each purpose. But
     
    44534458                            LogRel(("%s: Ctl#%d: redo entire operation\n", __FUNCTION__, ATACONTROLLER_IDX(pCtl)));
    44544459                            ataAsyncIOPutRequest(pCtl, pReq);
    4455                             ataSuspendRedo(pCtl);
    44564460                            break;
    44574461                        }
     
    45584562                    LogRel(("PIIX3 ATA: Ctl#%d: redo DMA operation\n", ATACONTROLLER_IDX(pCtl)));
    45594563                    ataAsyncIOPutRequest(pCtl, &ataDMARequest);
    4560                     ataSuspendRedo(pCtl);
    45614564                    break;
    45624565                }
Note: See TracChangeset for help on using the changeset viewer.

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