[haiku-commits] Change in haiku[master]: xfs: B+Tree ExtentMap reading

  • From: Gerrit <review@xxxxxxxxxxxxxxxxxxx>
  • To: waddlesplash <waddlesplash@xxxxxxxxx>, haiku-commits@xxxxxxxxxxxxx
  • Date: Sun, 2 Aug 2020 07:55:12 +0000

From Shubham Bhagat <shubhambhagat111@xxxxxxxxx>:

Shubham Bhagat has uploaded this change for review. ( 
https://review.haiku-os.org/c/haiku/+/3120 ;)


Change subject: xfs: B+Tree ExtentMap reading
......................................................................

xfs: B+Tree ExtentMap reading

We can now read all the extent maps from the leaves. This will be needed
to implement the GetNext() functionality.
---
M src/add-ons/kernel/file_systems/xfs/BPlusTree.cpp
M src/add-ons/kernel/file_systems/xfs/BPlusTree.h
M src/add-ons/kernel/file_systems/xfs/Directory.cpp
M src/add-ons/kernel/file_systems/xfs/Directory.h
M src/add-ons/kernel/file_systems/xfs/Jamfile
5 files changed, 249 insertions(+), 189 deletions(-)



  git pull ssh://git.haiku-os.org:22/haiku refs/changes/20/3120/1

diff --git a/src/add-ons/kernel/file_systems/xfs/BPlusTree.cpp 
b/src/add-ons/kernel/file_systems/xfs/BPlusTree.cpp
index b14f869..b2ef364 100644
--- a/src/add-ons/kernel/file_systems/xfs/BPlusTree.cpp
+++ b/src/add-ons/kernel/file_systems/xfs/BPlusTree.cpp
@@ -7,122 +7,205 @@
 #include "BPlusTree.h"
 

-void
-bplustree_short_block::SwapEndian()
+TreeDirectory::TreeDirectory(Inode* inode)
+       :
+       fInode(inode),
+       fRoot(NULL),
+       fCurLongBlock(NULL),
+       fExtents(NULL),
+       fExtentsWrapped(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()
+status_t
+TreeDirectory::Init()
 {
-       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);
-}
+       fRoot = new(std::nothrow) BlockInDataFork;
+       if (fRoot == NULL)
+               return B_NO_MEMORY;

+       fSingleDirBlock = new(std::nothrow) char[fInode->DirBlockSize()];
+       if (fSingleDirBlock == NULL)
+               return B_NO_MEMORY;

-void
-xfs_alloc_rec::SwapEndian()
-{
-       ar_startblock = B_BENDIAN_TO_HOST_INT32(ar_startblock);
-       ar_blockcount =  B_BENDIAN_TO_HOST_INT32(ar_blockcount);
-}
+       memcpy((void*)fRoot,
+               DIR_DFORK_PTR(fInode->Buffer()), sizeof(BlockInDataFork));

-
-uint32
-BPlusTree::BlockSize()
-{
-       return fVolume.SuperBlock().BlockSize();
+       return B_OK;
 }


 int
-BPlusTree::RecordSize()
+TreeDirectory::BlockLen()
 {
-       if (fRecType == ALLOC_FLAG)
-               return XFS_ALLOC_REC_SIZE;
-
-       return B_BAD_VALUE;
+       return XFS_BTREE_LBLOCK_SIZE;
 }


-int
-BPlusTree::MaxRecords(bool leaf)
+TreeKey
+TreeDirectory::GetKey(int pos)
 {
-       int blockLen = BlockSize();
+       return BlockLen() + (pos - 1) * XFS_KEY_SIZE;
+}

-       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));
+size_t
+TreeDirectory::KeySize()
+{
+       return XFS_KEY_SIZE;
+}
+
+
+size_t
+TreeDirectory::PtrSize()
+{
+       return XFS_PTR_SIZE;
+}
+
+
+TreePointer*
+TreeDirectory::GetPtr(int pos)
+{
+       size_t availableSpace = fInode->GetVolume()->BlockSize() - BlockLen();
+       size_t maxRecords = availableSpace/(KeySize() + PtrSize());
+       size_t offsetIntoNode =
+               BlockLen() + maxRecords * KeySize() + (pos - 1) * PtrSize();
+       return (TreePointer*)(void*)((char*)fCurLongBlock + offsetIntoNode);
+}
+
+
+size_t
+TreeDirectory::MaxRecordsPossible(size_t len)
+{
+       len -= sizeof(BlockInDataFork);
+       return len/(KeySize() + PtrSize());
+}
+
+
+status_t
+TreeDirectory::GetAllExtents()
+{
+       xfs_extnum_t noOfExtents = fInode->NoOfDataExtents();
+       fExtentsWrapped = new(std::nothrow) ExtentMapUnwrap[noOfExtents];
+       if (fExtentsWrapped == 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
+               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());
+
+       char* node = new(std::nothrow) char[volume->BlockSize()];
+               // This isn't for a directory block but for one of the tree 
nodes
+       if (node == NULL)
+               return B_NO_MEMORY;
+       /*
+        * Go down the tree by taking the leftest pointer to go to the first 
leaf
+        */
+       size_t len = sizeof(node);
+       uint64 fileSystemBlockNo;
+       TRACE("levels:(%d)\n", levelsInTree);
+       TRACE("Numrecs:(%d)\n", fRoot->NumRecords());
+       while (levelsInTree > 0) {
+               fileSystemBlockNo = B_BENDIAN_TO_HOST_INT64(*ptrToNode);
+                       // The fs block that contains node at next lower level. 
Now read.
+               uint64 readPos = 
fInode->FileSystemBlockToAddr(fileSystemBlockNo);
+               if (levelsInTree == 1) {
+                       // 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 = 0;
+                       break;
                }
+               if (read_pos(volume->Device(), readPos, node, len) != len) {
+                       ERROR("Extent::FillBlockBuffer(): IO Error");
+                       return B_IO_ERROR;
+               }
+               fCurLongBlock = (LongBlock*)node;
+               ASSERT(fCurLongBlock->Magic() == XFS_BMAP_MAGIC);
+               ptrToNode = GetPtr(1);
+                       // Get's the first pointer. This points to next node.
+               levelsInTree--;
        }

-       return B_BAD_VALUE;
+       /*
+        * 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++) {
+                       fExtentsWrapped[fCountOfFilledExtents].first =
+                               *(uint64*)(leafBuffer + offset);
+                       fExtentsWrapped[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");
+                               return B_IO_ERROR;
+               }
+       }
+       TRACE("Total covered: (%d)\n", fCountOfFilledExtents);
+       return UnWrapExtents();
 }


-int
-BPlusTree::KeyLen()
+status_t
+TreeDirectory::UnWrapExtents()
 {
-       if (fKeyType == ALLOC_FLAG)
-               return XFS_ALLOC_REC_SIZE;
-       return B_BAD_VALUE;
+       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(fExtentsWrapped[i].first);
+               second = B_BENDIAN_TO_HOST_INT64(fExtentsWrapped[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);
+       }
+       delete fExtentsWrapped;
+       fExtentsWrapped = NULL;
+
+       return B_OK;
 }


-int
-BPlusTree::BlockLen()
+TreeDirectory::~TreeDirectory()
 {
-       if (fPtrType == LONG_BLOCK_FLAG)
-               return XFS_BTREE_LBLOCK_SIZE;
-       if (fPtrType == SHORT_BLOCK_FLAG)
-               return XFS_BTREE_SBLOCK_SIZE;
-       return B_BAD_VALUE;
-}
-
-
-int
-BPlusTree::PtrLen()
-{
-       if (fPtrType == LONG_BLOCK_FLAG)
-               return sizeof(uint64);
-       else
-               return sizeof(uint32);
-}
-
-
-int
-BPlusTree::RecordOffset(int pos)
-{
-       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();
-}
+}
\ No newline at end of file
diff --git a/src/add-ons/kernel/file_systems/xfs/BPlusTree.h 
b/src/add-ons/kernel/file_systems/xfs/BPlusTree.h
index 371a4f4..791e2d5 100644
--- a/src/add-ons/kernel/file_systems/xfs/BPlusTree.h
+++ b/src/add-ons/kernel/file_systems/xfs/BPlusTree.h
@@ -5,136 +5,109 @@
 #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 uint64 TreePointer;


 /*
- * Headers are the "nodes" really and are called "blocks". The records, keys
+ * 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                        Init();
+                       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); // get the 
pos'th pointer
+                       status_t                        GetAllExtents();
+                       size_t                          
MaxRecordsPossible(size_t len);
+                       status_t                        UnWrapExtents();
 private:
-                       Volume*                         fVolume;
-                       xfs_agnumber_t          fAgnumber;
-                       btree_ptr*                      fRoot;
-                       int                                     fRecType;
-                       int                                     fKeyType;
-                       int                                     fPtrType;
-}
+                       Inode*                          fInode;
+                       BlockInDataFork*        fRoot;
+                       LongBlock*                      fCurLongBlock;
+                       ExtentMapUnwrap*        fExtentsWrapped;
+                       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 6f24315..8927754 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 @@
        fShortDir(NULL),
        fExtentDir(NULL),
        fLeafDir(NULL),
-       fNodeDir(NULL)
+       fNodeDir(NULL),
+       fTreeDir(NULL)
 {
 }

@@ -24,6 +25,7 @@
        delete fLeafDir;
        delete fExtentDir;
        delete fNodeDir;
+       delete fTreeDir;
 }


@@ -75,15 +77,14 @@
         * 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");
+               fTreeDir = new(std::nothrow) TreeDirectory(fInode);
+               if (fTreeDir == NULL)
+                       return B_NO_MEMORY;
+               fTreeDir->Init();
+               fTreeDir->GetAllExtents();
                return B_OK;
        }

diff --git a/src/add-ons/kernel/file_systems/xfs/Directory.h 
b/src/add-ons/kernel/file_systems/xfs/Directory.h
index 25efcea..fcf3a44 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 @@
                        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 2c2c74f..54fc1da 100644
--- a/src/add-ons/kernel/file_systems/xfs/Jamfile
+++ b/src/add-ons/kernel/file_systems/xfs/Jamfile
@@ -20,6 +20,7 @@
 UseHeaders [ FDirName $(HAIKU_TOP) src libs uuid ] : true ;

 local xfsSources =
+       BPlusTree.cpp
        DeviceOpener.cpp
        Directory.cpp
        Extent.cpp

--
To view, visit https://review.haiku-os.org/c/haiku/+/3120
To unsubscribe, or for help writing mail filters, visit 
https://review.haiku-os.org/settings

Gerrit-Project: haiku
Gerrit-Branch: master
Gerrit-Change-Id: Ic0b79a1bf44f20b6b90c8ed93f8392647d2f7b82
Gerrit-Change-Number: 3120
Gerrit-PatchSet: 1
Gerrit-Owner: Shubham Bhagat <shubhambhagat111@xxxxxxxxx>
Gerrit-MessageType: newchange

Other related posts: