Changeset 24101 in vbox
- Timestamp:
- Oct 27, 2009 12:03:09 AM (15 years ago)
- Location:
- trunk
- Files:
-
- 3 edited
-
include/VBox/pdmifs.h (modified) (1 diff)
-
src/VBox/Devices/Storage/DevLsiLogicSCSI.cpp (modified) (2 diffs)
-
src/VBox/Devices/Storage/DrvSCSI.cpp (modified) (7 diffs)
Legend:
- Unmodified
- Added
- Removed
-
trunk/include/VBox/pdmifs.h
r24098 r24101 2561 2561 DECLR3CALLBACKMEMBER(int, pfnSCSIRequestSend, (PPDMISCSICONNECTOR pInterface, PPDMSCSIREQUEST pSCSIRequest)); 2562 2562 2563 /**2564 * Wait for all current requests to complete.2565 *2566 * This can only be called while the VM is running.2567 *2568 * @returns VINF_SUCCESS, VERR_NO_MEMORY, VERR_INVALID_STATE or VERR_TIMEOUT.2569 * @param pInterface Pointer to this interface.2570 * @param cMillies The timeout in milliseconds or RT_INDEFINITE_WAIT.2571 */2572 DECLR3CALLBACKMEMBER(int, pfnSyncronizeRequests, (PPDMISCSICONNECTOR pInterface, uint32_t cMillies));2573 2574 2563 } PDMISCSICONNECTOR; 2575 2564 -
trunk/src/VBox/Devices/Storage/DevLsiLogicSCSI.cpp
r24099 r24101 4781 4781 } 4782 4782 4783 /**4784 * Waits until all I/O operations on all devices are complete.4785 *4786 * @retruns Flag which indicates if all I/O completed in the given timeout.4787 * @param pLsiLogic Pointer to the dveice instance to check.4788 * @param cMillis Timeout in milliseconds to wait per device.4789 */4790 static bool lsilogicWaitForAsyncIOFinished(PLSILOGICSCSI pLsiLogic, unsigned cMillies)4791 {4792 uint64_t u64Start;4793 unsigned i;4794 4795 /*4796 * Wait for any pending async operation to finish4797 */4798 u64Start = RTTimeMilliTS();4799 for (;;)4800 {4801 /* Check every port. */4802 for (i = 0; i < RT_ELEMENTS(pLsiLogic->aDeviceStates); i++)4803 if (ASMAtomicReadU32(&pLsiLogic->aDeviceStates[i].cOutstandingRequests))4804 break;4805 if (i >= RT_ELEMENTS(pLsiLogic->aDeviceStates))4806 return true;4807 4808 uint64_t cMsElapsed = RTTimeMilliTS() - u64Start;4809 if (cMsElapsed >= cMillies)4810 return false;4811 4812 /* Try synchronize the request queue for this device. */4813 PPDMISCSICONNECTOR pDrvSCSIConnector = pLsiLogic->aDeviceStates[i].pDrvSCSIConnector;4814 uint32_t cMsLeft = cMillies - (uint32_t)cMsElapsed;4815 pDrvSCSIConnector->pfnSyncronizeRequests(pDrvSCSIConnector, RT_MAX(cMsLeft, 100));4816 }4817 }4818 4819 4783 static DECLCALLBACK(int) lsilogicLiveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uPass) 4820 4784 { … … 5159 5123 PLSILOGICSCSI pLsiLogic = PDMINS_2_DATA(pDevIns, PLSILOGICSCSI); 5160 5124 int rc; 5161 5162 /** @todo r=bird: this is a deadlock trap. We're EMT(0), if there are5163 * outstanding requests they may require EMT interaction because of5164 * physical write backs around lsilogicDeviceSCSIRequestCompleted...5165 *5166 * I have some more generic solution for delayed suspend, reset and5167 * poweroff handling that I'm considering. The idea is that the5168 * notification callback returns a status indicating that it didn't5169 * complete and needs to be called again or something. EMT continues on5170 * the next device and when it's done, it processes incoming requests and5171 * does another notification round... This way we could combine the waits5172 * in the I/O controllers and reduce the time it takes to suspend a VM a5173 * wee bit...5174 *5175 * DrvSCSI should implement the reset notification, then we could retire this5176 * fun lsilogicWaitForAsyncIOFinished code. (The drivers are reset before the5177 * device.) The deadlock trap is still there though.5178 */5179 bool fIdle = lsilogicWaitForAsyncIOFinished(pLsiLogic, 20000);5180 Assert(fIdle);5181 5125 5182 5126 rc = lsilogicHardReset(pLsiLogic); -
trunk/src/VBox/Devices/Storage/DrvSCSI.cpp
r24098 r24101 89 89 /** Queue for passing the requests to the thread. */ 90 90 PRTREQQUEUE pQueueRequests; 91 /** Request that we've left pending on wakeup or reset. */ 92 PRTREQ pPendingDummyReq; 91 93 /** Release statistics: number of bytes written. */ 92 94 STAMCOUNTER StatBytesWritten; … … 671 673 672 674 /** 673 * Request function to syncronize the request execution. 675 * Dummy request function used by drvscsiReset to wait for all pending requests 676 * to complete prior to the device reset. 674 677 * 675 678 * @returns VINF_SUCCESS. … … 716 719 } 717 720 721 /** 722 * Deals with any pending dummy request 723 * 724 * @returns true if no pending dummy request, false if still pending. 725 * @param pThis The instance data. 726 * @param cMillies The number of milliseconds to wait for any 727 * pending request to finish. 728 */ 729 static bool drvscsiAsyncIOLoopNoPendingDummy(PDRVSCSI pThis, uint32_t cMillies) 730 { 731 if (!pThis->pPendingDummyReq) 732 return false; 733 int rc = RTReqWait(pThis->pPendingDummyReq, cMillies); 734 if (RT_FAILURE(rc)) 735 return false; 736 RTReqFree(pThis->pPendingDummyReq); 737 pThis->pPendingDummyReq = NULL; 738 return true; 739 } 740 718 741 static int drvscsiAsyncIOLoopWakeup(PPDMDRVINS pDrvIns, PPDMTHREAD pThread) 719 742 { 720 int rc;721 743 PDRVSCSI pThis = PDMINS_2_DATA(pDrvIns, PDRVSCSI); 722 744 PRTREQ pReq; 745 int rc; 723 746 724 747 AssertMsgReturn(pThis->pQueueRequests, ("pQueueRequests is NULL\n"), VERR_INVALID_STATE); 725 748 749 if (!drvscsiAsyncIOLoopNoPendingDummy(pThis, 10000 /* 10 sec */)) 750 { 751 LogRel(("drvscsiAsyncIOLoopWakeup#%u: previous dummy request is still pending\n", pDrvIns->iInstance)); 752 return VERR_TIMEOUT; 753 } 754 726 755 rc = RTReqCall(pThis->pQueueRequests, &pReq, 10000 /* 10 sec. */, (PFNRT)drvscsiAsyncIOLoopWakeupFunc, 0); 727 AssertMsgRC(rc, ("Inserting request into queue failed rc=%Rrc\n", rc));728 756 if (RT_SUCCESS(rc)) 729 757 RTReqFree(pReq); 730 /*else: leak it */ 758 else 759 { 760 pThis->pPendingDummyReq = pReq; 761 LogRel(("drvscsiAsyncIOLoopWakeup#%u: %Rrc pReq=%p\n", pDrvIns->iInstance, rc, pReq)); 762 } 731 763 732 764 return rc; … … 748 780 749 781 return VINF_SUCCESS; 750 }751 752 /** @copydoc PDMISCSICONNECTOR::pfnSyncronizeRequests. */753 static DECLCALLBACK(int) drvscsiSyncronizeRequests(PPDMISCSICONNECTOR pInterface, uint32_t cMillies)754 {755 int rc;756 PDRVSCSI pThis = PDMISCSICONNECTOR_2_DRVSCSI(pInterface);757 PRTREQ pReq;758 759 Assert(cMillies > 100);760 AssertReturn(pThis->pQueueRequests, VERR_INVALID_STATE);761 762 rc = RTReqCall(pThis->pQueueRequests, &pReq, cMillies, (PFNRT)drvscsiAsyncIOLoopSyncCallback, 0);763 AssertMsgRC(rc, ("Inserting request into queue failed rc=%Rrc\n", rc));764 if (RT_SUCCESS(rc))765 RTReqFree(pReq);766 /*else: leak it */767 768 return rc;769 782 } 770 783 … … 790 803 791 804 /** 805 * @copydoc FNPDMDRVRESET 806 */ 807 static DECLCALLBACK(void) drvscsiReset(PPDMDRVINS pDrvIns) 808 { 809 PDRVSCSI pThis = PDMINS_2_DATA(pDrvIns, PDRVSCSI); 810 int rc; 811 812 /* 813 * Try make sure any pending I/O has completed now. 814 */ 815 if (pThis->pQueueRequests) 816 { 817 if (!drvscsiAsyncIOLoopNoPendingDummy(pThis, 20000 /*ms*/)) 818 { 819 LogRel(("drvscsiReset#%u: previous dummy request is still pending\n", pDrvIns->iInstance)); 820 return; 821 } 822 823 if (RTReqIsBusy(pThis->pQueueRequests)) 824 { 825 PRTREQ pReq; 826 rc = RTReqCall(pThis->pQueueRequests, &pReq, 20000 /*ms*/, (PFNRT)drvscsiAsyncIOLoopSyncCallback, 0); 827 if (RT_SUCCESS(rc)) 828 RTReqFree(pReq); 829 else 830 { 831 pThis->pPendingDummyReq = pReq; 832 LogRel(("drvscsiReset#%u: %Rrc pReq=%p\n", pDrvIns->iInstance, rc, pReq)); 833 } 834 } 835 } 836 /** @todo r=bird: this is a deadlock trap. We're EMT(0), if there are 837 * outstanding requests they may require EMT interaction because of 838 * physical write backs around lsilogicDeviceSCSIRequestCompleted... 839 * 840 * I have some more generic solution for delayed suspend, reset and 841 * poweroff handling that I'm considering. The idea is that the 842 * notification callback returns a status indicating that it didn't 843 * complete and needs to be called again or something. EMT continues on 844 * the next device and when it's done, it processes incoming requests and 845 * does another notification round... This way we could combine the waits 846 * in the I/O controllers and reduce the time it takes to suspend a VM a 847 * wee bit... 848 */ 849 } 850 851 /** 792 852 * Destruct a driver instance. 793 853 * … … 826 886 pDrvIns->IBase.pfnQueryInterface = drvscsiQueryInterface; 827 887 pThis->ISCSIConnector.pfnSCSIRequestSend = drvscsiRequestSend; 828 pThis->ISCSIConnector.pfnSyncronizeRequests = drvscsiSyncronizeRequests;829 888 830 889 /* … … 929 988 NULL, 930 989 /* pfnReset */ 931 NULL,990 drvscsiReset, 932 991 /* pfnSuspend */ 933 992 NULL,
Note:
See TracChangeset
for help on using the changeset viewer.

