[haiku-commits] haiku: hrev51666 - src/add-ons/kernel/file_systems/btrfs

  • From: waddlesplash@xxxxxxxxx
  • To: haiku-commits@xxxxxxxxxxxxx
  • Date: Sun, 10 Dec 2017 17:05:12 +0100 (CET)

hrev51666 adds 27 changesets to branch 'master'
old head: d87218f79e132dc809e44f01be114bf279082949
new head: 99768086b1493648abee3f076683cc9fefa5923e
overview: 
http://cgit.haiku-os.org/haiku/log/?qt=range&q=99768086b149+%5Ed87218f79e13

----------------------------------------------------------------------------

e7156146138d: AVLTree: forward LeftMost and RightMost method from AVLTreeBase
  
  Signed-off-by: Augustin Cavalier <waddlesplash@xxxxxxxxx>

2ed88a489c8a: BTRFS: Fix node search slot
  
  * Not handle traversing type correctly (looks for the graph).
  * Reorder the codes because *slot is uninitialized if type is BTREE_EXACT.
  * Incorrect return type: int32 -> status_t
  
  Signed-off-by: Augustin Cavalier <waddlesplash@xxxxxxxxx>

16de9db54bf6: BTRFS: Fix mismatched type of item size (should be uint32), and 
ObjectID of first subvolume when lookup directory (described in commit bd2dab1)
  
  Signed-off-by: Augustin Cavalier <waddlesplash@xxxxxxxxx>

8160f31fc102: BTRFS: Node now holding Volume instead of cache to retrieve more 
values
  
  Signed-off-by: Augustin Cavalier <waddlesplash@xxxxxxxxx>

3216460dec54: BTRFS: Implement BTree::Path and change _Find.
  
  Remove attribute fCurrentSlot in BTree::Node as it will be handled by Path 
explicitly. BTree control Path by passing its type in
  BTree's method, Path also hold BTree type as its attribute to do some 
internal actions.
  Add constant BTREE_KEY_TYPE_ANY, find search key has this type will success 
regardless of the found key's type.
  
  Split the  the _Find function into Traverse and GetEntry. Traverse will fill 
in the Path (nodes and slots) along way its finding,
  GetEntry will get the item data, item size, key from leaf, if the slot is 
valid, that we have from Traverse. The _Find function also
  check type if is correct and then retrieve. Doing this way there will be more 
flexible, the "read" flag is not needed as we only
  need Path to manipulate tree, and it also enhance the performance at some 
points, because Path caches all the nodes from root to leaf,
  so that we don't have to block_cache_put and block_cache_get after each 
finding.
  
  Signed-off-by: Augustin Cavalier <waddlesplash@xxxxxxxxx>

bfd7a4fb4274: BTRFS: Reimplement TreeIterator, add some error checks and remove 
redundancies.
  
  Add BTree::Path as a attribute so enhance performance, so that everytime we 
iterate through items it wont search all the root to leaf
  again. The Iterator is initialized without rewinding to make more flexible.
  
  Signed-off-by: Augustin Cavalier <waddlesplash@xxxxxxxxx>

af419b0e9831: BTRFS: Implement ExtentAllocator
  
  There are 4 new classes, structs:
  * CachedExtent, is a AVLTreeNode, caches the extent locating in extent tree, 
a extent can be free, allocated, metadata or a data extent. It also hold a 
references count,
  that is incremented each time a new extent refer to it (COW) and item data, 
that is only for allocated extent (NULL for free).
  * CachedTreeExtent, is a AVLTree, cache the whole extent tree and has 
CachedExtent as its node.
  * BlockGroup represents the group of extents that represent the region for 
each type of allocated extent. For example, region for data extents, metada 
blocks. It
  responsible for inserting nodes in CachedTreeExtent.
  * And the final, ExtentAllocator it knows how to allocate/deallocate extents, 
but for now only the allocating is implemented, actually allocating and 
deallocating works
  are already implemented, they are in functions _AddFreeExtent, 
_AddAllocatedExtent in CachedTreeExtent. However the deallocating is not needed 
for now, so it will be
  finished later then.
  
  Signed-off-by: Augustin Cavalier <waddlesplash@xxxxxxxxx>

0deb03560f57: BTRFS: Fix mismatched type of index in inode_ref item.
  
  Signed-off-by: Augustin Cavalier <waddlesplash@xxxxxxxxx>

8137f447cb15: BTRFS: Fix memory leak
  
  Missing delete for some tree roots.
  
  Signed-off-by: Augustin Cavalier <waddlesplash@xxxxxxxxx>

1750cd1e9227: block_cache: Implement cache_has_block_in_transaction function 
that will check the existence of block in one specific transaction.
  
  Signed-off-by: Augustin Cavalier <waddlesplash@xxxxxxxxx>

c1320b3a3341: BTRFS: Implement a simple journaling approach, this is not 
finished and mostly satisfy the need for passing Transaction object for many 
functions.
  
  Some details about the current Journal:
  * Journal can only end transaction.
  * It holds a transaction id of fs (fCurrentGeneration) that increments each 
time a transaction starts.
  * _TransactionWritten now just printing message.
  
  Signed-off-by: Augustin Cavalier <waddlesplash@xxxxxxxxx>

4368661f03c3: BTRFS: Implement GetNewBlock() function that will find the 
logical address for allocating and convert it to physical block.
  
  Signed-off-by: Augustin Cavalier <waddlesplash@xxxxxxxxx>

27ffe0583b71: BTRFS: Implement some space relevant helpers.
  
  Signed-off-by: Augustin Cavalier <waddlesplash@xxxxxxxxx>

89484dc08d8e: BTRFS: Implement some copy relevant helpers.
  
  Copy() copys data from other node, MoveEntries() changes data on the current 
node.
  
  Signed-off-by: Augustin Cavalier <waddlesplash@xxxxxxxxx>

883b9bf29fae: BTRFS: Implement CopyOnWrite relevant functions, and BTree holds 
new attribute that record its root level.
  
  CopyOnWrite works like this:
  * Cache original node
  * Allocating new block
  * Cache new block to be writable
  * Copy original node to new node, and changing.
  Also if a node is already be COW-ed it cannot be COW-ed again, it will be 
changed in-place instead.
  
  InternalCopy does CopyOnWrite all the nodes that we don't need to change 
anything on them.
  
  Signed-off-by: Augustin Cavalier <waddlesplash@xxxxxxxxx>

2b6c2ec3905e: fs_shell: Added socket filetype.
  
  Signed-off-by: Augustin Cavalier <waddlesplash@xxxxxxxxx>

02bce792d846: BTRFS: Added function to convert standard filetypes to btrfs 
filetypes.
  
  Signed-off-by: Augustin Cavalier <waddlesplash@xxxxxxxxx>

84bc447cae63: BTRFS: Implement InsertEntries() that will insert consecutive 
items and its data.
  
  Signed-off-by: Augustin Cavalier <waddlesplash@xxxxxxxxx>

20185bb9c399: BTRFS: Implement RemoveEntries() for BTree that will remove 
consecutive items and its data.
  
  Signed-off-by: Augustin Cavalier <waddlesplash@xxxxxxxxx>

36a24fb34ef0: BTRFS: Implement Create() that allocate new Inode object.
  
  Signed-off-by: Augustin Cavalier <waddlesplash@xxxxxxxxx>

371935de1870: BTRFS: Implement Insert() in Inode that inserts inode_item.
  
  Signed-off-by: Augustin Cavalier <waddlesplash@xxxxxxxxx>

b44d924df453: BTRFS: Implement MakeReference() in Inode that will link file 
name to inode.
  
  Signed-off-by: Augustin Cavalier <waddlesplash@xxxxxxxxx>

8042a045b0af: BTRFS: Implement Remove() in Inode that removes inode_item.
  
  Signed-off-by: Augustin Cavalier <waddlesplash@xxxxxxxxx>

a9e85cb62f27: BTRFS: Implement Dereference() in Inode that remove the "name" 
and unlink it with inode.
  
  Signed-off-by: Augustin Cavalier <waddlesplash@xxxxxxxxx>

166917c9cdf7: BTRFS: Implement btrfs_create_dir that can create directories in 
most case.
  
  We need to handle a case when node is full, the solution should be split or 
push data to another node.
  
  Signed-off-by: Augustin Cavalier <waddlesplash@xxxxxxxxx>

4896a3735e1c: BTRFS: Implement btrfs_remove_dir that can remove directories in 
most case.
  
  We need to handle a case when node size is small reasonably it can be merged 
with another node or push data from other node to this node.
  
  Signed-off-by: Augustin Cavalier <waddlesplash@xxxxxxxxx>

99768086b149: BTRFS: Add author and license.
  
  Signed-off-by: Augustin Cavalier <waddlesplash@xxxxxxxxx>

                                              [ hyche <cvghy116@xxxxxxxxx> ]

----------------------------------------------------------------------------

32 files changed, 2599 insertions(+), 188 deletions(-)
headers/os/drivers/fs_cache.h                    |   1 +
headers/private/fs_shell/fssh_api_wrapper.h      |  16 +-
headers/private/fs_shell/fssh_fs_cache.h         |   2 +
headers/private/fs_shell/fssh_stat.h             |   1 +
headers/private/kernel/util/AVLTree.h            |  27 +
.../kernel/file_systems/btrfs/Attribute.cpp      |  12 +-
.../kernel/file_systems/btrfs/Attribute.h        |   3 +-
.../file_systems/btrfs/AttributeIterator.cpp     |  10 +-
.../file_systems/btrfs/AttributeIterator.h       |   1 +
src/add-ons/kernel/file_systems/btrfs/BTree.cpp  | 873 +++++++++++++++++--
src/add-ons/kernel/file_systems/btrfs/BTree.h    | 166 +++-
.../kernel/file_systems/btrfs/CachedBlock.h      |   1 +
src/add-ons/kernel/file_systems/btrfs/Chunk.cpp  |   1 +
src/add-ons/kernel/file_systems/btrfs/Chunk.h    |   1 +
.../file_systems/btrfs/DirectoryIterator.cpp     |  18 +-
.../file_systems/btrfs/DirectoryIterator.h       |   1 +
.../file_systems/btrfs/ExtentAllocator.cpp       | 698 +++++++++++++++
.../kernel/file_systems/btrfs/ExtentAllocator.h  | 157 ++++
src/add-ons/kernel/file_systems/btrfs/Inode.cpp  | 237 ++++-
src/add-ons/kernel/file_systems/btrfs/Inode.h    |  16 +
src/add-ons/kernel/file_systems/btrfs/Jamfile    |   2 +
.../kernel/file_systems/btrfs/Journal.cpp        | 169 ++++
src/add-ons/kernel/file_systems/btrfs/Journal.h  |  62 ++
src/add-ons/kernel/file_systems/btrfs/Utility.h  |  27 +
src/add-ons/kernel/file_systems/btrfs/Volume.cpp |  81 +-
src/add-ons/kernel/file_systems/btrfs/Volume.h   |  15 +
src/add-ons/kernel/file_systems/btrfs/btrfs.h    |  61 +-
.../file_systems/btrfs/kernel_interface.cpp      |  93 +-
.../file_systems/btrfs/system_dependencies.h     |   4 +
src/system/kernel/cache/block_cache.cpp          |  15 +
src/tools/btrfs_shell/Jamfile                    |   2 +
src/tools/fs_shell/block_cache.cpp               |  14 +

############################################################################

Commit:      e7156146138d6422c1d4d87d60ac526c898139d6
URL:         http://cgit.haiku-os.org/haiku/commit/?id=e7156146138d
Author:      hyche <cvghy116@xxxxxxxxx>
Date:        Sat Aug  5 13:23:52 2017 UTC
Committer:   Augustin Cavalier <waddlesplash@xxxxxxxxx>
Commit-Date: Sun Dec 10 15:56:08 2017 UTC

AVLTree: forward LeftMost and RightMost method from AVLTreeBase

Signed-off-by: Augustin Cavalier <waddlesplash@xxxxxxxxx>

----------------------------------------------------------------------------

diff --git a/headers/private/kernel/util/AVLTree.h 
b/headers/private/kernel/util/AVLTree.h
index 76d6b25..f0e27f8 100644
--- a/headers/private/kernel/util/AVLTree.h
+++ b/headers/private/kernel/util/AVLTree.h
@@ -47,6 +47,9 @@ public:
                        Value*                          Previous(Value* value) 
const;
                        Value*                          Next(Value* value) 
const;
 
+                       Value*                          LeftMost(Value* value) 
const;
+                       Value*                          RightMost(Value* value) 
const;
+
        inline  Iterator                        GetIterator();
        inline  ConstIterator           GetIterator() const;
 
@@ -256,6 +259,30 @@ AVLTree<Definition>::Next(Value* value) const
 
 
 template<typename Definition>
+inline typename AVLTree<Definition>::Value*
+AVLTree<Definition>::LeftMost(Value* value) const
+{
+       if (value == NULL)
+               return NULL;
+
+       AVLTreeNode* node = fTree.LeftMost(_GetAVLTreeNode(value));
+       return node != NULL ? _GetValue(node) : NULL;
+}
+
+
+template<typename Definition>
+inline typename AVLTree<Definition>::Value*
+AVLTree<Definition>::RightMost(Value* value) const
+{
+       if (value == NULL)
+               return NULL;
+
+       AVLTreeNode* node = fTree.RightMost(_GetAVLTreeNode(value));
+       return node != NULL ? _GetValue(node) : NULL;
+}
+
+
+template<typename Definition>
 inline typename AVLTree<Definition>::Iterator
 AVLTree<Definition>::GetIterator()
 {

############################################################################

Commit:      2ed88a489c8a06caa47b7d5f104e08a868d9ec3d
URL:         http://cgit.haiku-os.org/haiku/commit/?id=2ed88a489c8a
Author:      hyche <cvghy116@xxxxxxxxx>
Date:        Sat Aug  5 13:28:00 2017 UTC
Committer:   Augustin Cavalier <waddlesplash@xxxxxxxxx>
Commit-Date: Sun Dec 10 15:56:08 2017 UTC

BTRFS: Fix node search slot

* Not handle traversing type correctly (looks for the graph).
* Reorder the codes because *slot is uninitialized if type is BTREE_EXACT.
* Incorrect return type: int32 -> status_t

Signed-off-by: Augustin Cavalier <waddlesplash@xxxxxxxxx>

----------------------------------------------------------------------------

diff --git a/src/add-ons/kernel/file_systems/btrfs/BTree.cpp 
b/src/add-ons/kernel/file_systems/btrfs/BTree.cpp
index fec0dee..56813a0 100644
--- a/src/add-ons/kernel/file_systems/btrfs/BTree.cpp
+++ b/src/add-ons/kernel/file_systems/btrfs/BTree.cpp
@@ -90,8 +90,9 @@ BTree::Node::SetToWritable(off_t block, int32 transactionId, 
bool empty)
 }
 
 
-int32
-BTree::Node::SearchSlot(const btrfs_key& key, int* slot, btree_traversing 
type) const
+status_t
+BTree::Node::SearchSlot(const btrfs_key& key, int* slot, btree_traversing type)
+       const
 {
        //binary search for item slot in a node
        int entrySize = sizeof(btrfs_entry);
@@ -100,14 +101,13 @@ BTree::Node::SearchSlot(const btrfs_key& key, int* slot, 
btree_traversing type)
                entrySize = sizeof(btrfs_index);
        }
 
-       int low = 0;
        int high = ItemCount();
-       int mid, comp;
-       int base = sizeof(btrfs_header);
+       int low = 0, mid = 0, comp = 0;
+       uint8* base = (uint8*)fNode + sizeof(btrfs_header);
        const btrfs_key* other;
        while (low < high) {
                mid = (low + high) / 2;
-               other = (const btrfs_key*)((uint8*)fNode + base + mid * 
entrySize);
+               other = (const btrfs_key*)(base + mid * entrySize);
                comp = key.Compare(*other);
                if (comp < 0)
                        high = mid;
@@ -119,15 +119,25 @@ BTree::Node::SearchSlot(const btrfs_key& key, int* slot, 
btree_traversing type)
                }
        }
 
