diff --git a/src/add-ons/kernel/file_systems/xfs/BPlusTree.cpp b/src/add-ons/kernel/file_systems/xfs/BPlusTree.cpp index c77225b623..b789434b2b 100644 --- a/src/add-ons/kernel/file_systems/xfs/BPlusTree.cpp +++ b/src/add-ons/kernel/file_systems/xfs/BPlusTree.cpp @@ -38,7 +38,6 @@ TreeDirectory::TreeDirectory(Inode* inode) fPathForLeaves[i].blockData = NULL; fPathForData[i].blockData = NULL; } - } @@ -46,7 +45,7 @@ TreeDirectory::~TreeDirectory() { delete fRoot; delete[] fExtents; - delete fSingleDirBlock; + delete[] fSingleDirBlock; } @@ -285,50 +284,21 @@ TreeDirectory::GetAllExtents() ArrayDeleter extentsWrappedDeleter(extentsWrapped); - Volume* volume = fInode->GetVolume(); - uint16 levelsInTree = fRoot->Levels(); - size_t maxRecords = MaxRecordsPossibleRoot(); TRACE("Maxrecords: (%d)\n", maxRecords); - TreePointer* ptrToNode = GetPtrFromRoot(1); + Volume* volume = fInode->GetVolume(); size_t len = volume->BlockSize(); - char node[len]; - // This isn't for a directory block but for one of the tree nodes - TRACE("levels:(%d)\n", levelsInTree); - TRACE("Numrecs:(%d)\n", fRoot->NumRecords()); - - // Go down the tree by taking the leftest pointer to go to the first leaf - uint64 fileSystemBlockNo = B_BENDIAN_TO_HOST_INT64(*ptrToNode); - uint64 readPos = fInode->FileSystemBlockToAddr(fileSystemBlockNo); - while (levelsInTree != 1) { - fileSystemBlockNo = B_BENDIAN_TO_HOST_INT64(*ptrToNode); - // The fs block that contains node at next lower level. Now read. - readPos = fInode->FileSystemBlockToAddr(fileSystemBlockNo); - if (read_pos(volume->Device(), readPos, node, len) != len) { - ERROR("Extent::FillBlockBuffer(): IO Error"); - return B_IO_ERROR; - } - LongBlock* curLongBlock = (LongBlock*)node; - ASSERT(curLongBlock->Magic() == XFS_BMAP_MAGIC); - ptrToNode = GetPtrFromNode(1, (void*)curLongBlock); - // Get's the first pointer. This points to next node. - levelsInTree--; - } - - // Next level wil contain leaf nodes. Now Read Directory Buffer - len = fInode->DirBlockSize(); - if (read_pos(volume->Device(), readPos, fSingleDirBlock, len) - != len) { - ERROR("Extent::FillBlockBuffer(): IO Error"); - return B_IO_ERROR; - } - levelsInTree--; - ASSERT(levelsInTree == 0); + uint16 levelsInTree = fRoot->Levels(); + status_t status = fInode->GetNodefromTree(levelsInTree, volume, len, + fInode->DirBlockSize(), fSingleDirBlock); + if (status != B_OK) + return status; // We should be at the left most leaf node. // This could be a multilevel node type directory + uint64 fileSystemBlockNo; while (1) { // Run till you have leaf blocks to checkout char* leafBuffer = fSingleDirBlock; @@ -358,7 +328,7 @@ TreeDirectory::GetAllExtents() } TRACE("Total covered: (%d)\n", fCountOfFilledExtents); - status_t status = UnWrapExtents(extentsWrapped); + status = UnWrapExtents(extentsWrapped); return status; } diff --git a/src/add-ons/kernel/file_systems/xfs/BPlusTree.h b/src/add-ons/kernel/file_systems/xfs/BPlusTree.h index e37574cfdd..852a30db5c 100644 --- a/src/add-ons/kernel/file_systems/xfs/BPlusTree.h +++ b/src/add-ons/kernel/file_systems/xfs/BPlusTree.h @@ -13,20 +13,6 @@ #include "system_dependencies.h" -#define XFS_BTREE_SBLOCK_SIZE 18 - // Header for Short Format btree -#define XFS_BTREE_LBLOCK_SIZE 24 - // Header for Long Format btree -#define XFS_KEY_SIZE sizeof(xfs_fileoff_t) -#define XFS_PTR_SIZE sizeof(xfs_fsblock_t) -#define XFS_BMAP_MAGIC 0x424d4150 -#define MAX_TREE_DEPTH 5 - - -typedef xfs_fileoff_t TreeKey; -typedef xfs_fsblock_t TreePointer; - - /* * Headers(here, the LongBlock) are the "nodes" really and are called "blocks". * The records, keys and ptrs are calculated using helpers @@ -62,19 +48,6 @@ struct LongBlock { */ -// xfs_bmdr_block -struct BlockInDataFork { - uint16 Levels() - { return - B_BENDIAN_TO_HOST_INT16(bb_level); } - uint16 NumRecords() - { return - B_BENDIAN_TO_HOST_INT16(bb_numrecs); } - uint16 bb_level; - uint16 bb_numrecs; -}; - - struct ExtentMapUnwrap { uint64 first; uint64 second; diff --git a/src/add-ons/kernel/file_systems/xfs/Inode.cpp b/src/add-ons/kernel/file_systems/xfs/Inode.cpp index 4c58378fe3..e4d30421d7 100644 --- a/src/add-ons/kernel/file_systems/xfs/Inode.cpp +++ b/src/add-ons/kernel/file_systems/xfs/Inode.cpp @@ -5,7 +5,7 @@ #include "Inode.h" - +#include "BPlusTree.h" void xfs_inode_t::SwapEndian() @@ -216,10 +216,8 @@ Inode::UnWrapExtentFromWrappedEntry(uint64 wrappedExtent[2], status_t -Inode::ReadExtents() +Inode::ReadExtentsFromExtentBasedInode() { - if (Format() != XFS_DINODE_FMT_EXTENTS) - return B_NOT_SUPPORTED; fExtents = new(std::nothrow) ExtentMapEntry[DataExtentsCount()]; char* dataStart = (char*) DIR_DFORK_PTR(Buffer()); uint64 wrappedExtent[2]; @@ -233,6 +231,189 @@ Inode::ReadExtents() } +size_t +Inode::MaxRecordsPossibleInTreeRoot() +{ + size_t lengthOfDataFork; + if (ForkOffset() != 0) + lengthOfDataFork = ForkOffset() << 3; + else if(ForkOffset() == 0) { + lengthOfDataFork = GetVolume()->InodeSize() + - INODE_CORE_UNLINKED_SIZE; + } + + lengthOfDataFork -= sizeof(BlockInDataFork); + return lengthOfDataFork / (XFS_KEY_SIZE + XFS_PTR_SIZE); +} + + +size_t +Inode::GetPtrOffsetIntoRoot(int pos) +{ + size_t maxRecords = MaxRecordsPossibleInTreeRoot(); + return (sizeof(BlockInDataFork) + + maxRecords * XFS_KEY_SIZE + (pos - 1) * XFS_PTR_SIZE); +} + + +TreePointer* +Inode::GetPtrFromRoot(int pos) +{ + return (TreePointer*) + ((char*)DIR_DFORK_PTR(Buffer()) + GetPtrOffsetIntoRoot(pos)); +} + + +size_t +Inode::MaxRecordsPossibleNode() +{ + size_t availableSpace = GetVolume()->BlockSize() - XFS_BTREE_LBLOCK_SIZE; + return availableSpace / (XFS_KEY_SIZE + XFS_PTR_SIZE); +} + + +size_t +Inode::GetPtrOffsetIntoNode(int pos) +{ + size_t maxRecords = MaxRecordsPossibleNode(); + return XFS_BTREE_LBLOCK_SIZE + maxRecords * XFS_KEY_SIZE + + (pos - 1) * XFS_PTR_SIZE; +} + + +TreePointer* +Inode::GetPtrFromNode(int pos, void* buffer) +{ + size_t offsetIntoNode = GetPtrOffsetIntoNode(pos); + return (TreePointer*)((char*)buffer + offsetIntoNode); +} + + +status_t +Inode::GetNodefromTree(uint16& levelsInTree, Volume* volume, + size_t& len, size_t DirBlockSize, char* block) { + + char* node = new(std::nothrow) char[len]; + if (node == NULL) + return B_NO_MEMORY; + // This isn't for a directory block but for one of the tree nodes + + ArrayDeleter nodeDeleter(node); + + TRACE("levels:(%d)\n", levelsInTree); + TRACE("Numrecs:(%d)\n", fRoot->NumRecords()); + + TreePointer* ptrToNode = GetPtrFromRoot(1); + uint64 fileSystemBlockNo = B_BENDIAN_TO_HOST_INT64(*ptrToNode); + uint64 readPos = FileSystemBlockToAddr(fileSystemBlockNo); + // Go down the tree by taking the leftmost pointer to the first leaf + while (levelsInTree != 1) { + fileSystemBlockNo = B_BENDIAN_TO_HOST_INT64(*ptrToNode); + // The fs block that contains node at next lower level. Now read. + readPos = FileSystemBlockToAddr(fileSystemBlockNo); + if (read_pos(volume->Device(), readPos, node, len) != len) { + ERROR("Extent::FillBlockBuffer(): IO Error"); + return B_IO_ERROR; + } + LongBlock* curLongBlock = (LongBlock*)node; + ASSERT(curLongBlock->Magic() == XFS_BMAP_MAGIC); + ptrToNode = GetPtrFromNode(1, (void*)curLongBlock); + // Get's the first pointer. This points to next node. + levelsInTree--; + } + // Next level wil contain leaf nodes. Now Read Directory Buffer + len = DirBlockSize; + if (read_pos(volume->Device(), readPos, block, len) + != len) { + ERROR("Extent::FillBlockBuffer(): IO Error"); + return B_IO_ERROR; + } + levelsInTree--; + if (levelsInTree != 0) + return B_BAD_VALUE; + return B_OK; +} + + +status_t +Inode::ReadExtentsFromTreeInode() +{ + fExtents = new(std::nothrow) ExtentMapEntry[DataExtentsCount()]; + BlockInDataFork* root = new(std::nothrow) BlockInDataFork; + if (root == NULL) + return B_NO_MEMORY; + memcpy((void*)root, + DIR_DFORK_PTR(Buffer()), sizeof(BlockInDataFork)); + + size_t maxRecords = MaxRecordsPossibleInTreeRoot(); + TRACE("Maxrecords: (%d)\n", maxRecords); + + uint16 levelsInTree = root->Levels(); + delete root; + + Volume* volume = GetVolume(); + size_t len = volume->BlockSize(); + + len = DirBlockSize(); + char* block = new(std::nothrow) char[len]; + if (block == NULL) + return B_NO_MEMORY; + + ArrayDeleter blockDeleter(block); + + GetNodefromTree(levelsInTree, volume, len, DirBlockSize(), block); + + uint64 fileSystemBlockNo; + uint64 wrappedExtent[2]; + int indexIntoExtents = 0; + // We should be at the left most leaf node. + // This could be a multilevel node type directory + while (1) { + // Run till you have leaf blocks to checkout + char* leafBuffer = block; + ASSERT(((LongBlock*)leafBuffer)->Magic() == XFS_BMAP_MAGIC); + uint32 offset = sizeof(LongBlock); + int numRecs = ((LongBlock*)leafBuffer)->NumRecs(); + + for (int i = 0; i < numRecs; i++) { + wrappedExtent[0] = *(uint64*)(leafBuffer + offset); + wrappedExtent[1] + = *(uint64*)(leafBuffer + offset + sizeof(uint64)); + offset += sizeof(ExtentMapUnwrap); + UnWrapExtentFromWrappedEntry(wrappedExtent, + &fExtents[indexIntoExtents]); + indexIntoExtents++; + } + + fileSystemBlockNo = ((LongBlock*)leafBuffer)->Right(); + TRACE("Next leaf is at: (%d)\n", fileSystemBlockNo); + if (fileSystemBlockNo == -1) + break; + uint64 readPos = FileSystemBlockToAddr(fileSystemBlockNo); + if (read_pos(volume->Device(), readPos, block, len) + != len) { + ERROR("Extent::FillBlockBuffer(): IO Error"); + return B_IO_ERROR; + } + } + TRACE("Total covered: (%d)\n", indexIntoExtents); + return B_OK; +} + + +status_t +Inode::ReadExtents() +{ + if (fExtents != NULL) + return B_OK; + if (Format() == XFS_DINODE_FMT_BTREE) + return ReadExtentsFromTreeInode(); + if (Format() == XFS_DINODE_FMT_EXTENTS) + return ReadExtentsFromExtentBasedInode(); + return B_BAD_VALUE; +} + + int Inode::SearchMapInAllExtent(int blockNo) { @@ -328,6 +509,7 @@ Inode::ReadAt(off_t pos, uint8* buffer, size_t* length) blockNo = BLOCKNO_FROM_POSITION(pos, GetVolume()); offsetIntoBlock = BLOCKOFFSET_FROM_POSITION(pos, this); } + TRACE("lengthRead:(%d)\n", lengthRead); *length = lengthRead; return B_OK; diff --git a/src/add-ons/kernel/file_systems/xfs/Inode.h b/src/add-ons/kernel/file_systems/xfs/Inode.h index 448cbc04e7..a12bc972b4 100644 --- a/src/add-ons/kernel/file_systems/xfs/Inode.h +++ b/src/add-ons/kernel/file_systems/xfs/Inode.h @@ -45,6 +45,19 @@ #define BLOCKOFFSET_FROM_POSITION(n, inode) ((n) & (inode->BlockSize() - 1)) +// xfs_bmdr_block +struct BlockInDataFork { + uint16 Levels() + { return + B_BENDIAN_TO_HOST_INT16(bb_level); } + uint16 NumRecords() + { return + B_BENDIAN_TO_HOST_INT16(bb_numrecs); } + uint16 bb_level; + uint16 bb_numrecs; +}; + + // xfs_da_blkinfo_t struct BlockInfo { uint32 forw; @@ -146,7 +159,6 @@ struct xfs_inode_t { uint16 di_dmstate; uint16 di_flags; uint32 di_gen; - uint32 di_next_unlinked; }; @@ -218,9 +230,21 @@ public: { return fNode->ForkOffset(); } status_t ReadExtents(); status_t ReadAt(off_t pos, uint8* buffer, size_t* length); + status_t GetNodefromTree(uint16& levelsInTree, + Volume* volume, size_t& len, + size_t DirBlockSize, char* block); int SearchMapInAllExtent(int blockNo); void UnWrapExtentFromWrappedEntry( - uint64 wrappedExtent[2], ExtentMapEntry* entry); + uint64 wrappedExtent[2], + ExtentMapEntry* entry); + status_t ReadExtentsFromExtentBasedInode(); + status_t ReadExtentsFromTreeInode(); + size_t MaxRecordsPossibleInTreeRoot(); + size_t MaxRecordsPossibleNode(); + TreePointer* GetPtrFromRoot(int pos); + TreePointer* GetPtrFromNode(int pos, void* buffer); + size_t GetPtrOffsetIntoRoot(int pos); + size_t GetPtrOffsetIntoNode(int pos); private: status_t GetFromDisk(); xfs_inode_t* fNode; diff --git a/src/add-ons/kernel/file_systems/xfs/xfs.h b/src/add-ons/kernel/file_systems/xfs/xfs.h index 4bc49e8300..3c6a904d89 100644 --- a/src/add-ons/kernel/file_systems/xfs/xfs.h +++ b/src/add-ons/kernel/file_systems/xfs/xfs.h @@ -32,6 +32,16 @@ extern fs_volume_ops gxfsVolumeOps; // The size of a basic block should be 512 #define XFS_OPEN_MODE_USER_MASK 0x7fffffff +/* B+Tree related macros +*/ +#define XFS_BTREE_SBLOCK_SIZE 18 + // Header for Short Format btree +#define XFS_BTREE_LBLOCK_SIZE 24 + // Header for Long Format btree +#define XFS_BMAP_MAGIC 0x424d4150 +#define MAX_TREE_DEPTH 5 +#define XFS_KEY_SIZE sizeof(xfs_fileoff_t) +#define XFS_PTR_SIZE sizeof(xfs_fsblock_t) struct file_cookie { bigtime_t last_notification; diff --git a/src/add-ons/kernel/file_systems/xfs/xfs_types.h b/src/add-ons/kernel/file_systems/xfs/xfs_types.h index ae32585f26..5cb4301156 100644 --- a/src/add-ons/kernel/file_systems/xfs/xfs_types.h +++ b/src/add-ons/kernel/file_systems/xfs/xfs_types.h @@ -34,6 +34,8 @@ typedef uint64 xfs_rtblock_t; // extent number in the real-time sub-volume typedef uint64 xfs_fileoff_t; // block offset into a file typedef uint64 xfs_filblks_t; // block count for a file typedef int64 xfs_fsize_t; // byte size of a file +typedef xfs_fileoff_t TreeKey; +typedef xfs_fsblock_t TreePointer; // typedef unsigned char uuid_t[16];