diff --git a/src/add-ons/kernel/file_systems/xfs/BPlusTree.cpp b/src/add-ons/kernel/file_systems/xfs/BPlusTree.cpp index b14f869cc3..db2c8380a4 100644 --- a/src/add-ons/kernel/file_systems/xfs/BPlusTree.cpp +++ b/src/add-ons/kernel/file_systems/xfs/BPlusTree.cpp @@ -7,122 +7,219 @@ #include "BPlusTree.h" -void -bplustree_short_block::SwapEndian() +TreeDirectory::TreeDirectory(Inode* inode) + : + fInode(inode), + fInitStatus(B_OK), + fRoot(NULL), + fExtents(NULL), + fSingleDirBlock(NULL), + fCountOfFilledExtents(0) { - bb_magic = B_BENDIAN_TO_HOST_INT32(bb_magic); - bb_level = B_BENDIAN_TO_HOST_INT16(bb_level); - bb_numrecs = B_BENDIAN_TO_HOST_INT16(bb_numrecs); - bb_leftsib = B_BENDIAN_TO_HOST_INT32(bb_leftsib); - bb_rightsib = B_BENDIAN_TO_HOST_INT32(bb_rightsib); -} - - -void -bplustree_long_block::SwapEndian() -{ - bb_magic = B_BENDIAN_TO_HOST_INT32(bb_magic); - bb_level = B_BENDIAN_TO_HOST_INT16(bb_level); - bb_numrecs = B_BENDIAN_TO_HOST_INT16(bb_numrecs); - bb_leftsib = B_BENDIAN_TO_HOST_INT64(bb_leftsib); - bb_rightsib = B_BENDIAN_TO_HOST_INT64(bb_rightsib); -} - - -void -xfs_alloc_rec::SwapEndian() -{ - ar_startblock = B_BENDIAN_TO_HOST_INT32(ar_startblock); - ar_blockcount = B_BENDIAN_TO_HOST_INT32(ar_blockcount); -} - - -uint32 -BPlusTree::BlockSize() -{ - return fVolume.SuperBlock().BlockSize(); -} - - -int -BPlusTree::RecordSize() -{ - if (fRecType == ALLOC_FLAG) - return XFS_ALLOC_REC_SIZE; - - return B_BAD_VALUE; -} - - -int -BPlusTree::MaxRecords(bool leaf) -{ - int blockLen = BlockSize(); - - if (fPtrType == SHORT_BLOCK_FLAG) - blockLen - XFS_BTREE_SBLOCK_SIZE; - - if (leaf) { - if (fRecType == ALLOC_FLAG) - return blockLen / sizeof(xfs_alloc_rec_t); - } else { - if (fKeyType == ALLOC_FLAG) { - return blockLen / (sizeof(xfs_alloc_key_t) - + sizeof(xfs_alloc_ptr_t)); - } + fRoot = new(std::nothrow) BlockInDataFork; + if (fRoot == NULL) { + fInitStatus = B_NO_MEMORY; + return; } - return B_BAD_VALUE; + fSingleDirBlock = new(std::nothrow) char[fInode->DirBlockSize()]; + if (fSingleDirBlock == NULL) { + fInitStatus = B_NO_MEMORY; + return; + } + + memcpy((void*)fRoot, + DIR_DFORK_PTR(fInode->Buffer()), sizeof(BlockInDataFork)); +} + + +TreeDirectory::~TreeDirectory() +{ + delete fRoot; + delete[] fExtents; + delete fSingleDirBlock; +} + + +status_t +TreeDirectory::InitCheck() +{ + return fInitStatus; } int -BPlusTree::KeyLen() +TreeDirectory::BlockLen() { - if (fKeyType == ALLOC_FLAG) - return XFS_ALLOC_REC_SIZE; - return B_BAD_VALUE; + return XFS_BTREE_LBLOCK_SIZE; } -int -BPlusTree::BlockLen() +TreeKey +TreeDirectory::GetKey(int pos) { - if (fPtrType == LONG_BLOCK_FLAG) - return XFS_BTREE_LBLOCK_SIZE; - if (fPtrType == SHORT_BLOCK_FLAG) - return XFS_BTREE_SBLOCK_SIZE; - return B_BAD_VALUE; + return BlockLen() + (pos - 1) * XFS_KEY_SIZE; } -int -BPlusTree::PtrLen() +size_t +TreeDirectory::KeySize() { - if (fPtrType == LONG_BLOCK_FLAG) - return sizeof(uint64); + return XFS_KEY_SIZE; +} + + +size_t +TreeDirectory::PtrSize() +{ + return XFS_PTR_SIZE; +} + + +TreePointer* +TreeDirectory::GetPtr(int pos, LongBlock* curLongBlock) +{ + size_t availableSpace = fInode->GetVolume()->BlockSize() - BlockLen(); + size_t maxRecords = availableSpace / (KeySize() + PtrSize()); + size_t offsetIntoNode = + BlockLen() + maxRecords * KeySize() + (pos - 1) * PtrSize(); + return (TreePointer*)((char*)curLongBlock + offsetIntoNode); +} + + +size_t +TreeDirectory::MaxRecordsPossible(size_t len) +{ + len -= sizeof(BlockInDataFork); + return len / (KeySize() + PtrSize()); +} + + +status_t +TreeDirectory::GetAllExtents() +{ + xfs_extnum_t noOfExtents = fInode->DataExtentsCount(); + ExtentMapUnwrap* extentsWrapped + = new(std::nothrow) ExtentMapUnwrap[noOfExtents]; + if (extentsWrapped == NULL) + return B_NO_MEMORY; + + Volume* volume = fInode->GetVolume(); + uint16 levelsInTree = fRoot->Levels(); + + size_t lengthOfDataFork; + if (fInode->ForkOffset() != 0) + lengthOfDataFork = fInode->ForkOffset() << 3; else - return sizeof(uint32); + lengthOfDataFork = volume->InodeSize() - INODE_CORE_UNLINKED_SIZE; + + TRACE("Length Of Data Fork: (%d)\n", lengthOfDataFork); + size_t maxRecords = MaxRecordsPossible(lengthOfDataFork); + TRACE("Maxrecords: (%d)\n", maxRecords); + TreePointer* ptrToNode = (TreePointer*) + ((char*)DIR_DFORK_PTR(fInode->Buffer()) + + sizeof(BlockInDataFork) + maxRecords*KeySize()); + + 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"); + + delete[] extentsWrapped; + extentsWrapped = NULL; + return B_IO_ERROR; + } + LongBlock* curLongBlock = (LongBlock*)node; + ASSERT(curLongBlock->Magic() == XFS_BMAP_MAGIC); + ptrToNode = GetPtr(1, 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"); + + delete[] extentsWrapped; + extentsWrapped = NULL; + return B_IO_ERROR; + } + levelsInTree--; + ASSERT(levelsInTree == 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 = fSingleDirBlock; + ASSERT(((LongBlock*)leafBuffer)->Magic() == XFS_BMAP_MAGIC); + uint32 offset = sizeof(LongBlock); + int numRecs = ((LongBlock*)leafBuffer)->NumRecs(); + + for (int i = 0; i < numRecs; i++) { + extentsWrapped[fCountOfFilledExtents].first = + *(uint64*)(leafBuffer + offset); + extentsWrapped[fCountOfFilledExtents].second = + *(uint64*)(leafBuffer + offset + sizeof(uint64)); + offset += sizeof(ExtentMapUnwrap); + fCountOfFilledExtents++; + } + + fileSystemBlockNo = ((LongBlock*)leafBuffer)->Right(); + TRACE("Next leaf is at: (%d)\n", fileSystemBlockNo); + if (fileSystemBlockNo == -1) + break; + uint64 readPos = fInode->FileSystemBlockToAddr(fileSystemBlockNo); + if (read_pos(volume->Device(), readPos, fSingleDirBlock, len) + != len) { + ERROR("Extent::FillBlockBuffer(): IO Error"); + + delete[] extentsWrapped; + extentsWrapped = NULL; + return B_IO_ERROR; + } + } + TRACE("Total covered: (%d)\n", fCountOfFilledExtents); + + status_t status = UnWrapExtents(extentsWrapped); + + delete[] extentsWrapped; + extentsWrapped = NULL; + + return status; } -int -BPlusTree::RecordOffset(int pos) +status_t +TreeDirectory::UnWrapExtents(ExtentMapUnwrap* extentsWrapped) { - return BlockLen() + (pos - 1) * RecordSize(); -} - - -int -BPlusTree::KeyOffset(int pos) -{ - return BlockLen() + (pos - 1) * KeyLen(); -} - - -int -BPlusTree::PtrOffset(int pos, int level) -{ - return BlockLen() + MaxRecords(level > 0) * KeyLen() - + (pos - 1) * PtrLen(); + fExtents = new(std::nothrow) ExtentMapEntry[fCountOfFilledExtents]; + if (fExtents == NULL) + return B_NO_MEMORY; + uint64 first, second; + + for (int i = 0; i < fCountOfFilledExtents; i++) { + first = B_BENDIAN_TO_HOST_INT64(extentsWrapped[i].first); + second = B_BENDIAN_TO_HOST_INT64(extentsWrapped[i].second); + fExtents[i].br_state = first >> 63; + fExtents[i].br_startoff = (first & MASK(63)) >> 9; + fExtents[i].br_startblock = ((first & MASK(9)) << 43) | (second >> 21); + fExtents[i].br_blockcount = second & MASK(21); + } + + return B_OK; } diff --git a/src/add-ons/kernel/file_systems/xfs/BPlusTree.h b/src/add-ons/kernel/file_systems/xfs/BPlusTree.h index 371a4f4411..b2c73701c1 100644 --- a/src/add-ons/kernel/file_systems/xfs/BPlusTree.h +++ b/src/add-ons/kernel/file_systems/xfs/BPlusTree.h @@ -5,136 +5,115 @@ #ifndef _BPLUS_TREE_H_ #define _BPLUS_TREE_H_ + +#include "Extent.h" +#include "Inode.h" +#include "LeafDirectory.h" +#include "Node.h" #include "system_dependencies.h" -/* Allocation B+ Tree Format */ -#define XFS_ABTB_MAGICNUM 0x41425442 - // For block offset B+Tree -#define XFS_ABTC_MAGICNUM 0x41425443 - // For block count B+ Tree #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 + + +typedef xfs_fileoff_t TreeKey; +typedef xfs_fsblock_t TreePointer; /* - * Headers are the "nodes" really and are called "blocks". The records, keys - * and ptrs are calculated using helpers + * Headers(here, the LongBlock) are the "nodes" really and are called "blocks". + * The records, keys and ptrs are calculated using helpers */ -struct bplustree_short_block { - void SwapEndian(); +struct LongBlock { uint32 Magic() - { return bb_magic; } + { return B_BENDIAN_TO_HOST_INT32(bb_magic); } uint16 Level() - { return bb_level; } + { return B_BENDIAN_TO_HOST_INT16(bb_level); } uint16 NumRecs() - { return bb_numrecs; } + { return B_BENDIAN_TO_HOST_INT16(bb_numrecs); } - xfs_alloc_ptr_t Left() - { return bb_leftsib; } + TreePointer Left() + { return B_BENDIAN_TO_HOST_INT64(bb_leftsib); } - xfs_alloc_ptr_t Right() - { return bb_rightsib;} - - uint32 bb_magic; - uint16 bb_level; - uint16 bb_numrecs; - uint32 bb_leftsib; - uint32 bb_rightsib; -} - - -struct bplustree_long_block { - void SwapEndian(); - - uint32 Magic() - { return bb_magic; } - - uint16 Level() - { return bb_level; } - - uint16 NumRecs() - { return bb_numrecs; } - - xfs_alloc_ptr_t Left() - { return bb_leftsib; } - - xfs_alloc_ptr_t Right() - { return bb_rightsib;} + TreePointer Right() + { return B_BENDIAN_TO_HOST_INT64(bb_rightsib); } uint32 bb_magic; uint16 bb_level; uint16 bb_numrecs; uint64 bb_leftsib; uint64 bb_rightsib; -} +}; -/* Array of these records in the leaf node along with above headers */ -#define XFS_ALLOC_REC_SIZE 8 -typedef struct xfs_alloc_rec { - void SwapEndian(); - - uint32 StartBlock() - { return ar_startblock; } - - uint32 BlockCount() - { return ar_blockcount; } - - uint32 ar_startblock; - uint32 ar_blockcount; - -} xfs_alloc_rec_t, xfs_alloc_key_t; +/* We have an array of extent records in + * the leaf node along with above headers + * The behaviour is very much like node directories. + */ -typedef uint32 xfs_alloc_ptr_t; - // Node pointers, AG relative block pointer - -#define ALLOC_FLAG 0x1 -#define LONG_BLOCK_FLAG 0x1 -#define SHORT_BLOCK_FLAG 0x2 - -union btree_ptr { - bplustree_long_block fLongBlock; - bplustree_short_block fShortBlock; -} +//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; +}; -union btree_key { - xfs_alloc_key_t fAlloc; -} +struct ExtentMapUnwrap { + uint64 first; + uint64 second; +}; -union btree_rec { - xfs_alloc_rec_t fAlloc; -} - - -class BPlusTree { +/* + * This class should handle B+Tree based directories + */ +class TreeDirectory { public: - uint32 BlockSize(); - int RecordSize(); - int MaxRecords(bool leaf); - int KeyLen(); + TreeDirectory(Inode* inode); + ~TreeDirectory(); + status_t InitCheck(); + status_t GetNext(char* name, size_t* length, + xfs_ino_t* ino); + status_t Lookup(const char* name, size_t length, + xfs_ino_t* id); + int EntrySize(int len) const; int BlockLen(); - int PtrLen(); - int RecordOffset(int pos); // get the pos'th record - int KeyOffset(int pos); // get the pos'th key - int PtrOffset(int pos); // get the pos'th ptr + size_t PtrSize(); + size_t KeySize(); + TreeKey GetKey(int pos); + // get the pos'th key + TreePointer* GetPtr(int pos, LongBlock* pointer); + // get the pos'th pointer + status_t GetAllExtents(); + size_t MaxRecordsPossible(size_t len); private: - Volume* fVolume; - xfs_agnumber_t fAgnumber; - btree_ptr* fRoot; - int fRecType; - int fKeyType; - int fPtrType; -} + inline status_t UnWrapExtents(ExtentMapUnwrap* extentsWrapped); + +private: + Inode* fInode; + status_t fInitStatus; + BlockInDataFork* fRoot; + ExtentMapEntry* fExtents; + uint32 fCountOfFilledExtents; + char* fSingleDirBlock; +}; #endif diff --git a/src/add-ons/kernel/file_systems/xfs/Directory.cpp b/src/add-ons/kernel/file_systems/xfs/Directory.cpp index 9e51431d8c..c1529018e6 100644 --- a/src/add-ons/kernel/file_systems/xfs/Directory.cpp +++ b/src/add-ons/kernel/file_systems/xfs/Directory.cpp @@ -13,7 +13,8 @@ DirectoryIterator::DirectoryIterator(Inode* inode) fShortDir(NULL), fExtentDir(NULL), fLeafDir(NULL), - fNodeDir(NULL) + fNodeDir(NULL), + fTreeDir(NULL) { } @@ -24,6 +25,7 @@ DirectoryIterator::~DirectoryIterator() delete fLeafDir; delete fExtentDir; delete fNodeDir; + delete fTreeDir; } @@ -75,16 +77,13 @@ DirectoryIterator::Init() * we can atleast still list the shortform directory */ - //TODO: Reading from extent based directories - if (fInode->Format() == XFS_DINODE_FMT_EXTENTS) { - TRACE("Iterator:GetNext: EXTENTS"); - return B_OK; - } - //TODO: Reading from B+Trees based directories if (fInode->Format() == XFS_DINODE_FMT_BTREE) { TRACE("Iterator:GetNext: B+TREE"); - return B_OK; + fTreeDir = new(std::nothrow) TreeDirectory(fInode); + if (fTreeDir == NULL) + return B_NO_MEMORY; + return fTreeDir->InitCheck(); } return B_BAD_VALUE; diff --git a/src/add-ons/kernel/file_systems/xfs/Directory.h b/src/add-ons/kernel/file_systems/xfs/Directory.h index 25efcea289..fcf3a44af9 100644 --- a/src/add-ons/kernel/file_systems/xfs/Directory.h +++ b/src/add-ons/kernel/file_systems/xfs/Directory.h @@ -6,6 +6,7 @@ #define _DIRECTORY_H_ +#include "BPlusTree.h" #include "Extent.h" #include "Inode.h" #include "LeafDirectory.h" @@ -38,6 +39,7 @@ private: LeafDirectory* fLeafDir; // Extent based leaf directory NodeDirectory* fNodeDir; + TreeDirectory* fTreeDir; }; diff --git a/src/add-ons/kernel/file_systems/xfs/Jamfile b/src/add-ons/kernel/file_systems/xfs/Jamfile index 2c2c74f139..54fc1dab5f 100644 --- a/src/add-ons/kernel/file_systems/xfs/Jamfile +++ b/src/add-ons/kernel/file_systems/xfs/Jamfile @@ -20,6 +20,7 @@ DEFINES += DEBUG_APP="\\\"xfs\\\"" ; UseHeaders [ FDirName $(HAIKU_TOP) src libs uuid ] : true ; local xfsSources = + BPlusTree.cpp DeviceOpener.cpp Directory.cpp Extent.cpp diff --git a/src/tests/add-ons/kernel/file_systems/xfs/xfs_shell/Jamfile b/src/tests/add-ons/kernel/file_systems/xfs/xfs_shell/Jamfile index d10cd76d20..c2eb14ac16 100644 --- a/src/tests/add-ons/kernel/file_systems/xfs/xfs_shell/Jamfile +++ b/src/tests/add-ons/kernel/file_systems/xfs/xfs_shell/Jamfile @@ -39,6 +39,7 @@ UseHeaders [ FDirName $(HAIKU_TOP) headers private ] : true ; UseHeaders [ FDirName $(HAIKU_TOP) src tools fs_shell ] ; local xfsSource = + BPlusTree.cpp DeviceOpener.cpp Directory.cpp Extent.cpp