-       TRACE("SearchSlot() found slot %" B_PRId32 " comp %" B_PRId32 "\n",
-               *slot, comp);
-       if (type == BTREE_BACKWARD)
-               *slot = low - 1;
-       else if (type == BTREE_FORWARD)
-               *slot = low;
+       // |--item1--|--item2--|--item3--|--etc--|
+       //     m-1        m        m+1
+       //           k                          : comp < 0
+       //                     k                : comp > 0
+       if (type == BTREE_BACKWARD) {
+               *slot = mid - 1;
+               if (comp > 0)
+                       *slot = mid;
+       } else if (type == BTREE_FORWARD) {
+               *slot = mid;
+               if (comp > 0)
+                       *slot = mid + 1;
+       }
 
-       if (*slot < 0 || type == BTREE_EXACT)
+       if (type == BTREE_EXACT || *slot < 0)
                return B_ENTRY_NOT_FOUND;
+
+       TRACE("SearchSlot() found slot %" B_PRId32 " comp %" B_PRId32 "\n",
+               *slot, comp);
        return B_OK;
 }
 
diff --git a/src/add-ons/kernel/file_systems/btrfs/BTree.h 
b/src/add-ons/kernel/file_systems/btrfs/BTree.h
index eebd132..2fa8837 100644
--- a/src/add-ons/kernel/file_systems/btrfs/BTree.h
+++ b/src/add-ons/kernel/file_systems/btrfs/BTree.h
@@ -119,8 +119,8 @@ public:
                off_t   BlockNum() const { return fBlockNumber;}
                bool    IsWritable() const { return fWritable; }
 
-               int32   SearchSlot(const btrfs_key& key, int* slot,
-                                       btree_traversing type) const;
+               status_t        SearchSlot(const btrfs_key& key, int* slot,
+                                               btree_traversing type) const;
                private:
                Node(const Node&);
                Node& operator=(const Node&);

############################################################################

Commit:      16de9db54bf69fe8d02b228ff706026828f9cb7a
URL:         http://cgit.haiku-os.org/haiku/commit/?id=16de9db54bf6
Author:      hyche <cvghy116@xxxxxxxxx>
Date:        Sat Aug 12 09:50:07 2017 UTC
Committer:   Augustin Cavalier <waddlesplash@xxxxxxxxx>
Commit-Date: Sun Dec 10 15:56:09 2017 UTC

BTRFS: Fix mismatched type of item size (should be uint32), and ObjectID of 
first subvolume when lookup directory (described in commit bd2dab1)

Signed-off-by: Augustin Cavalier <waddlesplash@xxxxxxxxx>

----------------------------------------------------------------------------

diff --git a/src/add-ons/kernel/file_systems/btrfs/Attribute.cpp 
b/src/add-ons/kernel/file_systems/btrfs/Attribute.cpp
index ecb25ac..ddda28d 100644
--- a/src/add-ons/kernel/file_systems/btrfs/Attribute.cpp
+++ b/src/add-ons/kernel/file_systems/btrfs/Attribute.cpp
@@ -88,7 +88,7 @@ Attribute::Stat(struct stat& stat)
 
        size_t nameLength = strlen(fName);
        btrfs_dir_entry* entries;
-       size_t length;
+       uint32 length;
        status_t status = _Lookup(fName, nameLength, &entries, &length);
        if (status < B_OK)
                return status;
@@ -116,7 +116,7 @@ Attribute::Read(attr_cookie* cookie, off_t pos, uint8* 
buffer, size_t* _length)
 
        size_t nameLength = strlen(fName);
        btrfs_dir_entry* entries;
-       size_t length;
+       uint32 length;
        status_t status = _Lookup(fName, nameLength, &entries, &length);
        if (status < B_OK)
                return status;
