Changeset 76328 in vbox for trunk/src/VBox/Runtime/common/fs
- Timestamp:
- Dec 20, 2018 7:43:52 PM (6 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Runtime/common/fs/extvfs.cpp
r76318 r76328 59 59 #else 60 60 # define RTFSEXT_MAX_INODE_CACHE_SIZE _128K 61 #endif 62 /** The maximum extent/block map cache size (in bytes). */ 63 #if ARCH_BITS >= 64 64 # define RTFSEXT_MAX_BLOCK_CACHE_SIZE _512K 65 #else 66 # define RTFSEXT_MAX_BLOCK_CACHE_SIZE _128K 61 67 #endif 62 68 … … 118 124 /** Pointer to an in-memory inode. */ 119 125 typedef RTFSEXTINODE *PRTFSEXTINODE; 126 127 128 /** 129 * Block cache entry. 130 */ 131 typedef struct RTFSEXTBLOCKENTRY 132 { 133 /** AVL tree node, indexed by the filesystem block number. */ 134 AVLU64NODECORE Core; 135 /** List node for the inode LRU list used for eviction. */ 136 RTLISTNODE NdLru; 137 /** Reference counter. */ 138 volatile uint32_t cRefs; 139 /** The block data. */ 140 uint8_t abData[1]; 141 } RTFSEXTBLOCKENTRY; 142 /** Pointer to a block cache entry. */ 143 typedef RTFSEXTBLOCKENTRY *PRTFSEXTBLOCKENTRY; 120 144 121 145 … … 197 221 uint32_t fFeaturesIncompat; 198 222 199 200 223 /** @name Block group cache. 201 224 * @{ */ … … 216 239 /** Size of the cached inodes. */ 217 240 size_t cbInodes; 241 /** @} */ 242 243 /** @name Block cache. 244 * @{ */ 245 /** LRU list anchor for the block cache. */ 246 RTLISTANCHOR LstBlockLru; 247 /** Root of the cached block tree. */ 248 AVLU64TREE BlockRoot; 249 /** Size of cached blocks. */ 250 size_t cbBlocks; 218 251 /** @} */ 219 252 } RTFSEXTVOL; … … 628 661 * @param iBlockGroup Block group number. 629 662 */ 663 static PRTFSEXTBLOCKENTRY rtFsExtVol_BlockAlloc(PRTFSEXTVOL pThis, size_t cbAlloc, uint64_t iBlock) 664 { 665 PRTFSEXTBLOCKENTRY pBlock = (PRTFSEXTBLOCKENTRY)RTMemAllocZ(cbAlloc); 666 if (RT_LIKELY(pBlock)) 667 { 668 pBlock->Core.Key = iBlock; 669 pBlock->cRefs = 0; 670 pThis->cbBlocks += cbAlloc; 671 } 672 673 return pBlock; 674 } 675 676 677 /** 678 * Returns a new block entry utilizing the cache if possible. 679 * 680 * @returns Pointer to the new block entry or NULL if out of memory. 681 * @param pThis The ext volume instance. 682 * @param iBlock Block number. 683 */ 684 static PRTFSEXTBLOCKENTRY rtFsExtVol_BlockGetNew(PRTFSEXTVOL pThis, uint64_t iBlock) 685 { 686 PRTFSEXTBLOCKENTRY pBlock = NULL; 687 size_t cbAlloc = RT_UOFFSETOF_DYN(RTFSEXTBLOCKENTRY, abData[pThis->cbBlock]); 688 if (pThis->cbBlocks + cbAlloc <= RTFSEXT_MAX_BLOCK_GROUP_CACHE_SIZE) 689 pBlock = rtFsExtVol_BlockAlloc(pThis, cbAlloc, iBlock); 690 else 691 { 692 pBlock = RTListRemoveLast(&pThis->LstBlockLru, RTFSEXTBLOCKENTRY, NdLru); 693 if (!pBlock) 694 pBlock = rtFsExtVol_BlockAlloc(pThis, cbAlloc, iBlock); 695 else 696 { 697 /* Remove the block group from the tree because it gets a new key. */ 698 PAVLU64NODECORE pCore = RTAvlU64Remove(&pThis->BlockRoot, pBlock->Core.Key); 699 Assert(pCore == &pBlock->Core); RT_NOREF(pCore); 700 } 701 } 702 703 Assert(!pBlock->cRefs); 704 pBlock->Core.Key = iBlock; 705 pBlock->cRefs = 1; 706 707 return pBlock; 708 } 709 710 711 /** 712 * Frees the given block. 713 * 714 * @returns nothing. 715 * @param pThis The ext volume instance. 716 * @param pBlock The block to free. 717 */ 718 static void rtFsExtVol_BlockFree(PRTFSEXTVOL pThis, PRTFSEXTBLOCKENTRY pBlock) 719 { 720 Assert(!pBlock->cRefs); 721 722 /* 723 * Put it into the cache if the limit wasn't exceeded, otherwise the block group 724 * is freed right away. 725 */ 726 if (pThis->cbBlocks <= RTFSEXT_MAX_BLOCK_CACHE_SIZE) 727 { 728 /* Put onto the LRU list. */ 729 RTListPrepend(&pThis->LstBlockLru, &pBlock->NdLru); 730 } 731 else 732 { 733 /* Remove from the tree and free memory. */ 734 PAVLU64NODECORE pCore = RTAvlU64Remove(&pThis->BlockRoot, pBlock->Core.Key); 735 Assert(pCore == &pBlock->Core); RT_NOREF(pCore); 736 RTMemFree(pBlock); 737 pThis->cbBlocks -= RT_UOFFSETOF_DYN(RTFSEXTBLOCKENTRY, abData[pThis->cbBlock]); 738 } 739 } 740 741 742 /** 743 * Gets the specified block data from the volume. 744 * 745 * @returns IPRT status code. 746 * @param pThis The ext volume instance. 747 * @param iBlock The filesystem block to load. 748 * @param ppBlock Where to return the pointer to the block entry on success. 749 * @param ppvData Where to return the pointer to the block data on success. 750 */ 751 static int rtFsExtVol_BlockLoad(PRTFSEXTVOL pThis, uint64_t iBlock, PRTFSEXTBLOCKENTRY *ppBlock, void **ppvData) 752 { 753 int rc = VINF_SUCCESS; 754 755 /* Try to fetch the block group from the cache first. */ 756 PRTFSEXTBLOCKENTRY pBlock = (PRTFSEXTBLOCKENTRY)RTAvlU64Get(&pThis->BlockRoot, iBlock); 757 if (!pBlock) 758 { 759 /* Slow path, load from disk. */ 760 pBlock = rtFsExtVol_BlockGetNew(pThis, iBlock); 761 if (RT_LIKELY(pBlock)) 762 { 763 uint64_t offRead = rtFsExtBlockIdxToDiskOffset(pThis, iBlock); 764 rc = RTVfsFileReadAt(pThis->hVfsBacking, offRead, &pBlock->abData[0], pThis->cbBlock, NULL); 765 if (RT_SUCCESS(rc)) 766 { 767 bool fIns = RTAvlU64Insert(&pThis->BlockRoot, &pBlock->Core); 768 Assert(fIns); RT_NOREF(fIns); 769 } 770 } 771 else 772 rc = VERR_NO_MEMORY; 773 } 774 else 775 { 776 /* Remove from current LRU list position and add to the beginning. */ 777 uint32_t cRefs = ASMAtomicIncU32(&pBlock->cRefs); 778 if (cRefs == 1) /* Blocks get removed from the LRU list if they are referenced. */ 779 RTListNodeRemove(&pBlock->NdLru); 780 } 781 782 if (RT_SUCCESS(rc)) 783 { 784 *ppBlock = pBlock; 785 *ppvData = &pBlock->abData[0]; 786 } 787 else if (pBlock) 788 { 789 ASMAtomicDecU32(&pBlock->cRefs); 790 rtFsExtVol_BlockFree(pThis, pBlock); /* Free the block. */ 791 } 792 793 return rc; 794 } 795 796 797 /** 798 * Releases a reference of the given block. 799 * 800 * @returns nothing. 801 * @param pThis The ext volume instance. 802 * @param pBlock The block to release. 803 */ 804 static void rtFsExtVol_BlockRelease(PRTFSEXTVOL pThis, PRTFSEXTBLOCKENTRY pBlock) 805 { 806 uint32_t cRefs = ASMAtomicDecU32(&pBlock->cRefs); 807 if (!cRefs) 808 rtFsExtVol_BlockFree(pThis, pBlock); 809 } 810 811 812 /** 813 * Allocates a new block group. 814 * 815 * @returns Pointer to the new block group descriptor or NULL if out of memory. 816 * @param pThis The ext volume instance. 817 * @param cbAlloc How much to allocate. 818 * @param iBlockGroup Block group number. 819 */ 630 820 static PRTFSEXTBLKGRP rtFsExtBlockGroupAlloc(PRTFSEXTVOL pThis, size_t cbAlloc, uint32_t iBlockGroup) 631 821 { … … 1229 1419 else 1230 1420 { 1231 uint8_t *pbExtent = (uint8_t *)RTMemTmpAllocZ(pThis->cbBlock); 1232 if (RT_LIKELY(pbExtent)) 1421 uint8_t *pbExtent = NULL; 1422 PRTFSEXTBLOCKENTRY pBlock = NULL; 1423 uint64_t iBlockNext = 0; 1424 PCEXTEXTENTIDX paExtentIdx = (PCEXTEXTENTIDX)(pExtentHdr + 1); 1425 uint16_t cEntries = RT_LE2H_U16(pExtentHdr->cEntries); 1426 1427 /* Descend the tree until we reached the leaf nodes. */ 1428 do 1233 1429 { 1234 uint64_t iBlockNext = 0; 1235 PCEXTEXTENTIDX paExtentIdx = (PCEXTEXTENTIDX)(pExtentHdr + 1); 1236 uint16_t cEntries = RT_LE2H_U16(pExtentHdr->cEntries); 1237 1238 /* Descend the tree until we reached the leaf nodes. */ 1239 do 1240 { 1241 iBlockNext = rtFsExtInode_ExtentIndexLocateNextLvl(paExtentIdx, cEntries, iBlock); 1242 /* Read in the full block. */ 1243 uint64_t offRead = rtFsExtBlockIdxToDiskOffset(pThis, iBlockNext); 1244 rc = RTVfsFileReadAt(pThis->hVfsBacking, offRead, pbExtent, pThis->cbBlock, NULL); 1245 if (RT_SUCCESS(rc)) 1246 { 1247 pExtentHdr = (PCEXTEXTENTHDR)pbExtent; 1248 1249 #ifdef LOG_ENABLED 1250 rtFsExtExtentHdr_Log(pExtentHdr); 1251 #endif 1252 1253 if ( rtFsExtInode_ExtentHdrValidate(pExtentHdr) 1254 && RT_LE2H_U16(pExtentHdr->cMax) <= (pThis->cbBlock - sizeof(EXTEXTENTHDR)) / sizeof(EXTEXTENTIDX) 1255 && RT_LE2H_U16(pExtentHdr->uDepth) == uDepthCur - 1) 1256 { 1257 uDepthCur--; 1258 cEntries = RT_LE2H_U16(pExtentHdr->cEntries); 1259 paExtentIdx = (PCEXTEXTENTIDX)(pExtentHdr + 1); 1260 } 1261 else 1262 rc = VERR_VFS_BOGUS_FORMAT; 1263 } 1264 } 1265 while ( uDepthCur > 0 1266 && RT_SUCCESS(rc)); 1267 1430 iBlockNext = rtFsExtInode_ExtentIndexLocateNextLvl(paExtentIdx, cEntries, iBlock); 1431 /* Read in the full block. */ 1432 rc = rtFsExtVol_BlockLoad(pThis, iBlockNext, &pBlock, (void **)&pbExtent); 1268 1433 if (RT_SUCCESS(rc)) 1269 1434 { 1270 Assert(!uDepthCur); 1271 1272 /* We reached the leaf nodes. */ 1273 PCEXTEXTENT pExtent = (PCEXTEXTENT)(pExtentHdr + 1); 1274 for (uint32_t i = 0; i < RT_LE2H_U16(pExtentHdr->cEntries); i++) 1435 pExtentHdr = (PCEXTEXTENTHDR)pbExtent; 1436 1437 #ifdef LOG_ENABLED 1438 rtFsExtExtentHdr_Log(pExtentHdr); 1439 #endif 1440 1441 if ( rtFsExtInode_ExtentHdrValidate(pExtentHdr) 1442 && RT_LE2H_U16(pExtentHdr->cMax) <= (pThis->cbBlock - sizeof(EXTEXTENTHDR)) / sizeof(EXTEXTENTIDX) 1443 && RT_LE2H_U16(pExtentHdr->uDepth) == uDepthCur - 1) 1275 1444 { 1276 /* Check whether the extent intersects with the block. */ 1277 if (rtFsExtInode_ExtentParse(pExtent, iBlock, cBlocks, piBlockFs, pcBlocks, pfSparse)) 1278 { 1279 rc = VINF_SUCCESS; 1280 break; 1281 } 1282 pExtent++; 1445 uDepthCur--; 1446 cEntries = RT_LE2H_U16(pExtentHdr->cEntries); 1447 paExtentIdx = (PCEXTEXTENTIDX)(pExtentHdr + 1); 1448 if (uDepthCur) 1449 rtFsExtVol_BlockRelease(pThis, pBlock); 1283 1450 } 1451 else 1452 rc = VERR_VFS_BOGUS_FORMAT; 1284 1453 } 1285 1286 RTMemTmpFree(pbExtent);1287 1454 } 1288 else 1289 rc = VERR_NO_MEMORY; 1455 while ( uDepthCur > 0 1456 && RT_SUCCESS(rc)); 1457 1458 if (RT_SUCCESS(rc)) 1459 { 1460 Assert(!uDepthCur); 1461 1462 /* We reached the leaf nodes. */ 1463 PCEXTEXTENT pExtent = (PCEXTEXTENT)(pExtentHdr + 1); 1464 for (uint32_t i = 0; i < RT_LE2H_U16(pExtentHdr->cEntries); i++) 1465 { 1466 /* Check whether the extent intersects with the block. */ 1467 if (rtFsExtInode_ExtentParse(pExtent, iBlock, cBlocks, piBlockFs, pcBlocks, pfSparse)) 1468 { 1469 rc = VINF_SUCCESS; 1470 break; 1471 } 1472 pExtent++; 1473 } 1474 } 1475 1476 if (pBlock) 1477 rtFsExtVol_BlockRelease(pThis, pBlock); 1290 1478 } 1291 1479 } … … 1326 1514 { 1327 1515 uint32_t cEntriesPerBlockMap = (uint32_t)(pThis->cbBlock >> sizeof(uint32_t)); 1328 uint32_t *paBlockMap = (uint32_t *)RTMemTmpAllocZ(pThis->cbBlock);1329 1330 if (!paBlockMap)1331 return VERR_NO_MEMORY;1332 1516 1333 1517 if (iBlock <= cEntriesPerBlockMap + 11) 1334 1518 { 1335 1519 /* Indirect block. */ 1336 uint64_t offRead = rtFsExtBlockIdxToDiskOffset(pThis, pInode->aiBlocks[12]); 1337 rc = RTVfsFileReadAt(pThis->hVfsBacking, offRead, paBlockMap, pThis->cbBlock, NULL); 1520 PRTFSEXTBLOCKENTRY pBlock = NULL; 1521 uint32_t *paBlockMap = NULL; 1522 rc = rtFsExtVol_BlockLoad(pThis, pInode->aiBlocks[12], &pBlock, (void **)&paBlockMap); 1338 1523 if (RT_SUCCESS(rc)) 1524 { 1339 1525 *piBlockFs = RT_LE2H_U32(paBlockMap[iBlock - 12]); 1526 rtFsExtVol_BlockRelease(pThis, pBlock); 1527 } 1340 1528 } 1341 1529 else if (iBlock <= cEntriesPerBlockMap * cEntriesPerBlockMap + cEntriesPerBlockMap + 11) 1342 1530 { 1343 1531 /* Double indirect block. */ 1344 iBlock -= 12; 1345 uint64_t offRead = rtFsExtBlockIdxToDiskOffset(pThis, pInode->aiBlocks[13]); 1346 rc = RTVfsFileReadAt(pThis->hVfsBacking, offRead, paBlockMap, pThis->cbBlock, NULL); 1532 PRTFSEXTBLOCKENTRY pBlock = NULL; 1533 uint32_t *paBlockMap = NULL; 1534 1535 iBlock -= 12 + cEntriesPerBlockMap; 1536 rc = rtFsExtVol_BlockLoad(pThis, pInode->aiBlocks[13], &pBlock, (void **)&paBlockMap); 1347 1537 if (RT_SUCCESS(rc)) 1348 1538 { 1349 1539 uint32_t idxBlockL2 = iBlock / cEntriesPerBlockMap; 1350 1540 uint32_t idxBlockL1 = iBlock % cEntriesPerBlockMap; 1351 offRead = rtFsExtBlockIdxToDiskOffset(pThis, RT_LE2H_U32(paBlockMap[idxBlockL2])); 1352 rc = RTVfsFileReadAt(pThis->hVfsBacking, offRead, paBlockMap, pThis->cbBlock, NULL); 1541 uint32_t iBlockNext = RT_LE2H_U32(paBlockMap[idxBlockL2]); 1542 1543 rtFsExtVol_BlockRelease(pThis, pBlock); 1544 rc = rtFsExtVol_BlockLoad(pThis, iBlockNext, &pBlock, (void **)&paBlockMap); 1353 1545 if (RT_SUCCESS(rc)) 1546 { 1354 1547 *piBlockFs = RT_LE2H_U32(paBlockMap[idxBlockL1]); 1548 rtFsExtVol_BlockRelease(pThis, pBlock); 1549 } 1355 1550 } 1356 1551 } … … 1358 1553 { 1359 1554 /* Triple indirect block. */ 1360 rc = VERR_NOT_IMPLEMENTED; 1361 } 1362 1363 RTMemTmpFree(paBlockMap); 1555 PRTFSEXTBLOCKENTRY pBlock = NULL; 1556 uint32_t *paBlockMap = NULL; 1557 1558 iBlock -= 12 + cEntriesPerBlockMap * cEntriesPerBlockMap + cEntriesPerBlockMap; 1559 rc = rtFsExtVol_BlockLoad(pThis, pInode->aiBlocks[14], &pBlock, (void **)&paBlockMap); 1560 if (RT_SUCCESS(rc)) 1561 { 1562 uint32_t idxBlockL3 = iBlock / (cEntriesPerBlockMap * cEntriesPerBlockMap); 1563 uint32_t iBlockNext = RT_LE2H_U32(paBlockMap[idxBlockL3]); 1564 1565 rtFsExtVol_BlockRelease(pThis, pBlock); 1566 rc = rtFsExtVol_BlockLoad(pThis, iBlockNext, &pBlock, (void **)&paBlockMap); 1567 if (RT_SUCCESS(rc)) 1568 { 1569 uint32_t idxBlockL2 = (iBlock % (cEntriesPerBlockMap * cEntriesPerBlockMap)) / cEntriesPerBlockMap; 1570 uint32_t idxBlockL1 = iBlock % cEntriesPerBlockMap; 1571 iBlockNext = RT_LE2H_U32(paBlockMap[idxBlockL2]); 1572 1573 rtFsExtVol_BlockRelease(pThis, pBlock); 1574 rc = rtFsExtVol_BlockLoad(pThis, iBlockNext, &pBlock, (void **)&paBlockMap); 1575 if (RT_SUCCESS(rc)) 1576 { 1577 *piBlockFs = RT_LE2H_U32(paBlockMap[idxBlockL1]); 1578 rtFsExtVol_BlockRelease(pThis, pBlock); 1579 } 1580 } 1581 } 1582 } 1364 1583 } 1365 1584 … … 2236 2455 2237 2456 2457 static DECLCALLBACK(int) rtFsExtVolBlockTreeDestroy(PAVLU64NODECORE pCore, void *pvUser) 2458 { 2459 RT_NOREF(pvUser); 2460 2461 PRTFSEXTBLOCKENTRY pBlock = (PRTFSEXTBLOCKENTRY)pCore; 2462 Assert(!pBlock->cRefs); 2463 RTMemFree(pBlock); 2464 return VINF_SUCCESS; 2465 } 2466 2467 2238 2468 /** 2239 2469 * @interface_method_impl{RTVFSOBJOPS::Obj,pfnClose} … … 2252 2482 pThis->InodeRoot = NULL; 2253 2483 RTListInit(&pThis->LstInodeLru); 2484 2485 /* Destroy the block cache tree. */ 2486 RTAvlU64Destroy(&pThis->BlockRoot, rtFsExtVolBlockTreeDestroy, pThis); 2487 pThis->BlockRoot = NULL; 2488 RTListInit(&pThis->LstBlockLru); 2254 2489 2255 2490 /* … … 2479 2714 pThis->BlockGroupRoot = NULL; 2480 2715 pThis->InodeRoot = NULL; 2716 pThis->BlockRoot = NULL; 2481 2717 pThis->cbBlockGroups = 0; 2482 2718 pThis->cbInodes = 0; 2719 pThis->cbBlocks = 0; 2483 2720 RTListInit(&pThis->LstBlockGroupLru); 2484 2721 RTListInit(&pThis->LstInodeLru); 2722 RTListInit(&pThis->LstBlockLru); 2485 2723 2486 2724 rc = RTVfsFileGetSize(pThis->hVfsBacking, &pThis->cbBacking);
Note:
See TracChangeset
for help on using the changeset viewer.