Changeset 39893 in vbox
- Timestamp:
- Jan 26, 2012 9:24:35 PM (13 years ago)
- svn:sync-xref-src-repo-rev:
- 75943
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Storage/VD.cpp
r39798 r39893 230 230 /** Critical section protecting the disk against concurrent access. */ 231 231 RTCRITSECT CritSect; 232 /** Head of queued I/O contexts - LIFO order. */ 233 volatile PVDIOCTX pIoCtxHead; 232 234 /** Flag whether the disk is currently locked by growing write or a flush 233 235 * request. Other flush or growing write requests need to wait until … … 291 293 typedef struct VDIOCTX 292 294 { 295 /** Pointer to the next I/O context. */ 296 struct VDIOCTX * volatile pIoCtxNext; 293 297 /** Disk this is request is for. */ 294 298 PVBOXHDD pDisk; … … 1423 1427 if (RT_LIKELY(pIoCtx)) 1424 1428 { 1429 pIoCtx->pIoCtxNext = NULL; 1425 1430 pIoCtx->pDisk = pDisk; 1426 1431 pIoCtx->enmTxDir = VDIOCTXTXDIR_DISCARD; … … 1597 1602 } 1598 1603 1599 static int vdIoCtxProcess(PVDIOCTX pIoCtx) 1604 /** 1605 * Process the I/O context, core method which assumes that the critsect is acquired 1606 * by the calling thread. 1607 * 1608 * @returns VBox status code. 1609 * @param pIoCtx I/O context to process. 1610 */ 1611 static int vdIoCtxProcessLocked(PVDIOCTX pIoCtx) 1600 1612 { 1601 1613 int rc = VINF_SUCCESS; 1602 PVBOXHDD pDisk = pIoCtx->pDisk; 1614 1615 VD_THREAD_IS_CRITSECT_OWNER(pIoCtx->pDisk); 1603 1616 1604 1617 LogFlowFunc(("pIoCtx=%#p\n", pIoCtx)); 1605 1606 RTCritSectEnter(&pDisk->CritSect);1607 1618 1608 1619 if ( !pIoCtx->cMetaTransfersPending … … 1676 1687 1677 1688 out: 1678 RTCritSectLeave(&pDisk->CritSect);1679 1680 1689 LogFlowFunc(("pIoCtx=%#p rc=%Rrc cDataTransfersPending=%u cMetaTransfersPending=%u fComplete=%RTbool\n", 1681 1690 pIoCtx, rc, pIoCtx->cDataTransfersPending, pIoCtx->cMetaTransfersPending, 1682 1691 pIoCtx->fComplete)); 1692 1693 return rc; 1694 } 1695 1696 /** 1697 * Processes the list of waiting I/O contexts. 1698 * 1699 * @returns VBox status code. 1700 * @param pDisk The disk structure. 1701 * @param pIoCtxRc An I/O context handle which waits on the list. When processed 1702 * The status code is returned. NULL if there is no I/O context 1703 * to return the status code for. 1704 */ 1705 static int vdDiskProcessWaitingIoCtx(PVBOXHDD pDisk, PVDIOCTX pIoCtxRc) 1706 { 1707 int rc = VINF_SUCCESS; 1708 1709 LogFlowFunc(("pDisk=%#p pIoCtxRc=%#p\n", pDisk, pIoCtxRc)); 1710 1711 VD_THREAD_IS_CRITSECT_OWNER(pDisk); 1712 1713 /* Get the waiting list and process it in FIFO order. */ 1714 PVDIOCTX pIoCtxHead = ASMAtomicXchgPtrT(&pDisk->pIoCtxHead, NULL, PVDIOCTX); 1715 1716 /* Reverse it. */ 1717 PVDIOCTX pCur = pIoCtxHead; 1718 pIoCtxHead = NULL; 1719 while (pCur) 1720 { 1721 PVDIOCTX pInsert = pCur; 1722 pCur = pCur->pIoCtxNext; 1723 pInsert->pIoCtxNext = pIoCtxHead; 1724 pIoCtxHead = pInsert; 1725 } 1726 1727 /* Process now. */ 1728 pCur = pIoCtxHead; 1729 while (pCur) 1730 { 1731 int rcTmp; 1732 PVDIOCTX pTmp = pCur; 1733 1734 pCur = pCur->pIoCtxNext; 1735 pTmp->pIoCtxNext = NULL; 1736 1737 rcTmp = vdIoCtxProcessLocked(pTmp); 1738 if (pTmp == pIoCtxRc) 1739 { 1740 /* The given I/O context was processed, pass the return code to the caller. */ 1741 rc = rcTmp; 1742 } 1743 else if ( rcTmp == VINF_VD_ASYNC_IO_FINISHED 1744 && ASMAtomicCmpXchgBool(&pTmp->fComplete, true, false)) 1745 { 1746 LogFlowFunc(("Waiting I/O context completed pTmp=%#p\n", pTmp)); 1747 vdThreadFinishWrite(pDisk); 1748 pTmp->Type.Root.pfnComplete(pTmp->Type.Root.pvUser1, 1749 pTmp->Type.Root.pvUser2, 1750 pTmp->rcReq); 1751 vdIoCtxFree(pDisk, pTmp); 1752 } 1753 } 1754 1755 LogFlowFunc(("returns rc=%Rrc\n", rc)); 1756 return rc; 1757 } 1758 1759 /** 1760 * Leaves the critical section of the disk processing waiting I/O contexts. 1761 * 1762 * @returns VBox status code. 1763 * @param pDisk The disk to unlock. 1764 * @param pIoCtxRc An I/O context handle which waits on the list. When processed 1765 * The status code is returned. NULL if there is no I/O context 1766 * to return the status code for. 1767 */ 1768 static int vdDiskCritSectLeave(PVBOXHDD pDisk, PVDIOCTX pIoCtxRc) 1769 { 1770 int rc = VINF_SUCCESS; 1771 1772 LogFlowFunc(("pDisk=%#p pIoCtxRc=%#p\n", pDisk, pIoCtxRc)); 1773 1774 VD_THREAD_IS_CRITSECT_OWNER(pDisk); 1775 1776 rc = vdDiskProcessWaitingIoCtx(pDisk, pIoCtxRc); 1777 RTCritSectLeave(&pDisk->CritSect); 1778 1779 /* 1780 * We have to check for new waiting contexts here. It is possible that 1781 * another thread has queued another one while process waiting contexts 1782 * and because we still held the lock it was appended to the waiting list. 1783 * 1784 * @note Don't overwrite rc here because this might result in loosing 1785 * the status code of the given I/O context. 1786 */ 1787 while (ASMAtomicReadPtrT(&pDisk->pIoCtxHead, PVDIOCTX) != NULL) 1788 { 1789 int rc2 = RTCritSectTryEnter(&pDisk->CritSect); 1790 1791 if (RT_SUCCESS(rc2)) 1792 { 1793 /* 1794 * Don't pass status codes for any I/O context here. The context must hae been 1795 * in the first run. 1796 */ 1797 vdDiskProcessWaitingIoCtx(pDisk, NULL); 1798 RTCritSectLeave(&pDisk->CritSect); 1799 } 1800 else 1801 { 1802 /* 1803 * Another thread is holding the lock already and will process the list 1804 * whewn leaving the lock, nothing left to do for us. 1805 */ 1806 Assert(rc2 == VERR_SEM_BUSY); 1807 break; 1808 } 1809 } 1810 1811 LogFlowFunc(("returns rc=%Rrc\n", rc)); 1812 return rc; 1813 } 1814 1815 /** 1816 * Processes the I/O context trying to lock the criticial section. 1817 * The context is deferred if the critical section is busy. 1818 * 1819 * @returns VBox status code. 1820 * @param pIoCtx The I/O context to process. 1821 */ 1822 static int vdIoCtxProcessTryLockDefer(PVDIOCTX pIoCtx) 1823 { 1824 int rc = VINF_SUCCESS; 1825 PVBOXHDD pDisk = pIoCtx->pDisk; 1826 1827 LogFlowFunc(("pIoCtx=%#p\n", pIoCtx)); 1828 1829 /* Put it on the waiting list first. */ 1830 PVDIOCTX pNext = ASMAtomicUoReadPtrT(&pDisk->pIoCtxHead, PVDIOCTX); 1831 PVDIOCTX pHeadOld; 1832 pIoCtx->pIoCtxNext = pNext; 1833 while (!ASMAtomicCmpXchgExPtr(&pDisk->pIoCtxHead, pIoCtx, pNext, &pHeadOld)) 1834 { 1835 pNext = pHeadOld; 1836 Assert(pNext != pIoCtx); 1837 pIoCtx->pIoCtxNext = pNext; 1838 ASMNopPause(); 1839 } 1840 1841 rc = RTCritSectTryEnter(&pDisk->CritSect); 1842 if (RT_SUCCESS(rc)) 1843 { 1844 /* Leave it again, the context will be processed just before leaving the lock. */ 1845 LogFlowFunc(("Successfully acquired the critical section\n")); 1846 rc = vdDiskCritSectLeave(pDisk, pIoCtx); 1847 } 1848 else 1849 { 1850 AssertMsg(rc == VERR_SEM_BUSY, ("Invalid return code %Rrc\n", rc)); 1851 LogFlowFunc(("Critical section is busy\n")); 1852 rc = VERR_VD_ASYNC_IO_IN_PROGRESS; 1853 } 1854 1855 return rc; 1856 } 1857 1858 /** 1859 * Wrapper for vdIoCtxProcessLocked() which acquires the lock before. 1860 * 1861 * @returns VBox status code. 1862 * @param pIoCtx I/O context to process. 1863 */ 1864 static int vdIoCtxProcess(PVDIOCTX pIoCtx) 1865 { 1866 int rc = VINF_SUCCESS; 1867 PVBOXHDD pDisk = pIoCtx->pDisk; 1868 1869 LogFlowFunc(("pIoCtx=%#p\n", pIoCtx)); 1870 1871 RTCritSectEnter(&pDisk->CritSect); 1872 rc = vdIoCtxProcessLocked(pIoCtx); 1873 vdDiskCritSectLeave(pDisk, NULL); 1683 1874 1684 1875 return rc; … … 1736 1927 1737 1928 RTListMove(&ListTmp, &pDisk->ListWriteLocked); 1738 RTCritSectLeave(&pDisk->CritSect);1929 vdDiskCritSectLeave(pDisk, NULL); 1739 1930 1740 1931 /* Process the list. */ … … 1769 1960 } 1770 1961 else 1771 RTCritSectLeave(&pDisk->CritSect);1962 vdDiskCritSectLeave(pDisk, NULL); 1772 1963 } 1773 1964 … … 3709 3900 rc = VINF_SUCCESS; 3710 3901 3711 RTCritSectLeave(&pDisk->CritSect);3902 vdDiskCritSectLeave(pDisk, NULL); 3712 3903 3713 3904 return rc; … … 3794 3985 RTMemFree(pMetaXfer); 3795 3986 3796 RTCritSectLeave(&pDisk->CritSect);3987 vdDiskCritSectLeave(pDisk, NULL); 3797 3988 3798 3989 return VINF_SUCCESS; … … 4468 4659 vdIoCtxContinue(pIoCtx, rcReq); 4469 4660 4470 rc = RTCritSectLeave(&pDisk->CritSect); 4471 AssertRC(rc); 4661 vdDiskCritSectLeave(pDisk, NULL); 4472 4662 } 4473 4663 … … 9131 9321 } 9132 9322 9133 rc = vdIoCtxProcess (pIoCtx);9323 rc = vdIoCtxProcessTryLockDefer(pIoCtx); 9134 9324 if (rc == VINF_VD_ASYNC_IO_FINISHED) 9135 9325 { … … 9202 9392 } 9203 9393 9204 rc = vdIoCtxProcess (pIoCtx);9394 rc = vdIoCtxProcessTryLockDefer(pIoCtx); 9205 9395 if (rc == VINF_VD_ASYNC_IO_FINISHED) 9206 9396 { … … 9258 9448 } 9259 9449 9260 rc = vdIoCtxProcess (pIoCtx);9450 rc = vdIoCtxProcessTryLockDefer(pIoCtx); 9261 9451 if (rc == VINF_VD_ASYNC_IO_FINISHED) 9262 9452 { … … 9313 9503 } 9314 9504 9315 rc = vdIoCtxProcess (pIoCtx);9505 rc = vdIoCtxProcessTryLockDefer(pIoCtx); 9316 9506 if (rc == VINF_VD_ASYNC_IO_FINISHED) 9317 9507 {
Note:
See TracChangeset
for help on using the changeset viewer.