@@ -144,7 +144,7 @@ Attribute::Read(attr_cookie* cookie, off_t pos, uint8* 
buffer, size_t* _length)
 
 status_t
 Attribute::_Lookup(const char* name, size_t nameLength,
-       btrfs_dir_entry** _entries, size_t* _length)
+       btrfs_dir_entry** _entries, uint32* _length)
 {
        uint32 hash = calculate_crc((uint32)~1, (uint8*)name, nameLength);
        struct btrfs_key key;
@@ -153,7 +153,7 @@ Attribute::_Lookup(const char* name, size_t nameLength,
        key.SetOffset(hash);
 
        btrfs_dir_entry* entries;
-       size_t length;
+       uint32 length;
        status_t status = fInode->GetVolume()->FSTree()->FindExact(key,
                (void**)&entries, &length);
        if (status != B_OK) {
diff --git a/src/add-ons/kernel/file_systems/btrfs/Attribute.h 
b/src/add-ons/kernel/file_systems/btrfs/Attribute.h
index 7236673..ebbb3e9 100644
--- a/src/add-ons/kernel/file_systems/btrfs/Attribute.h
+++ b/src/add-ons/kernel/file_systems/btrfs/Attribute.h
@@ -39,7 +39,7 @@ public:
 private:
                        status_t                        _Lookup(const char* 
name, size_t nameLength,
                                                                        
btrfs_dir_entry** entries = NULL,
-                                                                       size_t* 
length = NULL);
+                                                                       uint32* 
length = NULL);
                        status_t                        
_FindEntry(btrfs_dir_entry* entries,
                                                                        size_t 
length, const char* name,
                                                                        size_t 
nameLength,
diff --git a/src/add-ons/kernel/file_systems/btrfs/AttributeIterator.cpp 
b/src/add-ons/kernel/file_systems/btrfs/AttributeIterator.cpp
index 3b67e83..f453a11 100644
--- a/src/add-ons/kernel/file_systems/btrfs/AttributeIterator.cpp
+++ b/src/add-ons/kernel/file_systems/btrfs/AttributeIterator.cpp
@@ -48,7 +48,7 @@ AttributeIterator::GetNext(char* name, size_t* _nameLength)
 {
        btrfs_key key;
        btrfs_dir_entry* entries;
-       size_t entries_length;
+       uint32 entries_length;
        status_t status = fIterator->GetPreviousEntry(key, (void**)&entries,
                &entries_length);
        if (status != B_OK)
diff --git a/src/add-ons/kernel/file_systems/btrfs/BTree.cpp 
b/src/add-ons/kernel/file_systems/btrfs/BTree.cpp
index 56813a0..726aa84 100644
--- a/src/add-ons/kernel/file_systems/btrfs/BTree.cpp
+++ b/src/add-ons/kernel/file_systems/btrfs/BTree.cpp
@@ -212,7 +212,7 @@ btrfs_key::Compare(const btrfs_key& key) const
        It can also return other errors to indicate that something went wrong.
 */
 status_t
-BTree::_Find(btrfs_key& key, void** _value, size_t* _size,
+BTree::_Find(btrfs_key& key, void** _value, uint32* _size,
        bool read, btree_traversing type)
 {
        TRACE("Find() objectid %" B_PRId64 " type %d offset %" B_PRId64 " \n",
@@ -268,21 +268,21 @@ BTree::_Find(btrfs_key& key, void** _value, size_t* _size,
 
 
 status_t
-BTree::FindNext(btrfs_key& key, void** _value, size_t* _size, bool read)
+BTree::FindNext(btrfs_key& key, void** _value, uint32* _size, bool read)
 {
        return _Find(key, _value, _size, read, BTREE_FORWARD);
 }
 
 
 status_t
-BTree::FindPrevious(btrfs_key& key, void** _value, size_t* _size, bool read)
+BTree::FindPrevious(btrfs_key& key, void** _value, uint32* _size, bool read)
 {
        return _Find(key, _value, _size, read, BTREE_BACKWARD);
 }
 
 
 status_t
-BTree::FindExact(btrfs_key& key, void** _value, size_t* _size, bool read)
+BTree::FindExact(btrfs_key& key, void** _value, uint32* _size, bool read)
 {
        return _Find(key, _value, _size, read, BTREE_EXACT);
 }
@@ -345,7 +345,7 @@ TreeIterator::~TreeIterator()
 */
 status_t
 TreeIterator::Traverse(btree_traversing direction, btrfs_key& key,
-       void** value, size_t* size)
+       void** value, uint32* size)
 {
        if (fTree == NULL)
                return B_INTERRUPTED;
diff --git a/src/add-ons/kernel/file_systems/btrfs/BTree.h 
b/src/add-ons/kernel/file_systems/btrfs/BTree.h
index 2fa8837..5a40fea 100644
--- a/src/add-ons/kernel/file_systems/btrfs/BTree.h
+++ b/src/add-ons/kernel/file_systems/btrfs/BTree.h
@@ -3,8 +3,8 @@
  * Copyright 2001-2010, Axel Dörfler, axeld@xxxxxxxxxxxxxxxx.
  * This file may be used under the terms of the MIT License.
  */
-#ifndef B_PLUS_TREE_H
-#define B_PLUS_TREE_H
+#ifndef B_TREE_H
+#define B_TREE_H
 
 
 #include "btrfs.h"
@@ -50,11 +50,11 @@ public:
                                                                        
fsblock_t rootBlock);
                                                                ~BTree();
                        status_t                        FindExact(btrfs_key& 
key, void** value,
-                                                                       size_t* 
size = NULL, bool read = true);
+                                                                       uint32* 
size = NULL, bool read = true);
                        status_t                        FindNext(btrfs_key& 
key, void** value,
-                                                                       size_t* 
size = NULL, bool read = true);
+                                                                       uint32* 
size = NULL, bool read = true);
                        status_t                        FindPrevious(btrfs_key& 
key, void** value,
-                                                                       size_t* 
size = NULL, bool read = true);
+                                                                       uint32* 
size = NULL, bool read = true);
 
                        Volume*                         SystemVolume() const { 
return fVolume; }
 
@@ -67,7 +67,7 @@ private:
                                                                BTree& 
operator=(const BTree& other);
                                                                        // no 
implementation
 
-                       status_t                        _Find(btrfs_key& key, 
void** value, size_t* size,
+                       status_t                        _Find(btrfs_key& key, 
void** value, uint32* size,
                                                                        bool 
read, btree_traversing type);
                        void                            
_AddIterator(TreeIterator* iterator);
                        void                            
_RemoveIterator(TreeIterator* iterator);
@@ -153,14 +153,14 @@ public:
 
                        status_t                        
Traverse(btree_traversing direction,
                                                                        
btrfs_key& key, void** value,
-                                                                       size_t* 
size = NULL);
+                                                                       uint32* 
size = NULL);
                        status_t                        Find(btrfs_key& key);
 
                        status_t                        Rewind();
                        status_t                        GetNextEntry(btrfs_key& 
key, void** value,
-                                                                       size_t* 
size = NULL);
+                                                                       uint32* 
size = NULL);
                        status_t                        
GetPreviousEntry(btrfs_key& key, void** value,
-                                                                       size_t* 
size = NULL);
+                                                                       uint32* 
size = NULL);
 
                        BTree*                  Tree() const { return fTree; }
 
@@ -188,7 +188,7 @@ TreeIterator::Rewind()
 
 
 inline status_t
-TreeIterator::GetNextEntry(btrfs_key& key, void** value, size_t* size)
+TreeIterator::GetNextEntry(btrfs_key& key, void** value, uint32* size)
 {
        return Traverse(BTREE_FORWARD, key, value, size);
 }
@@ -196,10 +196,10 @@ TreeIterator::GetNextEntry(btrfs_key& key, void** value, 
size_t* size)
 
 inline status_t
 TreeIterator::GetPreviousEntry(btrfs_key& key, void** value,
-       size_t* size)
+       uint32* size)
 {
        return Traverse(BTREE_BACKWARD, key, value, size);
 }
 
 
-#endif // B_PLUS_TREE_H
+#endif // B_TREE_H
diff --git a/src/add-ons/kernel/file_systems/btrfs/DirectoryIterator.cpp 
b/src/add-ons/kernel/file_systems/btrfs/DirectoryIterator.cpp
index b19dabf..4f9a1b7 100644
--- a/src/add-ons/kernel/file_systems/btrfs/DirectoryIterator.cpp
+++ b/src/add-ons/kernel/file_systems/btrfs/DirectoryIterator.cpp
@@ -33,7 +33,8 @@ DirectoryIterator::DirectoryIterator(Inode* inode)
 
 DirectoryIterator::~DirectoryIterator()
 {
-       delete fIterator;
+       if (fIterator != NULL)
+               delete fIterator;
 }
 
 
@@ -61,7 +62,7 @@ DirectoryIterator::GetNext(char* name, size_t* _nameLength, 
ino_t* _id)
                *_nameLength = 1;
                strlcpy(name, ".", *_nameLength + 1);
                fOffset = 2;
-               if (fInode->ID() == BTRFS_OBJECT_ID_CHUNK_TREE) {
+               if (fInode->ID() == BTRFS_FIRST_SUBVOLUME) {
                        *_id = fInode->ID();
                        return B_OK;
                }
@@ -70,7 +71,7 @@ DirectoryIterator::GetNext(char* name, size_t* _nameLength, 
ino_t* _id)
 
        btrfs_key key;
        btrfs_dir_entry* entries;
-       size_t entries_length;
+       uint32 entries_length;
        status_t status = fIterator->GetNextEntry(key, (void**)&entries,
                &entries_length);
        if (status != B_OK)
@@ -110,7 +111,7 @@ DirectoryIterator::Lookup(const char* name, size_t 
nameLength, ino_t* _id)
 {
        if (strcmp(name, ".") == 0 || strcmp(name, "..") == 0) {
                if (strcmp(name, ".") == 0
-                       || fInode->ID() == BTRFS_OBJECT_ID_CHUNK_TREE) {
+                       || fInode->ID() == BTRFS_FIRST_SUBVOLUME) {
                        *_id = fInode->ID();
                        return B_OK;
                }
@@ -124,7 +125,7 @@ DirectoryIterator::Lookup(const char* name, size_t 
nameLength, ino_t* _id)
        key.SetOffset(hash);
 
        btrfs_dir_entry* entries;
-       size_t length;
+       uint32 length;
        status_t status = fInode->GetVolume()->FSTree()->FindExact(key,
                (void**)&entries, &length);
        if (status != B_OK) {
diff --git a/src/add-ons/kernel/file_systems/btrfs/Inode.cpp 
b/src/add-ons/kernel/file_systems/btrfs/Inode.cpp
index ef66d34..a2e7bb8 100644
--- a/src/add-ons/kernel/file_systems/btrfs/Inode.cpp
+++ b/src/add-ons/kernel/file_systems/btrfs/Inode.cpp
@@ -167,7 +167,7 @@ Inode::ReadAt(off_t pos, uint8* buffer, size_t* _length)
        search_key.SetObjectID(fID);
        search_key.SetOffset(pos + 1);
 
-       size_t item_size;
+       uint32 item_size;
        btrfs_extent_data* extent_data;
        status_t status = fVolume->FSTree()->FindPrevious(search_key,
                (void**)&extent_data, &item_size);
@@ -222,7 +222,7 @@ Inode::ReadAt(off_t pos, uint8* buffer, size_t* _length)
 
                int status;
                ssize_t offset = 0;
-               size_t inline_size = item_size - 13;
+               uint32 inline_size = item_size - 13;
                bool headerRead = false;
 
                TRACE("Inode::ReadAt(%" B_PRIdINO ") diff %" B_PRIdOFF " size %"
diff --git a/src/add-ons/kernel/file_systems/btrfs/Volume.cpp 
b/src/add-ons/kernel/file_systems/btrfs/Volume.cpp
index 561a102..159f67e 100644
--- a/src/add-ons/kernel/file_systems/btrfs/Volume.cpp
+++ b/src/add-ons/kernel/file_systems/btrfs/Volume.cpp
@@ -486,7 +486,7 @@ Volume::FindBlock(off_t logical, off_t& physical)
        search_key.SetType(BTRFS_KEY_TYPE_CHUNK_ITEM);
        search_key.SetObjectID(BTRFS_OBJECT_ID_FIRST_CHUNK_TREE);
        btrfs_chunk* chunk;
-       size_t chunk_length;
+       uint32 chunk_length;
        status_t status = fChunkTree->FindPrevious(search_key, (void**)&chunk,
                &chunk_length);
        if (status != B_OK)

############################################################################

Commit:      8160f31fc102e46f9c3387b708a51b8807c90b72
URL:         http://cgit.haiku-os.org/haiku/commit/?id=8160f31fc102
Author:      hyche <cvghy116@xxxxxxxxx>
Date:        Wed Aug 16 13:56:09 2017 UTC
Committer:   Augustin Cavalier <waddlesplash@xxxxxxxxx>
Commit-Date: Sun Dec 10 15:56:10 2017 UTC

BTRFS: Node now holding Volume instead of cache to retrieve more values

Signed-off-by: Augustin Cavalier <waddlesplash@xxxxxxxxx>

----------------------------------------------------------------------------

diff --git a/src/add-ons/kernel/file_systems/btrfs/BTree.cpp 
b/src/add-ons/kernel/file_systems/btrfs/BTree.cpp
index 726aa84..4ca1ef1 100644
--- a/src/add-ons/kernel/file_systems/btrfs/BTree.cpp
+++ b/src/add-ons/kernel/file_systems/btrfs/BTree.cpp
@@ -20,10 +20,10 @@
 #      define ERROR(x...) dprintf("\33[34mbtrfs:\33[0m " x)
 
 
-BTree::Node::Node(void* cache)
+BTree::Node::Node(Volume* volume)
        :
        fNode(NULL),
-       fCache(cache),
+       fVolume(volume),
        fBlockNumber(0),
        fCurrentSlot(0),
        fWritable(false)
@@ -31,10 +31,10 @@ BTree::Node::Node(void* cache)
 }
 
 
-BTree::Node::Node(void* cache, off_t block)
+BTree::Node::Node(Volume* volume, off_t block)
        :
        fNode(NULL),
-       fCache(cache),
+       fVolume(volume),
        fBlockNumber(0),
        fCurrentSlot(0),
        fWritable(false)
@@ -59,7 +59,7 @@ void
 BTree::Node::Unset()
 {
        if (fNode != NULL) {
-               block_cache_put(fCache, fBlockNumber);
+               block_cache_put(fVolume->BlockCache(), fBlockNumber);
                fNode = NULL;
        }
 }
@@ -70,7 +70,7 @@ BTree::Node::SetTo(off_t block)
 {
        Unset();
        fBlockNumber = block;
-       fNode = (btrfs_stream*)block_cache_get(fCache, block);
+       fNode = (btrfs_stream*)block_cache_get(fVolume->BlockCache(), block);
 }
 
 
@@ -81,11 +81,11 @@ BTree::Node::SetToWritable(off_t block, int32 
transactionId, bool empty)
        fBlockNumber = block;
        fWritable = true;
        if (empty) {
-               fNode = (btrfs_stream*)block_cache_get_empty(fCache, block,
-                       transactionId);
+               fNode = 
(btrfs_stream*)block_cache_get_empty(fVolume->BlockCache(),
+                       block, transactionId);
        } else {
-               fNode = (btrfs_stream*)block_cache_get_writable(fCache, block,
-                       transactionId);
+               fNode = 
(btrfs_stream*)block_cache_get_writable(fVolume->BlockCache(),
+                       block, transactionId);
        }
 }
 
@@ -217,7 +217,7 @@ BTree::_Find(btrfs_key& key, void** _value, uint32* _size,
 {
        TRACE("Find() objectid %" B_PRId64 " type %d offset %" B_PRId64 " \n",
                key.ObjectID(), key.Type(), key.Offset());
-       BTree::Node node(fVolume->BlockCache(), fRootBlock);
+       BTree::Node node(fVolume, fRootBlock);
        int slot, ret;
        fsblock_t physicalBlock;
 
diff --git a/src/add-ons/kernel/file_systems/btrfs/BTree.h 
b/src/add-ons/kernel/file_systems/btrfs/BTree.h
index 5a40fea..bb034dd 100644
--- a/src/add-ons/kernel/file_systems/btrfs/BTree.h
+++ b/src/add-ons/kernel/file_systems/btrfs/BTree.h
@@ -83,8 +83,8 @@ private:
 public:
        class Node {
        public:
-               Node(void* cache);
-               Node(void* cache, off_t block);
+               Node(Volume* volume);
+               Node(Volume* volume, off_t block);
                ~Node();
 
                        // just return from Header
@@ -127,7 +127,7 @@ public:
                        //no implementation
 
                btrfs_stream*           fNode;
-               void*                           fCache;
+               Volume*                         fVolume;
                off_t                           fBlockNumber;
                uint32                          fCurrentSlot;
                bool                            fWritable;

############################################################################

Commit:      3216460dec5447c463e617b5dd537ac496dc0370
URL:         http://cgit.haiku-os.org/haiku/commit/?id=3216460dec54
Author:      hyche <cvghy116@xxxxxxxxx>
Date:        Sat Aug 12 17:30:06 2017 UTC
Committer:   Augustin Cavalier <waddlesplash@xxxxxxxxx>
Commit-Date: Sun Dec 10 15:56:11 2017 UTC

BTRFS: Implement BTree::Path and change _Find.

Remove attribute fCurrentSlot in BTree::Node as it will be handled by Path 
explicitly. BTree control Path by passing its type in
BTree's method, Path also hold BTree type as its attribute to do some internal 
actions.
Add constant BTREE_KEY_TYPE_ANY, find search key has this type will success 
regardless of the found key's type.

Split the  the _Find function into Traverse and GetEntry. Traverse will fill in 
the Path (nodes and slots) along way its finding,
GetEntry will get the item data, item size, key from leaf, if the slot is 
valid, that we have from Traverse. The _Find function also
check type if is correct and then retrieve. Doing this way there will be more 
flexible, the "read" flag is not needed as we only
need Path to manipulate tree, and it also enhance the performance at some 
points, because Path caches all the nodes from root to leaf,
so that we don't have to block_cache_put and block_cache_get after each finding.

Signed-off-by: Augustin Cavalier <waddlesplash@xxxxxxxxx>

----------------------------------------------------------------------------

diff --git a/src/add-ons/kernel/file_systems/btrfs/Attribute.cpp 
b/src/add-ons/kernel/file_systems/btrfs/Attribute.cpp
index ddda28d..1c0b286 100644
--- a/src/add-ons/kernel/file_systems/btrfs/Attribute.cpp
+++ b/src/add-ons/kernel/file_systems/btrfs/Attribute.cpp
@@ -151,10 +151,11 @@ Attribute::_Lookup(const char* name, size_t nameLength,
        key.SetType(BTRFS_KEY_TYPE_XATTR_ITEM);
        key.SetObjectID(fInode->ID());
        key.SetOffset(hash);
+       BTree::Path path(fInode->GetVolume()->FSTree());
 
        btrfs_dir_entry* entries;
        uint32 length;
-       status_t status = fInode->GetVolume()->FSTree()->FindExact(key,
+       status_t status = fInode->GetVolume()->FSTree()->FindExact(&path, key,
                (void**)&entries, &length);
        if (status != B_OK) {
                TRACE("AttributeIterator::Lookup(): Couldn't find entry with 
hash %"
diff --git a/src/add-ons/kernel/file_systems/btrfs/BTree.cpp 
b/src/add-ons/kernel/file_systems/btrfs/BTree.cpp
index 4ca1ef1..ce87f5a 100644
--- a/src/add-ons/kernel/file_systems/btrfs/BTree.cpp
+++ b/src/add-ons/kernel/file_systems/btrfs/BTree.cpp
@@ -25,7 +25,6 @@ BTree::Node::Node(Volume* volume)
        fNode(NULL),
        fVolume(volume),
        fBlockNumber(0),
-       fCurrentSlot(0),
        fWritable(false)
 {
 }
@@ -36,7 +35,6 @@ BTree::Node::Node(Volume* volume, off_t block)
        fNode(NULL),
        fVolume(volume),
        fBlockNumber(0),
-       fCurrentSlot(0),
        fWritable(false)
 {
        SetTo(block);
@@ -142,7 +140,109 @@ BTree::Node::SearchSlot(const btrfs_key& key, int* slot, 
btree_traversing type)
 }
 
 
-//-pragma mark
+//     #pragma mark - BTree::Path implementation
+
+
+BTree::Path::Path(BTree* tree)
+       :
+       fTree(tree)
+{
+       for (int i = 0; i < BTRFS_MAX_TREE_DEPTH; ++i) {
+               fNodes[i] = NULL;
+               fSlots[i] = 0;
+       }
+}
+
+
+BTree::Path::~Path()
+{
+       for (int i = 0; i < BTRFS_MAX_TREE_DEPTH; ++i) {
+               delete fNodes[i];
+               fNodes[i] = NULL;
+               fSlots[i] = 0;
+       }
+}
+
+
+BTree::Node*
+BTree::Path::GetNode(int level, int* _slot) const
+{
+       if (_slot != NULL)
+               *_slot = fSlots[level];
+       return fNodes[level];
+}
+
+
+BTree::Node*
+BTree::Path::SetNode(off_t block, int slot)
+{
+       Node node(fTree->SystemVolume(), block);
+       return SetNode(&node, slot);
+}
+
+
+BTree::Node*
+BTree::Path::SetNode(const Node* node, int slot)
+{
+       uint8 level = node->Level();
+       if (fNodes[level] == NULL) {
+               fNodes[level] = new Node(fTree->SystemVolume(), 
node->BlockNum());
+               if (fNodes[level] == NULL)
+                       return NULL;
+       } else
+               fNodes[level]->SetTo(node->BlockNum());
+
+       if (slot == -1)
+               fSlots[level] = fNodes[level]->ItemCount() - 1;
+       else
+               fSlots[level] = slot;
+       return fNodes[level];
+}
+
+
+int
+BTree::Path::Move(int level, int step)
+{
+       fSlots[level] += step;
+       if (fSlots[level] < 0)
+               return -1;
+       if (fSlots[level] >= fNodes[level]->ItemCount())
+               return 1;
+       return 0;
+}
+
+
+status_t
+BTree::Path::GetEntry(int slot, btrfs_key* _key, void** _value, uint32* _size,
+       uint32* _offset)
+{
+       BTree::Node* leaf = fNodes[0];
+       if (slot < 0 || slot >= leaf->ItemCount())
+               return B_ENTRY_NOT_FOUND;
+
+       if (_key != NULL)
+               *_key = leaf->Item(slot)->key;
+
+       uint32 itemSize = leaf->Item(slot)->Size();
+       if (_value != NULL) {
+               *_value = malloc(itemSize);
+               if (*_value == NULL)
+                       return B_NO_MEMORY;
+
+               memcpy(*_value, leaf->ItemData(slot), itemSize);
+       }
+
+       if (_size != NULL)
+               *_size = itemSize;
+
+       if (_offset != NULL)
+               *_offset = leaf->Item(slot)->Offset();
+
+       return B_OK;
+}
+
+
+//     #pragma mark - BTree implementation
 
 
 BTree::BTree(Volume* volume)
@@ -206,85 +306,180 @@ btrfs_key::Compare(const btrfs_key& key) const
 }
 
 
-/*!    Searches the key in the tree, and stores the allocated found item in
-       _value, if successful.
-       Returns B_OK when the key could be found, B_ENTRY_NOT_FOUND if not.
-       It can also return other errors to indicate that something went wrong.
-*/
+/* Traverse from root to fill in the path along way its finding.
+ * Return current slot at leaf if successful.
+ */
 status_t
-BTree::_Find(btrfs_key& key, void** _value, uint32* _size,
-       bool read, btree_traversing type)
+BTree::Traverse(btree_traversing type, Path* path, const btrfs_key& key)
+       const
 {
-       TRACE("Find() objectid %" B_PRId64 " type %d offset %" B_PRId64 " \n",
-               key.ObjectID(), key.Type(), key.Offset());
-       BTree::Node node(fVolume, fRootBlock);
-       int slot, ret;
-       fsblock_t physicalBlock;
+       TRACE("BTree::Traverse() objectid %" B_PRId64 " type %d offset %"
+               B_PRId64 " \n", key.ObjectID(), key.Type(), key.Offset());
+       fsblock_t physicalBlock = fRootBlock;
+       Node node(fVolume, physicalBlock);
+       int slot;
+       status_t status = B_OK;
 
        while (node.Level() != 0) {
-               TRACE("Find() level %d\n", node.Level());
-               ret = node.SearchSlot(key, &slot, BTREE_BACKWARD);
-               if (ret != B_OK)
-                       return ret;
-               TRACE("Find() getting index %" B_PRIu32 "\n", slot);
-
-               if (fVolume->FindBlock(node.Index(slot)->LogicalAddress(), 
physicalBlock)
-                       != B_OK) {
-                       ERROR("Find() unmapped block %" B_PRId64 "\n",
+               TRACE("BTree::Traverse() level %d count %d\n", node.Level(),
+                       node.ItemCount());
+               status = node.SearchSlot(key, &slot, BTREE_BACKWARD);
+               if (status != B_OK)
+                       return status;
+               if (path->SetNode(&node, slot) == NULL)
+                       return B_NO_MEMORY;
+
+               TRACE("BTree::Traverse() getting index %" B_PRIu32 "\n", slot);
+
+               status = fVolume->FindBlock(node.Index(slot)->LogicalAddress(),
+                               physicalBlock);
+               if (status != B_OK) {
+                       ERROR("BTree::Traverse() unmapped block %" B_PRId64 
"\n",
                                node.Index(slot)->LogicalAddress());
-                       return B_ERROR;
+                       return status;
                }
                node.SetTo(physicalBlock);
        }
 
-       TRACE("Find() dump count %" B_PRId32 "\n", node.ItemCount());
-       ret = node.SearchSlot(key, &slot, type);
-       if ((slot >= node.ItemCount() || node.Item(slot)->key.Type() != 
key.Type())
-                       && read == true
-               || ret != B_OK) {
-               TRACE("Find() not found %" B_PRId64 " %" B_PRId64 "\n", 
key.Offset(),
-                       key.ObjectID());
+       TRACE("BTree::Traverse() dump count %" B_PRId32 "\n", node.ItemCount());
+       status = node.SearchSlot(key, &slot, type);
+       if (status != B_OK)
+               return status;
+       if (path->SetNode(&node, slot) == NULL)
+               return B_NO_MEMORY;
+
+       TRACE("BTree::Traverse() found %" B_PRIu32 " %" B_PRIu32 "\n",
+               node.Item(slot)->Offset(), node.Item(slot)->Size());
+       return slot;
+}
+
+
+/*!    Searches the key in the tree, and stores the allocated found item in
+       _value, if successful.
+       Returns B_OK when the key could be found, B_ENTRY_NOT_FOUND if not.
+       It can also return other errors to indicate that something went wrong.
+*/
+status_t
+BTree::_Find(Path* path, btrfs_key& wanted, void** _value, uint32* _size,
+       uint32* _offset, btree_traversing type) const
+{
+       status_t status = Traverse(type, path, wanted);
+       if (status < B_OK)
+               return status;
+
+       btrfs_key found;
+       status = path->GetCurrentEntry(&found, _value, _size, _offset);
+       if (status != B_OK)
+               return status;
+
+       if (found.Type() != wanted.Type() && wanted.Type() != 
BTRFS_KEY_TYPE_ANY)
                return B_ENTRY_NOT_FOUND;
-       }
 
-       if (read == true) {
-               TRACE("Find() found %" B_PRIu32 " %" B_PRIu32 "\n",
-                       node.Item(slot)->Offset(), node.Item(slot)->Size());
-
-               if (_value != NULL) {
-                       *_value = malloc(node.Item(slot)->Size());
-                       memcpy(*_value, node.ItemData(slot),
-                               node.Item(slot)->Size());
-                       key.SetOffset(node.Item(slot)->key.Offset());
-                       key.SetObjectID(node.Item(slot)->key.ObjectID());
-                       if (_size != NULL)
-                               *_size = node.Item(slot)->Size();
-               }
-       } else {
-               *_value = (void*)&slot;
-       }
+       wanted = found;
        return B_OK;
 }
 
 
 status_t
-BTree::FindNext(btrfs_key& key, void** _value, uint32* _size, bool read)
+BTree::FindNext(Path* path, btrfs_key& key, void** _value, uint32* _size,
+       uint32* _offset) const
 {
-       return _Find(key, _value, _size, read, BTREE_FORWARD);
+       return _Find(path, key, _value, _size, _offset, BTREE_FORWARD);
 }
 
 
 status_t
-BTree::FindPrevious(btrfs_key& key, void** _value, uint32* _size, bool read)
+BTree::FindPrevious(Path* path, btrfs_key& key, void** _value, uint32* _size,
+       uint32* _offset) const
 {
-       return _Find(key, _value, _size, read, BTREE_BACKWARD);
+       return _Find(path, key, _value, _size, _offset, BTREE_BACKWARD);
 }
 
 
 status_t
-BTree::FindExact(btrfs_key& key, void** _value, uint32* _size, bool read)
+BTree::FindExact(Path* path, btrfs_key& key, void** _value, uint32* _size,
+       uint32* _offset) const
 {
-       return _Find(key, _value, _size, read, BTREE_EXACT);
+       return _Find(path, key, _value, _size, _offset, BTREE_EXACT);
+}
+
+
+status_t
+BTree::PreviousLeaf(Path* path) const
+{
+       // TODO: use Traverse() ???
+       int level = 0;
+       int slot;
+       Node* node = NULL;
+       // iterate to the root until satisfy the condition
+       while (true) {
+               node = path->GetNode(level, &slot);
+               if (node == NULL || slot != 0)
+                       break;
+               level++;
+       }
+
+       // the current leaf is already the left most leaf or
+       // path was not initialized
+       if (node == NULL)
+               return B_ENTRY_NOT_FOUND;
+
+       path->Move(level, BTREE_BACKWARD);
+       fsblock_t physicalBlock;
+       // change all nodes below this level and slot to the ending
+       do {
+               status_t status = fVolume->FindBlock(
+                       node->Index(slot)->LogicalAddress(), physicalBlock);
+               if (status != B_OK)
+                       return status;
+
+               node = path->SetNode(physicalBlock, -1);
+               if (node == NULL)
+                       return B_NO_MEMORY;
+               slot = node->ItemCount() - 1;
+               level--;
+       } while(level != 0);
+
+       return B_OK;
+}
+
+
+status_t
+BTree::NextLeaf(Path* path) const
+{
+       int level = 0;
+       int slot;
+       Node* node = NULL;
+       // iterate to the root until satisfy the condition
+       while (true) {
+               node = path->GetNode(level, &slot);
+               if (node == NULL || slot < node->ItemCount() - 1)
+                       break;
+               level++;
+       }
+
+       // the current leaf is already the right most leaf or
+       // path was not initialized
+       if (node == NULL)
+               return B_ENTRY_NOT_FOUND;
+
+       path->Move(level, BTREE_FORWARD);
+       fsblock_t physicalBlock;
+       // change all nodes below this level and slot to the beginning
+       do {
+               status_t status = fVolume->FindBlock(
+                       node->Index(slot)->LogicalAddress(), physicalBlock);
+               if (status != B_OK)
+                       return status;
+
+               node = path->SetNode(physicalBlock, 0);
+               if (node == NULL)
+                       return B_NO_MEMORY;
+               slot = 0;
+               level--;
+       } while(level != 0);
+
+       return B_OK;
 }
 
 
@@ -351,8 +546,8 @@ TreeIterator::Traverse(btree_traversing direction, 
btrfs_key& key,
                return B_INTERRUPTED;
 
        fCurrentKey.SetOffset(fCurrentKey.Offset() + direction);
-       status_t status = fTree->_Find(fCurrentKey, value, size,
-               true, direction);
+       BTree::Path path(fTree);
+       status_t status = fTree->_Find(&path, fCurrentKey, value, size, 
direction);
        if (status != B_OK) {
                TRACE("TreeIterator::Traverse() Find failed\n");
                return B_ENTRY_NOT_FOUND;
diff --git a/src/add-ons/kernel/file_systems/btrfs/BTree.h 
b/src/add-ons/kernel/file_systems/btrfs/BTree.h
index bb034dd..30afcaf 100644
--- a/src/add-ons/kernel/file_systems/btrfs/BTree.h
+++ b/src/add-ons/kernel/file_systems/btrfs/BTree.h
@@ -43,21 +43,33 @@ struct node_and_key {
 
 class BTree {
 public:
+       class Path;
+
+public:
                                                                BTree(Volume* 
volume);
                                                                BTree(Volume* 
volume,
                                                                        
btrfs_stream* stream);
                                                                BTree(Volume* 
volume,
                                                                        
fsblock_t rootBlock);
                                                                ~BTree();
-                       status_t                        FindExact(btrfs_key& 
key, void** value,
-                                                                       uint32* 
size = NULL, bool read = true);
-                       status_t                        FindNext(btrfs_key& 
key, void** value,
-                                                                       uint32* 
size = NULL, bool read = true);
-                       status_t                        FindPrevious(btrfs_key& 
key, void** value,
-                                                                       uint32* 
size = NULL, bool read = true);
 
-                       Volume*                         SystemVolume() const { 
return fVolume; }
+                       status_t                        FindExact(Path* path, 
btrfs_key& key,
+                                                                       void** 
_value, uint32* _size = NULL,
+                                                                       uint32* 
_offset = NULL) const;
+                       status_t                        FindNext(Path* path, 
btrfs_key& key,
+                                                                       void** 
_value, uint32* _size = NULL,
+                                                                       uint32* 
_offset = NULL) const;
+                       status_t                        FindPrevious(Path* 
path, btrfs_key& key,
+                                                                       void** 
_value, uint32* _size = NULL,
+                                                                       uint32* 
_offset = NULL) const;
+
+                       status_t                        
Traverse(btree_traversing type, Path* path,
+                                                                       const 
btrfs_key& key) const;
+
+                       status_t                        PreviousLeaf(Path* 
path) const;
+                       status_t                        NextLeaf(Path* path) 
const;
 
+                       Volume*                         SystemVolume() const { 
return fVolume; }
                        status_t                        SetRoot(off_t logical, 
fsblock_t* block);
                        fsblock_t                       RootBlock() const { 
return fRootBlock; }
                        off_t                           LogicalRoot() const { 
return fLogicalRoot; }
@@ -67,8 +79,10 @@ private:
                                                                BTree& 
operator=(const BTree& other);
                                                                        // no 
implementation
 
-                       status_t                        _Find(btrfs_key& key, 
void** value, uint32* size,
-                                                                       bool 
read, btree_traversing type);
+                       status_t                        _Find(Path* path, 
btrfs_key& key,
+                                                                       void** 
_value, uint32* _size,
+                                                                       uint32* 
_offset, btree_traversing type)
+                                                                       const;
                        void                            
_AddIterator(TreeIterator* iterator);
                        void                            
_RemoveIterator(TreeIterator* iterator);
 private:
@@ -113,8 +127,7 @@ public:
                void    Unset();
 
                void    SetTo(off_t block);
-               void    SetToWritable(off_t block,
-                               int32 transactionId, bool empty);
+               void    SetToWritable(off_t block, int32 transactionId, bool 
empty);
 
                off_t   BlockNum() const { return fBlockNumber;}
                bool    IsWritable() const { return fWritable; }
@@ -129,18 +142,33 @@ public:
                btrfs_stream*           fNode;
                Volume*                         fVolume;
                off_t                           fBlockNumber;
-               uint32                          fCurrentSlot;
                bool                            fWritable;
        };
 
 
        class Path {
        public:
-               Path();
+               Path(BTree* tree);
+               ~Path();
+
+               Node*           GetNode(int level, int* _slot = NULL) const;
+               Node*           SetNode(off_t block, int slot);
+               Node*           SetNode(const Node* node, int slot);
+               status_t        GetCurrentEntry(btrfs_key* _key, void** _value,
+                                               uint32* _size = NULL, uint32* 
_offset = NULL);
+               status_t        GetEntry(int slot, btrfs_key* _key, void** 
_value,
+                                               uint32* _size = NULL, uint32* 
_offset = NULL);
+
+               int                     Move(int level, int step);
+
+               BTree*          Tree() const { return fTree; }
        private:
                Path(const Path&);
                Path operator=(const Path&);
-               Node*   nodes[BTRFS_MAX_TREE_DEPTH];
+       private:
+               Node*   fNodes[BTRFS_MAX_TREE_DEPTH];
+               int             fSlots[BTRFS_MAX_TREE_DEPTH];
+               BTree*  fTree;
        };
 
 };     // class BTree
@@ -176,6 +204,17 @@ private:
 };
 
 
+//     #pragma mark - BTree::Path inline functions
+
+
+inline status_t
+BTree::Path::GetCurrentEntry(btrfs_key* _key, void** _value, uint32* _size,
+       uint32* _offset)
+{
+       return GetEntry(fSlots[0], _key, _value, _size, _offset);
+}
+
+
 //     #pragma mark - TreeIterator inline functions
 
 
diff --git a/src/add-ons/kernel/file_systems/btrfs/DirectoryIterator.cpp 
b/src/add-ons/kernel/file_systems/btrfs/DirectoryIterator.cpp
index 4f9a1b7..ccfd1b2 100644
--- a/src/add-ons/kernel/file_systems/btrfs/DirectoryIterator.cpp
+++ b/src/add-ons/kernel/file_systems/btrfs/DirectoryIterator.cpp
@@ -123,10 +123,11 @@ DirectoryIterator::Lookup(const char* name, size_t 
nameLength, ino_t* _id)
        key.SetType(BTRFS_KEY_TYPE_DIR_ITEM);
        key.SetObjectID(fInode->ID());
        key.SetOffset(hash);
+       BTree::Path path(fInode->GetVolume()->FSTree());
 
        btrfs_dir_entry* entries;
        uint32 length;
-       status_t status = fInode->GetVolume()->FSTree()->FindExact(key,
+       status_t status = fInode->GetVolume()->FSTree()->FindExact(&path, key,
                (void**)&entries, &length);
        if (status != B_OK) {
                TRACE("DirectoryIterator::Lookup(): Couldn't find entry with 
hash %" B_PRIu32
diff --git a/src/add-ons/kernel/file_systems/btrfs/Inode.cpp 
b/src/add-ons/kernel/file_systems/btrfs/Inode.cpp
index a2e7bb8..173fe19 100644
--- a/src/add-ons/kernel/file_systems/btrfs/Inode.cpp
+++ b/src/add-ons/kernel/file_systems/btrfs/Inode.cpp
@@ -78,9 +78,11 @@ Inode::UpdateNodeFromDisk()
        search_key.SetType(BTRFS_KEY_TYPE_INODE_ITEM);
        search_key.SetObjectID(fID);
        search_key.SetOffset(0);
+       BTree::Path path(fVolume->FSTree());
 
        btrfs_inode* node;
-       if (fVolume->FSTree()->FindExact(search_key, (void**)&node) != B_OK) {
+       if (fVolume->FSTree()->FindExact(&path, search_key, (void**)&node)
+               != B_OK) {
                ERROR("Inode::UpdateNodeFromDisk(): Couldn't find inode %"
                        B_PRIdINO "\n", fID);
                return B_ENTRY_NOT_FOUND;
@@ -111,9 +113,10 @@ Inode::FindBlock(off_t pos, off_t& physical, off_t* 
_length)
        search_key.SetType(BTRFS_KEY_TYPE_EXTENT_DATA);
        search_key.SetObjectID(fID);
        search_key.SetOffset(pos + 1);
+       BTree::Path path(fVolume->FSTree());
 
        btrfs_extent_data* extent_data;
-       status_t status = fVolume->FSTree()->FindPrevious(search_key,
+       status_t status = fVolume->FSTree()->FindPrevious(&path, search_key,
                (void**)&extent_data);
        if (status != B_OK) {
                ERROR("Inode::FindBlock(): Couldn't find extent_data 0x%" 
B_PRIx32
@@ -166,10 +169,11 @@ Inode::ReadAt(off_t pos, uint8* buffer, size_t* _length)
        search_key.SetType(BTRFS_KEY_TYPE_EXTENT_DATA);
        search_key.SetObjectID(fID);
        search_key.SetOffset(pos + 1);
+       BTree::Path path(fVolume->FSTree());
 
        uint32 item_size;
        btrfs_extent_data* extent_data;
-       status_t status = fVolume->FSTree()->FindPrevious(search_key,
+       status_t status = fVolume->FSTree()->FindPrevious(&path, search_key,
                (void**)&extent_data, &item_size);
        if (status != B_OK) {
                ERROR("Inode::FindBlock(): Couldn't find extent_data 0x%" 
B_PRIx32
@@ -292,9 +296,10 @@ Inode::FindParent(ino_t* id)
        search_key.SetType(BTRFS_KEY_TYPE_INODE_REF);
        search_key.SetObjectID(fID);
        search_key.SetOffset(-1);
+       BTree::Path path(fVolume->FSTree());
 
        void* node_ref;
-       if (fVolume->FSTree()->FindPrevious(search_key, &node_ref) != B_OK) {
+       if (fVolume->FSTree()->FindPrevious(&path, search_key, &node_ref) != 
B_OK) {
                ERROR("Inode::FindParent(): Couldn't find inode for %" 
B_PRIdINO "\n",
                        fID);
                return B_ERROR;
diff --git a/src/add-ons/kernel/file_systems/btrfs/Volume.cpp 
b/src/add-ons/kernel/file_systems/btrfs/Volume.cpp
index 159f67e..dc2fffe 100644
--- a/src/add-ons/kernel/file_systems/btrfs/Volume.cpp
+++ b/src/add-ons/kernel/file_systems/btrfs/Volume.cpp
@@ -317,15 +317,18 @@ Volume::Mount(const char* deviceName, uint32 flags)
        TRACE("Volume::Mount() root: %" B_PRIu64 " (physical block %" B_PRIu64 
")\n",
                fSuperBlock.Root(), fRootTree->RootBlock());
 
+       BTree::Path path(fRootTree);
+
        TRACE("Volume::Mount(): Searching extent root\n");
        btrfs_key search_key;
        search_key.SetOffset(0);
        search_key.SetType(BTRFS_KEY_TYPE_ROOT_ITEM);
        search_key.SetObjectID(BTRFS_OBJECT_ID_EXTENT_TREE);
        btrfs_root* root;
-       if (fRootTree->FindExact(search_key, (void**)&root) != B_OK) {
+       status = fRootTree->FindExact(&path, search_key, (void**)&root);
+       if (status != B_OK) {
                ERROR("Volume::Mount(): Couldn't find extent root\n");
-               return B_ERROR;
+               return status;
        }
        TRACE("Volume::Mount(): Found extent root: %" B_PRIu64 "\n",
                root->LogicalAddress());
@@ -338,9 +341,10 @@ Volume::Mount(const char* deviceName, uint32 flags)
        TRACE("Volume::Mount(): Searching fs root\n");
        search_key.SetOffset(0);
        search_key.SetObjectID(BTRFS_OBJECT_ID_FS_TREE);
-       if (fRootTree->FindExact(search_key, (void**)&root) != B_OK) {
+       status = fRootTree->FindExact(&path, search_key, (void**)&root);
+       if (status != B_OK) {
                ERROR("Volume::Mount(): Couldn't find fs root\n");
-               return B_ERROR;
+               return status;
        }
        TRACE("Volume::Mount(): Found fs root: %" B_PRIu64 "\n",
                root->LogicalAddress());
@@ -353,9 +357,10 @@ Volume::Mount(const char* deviceName, uint32 flags)
        TRACE("Volume::Mount(): Searching dev root\n");
        search_key.SetOffset(0);
        search_key.SetObjectID(BTRFS_OBJECT_ID_DEV_TREE);
-       if (fRootTree->FindExact(search_key, (void**)&root) != B_OK) {
+       status = fRootTree->FindExact(&path, search_key, (void**)&root);
+       if (status != B_OK) {
                ERROR("Volume::Mount(): Couldn't find dev root\n");
-               return B_ERROR;
+               return status;
        }
        TRACE("Volume::Mount(): Found dev root: %" B_PRIu64 "\n",
                root->LogicalAddress());
@@ -368,9 +373,10 @@ Volume::Mount(const char* deviceName, uint32 flags)
        TRACE("Volume::Mount(): Searching checksum root\n");
        search_key.SetOffset(0);
        search_key.SetObjectID(BTRFS_OBJECT_ID_CHECKSUM_TREE);
-       if (fRootTree->FindExact(search_key, (void**)&root) != B_OK) {
+       status = fRootTree->FindExact(&path, search_key, (void**)&root);
+       if (status != B_OK) {
                ERROR("Volume::Mount(): Couldn't find checksum root\n");
-               return B_ERROR;
+               return status;
        }
        TRACE("Volume::Mount(): Found checksum root: %" B_PRIu64 "\n",
                root->LogicalAddress());
@@ -484,11 +490,11 @@ Volume::FindBlock(off_t logical, off_t& physical)
        btrfs_key search_key;
        search_key.SetOffset(logical);
        search_key.SetType(BTRFS_KEY_TYPE_CHUNK_ITEM);
-       search_key.SetObjectID(BTRFS_OBJECT_ID_FIRST_CHUNK_TREE);
+       search_key.SetObjectID(BTRFS_OBJECT_ID_FIRST_CHUNK_TREE);
        btrfs_chunk* chunk;
-       uint32 chunk_length;
-       status_t status = fChunkTree->FindPrevious(search_key, (void**)&chunk,
-               &chunk_length);
+       BTree::Path path(fChunkTree);
+       status_t status = fChunkTree->FindPrevious(&path, search_key,
+               (void**)&chunk);
        if (status != B_OK)
                return status;
 
diff --git a/src/add-ons/kernel/file_systems/btrfs/btrfs.h 
b/src/add-ons/kernel/file_systems/btrfs/btrfs.h
index 54e4634..d2f4518 100644
--- a/src/add-ons/kernel/file_systems/btrfs/btrfs.h
+++ b/src/add-ons/kernel/file_systems/btrfs/btrfs.h
@@ -427,6 +427,7 @@ struct btrfs_extent_data_ref {
 #define BTRFS_OBJECT_ID_CHECKSUM_TREE          7
 #define BTRFS_OBJECT_ID_FIRST_CHUNK_TREE       256
 
+#define BTRFS_KEY_TYPE_ANY                                     0
 #define BTRFS_KEY_TYPE_INODE_ITEM                      1
 #define BTRFS_KEY_TYPE_INODE_REF                       12
 #define BTRFS_KEY_TYPE_XATTR_ITEM                      24

############################################################################

Commit:      bfd7a4fb427485418bc5f2edec48201fd94a1625
URL:         http://cgit.haiku-os.org/haiku/commit/?id=bfd7a4fb4274
Author:      hyche <cvghy116@xxxxxxxxx>
Date:        Sat Aug 12 21:29:18 2017 UTC
Committer:   Augustin Cavalier <waddlesplash@xxxxxxxxx>
Commit-Date: Sun Dec 10 15:56:11 2017 UTC

BTRFS: Reimplement TreeIterator, add some error checks and remove redundancies.

Add BTree::Path as a attribute so enhance performance, so that everytime we 
iterate through items it wont search all the root to leaf
again. The Iterator is initialized without rewinding to make more flexible.

Signed-off-by: Augustin Cavalier <waddlesplash@xxxxxxxxx>

----------------------------------------------------------------------------

diff --git a/src/add-ons/kernel/file_systems/btrfs/AttributeIterator.cpp 
b/src/add-ons/kernel/file_systems/btrfs/AttributeIterator.cpp
index f453a11..b9dfc91 100644
--- a/src/add-ons/kernel/file_systems/btrfs/AttributeIterator.cpp
+++ b/src/add-ons/kernel/file_systems/btrfs/AttributeIterator.cpp
@@ -22,9 +22,10 @@ AttributeIterator::AttributeIterator(Inode* inode)
        fInode(inode),
        fIterator(NULL)
 {
-       struct btrfs_key key;
+       btrfs_key key;
        key.SetType(BTRFS_KEY_TYPE_XATTR_ITEM);
        key.SetObjectID(inode->ID());
+       key.SetOffset(BTREE_BEGIN);
        fIterator = new(std::nothrow) TreeIterator(inode->GetVolume()->FSTree(),
                key);
 }
@@ -33,6 +34,7 @@ AttributeIterator::AttributeIterator(Inode* inode)
 AttributeIterator::~AttributeIterator()
 {
        delete fIterator;
+       fIterator = NULL;
 }
 
 
@@ -46,10 +48,9 @@ AttributeIterator::InitCheck()
 status_t
 AttributeIterator::GetNext(char* name, size_t* _nameLength)
 {
-       btrfs_key key;
        btrfs_dir_entry* entries;
        uint32 entries_length;
-       status_t status = fIterator->GetPreviousEntry(key, (void**)&entries,
+       status_t status = fIterator->GetPreviousEntry((void**)&entries,
                &entries_length);
        if (status != B_OK)
                return status;
diff --git a/src/add-ons/kernel/file_systems/btrfs/BTree.cpp 
b/src/add-ons/kernel/file_systems/btrfs/BTree.cpp
index ce87f5a..bf93bf3 100644
--- a/src/add-ons/kernel/file_systems/btrfs/BTree.cpp
+++ b/src/add-ons/kernel/file_systems/btrfs/BTree.cpp
@@ -519,13 +519,16 @@ BTree::_RemoveIterator(TreeIterator* iterator)
 //     #pragma mark -
 
 
-TreeIterator::TreeIterator(BTree* tree, btrfs_key& key)
+TreeIterator::TreeIterator(BTree* tree, const btrfs_key& key)
        :
        fTree(tree),
-       fCurrentKey(key)
+       fKey(key),
+       fIteratorStatus(B_NO_INIT)
 {
-       Rewind();
        tree->_AddIterator(this);
+       fPath = new(std::nothrow) BTree::Path(tree);
+       if (fPath == NULL)
+               fIteratorStatus = B_NO_MEMORY;
 }
 
 
@@ -533,26 +536,72 @@ TreeIterator::~TreeIterator()
 {
        if (fTree)
                fTree->_RemoveIterator(this);
+
+       delete fPath;
+       fPath = NULL;
+}
+
+
+void
+TreeIterator::Rewind(bool inverse)
+{
+       if (inverse)
+               fKey.SetOffset(BTREE_END);
+       else
+               fKey.SetOffset(BTREE_BEGIN);
+       fIteratorStatus = B_NO_INIT;
 }
 
 
 /*!    Iterates through the tree in the specified direction.
 */
 status_t
-TreeIterator::Traverse(btree_traversing direction, btrfs_key& key,
-       void** value, uint32* size)
+TreeIterator::_Traverse(btree_traversing direction)
 {
-       if (fTree == NULL)
-               return B_INTERRUPTED;
+       status_t status = fTree->Traverse(direction, fPath, fKey);
+       if (status < B_OK) {
+               ERROR("TreeIterator::Traverse() Find failed\n");
+               return status;
+       }
 
-       fCurrentKey.SetOffset(fCurrentKey.Offset() + direction);
-       BTree::Path path(fTree);
-       status_t status = fTree->_Find(&path, fCurrentKey, value, size, 
direction);
-       if (status != B_OK) {
-               TRACE("TreeIterator::Traverse() Find failed\n");
-               return B_ENTRY_NOT_FOUND;
+       return (fIteratorStatus = B_OK);
+}
+
+
+// Like GetEntry in BTree::Path but here we check the type and moving.
+status_t
+TreeIterator::_GetEntry(btree_traversing type, void** _value, uint32* _size,
+       uint32* _offset)
+{
+       status_t status;
+       if (fIteratorStatus == B_NO_INIT) {
+               status = _Traverse(type);
+               if (status != B_OK)
+                       return status;
+               type = BTREE_EXACT;
        }
 
+       if (fIteratorStatus != B_OK)
+               return fIteratorStatus;
+
+       int move = fPath->Move(0, type);
+       if (move > 0)
+               status = fTree->NextLeaf(fPath);
+       else if (move < 0)
+               status = fTree->PreviousLeaf(fPath);
+       if (status != B_OK)
+               return status;
+
+       btrfs_key found;
+       status = fPath->GetCurrentEntry(&found, _value, _size, _offset);
+       if (status != B_OK)
+               return status;
+
+       fKey.SetObjectID(found.ObjectID());
+       fKey.SetOffset(found.Offset());
+       if (fKey.Type() != found.Type() && fKey.Type() != BTRFS_KEY_TYPE_ANY)
+               return B_ENTRY_NOT_FOUND;
+
        return B_OK;
 }
 
@@ -560,11 +609,13 @@ TreeIterator::Traverse(btree_traversing direction, 
btrfs_key& key,
 /*!    just sets the current key in the iterator.
 */
 status_t
-TreeIterator::Find(btrfs_key& key)
+TreeIterator::Find(const btrfs_key& key)
 {
-       if (fTree == NULL)
-               return B_INTERRUPTED;
-       fCurrentKey = key;
+       if (fIteratorStatus == B_INTERRUPTED)
+               return fIteratorStatus;
+
+       fKey = key;
+       fIteratorStatus = B_NO_INIT;
        return B_OK;
 }
 
@@ -573,4 +624,5 @@ void
 TreeIterator::Stop()
 {
        fTree = NULL;
+       fIteratorStatus = B_INTERRUPTED;
 }
diff --git a/src/add-ons/kernel/file_systems/btrfs/BTree.h 
b/src/add-ons/kernel/file_systems/btrfs/BTree.h
index 30afcaf..d44a401 100644
--- a/src/add-ons/kernel/file_systems/btrfs/BTree.h
+++ b/src/add-ons/kernel/file_systems/btrfs/BTree.h
@@ -176,31 +176,37 @@ public:
 
 class TreeIterator : public SinglyLinkedListLinkImpl<TreeIterator> {
 public:
-                                                               
TreeIterator(BTree* tree, btrfs_key& key);
+                                                               
TreeIterator(BTree* tree, const btrfs_key& key);
                                                                ~TreeIterator();
 
-                       status_t                        
Traverse(btree_traversing direction,
-                                                                       
btrfs_key& key, void** value,
-                                                                       uint32* 
size = NULL);
-                       status_t                        Find(btrfs_key& key);
+                       void                            Rewind(bool inverse = 
false);
+                       status_t                        Find(const btrfs_key& 
key);
+                       status_t                        GetNextEntry(void** 
_value,
+                                                                       uint32* 
_size = NULL,
+                                                                       uint32* 
_offset = NULL);
+                       status_t                        GetPreviousEntry(void** 
_value,
+                                                                       uint32* 
_size = NULL,
+                                                                       uint32* 
_offset = NULL);
 
-                       status_t                        Rewind();
-                       status_t                        GetNextEntry(btrfs_key& 
key, void** value,
-                                                                       uint32* 
size = NULL);
-                       status_t                        
GetPreviousEntry(btrfs_key& key, void** value,
-                                                                       uint32* 
size = NULL);
-
-                       BTree*                  Tree() const { return fTree; }
+                       BTree*                          Tree() const { return 
fTree; }
+                       btrfs_key                       Key() const { return 
fKey; }
 
 private:
                        friend class BTree;
 
+                       status_t                        
_Traverse(btree_traversing direction);
+                       status_t                        _Find(btree_traversing 
type, btrfs_key& key,
+                                                                       void** 
_value);
+                       status_t                        
_GetEntry(btree_traversing type, void** _value,
+                                                                       uint32* 
_size, uint32* _offset);
                        // called by BTree
                        void                            Stop();
 
 private:
                        BTree*                  fTree;
-                       btrfs_key       fCurrentKey;
+                       BTree::Path*    fPath;
+                       btrfs_key               fKey;
+                       status_t                fIteratorStatus;
 };
 
 
@@ -219,25 +225,16 @@ BTree::Path::GetCurrentEntry(btrfs_key* _key, void** 
_value, uint32* _size,
 
 
 inline status_t
-TreeIterator::Rewind()
-{
-       fCurrentKey.SetOffset(BTREE_BEGIN);
-       return B_OK;
-}
-
-
-inline status_t
-TreeIterator::GetNextEntry(btrfs_key& key, void** value, uint32* size)
+TreeIterator::GetNextEntry(void** _value, uint32* _size, uint32* _offset)
 {
-       return Traverse(BTREE_FORWARD, key, value, size);
+       return _GetEntry(BTREE_FORWARD, _value, _size, _offset);
 }
 
 
 inline status_t
-TreeIterator::GetPreviousEntry(btrfs_key& key, void** value,
-       uint32* size)
+TreeIterator::GetPreviousEntry(void** _value, uint32* _size, uint32* _offset)
 {
-       return Traverse(BTREE_BACKWARD, key, value, size);
+       return _GetEntry(BTREE_BACKWARD, _value, _size, _offset);
 }
 
 
diff --git a/src/add-ons/kernel/file_systems/btrfs/DirectoryIterator.cpp 
b/src/add-ons/kernel/file_systems/btrfs/DirectoryIterator.cpp
index ccfd1b2..0be81a4 100644
--- a/src/add-ons/kernel/file_systems/btrfs/DirectoryIterator.cpp
+++ b/src/add-ons/kernel/file_systems/btrfs/DirectoryIterator.cpp
@@ -26,6 +26,7 @@ DirectoryIterator::DirectoryIterator(Inode* inode)
        btrfs_key key;
        key.SetType(BTRFS_KEY_TYPE_DIR_INDEX);
        key.SetObjectID(inode->ID());
+       key.SetOffset(BTREE_BEGIN);
        fIterator = new(std::nothrow) TreeIterator(inode->GetVolume()->FSTree(),
                key);
 }
@@ -33,8 +34,8 @@ DirectoryIterator::DirectoryIterator(Inode* inode)
 
 DirectoryIterator::~DirectoryIterator()
 {
-       if (fIterator != NULL)
-               delete fIterator;
+       delete fIterator;
+       fIterator = NULL;
 }
 
 
@@ -69,11 +70,9 @@ DirectoryIterator::GetNext(char* name, size_t* _nameLength, 
ino_t* _id)
                return fInode->FindParent(_id);
        }
 
-       btrfs_key key;
        btrfs_dir_entry* entries;
        uint32 entries_length;
-       status_t status = fIterator->GetNextEntry(key, (void**)&entries,
-               &entries_length);
+       status_t status = fIterator->GetNextEntry((void**)&entries, 
&entries_length);
        if (status != B_OK)
                return status;
 

############################################################################

Commit:      af419b0e9831ff414b8dc53eba9f7d00e7963711
URL:         http://cgit.haiku-os.org/haiku/commit/?id=af419b0e9831
Author:      hyche <cvghy116@xxxxxxxxx>
Date:        Sun Aug 13 09:42:23 2017 UTC
Committer:   Augustin Cavalier <waddlesplash@xxxxxxxxx>
Commit-Date: Sun Dec 10 15:56:12 2017 UTC

BTRFS: Implement ExtentAllocator

There are 4 new classes, structs:
* CachedExtent, is a AVLTreeNode, caches the extent locating in extent tree, a 
extent can be free, allocated, metadata or a data extent. It also hold a 
references count,
that is incremented each time a new extent refer to it (COW) and item data, 
that is only for allocated extent (NULL for free).
* CachedTreeExtent, is a AVLTree, cache the whole extent tree and has 
CachedExtent as its node.
* BlockGroup represents the group of extents that represent the region for each 
type of allocated extent. For example, region for data extents, metada blocks. 
It
responsible for inserting nodes in CachedTreeExtent.
* And the final, ExtentAllocator it knows how to allocate/deallocate extents, 
but for now only the allocating is implemented, actually allocating and 
deallocating works
are already implemented, they are in functions _AddFreeExtent, 
_AddAllocatedExtent in CachedTreeExtent. However the deallocating is not needed 
for now, so it will be
finished later then.

Signed-off-by: Augustin Cavalier <waddlesplash@xxxxxxxxx>

----------------------------------------------------------------------------

diff --git a/src/add-ons/kernel/file_systems/btrfs/ExtentAllocator.cpp 
b/src/add-ons/kernel/file_systems/btrfs/ExtentAllocator.cpp
new file mode 100644
index 0000000..bb57dc2
--- /dev/null
+++ b/src/add-ons/kernel/file_systems/btrfs/ExtentAllocator.cpp
@@ -0,0 +1,692 @@
+#include "ExtentAllocator.h"
+#include "Chunk.h"
+
+
+CachedExtent*
+CachedExtent::Create(uint64 offset, uint64 length, uint64 flags)
+{
+       CachedExtent* self = new(std::nothrow) CachedExtent();
+       if (self == NULL)
+               return NULL;
+
+       self->offset = offset;
+       self->length = length;
+       self->refCount = 0;
+       if ((flags & BTRFS_EXTENT_FLAG_ALLOCATED) != 0)
+               self->refCount = 1;
+       self->flags = flags;
+       self->item = NULL;
+       return self;
+}
+
+
+void
+CachedExtent::Delete()
+{
+       if (item != NULL)
+               free(item);
+       item = NULL;
+       delete this;
+}
+
+
+bool
+CachedExtent::IsAllocated() const
+{
+       return (flags & BTRFS_EXTENT_FLAG_ALLOCATED) != 0;
+}
+
+
+bool
+CachedExtent::IsData() const
+{
+       return (flags & BTRFS_EXTENT_FLAG_DATA) != 0;
+}
+
+
+void
+CachedExtent::Info() const
+{
+       const char* extentType = "allocated tree block";
+       if (IsAllocated() == false && IsData() == false)
+               extentType = "free tree block";
+       else if (IsAllocated() == false && IsData() == true)
+               extentType = "free data extent";
+       else if (IsAllocated() == true && IsData() == true)
+               extentType = "allocated data extent";
+
+       TRACE("%s at %" B_PRIu64 " length %" B_PRIu64 " refCount %i\n",
+               extentType, offset, length, refCount);
+}
+
+
+// ExtentTree Implementation
+
+
+CachedExtentTree::CachedExtentTree(const TreeDefinition& definition)
+       :
+       AVLTree<TreeDefinition>(definition)
+{
+}
+
+
+CachedExtentTree::~CachedExtentTree()
+{
+       Delete();
+}
+
+
+/* Find extent that cover or after "offset" and has length >= "size"
+ * it must also satisfy the condition "type".
+ */
+status_t
+CachedExtentTree::FindNext(CachedExtent** chosen, uint64 offset, uint64 size,
+       uint64 type)
+{
+       CachedExtent* found = Find(offset);
+       while (found != NULL && (found->flags != type || found->length < size))
+               found = Next(found);
+
+       if (found == NULL)
+               return B_ENTRY_NOT_FOUND;
+       *chosen = found;
+       return B_OK;
+}
+
+
+/* this will insert all free extents that are holes,
+ * created by existed allocated extents in the tree
+ * from lowerBound to upperBound
+ */
+status_t
+CachedExtentTree::FillFreeExtents(uint64 lowerBound, uint64 upperBound)
+{
+       CachedExtent* node = FindClosest(lowerBound, false);
+       CachedExtent* hole = NULL;
+       status_t status = B_OK;
+       uint64 flags = node->flags & (~BTRFS_EXTENT_FLAG_ALLOCATED);
+       if (lowerBound < node->offset) {
+               hole = CachedExtent::Create(lowerBound, node->offset - 
lowerBound,
+                       flags);
+               status = _AddFreeExtent(hole);
+               if (status != B_OK)
+                       return status;
+       }
+
+       CachedExtent* next = NULL;
+       while ((next = Next(node)) != NULL && next->End() < upperBound) {
+               if (node->End() == next->offset) {
+                       node = next;
+                       continue;
+               }
+
+               hole = CachedExtent::Create(node->End(), next->offset - 
node->End(),
+                       flags);
+               status = _AddFreeExtent(hole);
+               if (status != B_OK)
+                       return status;
+               node = next;
+       }
+
+       // final node should be a right most node
+       if (upperBound > node->End()) {
+               hole = CachedExtent::Create(node->End(), upperBound - 
node->End(),
+                       flags);
+               status = _AddFreeExtent(hole);
+       }
+
+       return status;
+}
+
+
+void
+CachedExtentTree::_RemoveExtent(CachedExtent* node)
+{
+       node->refCount--;
+       if (node->refCount <= 0) {
+               Remove(node);
+               node->Delete();
+       }
+}
+
+
+status_t
+CachedExtentTree::_AddAllocatedExtent(CachedExtent* node)
+{
+       if (node == NULL || node->IsAllocated() == false)
+               return B_BAD_VALUE;
+
+       CachedExtent* found = Find(node->offset);
+       if (found == NULL) {
+               Insert(node);
+               return B_OK;
+       }
+
+       if ((found->IsData() && !node->IsData())
+               || (!found->IsData() && node->IsData())) {
+               // this shouldn't happen as because different type has
+               // its different region for locating.
+               node->Delete();
+               return B_BAD_VALUE;
+       }
+
+       if (found->IsAllocated() == false) {
+               // split free extents (found)
+               if (node->End() > found->End()) {
+                       // TODO: when to handle this ?
+                       node->Delete();
+                       return B_BAD_VALUE;
+               }
+
+               // |----- found ------|
+               //    |-- node ---|
+               uint64 diff = node->offset - found->offset;
+               found->offset += diff + node->length;
+               found->length -= diff + node->length;
+               // diff < 0 couldn't happen because of the Compare function
+               if (diff > 0) {
+                       CachedExtent* leftEmpty = CachedExtent::Create(
+                               node->offset - diff, diff, found->flags);
+                       _AddFreeExtent(leftEmpty);
+               }
+
+               if (found->length == 0) {
+                       // free-extent that has no space
+                       _RemoveExtent(found);
+               }
+
+               Insert(node);
+               return B_OK;
+       }
+
+       if (found->length == node->length) {
+               found->refCount++;
+       } else {
+               // TODO: What should we do in this case ?
+               return B_BAD_VALUE;
+       }
+       node->Delete();
+
+       return B_OK;
+}
+
+
+status_t
+CachedExtentTree::_AddFreeExtent(CachedExtent* node)
+{
+       if (node == NULL || node->IsAllocated() == true)
+               return B_BAD_VALUE;
+
+       CachedExtent* found = Find(node->offset);
+       if (found == NULL) {
+               Insert(node);
+               _CombineFreeExtent(node);
+               return B_OK;
+       }
+
+       if ((found->IsData() && !node->IsData())
+               || (!found->IsData() && node->IsData())) {
+               // this shouldn't happen as because different type has
+               // its different region for locating.
+               node->Delete();
+               return B_BAD_VALUE;
+       }
+
+       if (found->End() < node->End()) {
+               // |---- found-----|
+               //      |--- node ------|
+               CachedExtent* rightEmpty = CachedExtent::Create(found->End(),
+                       node->End() - found->End(), node->flags);
+               _AddFreeExtent(rightEmpty);
+               node->length -= node->End() - found->End();
+       }
+
+       if (found->IsAllocated() == true) {
+               // free part of the allocated extents(found)
+               // |----- found ------|
+               //    |-- node ---|
+               uint64 diff = node->offset - found->offset;
+               found->offset += diff + node->length;
+               found->length -= diff + node->length;
+               // diff < 0 couldn't happen because of the Compare function
+               if (diff > 0){
+                       CachedExtent* left = CachedExtent::Create(node->offset 
- diff,
+                               diff, found->flags);
+                       _AddAllocatedExtent(left);
+               }
+
+               if (found->length == 0)
+                       _RemoveExtent(found);
+
+               Insert(node);
+               _CombineFreeExtent(node);
+       }
+
+       return B_OK;
+}
+
+
+status_t
+CachedExtentTree::AddExtent(CachedExtent* extent)
+{
+       if (extent->IsAllocated() == true)
+               return _AddAllocatedExtent(extent);
+       return _AddFreeExtent(extent);
+}
+
+
+void
+CachedExtentTree::_CombineFreeExtent(CachedExtent* node)
+{
+       // node should be inserted first to call this function,
+       // otherwise it will overdelete.
+       if (node->IsAllocated() == true)
+               return;
+
+       CachedExtent* other = Next(node);
+       if (other != NULL) {
+               if (node->End() == other->offset && node->flags == 
other->flags) {
+                       node->length += other->length;
+                       _RemoveExtent(other);
+               }
+       }
+
+       other = Previous(node);
+       if (other != NULL) {
+               if (other->End() == node->offset && node->flags == 
other->flags) {
+                       other->length += node->length;
+                       _RemoveExtent(node);
+               }
+       }
+}
+
+
+void
+CachedExtentTree::_DumpInOrder(CachedExtent* node) const
+{
+       if (node == NULL)
+               return;
+       _DumpInOrder(_GetValue(node->left));
+       node->Info();
+       _DumpInOrder(_GetValue(node->right));
+}
+
+
+void
+CachedExtentTree::DumpInOrder() const
+{
+       TRACE("\n");
+       _DumpInOrder(RootNode());
+       TRACE("\n");
+}
+
+
+void
+CachedExtentTree::Delete()
+{
+       _Delete(RootNode());
+       Clear();
+}
+
+
+void
+CachedExtentTree::_Delete(CachedExtent* node)
+{
+       if (node == NULL)
+               return;
+       _Delete(_GetValue(node->left));
+       _Delete(_GetValue(node->right));
+       node->Delete();
+}
+
+
+// BlockGroup
+
+
+BlockGroup::BlockGroup(BTree* extentTree)
+       :
+       fItem(NULL)
+{
+       fCurrentExtentTree = new(std::nothrow) BTree(extentTree->SystemVolume(),
+               extentTree->RootBlock());
+}
+
+
+BlockGroup::~BlockGroup()
+{
+       if (fItem != NULL) {
+               free(fItem);
+               fItem = NULL;
+       }
+
+       delete fCurrentExtentTree;
+       fCurrentExtentTree = NULL;
+}
+
+
+status_t
+BlockGroup::SetExtentTree(off_t rootAddress)
+{
+       status_t status = fCurrentExtentTree->SetRoot(rootAddress, NULL);
+       if (status != B_OK)
+               return status;
+
+       if (fItem != NULL) {
+               // re-allocate BlockGroup;
+               uint64 flags = Flags();
+               return Initialize(flags);
+       }
+
+       return B_OK;
+}
+
+
+/* Initialize BlockGroup that has flag
+ */
+status_t
+BlockGroup::Initialize(uint64 flag)
+{
+       if (fCurrentExtentTree == NULL)
+               return B_NO_MEMORY;
+
+       if (fItem != NULL)
+               free(fItem);
+
+       TRACE("BlockGroup::Initialize() find block group has flag: %"
+               B_PRIu64 "\n", flag);
+       BTree::Path path(fCurrentExtentTree);
+       fKey.SetObjectID(0);
+       // find first item in extent to get the ObjectID
+       // ignore type because block_group is not always the first item
+       fKey.SetType(BTRFS_KEY_TYPE_ANY);
+       fCurrentExtentTree->FindNext(&path, fKey, NULL);
+
+       fKey.SetType(BTRFS_KEY_TYPE_BLOCKGROUP_ITEM);
+       fKey.SetOffset(0);
+       status_t status;
+
+       while(true) {
+               status = fCurrentExtentTree->FindNext(&path, fKey, 
(void**)&fItem);
+               if ((Flags() & flag) == flag || status != B_OK)
+                       break;
+               fKey.SetObjectID(End());
+               fKey.SetOffset(0);
+       }
+
+       if (status != B_OK)
+               ERROR("BlockGroup::Initialize() cannot find block group\n");
+
+       return status;
+}
+
+
+status_t
+BlockGroup::LoadExtent(CachedExtentTree* tree, bool inverse)
+{
+       if (fItem == NULL)
+               return B_NO_INIT;
+
+       uint64 flags = (Flags() & BTRFS_BLOCKGROUP_FLAG_DATA) != 0 ?
+               BTRFS_EXTENT_FLAG_DATA : BTRFS_EXTENT_FLAG_TREE_BLOCK;
+       if (inverse == false)
+               flags |= BTRFS_EXTENT_FLAG_ALLOCATED;
+
+       uint64 start = Start();
+       CachedExtent* insert;
+       void* data;
+       uint64 extentSize = fCurrentExtentTree->SystemVolume()->BlockSize();
+
+       btrfs_key key;
+       key.SetType(BTRFS_KEY_TYPE_METADATA_ITEM);
+       if ((flags & BTRFS_EXTENT_FLAG_DATA) != 0)
+               key.SetType(BTRFS_KEY_TYPE_EXTENT_ITEM);
+       key.SetObjectID(start);
+       key.SetOffset(0);
+
+       TreeIterator iterator(fCurrentExtentTree, key);
+       status_t status;
+       while(true) {
+               status = iterator.GetNextEntry(&data);
+               key = iterator.Key();
+               if (status != B_OK) {
+                       if (key.ObjectID() != Start())
+                               break;
+                       // When we couldn't find the item and key has
+                       // objectid == BlockGroup's objectID, because
+                       // key's type < BLOCKGROUP_ITEM
+                       continue;
+               }
+
+               if (inverse == false) {
+                       if ((flags & BTRFS_EXTENT_FLAG_DATA) != 0)
+                               extentSize = key.Offset();
+                       insert = CachedExtent::Create(key.ObjectID(), 
extentSize, flags);
+                       insert->item = (btrfs_extent*)data;
+               } else {
+                       extentSize = key.ObjectID() - start;
+                       insert = CachedExtent::Create(start, extentSize, flags);
+                       free(data);             // free extent doesn't have 
data;
+               }
+               _InsertExtent(tree, insert);
+               start = key.ObjectID() + extentSize;
+       }
+
+       if (inverse == true)
+               _InsertExtent(tree, start, End() - start, flags);
+
+       return B_OK;
+}
+
+
+status_t
+BlockGroup::_InsertExtent(CachedExtentTree* tree, uint64 start, uint64 length,
+       uint64 flags)
+{
+       CachedExtent* extent = CachedExtent::Create(start, length, flags);
+       return _InsertExtent(tree, extent);
+}
+
+
+status_t
+BlockGroup::_InsertExtent(CachedExtentTree* tree, CachedExtent* extent)
+{
+       if (extent->length == 0)
+               return B_BAD_VALUE;
+
+       status_t status = tree->AddExtent(extent);
+       if (status != B_OK) {
+               return status;
+       }
+       return B_OK;
+}
+
+
+// ExtentAllocator
+
+
+ExtentAllocator::ExtentAllocator(Volume* volume)
+       :
+       fVolume(volume),
+       fTree(NULL),
+       fStart((uint64)-1),
+       fEnd(0)
+{
+       fTree = new(std::nothrow) CachedExtentTree(TreeDefinition());
+}
+
+
+ExtentAllocator::~ExtentAllocator()
+{
+       delete fTree;
+       fTree = NULL;
+}
+
+
+status_t
+ExtentAllocator::_LoadExtentTree(uint64 flags)
+{
+       TRACE("ExtentAllocator::_LoadExtentTree() flags: %" B_PRIu64 "\n", 
flags);
+       BlockGroup blockGroup(fVolume->ExtentTree());
+       status_t status = blockGroup.Initialize(flags);
+       if (status != B_OK)
+               return status;
+
+       for (int i = 0; i < BTRFS_NUM_ROOT_BACKUPS; i++) {
+               uint64 extentRootAddr =
+                       fVolume->SuperBlock().backup_roots[i].ExtentRoot();
+               if (extentRootAddr == 0)
+                       continue;       // new device has 0 root address
+
+               status = blockGroup.SetExtentTree(extentRootAddr);
+               if (status != B_OK)
+                       return status;
+               status = blockGroup.LoadExtent(fTree, false);
+               if (status != B_OK)
+                       return status;
+       }
+
+       if (fTree->IsEmpty())   // 4 backup roots is 0
+               return B_OK;
+
+       uint64 lowerBound = blockGroup.Start();
+       uint64 upperBound = blockGroup.End();
+       status = fTree->FillFreeExtents(lowerBound, upperBound);
+       if (status != B_OK) {
+               ERROR("ExtentAllocator::_LoadExtentTree() could not fill free 
extents"
+                       "start %" B_PRIu64 " end %" B_PRIu64 "\n", lowerBound,
+                       upperBound);
+               return status;
+       }
+
+       if (fStart > lowerBound)
+               fStart = lowerBound;
+       if (fEnd < upperBound)
+               fEnd = upperBound;
+       return B_OK;
+}
+
+
+status_t
+ExtentAllocator::Initialize()
+{
+       TRACE("ExtentAllocator::Initialize()\n");
+       if (fTree == NULL)
+               return B_NO_MEMORY;
+
+       status_t status = _LoadExtentTree(BTRFS_BLOCKGROUP_FLAG_DATA);
+       if (status != B_OK) {
+               ERROR("ExtentAllocator:: could not load exent tree (data)\n");
+               return status;
+       }
+
+       status = _LoadExtentTree(BTRFS_BLOCKGROUP_FLAG_SYSTEM);
+       if (status != B_OK) {
+               ERROR("ExtentAllocator:: could not load exent tree (system)\n");
+               return status;
+       }
+
+       status = _LoadExtentTree(BTRFS_BLOCKGROUP_FLAG_METADATA);
+       if (status != B_OK) {
+               ERROR("ExtentAllocator:: could not load exent tree 
(metadata)\n");
+               return status;
+       }
+
+       fTree->DumpInOrder();
+       return B_OK;
+}
+
+
+/* Allocate extent that
+ * startwith or after "start" and has size >= "size"
+ * For now the allocating strategy is "first fit"
+ */
+status_t
+ExtentAllocator::_Allocate(uint64& found, uint64 start, uint64 size,
+       uint64 type)
+{
+       TRACE("ExtentAllocator::_Allocate() start %" B_PRIu64 " size %" 
B_PRIu64 " type %"
+               B_PRIu64 "\n", start, size, type);
+       CachedExtent* chosen;
+       status_t status;
+       while(true) {
+               status = fTree->FindNext(&chosen, start, size, type);
+               if (status != B_OK)
+                       return status;
+
+               if (TreeDefinition().Compare(start, chosen) == 0) {
+                       if (chosen->End() - start >= size) {
+                               // if covered and have enough space for 
allocating
+                               break;
+                       }
+                       start = chosen->End();  // set new start and retry
+               } else
+                       start = chosen->offset;
+       }
+
+       TRACE("ExtentAllocator::_Allocate() found %" B_PRIu64 "\n", start);
+       chosen = CachedExtent::Create(start, size,
+               type | BTRFS_EXTENT_FLAG_ALLOCATED);
+       status = fTree->AddExtent(chosen);
+       if (status != B_OK)
+               return status;
+
+       found = start;
+       return B_OK;
+}
+
+
+// Allocate block for metadata
+// flags is BLOCKGROUP's flags
+status_t
+ExtentAllocator::AllocateTreeBlock(uint64& found, uint64 start, uint64 flags)
+{
+       // TODO: implement more features here with flags, e.g DUP, RAID, etc
+
+       BlockGroup blockGroup(fVolume->ExtentTree());
+       status_t status = blockGroup.Initialize(flags);
+       if (status != B_OK)
+               return status;
+       if (start == (uint64)-1)
+               start = blockGroup.Start();
+
+       // normalize inputs
+       uint64 remainder = start % fVolume->BlockSize();
+       if (remainder != 0)
+               start += fVolume->BlockSize() - remainder;
+
+       status = _Allocate(found, start, fVolume->BlockSize(),
+               BTRFS_EXTENT_FLAG_TREE_BLOCK);
+       if (status != B_OK)
+               return status;
+
+       // check here because tree block locate in 2 blockgroups (system and
+       // metadata), and there might be a case one can get over the limit.
+       if (found >= blockGroup.End())
+               return B_BAD_DATA;
+       return B_OK;
+}
+
+
+// Allocate block for file data
+status_t
+ExtentAllocator::AllocateDataBlock(uint64& found, uint64 size, uint64 start,
+       uint64 flags)
+{
+       // TODO: implement more features here with flags, e.g DUP, RAID, etc
+
+       if (start == (uint64)-1) {
+               BlockGroup blockGroup(fVolume->ExtentTree());
+               status_t status = blockGroup.Initialize(flags);
+               if (status != B_OK)
+                       return status;
+               start = blockGroup.Start();
+       }
+
+       // normalize inputs
+       uint64 remainder = start % fVolume->SectorSize();
+       if (remainder != 0)
+               start += fVolume->SectorSize() - remainder;
+       size = size / fVolume->SectorSize() * fVolume->SectorSize();
+
+       return _Allocate(found, start, size, BTRFS_EXTENT_FLAG_DATA);
+}
diff --git a/src/add-ons/kernel/file_systems/btrfs/ExtentAllocator.h 
b/src/add-ons/kernel/file_systems/btrfs/ExtentAllocator.h
new file mode 100644
index 0000000..310f8ac
--- /dev/null
+++ b/src/add-ons/kernel/file_systems/btrfs/ExtentAllocator.h
@@ -0,0 +1,153 @@
+#ifndef EXTENT_ALLOCATOR_H
+#define EXTENT_ALLOCATOR_H
+
+
+#include "Volume.h"
+#include "BTree.h"
+
+
+//#define TRACE_BTRFS
+#ifdef TRACE_BTRFS
+#      define TRACE(x...) dprintf("\33[34mbtrfs:\33[0m " x)
+#else
+#      define TRACE(x...) ;
+#endif
+
+#define ERROR(x...) dprintf("\33[34mbtrfs:\33[0m " x)
+
+
+struct CachedExtent : AVLTreeNode {
+       uint64          offset;
+       uint64          length;
+       int                     refCount;
+       uint64          flags;
+       btrfs_extent* item;
+
+       static  CachedExtent*           Create(uint64 offset, uint64 length,
+                                                                       uint64 
flags);
+                       void                            Delete();
+
+                       uint64                          End() const { return 
offset + length; }
+                       bool                            IsAllocated() const;
+                       bool                            IsData() const;
+
+                       void                            Info() const;
+
+private:
+                                                               CachedExtent() 
{}
+                                                               
CachedExtent(const CachedExtent& other);
+};
+
+
+struct TreeDefinition {
+       typedef uint64                  Key;
+       typedef CachedExtent    Value;
+
+       AVLTreeNode* GetAVLTreeNode(Value* value) const
+       {
+               return value;
+       }
+
+       Value* GetValue(AVLTreeNode* node) const
+       {
+               return static_cast<Value*>(node);
+       }
+
+       int Compare(const Key& a, const Value* b) const
+       {
+               if (a < b->offset)
+                       return -1;
+               if (a >= b->End())
+                       return 1;
+               return 0;
+       }
+
+       int Compare(const Value* a, const Value* b) const
+       {
+               int comp = Compare(a->offset, b);
+               //TODO: check more conditions here if necessary
+               return comp;
+       }
+};
+
+
+struct CachedExtentTree : AVLTree<TreeDefinition> {
+public:
+                                                               
CachedExtentTree(
+                                                                       const 
TreeDefinition& definition);
+                                                               
~CachedExtentTree();
+
+                       status_t                        FindNext(CachedExtent** 
chosen, uint64 offset,
+                                                                       uint64 
size, uint64 type);
+                       status_t                        AddExtent(CachedExtent* 
extent);
+                       status_t                        FillFreeExtents(uint64 
lowerBound,
+                                                                       uint64 
upperBound);
+                       void                            DumpInOrder() const;
+                       void                            Delete();
+private:
+                       status_t                        
_AddAllocatedExtent(CachedExtent* node);
+                       status_t                        
_AddFreeExtent(CachedExtent* node);
+                       void                            
_CombineFreeExtent(CachedExtent* node);
+                       void                            
_RemoveExtent(CachedExtent* node);
+                       void                            
_DumpInOrder(CachedExtent* node) const;
+                       void                            _Delete(CachedExtent* 
node);
+};
+
+
+class BlockGroup {
+public:
+                                                               
BlockGroup(BTree* extentTree);
+                                                               ~BlockGroup();
+
+                       status_t                        SetExtentTree(off_t 
rootAddress);
+                       status_t                        Initialize(uint64 flag);
+                       status_t                        
LoadExtent(CachedExtentTree* tree,
+                                                                       bool 
inverse = false);
+
+                       uint64                          Flags() const { return 
fItem->Flags(); }
+                       uint64                          Start() const { return 
fKey.ObjectID(); }
+                       uint64                          End() const
+                                                                       { 
return fKey.ObjectID() + fKey.Offset(); }
+
+private:
+                                                               
BlockGroup(const BlockGroup&);
+                                                               BlockGroup& 
operator=(const BlockGroup&);
+                       status_t                        
_InsertExtent(CachedExtentTree* tree,
+                                                                       uint64 
size, uint64 length, uint64 flags);
+                       status_t                        
_InsertExtent(CachedExtentTree* tree,
+                                                                       
CachedExtent* extent);
+
+private:
+                       btrfs_key                       fKey;
+                       btrfs_block_group*      fItem;
+                       BTree*                          fCurrentExtentTree;
+};
+
+
+class ExtentAllocator {
+public:
+                                                               
ExtentAllocator(Volume* volume);
+                                                               
~ExtentAllocator();
+
+                       status_t                        Initialize();
+                       status_t                        
AllocateTreeBlock(uint64& found,
+                                                                       uint64 
start = (uint64)-1,
+                                                                       uint64 
flags = BTRFS_BLOCKGROUP_FLAG_METADATA);
+                       status_t                        
AllocateDataBlock(uint64& found, uint64 size,
+                                                                       uint64 
start = (uint64)-1,
+                                                                       uint64 
flags = BTRFS_BLOCKGROUP_FLAG_DATA);
+private:
+                                                               
ExtentAllocator(const ExtentAllocator&);
+                                                               
ExtentAllocator& operator=(const ExtentAllocator&);
+                       status_t                        _LoadExtentTree(uint64 
flags);
+                       status_t                        _Allocate(uint64& 
found, uint64 start,
+                                                                       uint64 
size, uint64 type);
+private:
+                       Volume*                         fVolume;
+                       CachedExtentTree*       fTree;
+                       uint64                          fStart;
+                       uint64                          fEnd;
+};
+
+
+#endif // EXTENT_ALLOCATOR_H
diff --git a/src/add-ons/kernel/file_systems/btrfs/Jamfile 
b/src/add-ons/kernel/file_systems/btrfs/Jamfile
index d408e55..78ba20c 100644
--- a/src/add-ons/kernel/file_systems/btrfs/Jamfile
+++ b/src/add-ons/kernel/file_systems/btrfs/Jamfile
@@ -16,6 +16,7 @@ KernelAddon btrfs :
        Chunk.cpp
        CRCTable.cpp
        DirectoryIterator.cpp
+       ExtentAllocator.cpp
        Inode.cpp
        Volume.cpp
        : kernel_libz.a
diff --git a/src/add-ons/kernel/file_systems/btrfs/Volume.cpp 
b/src/add-ons/kernel/file_systems/btrfs/Volume.cpp
index dc2fffe..c219d40 100644
--- a/src/add-ons/kernel/file_systems/btrfs/Volume.cpp
+++ b/src/add-ons/kernel/file_systems/btrfs/Volume.cpp
@@ -13,6 +13,7 @@
 #include "CachedBlock.h"
 #include "Chunk.h"
 #include "Inode.h"
+#include "ExtentAllocator.h"
 
 
 //#define TRACE_BTRFS
@@ -386,6 +387,16 @@ Volume::Mount(const char* deviceName, uint32 flags)
        fChecksumTree->SetRoot(root->LogicalAddress(), NULL);
        free(root);
 
+       // Initialize ExtentAllocator;
+       fExtentAllocator = new(std::nothrow) ExtentAllocator(this);
+       if (fExtentAllocator == NULL)
+               return B_NO_MEMORY;
+       status = fExtentAllocator->Initialize();
+       if (status != B_OK) {
+               ERROR("could not initalize extent allocator!\n");
+               return status;
+       }
+
        // ready
        status = get_vnode(fFSVolume, BTRFS_FIRST_SUBVOLUME,
                (void**)&fRootNode);
@@ -432,10 +443,12 @@ Volume::Unmount()
        delete fChecksumTree;
        delete fFSTree;
        delete fDevTree;
+       delete fExtentAllocator;
        fExtentTree = NULL;
        fChecksumTree = NULL;
        fFSTree = NULL;
        fDevTree = NULL;
+       fExtentAllocator = NULL;
 
        TRACE("Volume::Unmount(): Putting root node\n");
        put_vnode(fFSVolume, RootNode()->ID());
diff --git a/src/add-ons/kernel/file_systems/btrfs/Volume.h 
b/src/add-ons/kernel/file_systems/btrfs/Volume.h
index d839dc0..a4b292c 100644
--- a/src/add-ons/kernel/file_systems/btrfs/Volume.h
+++ b/src/add-ons/kernel/file_systems/btrfs/Volume.h
@@ -17,6 +17,7 @@ enum volume_flags {
 class BTree;
 class Chunk;
 class Inode;
+class ExtentAllocator;
 
 
 class Volume {
@@ -45,6 +46,7 @@ public:
                        uint32                          SectorSize() const { 
return fSectorSize; }
                        uint32                          BlockSize() const { 
return fBlockSize; }
                        Chunk*                          SystemChunk() const { 
return fChunk; }
+                       ExtentAllocator*        GetAllocator() const { return 
fExtentAllocator; }
 
                        btrfs_super_block&      SuperBlock() { return 
fSuperBlock; }
 
@@ -72,6 +74,7 @@ private:
                        void*                           fBlockCache;
                        Inode*                          fRootNode;
 
+                       ExtentAllocator*        fExtentAllocator;
                        Chunk*                          fChunk;
                        BTree*                          fChunkTree;
                        BTree*                          fRootTree;
diff --git a/src/add-ons/kernel/file_systems/btrfs/btrfs.h 
b/src/add-ons/kernel/file_systems/btrfs/btrfs.h
index d2f4518..a6b4963 100644
--- a/src/add-ons/kernel/file_systems/btrfs/btrfs.h
+++ b/src/add-ons/kernel/file_systems/btrfs/btrfs.h
@@ -449,10 +449,11 @@ struct btrfs_extent_data_ref {
 #define BTRFS_EXTENT_DATA_PRE                          2
 #define BTRFS_EXTENT_FLAG_DATA                         1
 #define BTRFS_EXTENT_FLAG_TREE_BLOCK           2
+#define BTRFS_EXTENT_FLAG_ALLOCATED                    4
 
 #define BTRFS_BLOCKGROUP_FLAG_DATA                     1
 #define BTRFS_BLOCKGROUP_FLAG_SYSTEM           2
-#define BTRFS_BLOCKGROUP_FLAG_METADA           4
+#define BTRFS_BLOCKGROUP_FLAG_METADATA         4
 #define BTRFS_BLOCKGROUP_FLAG_RAID0                    8
 #define BTRFS_BLOCKGROUP_FLAG_RAID1                    16
 #define BTRFS_BLOCKGROUP_FLAG_DUP                      32
diff --git a/src/tools/btrfs_shell/Jamfile b/src/tools/btrfs_shell/Jamfile
index 5029613..99231c8 100644
--- a/src/tools/btrfs_shell/Jamfile
+++ b/src/tools/btrfs_shell/Jamfile
@@ -42,6 +42,7 @@ local btrfsSources =
        Chunk.cpp
        CRCTable.cpp
        DirectoryIterator.cpp
+       ExtentAllocator.cpp
        Inode.cpp
        Volume.cpp
        kernel_interface.cpp

############################################################################

Commit:      0deb03560f570db9fff0159f2b46731281c20dae
URL:         http://cgit.haiku-os.org/haiku/commit/?id=0deb03560f57
Author:      hyche <cvghy116@xxxxxxxxx>
Date:        Thu Aug 17 16:58:52 2017 UTC
Committer:   Augustin Cavalier <waddlesplash@xxxxxxxxx>
Commit-Date: Sun Dec 10 16:02:54 2017 UTC

BTRFS: Fix mismatched type of index in inode_ref item.

Signed-off-by: Augustin Cavalier <waddlesplash@xxxxxxxxx>

----------------------------------------------------------------------------

diff --git a/src/add-ons/kernel/file_systems/btrfs/btrfs.h 
b/src/add-ons/kernel/file_systems/btrfs/btrfs.h
index a6b4963..59f58e2 100644
--- a/src/add-ons/kernel/file_systems/btrfs/btrfs.h
+++ b/src/add-ons/kernel/file_systems/btrfs/btrfs.h
@@ -294,11 +294,11 @@ struct btrfs_inode {
 
 
 struct btrfs_inode_ref {
-       uint8   index;
+       uint64  index;
        uint16  name_length;
        uint8   name[];
 
-       uint8 Index() const { return index; }
+       uint64 Index() const { return index; }
        uint16 NameLength() const { return 
B_LENDIAN_TO_HOST_INT16(name_length); }
 } _PACKED;
 

############################################################################

Commit:      8137f447cb159923ca8238e136a40df5166743d8
URL:         http://cgit.haiku-os.org/haiku/commit/?id=8137f447cb15
Author:      hyche <cvghy116@xxxxxxxxx>
Date:        Sun Aug 20 17:36:07 2017 UTC
Committer:   Augustin Cavalier <waddlesplash@xxxxxxxxx>
Commit-Date: Sun Dec 10 16:02:55 2017 UTC

BTRFS: Fix memory leak

Missing delete for some tree roots.

Signed-off-by: Augustin Cavalier <waddlesplash@xxxxxxxxx>

----------------------------------------------------------------------------

diff --git a/src/add-ons/kernel/file_systems/btrfs/Volume.cpp 
b/src/add-ons/kernel/file_systems/btrfs/Volume.cpp
index c219d40..3ed2f2d 100644
--- a/src/add-ons/kernel/file_systems/btrfs/Volume.cpp
+++ b/src/add-ons/kernel/file_systems/btrfs/Volume.cpp
@@ -439,12 +439,16 @@ status_t
 Volume::Unmount()
 {
        TRACE("Volume::Unmount()\n");
+       delete fRootTree;
        delete fExtentTree;
+       delete fChunkTree;
        delete fChecksumTree;
        delete fFSTree;
        delete fDevTree;
        delete fExtentAllocator;
+       fRootTree = NULL;
        fExtentTree = NULL;
+       fChunkTree = NULL;
        fChecksumTree = NULL;
        fFSTree = NULL;
        fDevTree = NULL;

############################################################################

Commit:      1750cd1e92275f586b129483441ad3c8fd021369
URL:         http://cgit.haiku-os.org/haiku/commit/?id=1750cd1e9227
Author:      hyche <cvghy116@xxxxxxxxx>
Date:        Wed Aug 23 18:25:09 2017 UTC
Committer:   Augustin Cavalier <waddlesplash@xxxxxxxxx>
Commit-Date: Sun Dec 10 16:02:56 2017 UTC

block_cache: Implement cache_has_block_in_transaction function that will check 
the existence of block in one specific transaction.

Signed-off-by: Augustin Cavalier <waddlesplash@xxxxxxxxx>

----------------------------------------------------------------------------

diff --git a/headers/os/drivers/fs_cache.h b/headers/os/drivers/fs_cache.h
index 9a71a5b..8c8193c 100644
--- a/headers/os/drivers/fs_cache.h
+++ b/headers/os/drivers/fs_cache.h
@@ -53,6 +53,7 @@ extern status_t cache_next_block_in_transaction(void *cache, 
int32 id,
 extern int32 cache_blocks_in_transaction(void *cache, int32 id);
 extern int32 cache_blocks_in_main_transaction(void *cache, int32 id);
 extern int32 cache_blocks_in_sub_transaction(void *cache, int32 id);
+extern bool cache_has_block_in_transaction(void* cache, int32 id, off_t 
blockNumber);
 
 /* block cache */
 extern void block_cache_delete(void *cache, bool allowWrites);
diff --git a/headers/private/fs_shell/fssh_api_wrapper.h 
b/headers/private/fs_shell/fssh_api_wrapper.h
index 233f8b4..7c1e0b3 100644
--- a/headers/private/fs_shell/fssh_api_wrapper.h
+++ b/headers/private/fs_shell/fssh_api_wrapper.h
@@ -835,6 +835,7 @@
 #define cache_blocks_in_transaction            fssh_cache_blocks_in_transaction
 #define cache_blocks_in_main_transaction fssh_cache_blocks_in_main_transaction
 #define cache_blocks_in_sub_transaction        
fssh_cache_blocks_in_sub_transaction
+#define cache_has_block_in_transaction fssh_cache_has_block_in_transaction
 
 /* block cache */
 #define block_cache_delete                             fssh_block_cache_delete
diff --git a/headers/private/fs_shell/fssh_fs_cache.h 
b/headers/private/fs_shell/fssh_fs_cache.h
index 88cc9a3..c27052c 100644

[ *** diff truncated: 62 lines dropped *** ]


############################################################################

Commit:      c1320b3a33417a6702471014dac9d089c7036bc3
URL:         http://cgit.haiku-os.org/haiku/commit/?id=c1320b3a3341
Author:      hyche <cvghy116@xxxxxxxxx>
Date:        Wed Aug 23 18:38:54 2017 UTC
Committer:   Augustin Cavalier <waddlesplash@xxxxxxxxx>
Commit-Date: Sun Dec 10 16:02:57 2017 UTC

BTRFS: Implement a simple journaling approach, this is not finished and mostly 
satisfy the need for passing Transaction object for many functions.

Some details about the current Journal:
* Journal can only end transaction.
* It holds a transaction id of fs (fCurrentGeneration) that increments each 
time a transaction starts.
* _TransactionWritten now just printing message.

Signed-off-by: Augustin Cavalier <waddlesplash@xxxxxxxxx>

----------------------------------------------------------------------------

############################################################################

Commit:      4368661f03c331391322659823f38d92ece893e7
URL:         http://cgit.haiku-os.org/haiku/commit/?id=4368661f03c3
Author:      hyche <cvghy116@xxxxxxxxx>
Date:        Wed Aug 23 19:02:17 2017 UTC
Committer:   Augustin Cavalier <waddlesplash@xxxxxxxxx>
Commit-Date: Sun Dec 10 16:02:57 2017 UTC

BTRFS: Implement GetNewBlock() function that will find the logical address for 
allocating and convert it to physical block.

Signed-off-by: Augustin Cavalier <waddlesplash@xxxxxxxxx>

----------------------------------------------------------------------------

############################################################################

Commit:      27ffe0583b71adcfb7814a3af1358271c1800877
URL:         http://cgit.haiku-os.org/haiku/commit/?id=27ffe0583b71
Author:      hyche <cvghy116@xxxxxxxxx>
Date:        Wed Aug 23 19:22:02 2017 UTC
Committer:   Augustin Cavalier <waddlesplash@xxxxxxxxx>
Commit-Date: Sun Dec 10 16:02:58 2017 UTC

BTRFS: Implement some space relevant helpers.

Signed-off-by: Augustin Cavalier <waddlesplash@xxxxxxxxx>

----------------------------------------------------------------------------

############################################################################

Commit:      89484dc08d8e03fb458893ec0749f859b6bfd5f6
URL:         http://cgit.haiku-os.org/haiku/commit/?id=89484dc08d8e
Author:      hyche <cvghy116@xxxxxxxxx>
Date:        Wed Aug 23 19:26:49 2017 UTC
Committer:   Augustin Cavalier <waddlesplash@xxxxxxxxx>
Commit-Date: Sun Dec 10 16:02:58 2017 UTC

BTRFS: Implement some copy relevant helpers.

Copy() copys data from other node, MoveEntries() changes data on the current 
node.

Signed-off-by: Augustin Cavalier <waddlesplash@xxxxxxxxx>

----------------------------------------------------------------------------

############################################################################

Commit:      883b9bf29faede9fb578879f04e26cfca667e3df
URL:         http://cgit.haiku-os.org/haiku/commit/?id=883b9bf29fae
Author:      hyche <cvghy116@xxxxxxxxx>
Date:        Wed Aug 23 20:09:00 2017 UTC
Committer:   Augustin Cavalier <waddlesplash@xxxxxxxxx>
Commit-Date: Sun Dec 10 16:02:59 2017 UTC

BTRFS: Implement CopyOnWrite relevant functions, and BTree holds new attribute 
that record its root level.

CopyOnWrite works like this:
* Cache original node
* Allocating new block
* Cache new block to be writable
* Copy original node to new node, and changing.
Also if a node is already be COW-ed it cannot be COW-ed again, it will be 
changed in-place instead.

InternalCopy does CopyOnWrite all the nodes that we don't need to change 
anything on them.

Signed-off-by: Augustin Cavalier <waddlesplash@xxxxxxxxx>

----------------------------------------------------------------------------

############################################################################

Commit:      2b6c2ec3905e7cbf4385b93356a51737554e4092
URL:         http://cgit.haiku-os.org/haiku/commit/?id=2b6c2ec3905e
Author:      hyche <cvghy116@xxxxxxxxx>
Date:        Sat Aug 26 22:13:22 2017 UTC
Committer:   Augustin Cavalier <waddlesplash@xxxxxxxxx>
Commit-Date: Sun Dec 10 16:02:59 2017 UTC

fs_shell: Added socket filetype.

Signed-off-by: Augustin Cavalier <waddlesplash@xxxxxxxxx>

----------------------------------------------------------------------------

############################################################################

Commit:      02bce792d84640327692fc044c24cf01162a04d9
URL:         http://cgit.haiku-os.org/haiku/commit/?id=02bce792d846
Author:      hyche <cvghy116@xxxxxxxxx>
Date:        Sat Aug 26 22:18:04 2017 UTC
Committer:   Augustin Cavalier <waddlesplash@xxxxxxxxx>
Commit-Date: Sun Dec 10 16:03:00 2017 UTC

BTRFS: Added function to convert standard filetypes to btrfs filetypes.

Signed-off-by: Augustin Cavalier <waddlesplash@xxxxxxxxx>

----------------------------------------------------------------------------

############################################################################

Commit:      84bc447cae639842c6c3b7fe2d28bd52e2384eab
URL:         http://cgit.haiku-os.org/haiku/commit/?id=84bc447cae63
Author:      hyche <cvghy116@xxxxxxxxx>
Date:        Mon Aug 28 19:07:52 2017 UTC
Committer:   Augustin Cavalier <waddlesplash@xxxxxxxxx>
Commit-Date: Sun Dec 10 16:03:00 2017 UTC

BTRFS: Implement InsertEntries() that will insert consecutive items and its 
data.

Signed-off-by: Augustin Cavalier <waddlesplash@xxxxxxxxx>

----------------------------------------------------------------------------

############################################################################

Commit:      20185bb9c399a31ba2b509807c41d77ff62a52aa
URL:         http://cgit.haiku-os.org/haiku/commit/?id=20185bb9c399
Author:      hyche <cvghy116@xxxxxxxxx>
Date:        Mon Aug 28 19:10:11 2017 UTC
Committer:   Augustin Cavalier <waddlesplash@xxxxxxxxx>
Commit-Date: Sun Dec 10 16:03:00 2017 UTC

BTRFS: Implement RemoveEntries() for BTree that will remove consecutive items 
and its data.

Signed-off-by: Augustin Cavalier <waddlesplash@xxxxxxxxx>

----------------------------------------------------------------------------

############################################################################

Commit:      36a24fb34ef0f8cdfae1f25203ee3004390582d1
URL:         http://cgit.haiku-os.org/haiku/commit/?id=36a24fb34ef0
Author:      hyche <cvghy116@xxxxxxxxx>
Date:        Mon Aug 28 23:08:43 2017 UTC
Committer:   Augustin Cavalier <waddlesplash@xxxxxxxxx>
Commit-Date: Sun Dec 10 16:03:01 2017 UTC

BTRFS: Implement Create() that allocate new Inode object.

Signed-off-by: Augustin Cavalier <waddlesplash@xxxxxxxxx>

----------------------------------------------------------------------------

############################################################################

Commit:      371935de1870f14564a49effc98d0a10a145ecae
URL:         http://cgit.haiku-os.org/haiku/commit/?id=371935de1870
Author:      hyche <cvghy116@xxxxxxxxx>
Date:        Mon Aug 28 23:21:42 2017 UTC
Committer:   Augustin Cavalier <waddlesplash@xxxxxxxxx>
Commit-Date: Sun Dec 10 16:03:01 2017 UTC

BTRFS: Implement Insert() in Inode that inserts inode_item.

Signed-off-by: Augustin Cavalier <waddlesplash@xxxxxxxxx>

----------------------------------------------------------------------------

############################################################################

Commit:      b44d924df453be386d656805c53efe0f0dd0fe2f
URL:         http://cgit.haiku-os.org/haiku/commit/?id=b44d924df453
Author:      hyche <cvghy116@xxxxxxxxx>
Date:        Mon Aug 28 23:38:42 2017 UTC
Committer:   Augustin Cavalier <waddlesplash@xxxxxxxxx>
Commit-Date: Sun Dec 10 16:03:02 2017 UTC

BTRFS: Implement MakeReference() in Inode that will link file name to inode.

Signed-off-by: Augustin Cavalier <waddlesplash@xxxxxxxxx>

----------------------------------------------------------------------------

############################################################################

Commit:      8042a045b0af37802c48e49a134af3583021650d
URL:         http://cgit.haiku-os.org/haiku/commit/?id=8042a045b0af
Author:      hyche <cvghy116@xxxxxxxxx>
Date:        Mon Aug 28 23:41:56 2017 UTC
Committer:   Augustin Cavalier <waddlesplash@xxxxxxxxx>
Commit-Date: Sun Dec 10 16:03:02 2017 UTC

BTRFS: Implement Remove() in Inode that removes inode_item.

Signed-off-by: Augustin Cavalier <waddlesplash@xxxxxxxxx>

----------------------------------------------------------------------------

############################################################################

Commit:      a9e85cb62f27986fc58b31877713e1a64a38db8d
URL:         http://cgit.haiku-os.org/haiku/commit/?id=a9e85cb62f27
Author:      hyche <cvghy116@xxxxxxxxx>
Date:        Mon Aug 28 23:43:21 2017 UTC
Committer:   Augustin Cavalier <waddlesplash@xxxxxxxxx>
Commit-Date: Sun Dec 10 16:03:03 2017 UTC

BTRFS: Implement Dereference() in Inode that remove the "name" and unlink it 
with inode.

Signed-off-by: Augustin Cavalier <waddlesplash@xxxxxxxxx>

----------------------------------------------------------------------------

############################################################################

Commit:      166917c9cdf715d911f8de9415903718b075ee2c
URL:         http://cgit.haiku-os.org/haiku/commit/?id=166917c9cdf7
Author:      hyche <cvghy116@xxxxxxxxx>
Date:        Mon Aug 28 23:47:02 2017 UTC
Committer:   Augustin Cavalier <waddlesplash@xxxxxxxxx>
Commit-Date: Sun Dec 10 16:03:03 2017 UTC

BTRFS: Implement btrfs_create_dir that can create directories in most case.

We need to handle a case when node is full, the solution should be split or 
push data to another node.

Signed-off-by: Augustin Cavalier <waddlesplash@xxxxxxxxx>

----------------------------------------------------------------------------

############################################################################

Commit:      4896a3735e1cf5209686f3c78c8ac5935206ce7f
URL:         http://cgit.haiku-os.org/haiku/commit/?id=4896a3735e1c
Author:      hyche <cvghy116@xxxxxxxxx>
Date:        Mon Aug 28 23:55:13 2017 UTC
Committer:   Augustin Cavalier <waddlesplash@xxxxxxxxx>
Commit-Date: Sun Dec 10 16:03:04 2017 UTC

BTRFS: Implement btrfs_remove_dir that can remove directories in most case.

We need to handle a case when node size is small reasonably it can be merged 
with another node or push data from other node to this node.

Signed-off-by: Augustin Cavalier <waddlesplash@xxxxxxxxx>

----------------------------------------------------------------------------

############################################################################

Revision:    hrev51666
Commit:      99768086b1493648abee3f076683cc9fefa5923e
URL:         http://cgit.haiku-os.org/haiku/commit/?id=99768086b149
Author:      hyche <cvghy116@xxxxxxxxx>
Date:        Wed Aug 30 00:40:57 2017 UTC
Committer:   Augustin Cavalier <waddlesplash@xxxxxxxxx>
Commit-Date: Sun Dec 10 16:03:56 2017 UTC

BTRFS: Add author and license.

Signed-off-by: Augustin Cavalier <waddlesplash@xxxxxxxxx>

----------------------------------------------------------------------------


Other related posts:

  • » [haiku-commits] haiku: hrev51666 - src/add-ons/kernel/file_systems/btrfs - waddlesplash