1299aba38Shyche /* 299768086Shyche * Copyright 2017, Chế Vũ Gia Hy, cvghy116@gmail.com. 3299aba38Shyche * Copyright 2011, Jérôme Duval, korli@users.berlios.de. 4299aba38Shyche * Copyright 2001-2010, Axel Dörfler, axeld@pinc-software.de. 5299aba38Shyche * This file may be used under the terms of the MIT License. 6299aba38Shyche */ 7299aba38Shyche 8299aba38Shyche 9299aba38Shyche //! BTree implementation 10299aba38Shyche 11299aba38Shyche 12299aba38Shyche #include "BTree.h" 13883b9bf2Shyche #include "Journal.h" 14299aba38Shyche 15299aba38Shyche 16299aba38Shyche //#define TRACE_BTRFS 17299aba38Shyche #ifdef TRACE_BTRFS 18299aba38Shyche # define TRACE(x...) dprintf("\33[34mbtrfs:\33[0m " x) 19299aba38Shyche #else 20299aba38Shyche # define TRACE(x...) ; 21299aba38Shyche #endif 22299aba38Shyche # define ERROR(x...) dprintf("\33[34mbtrfs:\33[0m " x) 23299aba38Shyche 24299aba38Shyche 258160f31fShyche BTree::Node::Node(Volume* volume) 261481c49cShyche : 271481c49cShyche fNode(NULL), 288160f31fShyche fVolume(volume), 291481c49cShyche fBlockNumber(0), 301481c49cShyche fWritable(false) 311481c49cShyche { 321481c49cShyche } 331481c49cShyche 341481c49cShyche 358160f31fShyche BTree::Node::Node(Volume* volume, off_t block) 361481c49cShyche : 371481c49cShyche fNode(NULL), 388160f31fShyche fVolume(volume), 391481c49cShyche fBlockNumber(0), 401481c49cShyche fWritable(false) 411481c49cShyche { 421481c49cShyche SetTo(block); 431481c49cShyche } 441481c49cShyche 451481c49cShyche 46548a0d80Shyche BTree::Node::~Node() 471481c49cShyche { 481481c49cShyche Unset(); 491481c49cShyche } 501481c49cShyche 511481c49cShyche 521481c49cShyche void 53548a0d80Shyche BTree::Node::Unset() 541481c49cShyche { 551481c49cShyche if (fNode != NULL) { 568160f31fShyche block_cache_put(fVolume->BlockCache(), fBlockNumber); 571481c49cShyche fNode = NULL; 581481c49cShyche } 591481c49cShyche } 601481c49cShyche 611481c49cShyche 621481c49cShyche void 63548a0d80Shyche BTree::Node::SetTo(off_t block) 641481c49cShyche { 651481c49cShyche Unset(); 661481c49cShyche fBlockNumber = block; 678160f31fShyche fNode = (btrfs_stream*)block_cache_get(fVolume->BlockCache(), block); 681481c49cShyche } 691481c49cShyche 701481c49cShyche 711481c49cShyche void 72548a0d80Shyche BTree::Node::SetToWritable(off_t block, int32 transactionId, bool empty) 731481c49cShyche { 741481c49cShyche Unset(); 751481c49cShyche fBlockNumber = block; 761481c49cShyche fWritable = true; 771481c49cShyche if (empty) { 788160f31fShyche fNode = (btrfs_stream*)block_cache_get_empty(fVolume->BlockCache(), 798160f31fShyche block, transactionId); 801481c49cShyche } else { 818160f31fShyche fNode = (btrfs_stream*)block_cache_get_writable(fVolume->BlockCache(), 828160f31fShyche block, transactionId); 831481c49cShyche } 841481c49cShyche } 851481c49cShyche 861481c49cShyche 872ed88a48Shyche status_t 882ed88a48Shyche BTree::Node::SearchSlot(const btrfs_key& key, int* slot, btree_traversing type) 892ed88a48Shyche const 9091d7f850Shyche { 9191d7f850Shyche // binary search for item slot in a node 9291d7f850Shyche int entrySize = sizeof(btrfs_entry); 9391d7f850Shyche if (Level() != 0) { 9491d7f850Shyche // internal node 9591d7f850Shyche entrySize = sizeof(btrfs_index); 9691d7f850Shyche } 9791d7f850Shyche 9891d7f850Shyche int high = ItemCount(); 992ed88a48Shyche int low = 0, mid = 0, comp = 0; 1002ed88a48Shyche uint8* base = (uint8*)fNode + sizeof(btrfs_header); 10191d7f850Shyche const btrfs_key* other; 10291d7f850Shyche while (low < high) { 10391d7f850Shyche mid = (low + high) / 2; 1042ed88a48Shyche other = (const btrfs_key*)(base + mid * entrySize); 1050d726c5cShyche comp = key.Compare(*other); 10691d7f850Shyche if (comp < 0) 10791d7f850Shyche high = mid; 10891d7f850Shyche else if (comp > 0) 10991d7f850Shyche low = mid + 1; 11091d7f850Shyche else { 11191d7f850Shyche *slot = mid; 1120d726c5cShyche return B_OK; // if key is in node 11391d7f850Shyche } 11491d7f850Shyche } 1150d726c5cShyche 1162ed88a48Shyche // |--item1--|--item2--|--item3--|--etc--| 1172ed88a48Shyche // m-1 m m+1 1182ed88a48Shyche // k : comp < 0 1192ed88a48Shyche // k : comp > 0 120b568492fShyche if (type == BTREE_BACKWARD && comp < 0) 121b568492fShyche mid--; 122b568492fShyche else if (type == BTREE_FORWARD && comp > 0) 123b568492fShyche mid++; 1242ed88a48Shyche 125b568492fShyche if (type == BTREE_EXACT || mid < 0) 1262ed88a48Shyche return B_ENTRY_NOT_FOUND; 1272ed88a48Shyche 128b568492fShyche *slot = mid; 1290d726c5cShyche TRACE("SearchSlot() found slot %" B_PRId32 " comp %" B_PRId32 "\n", 1300d726c5cShyche *slot, comp); 1310d726c5cShyche return B_OK; 13291d7f850Shyche } 13391d7f850Shyche 13491d7f850Shyche 13527ffe058Shyche int 13627ffe058Shyche BTree::Node::_CalculateSpace(uint32 from, uint32 to, uint8 type) const 13727ffe058Shyche { 13827ffe058Shyche if (to < from || to >= ItemCount()) 13927ffe058Shyche return 0; 14027ffe058Shyche 14127ffe058Shyche if (Level() != 0) 14227ffe058Shyche return sizeof(btrfs_index) * (to - from + 1); 14327ffe058Shyche 14427ffe058Shyche uint32 result = 0; 14527ffe058Shyche if ((type & 1) == 1) { 14627ffe058Shyche result += sizeof(btrfs_entry) * (to - from + 1); 14727ffe058Shyche } 14827ffe058Shyche if ((type & 2) == 2) { 14927ffe058Shyche result += Item(from)->Offset() + Item(from)->Size() 15027ffe058Shyche - Item(to)->Offset(); 15127ffe058Shyche } 15227ffe058Shyche 15327ffe058Shyche return result; 15427ffe058Shyche } 15527ffe058Shyche 15627ffe058Shyche 15727ffe058Shyche int 15827ffe058Shyche BTree::Node::SpaceUsed() const 15927ffe058Shyche { 16027ffe058Shyche if (Level() == 0) 16127ffe058Shyche return _CalculateSpace(0, ItemCount() - 1, 3); 16227ffe058Shyche return _CalculateSpace(0, ItemCount() - 1, 0); 16327ffe058Shyche } 16427ffe058Shyche 16527ffe058Shyche 16627ffe058Shyche int 16727ffe058Shyche BTree::Node::SpaceLeft() const 16827ffe058Shyche { 16927ffe058Shyche return fVolume->BlockSize() - SpaceUsed() - sizeof(btrfs_header); 17027ffe058Shyche } 17127ffe058Shyche 17227ffe058Shyche 17389484dc0Shyche void 17489484dc0Shyche BTree::Node::_Copy(const Node* origin, uint32 at, uint32 from, uint32 to, 17589484dc0Shyche int length) const 17689484dc0Shyche { 17789484dc0Shyche TRACE("Node::_Copy() at: %d from: %d to: %d length: %d\n", 17889484dc0Shyche at, from, to, length); 17989484dc0Shyche 18089484dc0Shyche if (Level() == 0) { 18189484dc0Shyche memcpy(Item(at), origin->Item(from), origin->_CalculateSpace(from, to)); 18289484dc0Shyche // Item offset of copied node must be changed to get the 18389484dc0Shyche // item data offset correctly. length can be zero 18489484dc0Shyche // but let it there doesn't harm anything. 18589484dc0Shyche for (uint32 i = at; i - at <= to - from; ++i) 18689484dc0Shyche Item(i)->SetOffset(Item(i)->Offset() - length); 18789484dc0Shyche 18889484dc0Shyche memcpy(ItemData(at + to - from), origin->ItemData(to), 18989484dc0Shyche origin->_CalculateSpace(from, to, 2)); 19089484dc0Shyche } else { 19189484dc0Shyche memcpy(Index(at), origin->Index(from), 19289484dc0Shyche origin->_CalculateSpace(from, to)); 19389484dc0Shyche } 19489484dc0Shyche } 19589484dc0Shyche 19689484dc0Shyche 19727ffe058Shyche status_t 19827ffe058Shyche BTree::Node::_SpaceCheck(int length) const 19927ffe058Shyche { 20027ffe058Shyche // this is a little bit weird here because we can't find 20127ffe058Shyche // any suitable error code 202*bb2b9b02SNiels Sascha Reedijk if (length < 0 && abs(length) >= SpaceUsed()) 20327ffe058Shyche return B_DIRECTORY_NOT_EMPTY; // not enough data to delete 20427ffe058Shyche if (length > 0 && length >= SpaceLeft()) 20527ffe058Shyche return B_DEVICE_FULL; // no spare space 20627ffe058Shyche return B_OK; 20727ffe058Shyche } 20827ffe058Shyche 20927ffe058Shyche 21089484dc0Shyche status_t 21189484dc0Shyche BTree::Node::Copy(const Node* origin, uint32 start, uint32 end, int length) 21289484dc0Shyche const 21389484dc0Shyche { 21489484dc0Shyche status_t status = origin->_SpaceCheck(length); 21589484dc0Shyche if (status != B_OK) 21689484dc0Shyche return status; 21789484dc0Shyche 21889484dc0Shyche memcpy(fNode, origin->fNode, sizeof(btrfs_header)); 21989484dc0Shyche if (length == 0) { 22089484dc0Shyche // like removing [0, start - 1] and keeping [start, end] 22189484dc0Shyche length = -origin->_CalculateSpace(0, start - 1, 2); 22289484dc0Shyche _Copy(origin, 0, start, end, length); 22389484dc0Shyche } else if (length < 0) { 22489484dc0Shyche // removing all items in [start, end] 22589484dc0Shyche if (start > 0) 22689484dc0Shyche _Copy(origin, 0, 0, start - 1, 0); // <-- [start,... 22789484dc0Shyche if (end + 1 < origin->ItemCount()) { 22889484dc0Shyche // ..., end] --> 22989484dc0Shyche // we only care data size 23089484dc0Shyche length += origin->_CalculateSpace(start, end); 23189484dc0Shyche _Copy(origin, start, end + 1, origin->ItemCount() - 1, length); 23289484dc0Shyche } 23389484dc0Shyche } else { 23489484dc0Shyche // inserting in [start, end] - make a hole for later 23589484dc0Shyche if (start > 0) 23689484dc0Shyche _Copy(origin, 0, 0, start - 1, 0); 23789484dc0Shyche if (start < origin->ItemCount()) { 23889484dc0Shyche length -= origin->_CalculateSpace(start, end); 23989484dc0Shyche _Copy(origin, end + 1, start, origin->ItemCount() - 1, length); 24089484dc0Shyche } 24189484dc0Shyche } 24289484dc0Shyche 24389484dc0Shyche return B_OK; 24489484dc0Shyche } 24589484dc0Shyche 24689484dc0Shyche 24789484dc0Shyche status_t 24889484dc0Shyche BTree::Node::MoveEntries(uint32 start, uint32 end, int length) const 24989484dc0Shyche { 25089484dc0Shyche status_t status = _SpaceCheck(length); 25189484dc0Shyche if (status != B_OK || length == 0/*B_OK*/) 25289484dc0Shyche return status; 25389484dc0Shyche 25489484dc0Shyche int entrySize = sizeof(btrfs_entry); 25589484dc0Shyche if (Level() != 0) 25689484dc0Shyche entrySize = sizeof(btrfs_index); 25789484dc0Shyche 25889484dc0Shyche uint8* base = (uint8*)fNode + sizeof(btrfs_header); 25989484dc0Shyche end++; 26089484dc0Shyche if (length < 0) { 26189484dc0Shyche // removing [start, end] 26289484dc0Shyche TRACE("Node::MoveEntries() removing ... start %" B_PRIu32 " end %" 26389484dc0Shyche B_PRIu32 " length %i\n", start, end, length); 26489484dc0Shyche length += _CalculateSpace(start, end - 1); 26589484dc0Shyche } else { 26689484dc0Shyche // length > 0 26789484dc0Shyche // inserting into [start, end] - make room for later 26889484dc0Shyche TRACE("Node::MoveEntries() inserting ... start %" B_PRIu32 " end %" 26989484dc0Shyche B_PRIu32 " length %i\n", start, end, length); 27089484dc0Shyche length -= _CalculateSpace(start, end - 1); 271cddaf762SAdrien Destugues uint32 tmp = start; 272cddaf762SAdrien Destugues start = end; 273cddaf762SAdrien Destugues end = tmp; 27489484dc0Shyche } 27589484dc0Shyche 27689484dc0Shyche if (end >= ItemCount()) 27789484dc0Shyche return B_OK; 27889484dc0Shyche 27989484dc0Shyche int dataSize = _CalculateSpace(end, ItemCount() - 1, 2); 28089484dc0Shyche // moving items/block pointers 28189484dc0Shyche memmove(base + start * entrySize, base + end * entrySize, 28289484dc0Shyche _CalculateSpace(end, ItemCount() - 1)); 28389484dc0Shyche if (Level() == 0) { 28489484dc0Shyche // moving item data 28589484dc0Shyche int num = start - end; 28689484dc0Shyche for (uint32 i = start; i < ItemCount() + num; ++i) 28789484dc0Shyche Item(i)->SetOffset(Item(i)->Offset() - length); 28889484dc0Shyche 28989484dc0Shyche memmove(ItemData(ItemCount() - 1) - length, ItemData(ItemCount() - 1), 29089484dc0Shyche dataSize); 29189484dc0Shyche } 29289484dc0Shyche 29389484dc0Shyche return B_OK; 29489484dc0Shyche } 29589484dc0Shyche 29689484dc0Shyche 2973216460dShyche // #pragma mark - BTree::Path implementation 2983216460dShyche 2993216460dShyche 3003216460dShyche BTree::Path::Path(BTree* tree) 3013216460dShyche : 3023216460dShyche fTree(tree) 3033216460dShyche { 3043216460dShyche for (int i = 0; i < BTRFS_MAX_TREE_DEPTH; ++i) { 3053216460dShyche fNodes[i] = NULL; 3063216460dShyche fSlots[i] = 0; 3073216460dShyche } 3083216460dShyche } 3093216460dShyche 3103216460dShyche 3113216460dShyche BTree::Path::~Path() 3123216460dShyche { 3133216460dShyche for (int i = 0; i < BTRFS_MAX_TREE_DEPTH; ++i) { 3143216460dShyche delete fNodes[i]; 3153216460dShyche fNodes[i] = NULL; 3163216460dShyche fSlots[i] = 0; 3173216460dShyche } 3183216460dShyche } 3193216460dShyche 3203216460dShyche 3213216460dShyche BTree::Node* 3223216460dShyche BTree::Path::GetNode(int level, int* _slot) const 3233216460dShyche { 3243216460dShyche if (_slot != NULL) 3253216460dShyche *_slot = fSlots[level]; 3263216460dShyche return fNodes[level]; 3273216460dShyche } 3283216460dShyche 3293216460dShyche 3303216460dShyche BTree::Node* 3313216460dShyche BTree::Path::SetNode(off_t block, int slot) 3323216460dShyche { 3333216460dShyche Node node(fTree->SystemVolume(), block); 3343216460dShyche return SetNode(&node, slot); 3353216460dShyche } 3363216460dShyche 3373216460dShyche 3383216460dShyche BTree::Node* 3393216460dShyche BTree::Path::SetNode(const Node* node, int slot) 3403216460dShyche { 3413216460dShyche uint8 level = node->Level(); 3423216460dShyche if (fNodes[level] == NULL) { 3433216460dShyche fNodes[level] = new Node(fTree->SystemVolume(), node->BlockNum()); 3443216460dShyche if (fNodes[level] == NULL) 3453216460dShyche return NULL; 3463216460dShyche } else 3473216460dShyche fNodes[level]->SetTo(node->BlockNum()); 3483216460dShyche 3493216460dShyche if (slot == -1) 3503216460dShyche fSlots[level] = fNodes[level]->ItemCount() - 1; 3513216460dShyche else 3523216460dShyche fSlots[level] = slot; 3533216460dShyche return fNodes[level]; 3543216460dShyche } 3553216460dShyche 3563216460dShyche 3573216460dShyche int 3583216460dShyche BTree::Path::Move(int level, int step) 3593216460dShyche { 3603216460dShyche fSlots[level] += step; 3613216460dShyche if (fSlots[level] < 0) 3623216460dShyche return -1; 3633216460dShyche if (fSlots[level] >= fNodes[level]->ItemCount()) 3643216460dShyche return 1; 3653216460dShyche return 0; 3663216460dShyche } 3673216460dShyche 3683216460dShyche 3693216460dShyche status_t 3703216460dShyche BTree::Path::GetEntry(int slot, btrfs_key* _key, void** _value, uint32* _size, 3713216460dShyche uint32* _offset) 3723216460dShyche { 3733216460dShyche BTree::Node* leaf = fNodes[0]; 3743216460dShyche if (slot < 0 || slot >= leaf->ItemCount()) 3753216460dShyche return B_ENTRY_NOT_FOUND; 3763216460dShyche 3773216460dShyche if (_key != NULL) 3783216460dShyche *_key = leaf->Item(slot)->key; 3793216460dShyche 3803216460dShyche uint32 itemSize = leaf->Item(slot)->Size(); 3813216460dShyche if (_value != NULL) { 3823216460dShyche *_value = malloc(itemSize); 3833216460dShyche if (*_value == NULL) 3843216460dShyche return B_NO_MEMORY; 3853216460dShyche 3863216460dShyche memcpy(*_value, leaf->ItemData(slot), itemSize); 3873216460dShyche } 3883216460dShyche 3893216460dShyche if (_size != NULL) 3903216460dShyche *_size = itemSize; 3913216460dShyche 3923216460dShyche if (_offset != NULL) 3933216460dShyche *_offset = leaf->Item(slot)->Offset(); 3943216460dShyche 3953216460dShyche return B_OK; 3963216460dShyche } 3973216460dShyche 3983216460dShyche 39984bc447cShyche status_t 40084bc447cShyche BTree::Path::SetEntry(int slot, const btrfs_entry& entry, void* value) 40184bc447cShyche { 40284bc447cShyche if (slot < 0) 40384bc447cShyche return B_ENTRY_NOT_FOUND; 40484bc447cShyche 40584bc447cShyche memcpy(fNodes[0]->Item(slot), &entry, sizeof(btrfs_entry)); 40684bc447cShyche memcpy(fNodes[0]->ItemData(slot), value, entry.Size()); 40784bc447cShyche return B_OK; 40884bc447cShyche } 40984bc447cShyche 41084bc447cShyche 411883b9bf2Shyche status_t 412883b9bf2Shyche BTree::Path::CopyOnWrite(Transaction& transaction, int level, uint32 start, 413883b9bf2Shyche int num, int length) 414883b9bf2Shyche { 415883b9bf2Shyche Node* node = fNodes[level]; 416883b9bf2Shyche if (node == NULL) 417883b9bf2Shyche return B_BAD_VALUE; 418883b9bf2Shyche 419883b9bf2Shyche status_t status; 420883b9bf2Shyche if (transaction.HasBlock(node->BlockNum())) { 421883b9bf2Shyche // cow-ed block can not be cow-ed again 422883b9bf2Shyche status = node->MoveEntries(start, start + num - 1, length); 423883b9bf2Shyche if (status != B_OK) 424883b9bf2Shyche return status; 425883b9bf2Shyche 426883b9bf2Shyche node->SetGeneration(transaction.SystemID()); 427883b9bf2Shyche if (length < 0) 428883b9bf2Shyche node->SetItemCount(node->ItemCount() - num); 429883b9bf2Shyche else if (length > 0) 430883b9bf2Shyche node->SetItemCount(node->ItemCount() + num); 431883b9bf2Shyche 432883b9bf2Shyche return B_OK; 433883b9bf2Shyche } 434883b9bf2Shyche 435883b9bf2Shyche uint64 address; 436883b9bf2Shyche fsblock_t block; 437883b9bf2Shyche status = fTree->SystemVolume()->GetNewBlock(address, block); 438883b9bf2Shyche if (status != B_OK) 439883b9bf2Shyche return status; 440883b9bf2Shyche 441883b9bf2Shyche fNodes[level] = new(std::nothrow) BTree::Node(fTree->SystemVolume()); 442883b9bf2Shyche if (fNodes[level] == NULL) 443883b9bf2Shyche return B_NO_MEMORY; 444883b9bf2Shyche 445883b9bf2Shyche fNodes[level]->SetToWritable(block, transaction.ID(), true); 446883b9bf2Shyche 447883b9bf2Shyche status = fNodes[level]->Copy(node, start, start + num - 1, length); 448883b9bf2Shyche if (status != B_OK) 449883b9bf2Shyche return status; 450883b9bf2Shyche 451883b9bf2Shyche fNodes[level]->SetGeneration(transaction.SystemID()); 452883b9bf2Shyche fNodes[level]->SetLogicalAddress(address); 453883b9bf2Shyche if (length < 0) 454883b9bf2Shyche fNodes[level]->SetItemCount(node->ItemCount() - num); 455883b9bf2Shyche else if (length > 0) 456883b9bf2Shyche fNodes[level]->SetItemCount(node->ItemCount() + num); 457883b9bf2Shyche else 458883b9bf2Shyche fNodes[level]->SetItemCount(num); 459883b9bf2Shyche 460883b9bf2Shyche // change pointer of this node in parent 461883b9bf2Shyche int parentSlot; 462883b9bf2Shyche Node* parentNode = GetNode(level + 1, &parentSlot); 463883b9bf2Shyche if (parentNode != NULL) 464883b9bf2Shyche parentNode->Index(parentSlot)->SetLogicalAddress(address); 465883b9bf2Shyche 466883b9bf2Shyche if (level == fTree->RootLevel()) 467883b9bf2Shyche fTree->SetRoot(fNodes[level]); 468883b9bf2Shyche 469883b9bf2Shyche delete node; 470883b9bf2Shyche return B_OK; 471883b9bf2Shyche } 472883b9bf2Shyche 473883b9bf2Shyche 474883b9bf2Shyche status_t 475883b9bf2Shyche BTree::Path::InternalCopy(Transaction& transaction, int level) 476883b9bf2Shyche { 477*bb2b9b02SNiels Sascha Reedijk if (abs(level) >= fTree->RootLevel()) 478883b9bf2Shyche return B_OK; 479883b9bf2Shyche 480883b9bf2Shyche TRACE("Path::InternalCopy() level %i\n", level); 481883b9bf2Shyche int from, to; 482883b9bf2Shyche if (level > 0) { 483883b9bf2Shyche from = level; 484883b9bf2Shyche to = fTree->RootLevel(); 485883b9bf2Shyche } else { 486b951cbd3Sbrjhaiku 487b951cbd3Sbrjhaiku 488883b9bf2Shyche from = 0; 489*bb2b9b02SNiels Sascha Reedijk to = abs(level); 490883b9bf2Shyche } 491883b9bf2Shyche 492883b9bf2Shyche Node* node = NULL; 493883b9bf2Shyche status_t status; 494883b9bf2Shyche while (from <= to) { 495883b9bf2Shyche node = fNodes[from]; 496883b9bf2Shyche status = CopyOnWrite(transaction, from, 0, node->ItemCount(), 0); 497883b9bf2Shyche from++; 498883b9bf2Shyche if (status != B_OK) 499883b9bf2Shyche return status; 500883b9bf2Shyche } 501883b9bf2Shyche 502883b9bf2Shyche return B_OK; 503883b9bf2Shyche } 504883b9bf2Shyche 505883b9bf2Shyche 5063216460dShyche // #pragma mark - BTree implementation 5071481c49cShyche 5081481c49cShyche 509fc4a1e78Shyche BTree::BTree(Volume* volume) 510fc4a1e78Shyche : 511fc4a1e78Shyche fRootBlock(0), 512883b9bf2Shyche fRootLevel(0), 513fc4a1e78Shyche fVolume(volume) 514fc4a1e78Shyche { 515fc4a1e78Shyche mutex_init(&fIteratorLock, "btrfs b+tree iterator"); 516fc4a1e78Shyche } 517fc4a1e78Shyche 518fc4a1e78Shyche 519299aba38Shyche BTree::BTree(Volume* volume, btrfs_stream* stream) 520299aba38Shyche : 521299aba38Shyche fRootBlock(0), 522883b9bf2Shyche fRootLevel(0), 523299aba38Shyche fVolume(volume) 524299aba38Shyche { 525299aba38Shyche mutex_init(&fIteratorLock, "btrfs b+tree iterator"); 526299aba38Shyche } 527299aba38Shyche 528299aba38Shyche 529299aba38Shyche BTree::BTree(Volume* volume, fsblock_t rootBlock) 530299aba38Shyche : 531299aba38Shyche fRootBlock(rootBlock), 532299aba38Shyche fVolume(volume) 533299aba38Shyche { 534299aba38Shyche mutex_init(&fIteratorLock, "btrfs b+tree iterator"); 535299aba38Shyche } 536299aba38Shyche 537299aba38Shyche 538299aba38Shyche BTree::~BTree() 539299aba38Shyche { 540299aba38Shyche // if there are any TreeIterators left, we need to stop them 541299aba38Shyche // (can happen when the tree's inode gets deleted while 542299aba38Shyche // traversing the tree - a TreeIterator doesn't lock the inode) 543299aba38Shyche mutex_lock(&fIteratorLock); 544299aba38Shyche 545299aba38Shyche SinglyLinkedList<TreeIterator>::Iterator iterator 546299aba38Shyche = fIterators.GetIterator(); 547299aba38Shyche while (iterator.HasNext()) 548299aba38Shyche iterator.Next()->Stop(); 549299aba38Shyche mutex_destroy(&fIteratorLock); 550299aba38Shyche } 551299aba38Shyche 552299aba38Shyche 553299aba38Shyche int32 554875a0552Shyche btrfs_key::Compare(const btrfs_key& key) const 555299aba38Shyche { 556875a0552Shyche if (ObjectID() > key.ObjectID()) 557299aba38Shyche return 1; 558875a0552Shyche if (ObjectID() < key.ObjectID()) 559299aba38Shyche return -1; 560875a0552Shyche if (Type() > key.Type()) 561299aba38Shyche return 1; 562875a0552Shyche if (Type() < key.Type()) 563299aba38Shyche return -1; 564875a0552Shyche if (Offset() > key.Offset()) 565299aba38Shyche return 1; 566875a0552Shyche if (Offset() < key.Offset()) 567299aba38Shyche return -1; 568299aba38Shyche return 0; 569299aba38Shyche } 570299aba38Shyche 571299aba38Shyche 5723216460dShyche status_t 5733216460dShyche BTree::Traverse(btree_traversing type, Path* path, const btrfs_key& key) 5743216460dShyche const 5753216460dShyche { 5763216460dShyche TRACE("BTree::Traverse() objectid %" B_PRId64 " type %d offset %" 5773216460dShyche B_PRId64 " \n", key.ObjectID(), key.Type(), key.Offset()); 5783216460dShyche fsblock_t physicalBlock = fRootBlock; 5793216460dShyche Node node(fVolume, physicalBlock); 5803216460dShyche int slot; 5813216460dShyche status_t status = B_OK; 5823216460dShyche 5833216460dShyche while (node.Level() != 0) { 5843216460dShyche TRACE("BTree::Traverse() level %d count %d\n", node.Level(), 5853216460dShyche node.ItemCount()); 5863216460dShyche status = node.SearchSlot(key, &slot, BTREE_BACKWARD); 5873216460dShyche if (status != B_OK) 5883216460dShyche return status; 5893216460dShyche if (path->SetNode(&node, slot) == NULL) 5903216460dShyche return B_NO_MEMORY; 5913216460dShyche 5923216460dShyche TRACE("BTree::Traverse() getting index %" B_PRIu32 "\n", slot); 5933216460dShyche 5943216460dShyche status = fVolume->FindBlock(node.Index(slot)->LogicalAddress(), 5953216460dShyche physicalBlock); 5963216460dShyche if (status != B_OK) { 5973216460dShyche ERROR("BTree::Traverse() unmapped block %" B_PRId64 "\n", 5983216460dShyche node.Index(slot)->LogicalAddress()); 5993216460dShyche return status; 6003216460dShyche } 6013216460dShyche node.SetTo(physicalBlock); 6023216460dShyche } 6033216460dShyche 6043216460dShyche TRACE("BTree::Traverse() dump count %" B_PRId32 "\n", node.ItemCount()); 6053216460dShyche status = node.SearchSlot(key, &slot, type); 6063216460dShyche if (status != B_OK) 6073216460dShyche return status; 6083216460dShyche if (path->SetNode(&node, slot) == NULL) 6093216460dShyche return B_NO_MEMORY; 6103216460dShyche 6113216460dShyche TRACE("BTree::Traverse() found %" B_PRIu32 " %" B_PRIu32 "\n", 6123216460dShyche node.Item(slot)->Offset(), node.Item(slot)->Size()); 6133216460dShyche return slot; 6143216460dShyche } 6153216460dShyche 6163216460dShyche 617299aba38Shyche status_t 6183216460dShyche BTree::_Find(Path* path, btrfs_key& wanted, void** _value, uint32* _size, 6193216460dShyche uint32* _offset, btree_traversing type) const 620299aba38Shyche { 6213216460dShyche status_t status = Traverse(type, path, wanted); 6223216460dShyche if (status < B_OK) 6233216460dShyche return status; 624299aba38Shyche 6253216460dShyche btrfs_key found; 6263216460dShyche status = path->GetCurrentEntry(&found, _value, _size, _offset); 6273216460dShyche if (status != B_OK) 6283216460dShyche return status; 629299aba38Shyche 630690d16c6Shyche if (found.Type() != wanted.Type() && wanted.Type() != BTRFS_KEY_TYPE_ANY) { 631690d16c6Shyche ERROR("Find() not found wanted: %" B_PRIu64 " %" B_PRIu8 " %" 632690d16c6Shyche B_PRIu64 " found: %" B_PRIu64 " %" B_PRIu8 " %" B_PRIu64 "\n", 633690d16c6Shyche wanted.ObjectID(), wanted.Type(), wanted.Offset(), found.ObjectID(), 634690d16c6Shyche found.Type(), found.Offset()); 63546eba5c0Shyche return B_ENTRY_NOT_FOUND; 636690d16c6Shyche } 637299aba38Shyche 6383216460dShyche wanted = found; 639299aba38Shyche return B_OK; 640299aba38Shyche } 641299aba38Shyche 642299aba38Shyche 64346eba5c0Shyche status_t 6443216460dShyche BTree::FindNext(Path* path, btrfs_key& key, void** _value, uint32* _size, 6453216460dShyche uint32* _offset) const 64646eba5c0Shyche { 6473216460dShyche return _Find(path, key, _value, _size, _offset, BTREE_FORWARD); 648299aba38Shyche } 649299aba38Shyche 650299aba38Shyche 651299aba38Shyche status_t 6523216460dShyche BTree::FindPrevious(Path* path, btrfs_key& key, void** _value, uint32* _size, 6533216460dShyche uint32* _offset) const 654299aba38Shyche { 6553216460dShyche return _Find(path, key, _value, _size, _offset, BTREE_BACKWARD); 656299aba38Shyche } 657299aba38Shyche 658299aba38Shyche 659299aba38Shyche status_t 6603216460dShyche BTree::FindExact(Path* path, btrfs_key& key, void** _value, uint32* _size, 6613216460dShyche uint32* _offset) const 662299aba38Shyche { 6633216460dShyche return _Find(path, key, _value, _size, _offset, BTREE_EXACT); 6643216460dShyche } 6653216460dShyche 6663216460dShyche 66784bc447cShyche status_t 66884bc447cShyche BTree::MakeEntries(Transaction& transaction, Path* path, 66984bc447cShyche const btrfs_key& startKey, int num, int length) 67084bc447cShyche { 67184bc447cShyche TRACE("BTree::MakeEntries() num %i key (% " B_PRIu64 " %" B_PRIu8 " %" 67284bc447cShyche B_PRIu64 ")\n", num, startKey.ObjectID(), startKey.Type(), 67384bc447cShyche startKey.Offset()); 67484bc447cShyche 67584bc447cShyche status_t status = Traverse(BTREE_FORWARD, path, startKey); 67684bc447cShyche if (status < B_OK) 67784bc447cShyche return status; 67884bc447cShyche 67984bc447cShyche int slot = status; 68084bc447cShyche status = path->InternalCopy(transaction, 1); 68184bc447cShyche if (status != B_OK) 68284bc447cShyche return status; 68384bc447cShyche 68484bc447cShyche status = path->CopyOnWrite(transaction, 0, slot, num, length); 68584bc447cShyche if (status == B_DEVICE_FULL) { 68684bc447cShyche // TODO: push data or split node 68784bc447cShyche return status; 68884bc447cShyche } 68984bc447cShyche 69084bc447cShyche if (status != B_OK) 69184bc447cShyche return status; 69284bc447cShyche return slot; 69384bc447cShyche } 69484bc447cShyche 69584bc447cShyche 69684bc447cShyche status_t 69784bc447cShyche BTree::InsertEntries(Transaction& transaction, Path* path, 69884bc447cShyche btrfs_entry* entries, void** data, int num) 69984bc447cShyche { 70084bc447cShyche int totalLength = sizeof(btrfs_entry) * num; 70184bc447cShyche for (int i = 0; i < num; i++) 70284bc447cShyche totalLength += entries[i].Size(); 70384bc447cShyche 70484bc447cShyche status_t slot = MakeEntries(transaction, path, entries[0].key, num, 70584bc447cShyche totalLength); 70684bc447cShyche if (slot < B_OK) 70784bc447cShyche return slot; 70884bc447cShyche 70984bc447cShyche uint32 upperLimit; 71084bc447cShyche if (slot > 0) { 71184bc447cShyche path->GetEntry(slot - 1, NULL, NULL, NULL, &upperLimit); 71284bc447cShyche } else 71384bc447cShyche upperLimit = fVolume->BlockSize() - sizeof(btrfs_header); 71484bc447cShyche 71584bc447cShyche TRACE("BTree::InsertEntries() num: %i upper limit %" B_PRIu32 "\n", num, 71684bc447cShyche upperLimit); 71784bc447cShyche for (int i = 0; i < num; i++) { 71884bc447cShyche upperLimit -= entries[i].Size(); 71984bc447cShyche entries[i].SetOffset(upperLimit); 72084bc447cShyche path->SetEntry(slot + i, entries[i], data[i]); 72184bc447cShyche } 72284bc447cShyche 72384bc447cShyche return B_OK; 72484bc447cShyche } 72584bc447cShyche 72684bc447cShyche 72720185bb9Shyche status_t 72820185bb9Shyche BTree::RemoveEntries(Transaction& transaction, Path* path, 72920185bb9Shyche const btrfs_key& startKey, void** _data, int num) 73020185bb9Shyche { 73120185bb9Shyche TRACE("BTree::RemoveEntries() num %i key (% " B_PRIu64 " %" B_PRIu8 " %" 73220185bb9Shyche B_PRIu64 ")\n", num, startKey.ObjectID(), startKey.Type(), 73320185bb9Shyche startKey.Offset()); 73420185bb9Shyche 73520185bb9Shyche status_t status = Traverse(BTREE_EXACT, path, startKey); 73620185bb9Shyche if (status < B_OK) 73720185bb9Shyche return status; 73820185bb9Shyche 73920185bb9Shyche int slot = status; 74020185bb9Shyche int length = -sizeof(btrfs_entry) * num; 74120185bb9Shyche for (int i = 0; i < num; i++) { 74220185bb9Shyche uint32 itemSize; 74320185bb9Shyche path->GetEntry(slot + i, NULL, &_data[i], &itemSize); 74420185bb9Shyche length -= itemSize; 74520185bb9Shyche } 74620185bb9Shyche 74720185bb9Shyche status = path->InternalCopy(transaction, 1); 74820185bb9Shyche if (status != B_OK) 74920185bb9Shyche return status; 75020185bb9Shyche 75120185bb9Shyche status = path->CopyOnWrite(transaction, 0, slot, num, length); 75220185bb9Shyche if (status == B_DIRECTORY_NOT_EMPTY) { 75320185bb9Shyche // TODO: merge node or push data 75420185bb9Shyche } 75520185bb9Shyche 75620185bb9Shyche return status; 75720185bb9Shyche } 75820185bb9Shyche 75920185bb9Shyche 7603216460dShyche status_t 7613216460dShyche BTree::PreviousLeaf(Path* path) const 7623216460dShyche { 7633216460dShyche // TODO: use Traverse() ??? 7643216460dShyche int level = 0; 7653216460dShyche int slot; 7663216460dShyche Node* node = NULL; 7673216460dShyche // iterate to the root until satisfy the condition 7683216460dShyche while (true) { 7693216460dShyche node = path->GetNode(level, &slot); 7703216460dShyche if (node == NULL || slot != 0) 7713216460dShyche break; 7723216460dShyche level++; 7733216460dShyche } 7743216460dShyche 7753216460dShyche // the current leaf is already the left most leaf or 7763216460dShyche // path was not initialized 7773216460dShyche if (node == NULL) 7783216460dShyche return B_ENTRY_NOT_FOUND; 7793216460dShyche 7803216460dShyche path->Move(level, BTREE_BACKWARD); 7813216460dShyche fsblock_t physicalBlock; 7823216460dShyche // change all nodes below this level and slot to the ending 7833216460dShyche do { 7843216460dShyche status_t status = fVolume->FindBlock( 7853216460dShyche node->Index(slot)->LogicalAddress(), physicalBlock); 7863216460dShyche if (status != B_OK) 7873216460dShyche return status; 7883216460dShyche 7893216460dShyche node = path->SetNode(physicalBlock, -1); 7903216460dShyche if (node == NULL) 7913216460dShyche return B_NO_MEMORY; 7923216460dShyche slot = node->ItemCount() - 1; 7933216460dShyche level--; 7943216460dShyche } while (level != 0); 7953216460dShyche 7963216460dShyche return B_OK; 7973216460dShyche } 7983216460dShyche 7993216460dShyche 8003216460dShyche status_t 8013216460dShyche BTree::NextLeaf(Path* path) const 8023216460dShyche { 8033216460dShyche int level = 0; 8043216460dShyche int slot; 8053216460dShyche Node* node = NULL; 8063216460dShyche // iterate to the root until satisfy the condition 8073216460dShyche while (true) { 8083216460dShyche node = path->GetNode(level, &slot); 8093216460dShyche if (node == NULL || slot < node->ItemCount() - 1) 8103216460dShyche break; 8113216460dShyche level++; 8123216460dShyche } 8133216460dShyche 8143216460dShyche // the current leaf is already the right most leaf or 8153216460dShyche // path was not initialized 8163216460dShyche if (node == NULL) 8173216460dShyche return B_ENTRY_NOT_FOUND; 8183216460dShyche 8193216460dShyche path->Move(level, BTREE_FORWARD); 8203216460dShyche fsblock_t physicalBlock; 8213216460dShyche // change all nodes below this level and slot to the beginning 8223216460dShyche do { 8233216460dShyche status_t status = fVolume->FindBlock( 8243216460dShyche node->Index(slot)->LogicalAddress(), physicalBlock); 8253216460dShyche if (status != B_OK) 8263216460dShyche return status; 8273216460dShyche 8283216460dShyche node = path->SetNode(physicalBlock, 0); 8293216460dShyche if (node == NULL) 8303216460dShyche return B_NO_MEMORY; 8313216460dShyche slot = 0; 8323216460dShyche level--; 8333216460dShyche } while (level != 0); 8343216460dShyche 8353216460dShyche return B_OK; 836299aba38Shyche } 837299aba38Shyche 838299aba38Shyche 839fc4a1e78Shyche status_t 840fc4a1e78Shyche BTree::SetRoot(off_t logical, fsblock_t* block) 841fc4a1e78Shyche { 842fc4a1e78Shyche if (block != NULL) { 843fc4a1e78Shyche fRootBlock = *block; 844fc4a1e78Shyche } else { 845fc4a1e78Shyche if (fVolume->FindBlock(logical, fRootBlock) != B_OK) { 846ce029df2Shyche ERROR("SetRoot() unmapped block %" B_PRId64 " %" B_PRId64 "\n", 847ce029df2Shyche logical, fRootBlock); 848fc4a1e78Shyche return B_ERROR; 849fc4a1e78Shyche } 850fc4a1e78Shyche } 851883b9bf2Shyche 852883b9bf2Shyche btrfs_header header; 853883b9bf2Shyche read_pos(fVolume->Device(), fRootBlock * fVolume->BlockSize(), &header, 854883b9bf2Shyche sizeof(btrfs_header)); 855883b9bf2Shyche fRootLevel = header.Level(); 856883b9bf2Shyche fLogicalRoot = header.LogicalAddress(); 857fc4a1e78Shyche return B_OK; 858fc4a1e78Shyche } 859fc4a1e78Shyche 860fc4a1e78Shyche 861299aba38Shyche void 862883b9bf2Shyche BTree::SetRoot(Node* root) 863883b9bf2Shyche { 864883b9bf2Shyche fRootBlock = root->BlockNum(); 865883b9bf2Shyche fLogicalRoot = root->LogicalAddress(); 866883b9bf2Shyche fRootLevel = root->Level(); 867883b9bf2Shyche } 868883b9bf2Shyche 869883b9bf2Shyche 870883b9bf2Shyche void 871299aba38Shyche BTree::_AddIterator(TreeIterator* iterator) 872299aba38Shyche { 873299aba38Shyche MutexLocker _(fIteratorLock); 874299aba38Shyche fIterators.Add(iterator); 875299aba38Shyche } 876299aba38Shyche 877299aba38Shyche 878299aba38Shyche void 879299aba38Shyche BTree::_RemoveIterator(TreeIterator* iterator) 880299aba38Shyche { 881299aba38Shyche MutexLocker _(fIteratorLock); 882299aba38Shyche fIterators.Remove(iterator); 883299aba38Shyche } 884299aba38Shyche 885299aba38Shyche 886299aba38Shyche // #pragma mark - 887299aba38Shyche 888299aba38Shyche 889bfd7a4fbShyche TreeIterator::TreeIterator(BTree* tree, const btrfs_key& key) 890299aba38Shyche : 891299aba38Shyche fTree(tree), 892bfd7a4fbShyche fKey(key), 893bfd7a4fbShyche fIteratorStatus(B_NO_INIT) 894299aba38Shyche { 895299aba38Shyche tree->_AddIterator(this); 896bfd7a4fbShyche fPath = new(std::nothrow) BTree::Path(tree); 897bfd7a4fbShyche if (fPath == NULL) 898bfd7a4fbShyche fIteratorStatus = B_NO_MEMORY; 899299aba38Shyche } 900299aba38Shyche 901299aba38Shyche 902299aba38Shyche TreeIterator::~TreeIterator() 903299aba38Shyche { 904299aba38Shyche if (fTree) 905299aba38Shyche fTree->_RemoveIterator(this); 906bfd7a4fbShyche 907bfd7a4fbShyche delete fPath; 908bfd7a4fbShyche fPath = NULL; 909bfd7a4fbShyche } 910bfd7a4fbShyche 911bfd7a4fbShyche 912bfd7a4fbShyche void 913bfd7a4fbShyche TreeIterator::Rewind(bool inverse) 914bfd7a4fbShyche { 915bfd7a4fbShyche if (inverse) 916bfd7a4fbShyche fKey.SetOffset(BTREE_END); 917bfd7a4fbShyche else 918bfd7a4fbShyche fKey.SetOffset(BTREE_BEGIN); 919bfd7a4fbShyche fIteratorStatus = B_NO_INIT; 920299aba38Shyche } 921299aba38Shyche 922299aba38Shyche 923299aba38Shyche status_t 924bfd7a4fbShyche TreeIterator::_Traverse(btree_traversing direction) 925299aba38Shyche { 926bfd7a4fbShyche status_t status = fTree->Traverse(direction, fPath, fKey); 927bfd7a4fbShyche if (status < B_OK) { 928bfd7a4fbShyche ERROR("TreeIterator::Traverse() Find failed\n"); 929bfd7a4fbShyche return status; 930299aba38Shyche } 931299aba38Shyche 932bfd7a4fbShyche return (fIteratorStatus = B_OK); 933bfd7a4fbShyche } 934bfd7a4fbShyche 935bfd7a4fbShyche 936bfd7a4fbShyche status_t 937bfd7a4fbShyche TreeIterator::_GetEntry(btree_traversing type, void** _value, uint32* _size, 938bfd7a4fbShyche uint32* _offset) 939bfd7a4fbShyche { 9405686d4e1Shyche status_t status = B_OK; 941bfd7a4fbShyche if (fIteratorStatus == B_NO_INIT) { 942bfd7a4fbShyche status = _Traverse(type); 943bfd7a4fbShyche if (status != B_OK) 944bfd7a4fbShyche return status; 945bfd7a4fbShyche type = BTREE_EXACT; 946bfd7a4fbShyche } 947bfd7a4fbShyche 948bfd7a4fbShyche if (fIteratorStatus != B_OK) 949bfd7a4fbShyche return fIteratorStatus; 950bfd7a4fbShyche 951bfd7a4fbShyche int move = fPath->Move(0, type); 952bfd7a4fbShyche if (move > 0) 953bfd7a4fbShyche status = fTree->NextLeaf(fPath); 954bfd7a4fbShyche else if (move < 0) 955bfd7a4fbShyche status = fTree->PreviousLeaf(fPath); 956bfd7a4fbShyche if (status != B_OK) 957bfd7a4fbShyche return status; 958bfd7a4fbShyche 959bfd7a4fbShyche btrfs_key found; 960bfd7a4fbShyche status = fPath->GetCurrentEntry(&found, _value, _size, _offset); 961bfd7a4fbShyche if (status != B_OK) 962bfd7a4fbShyche return status; 963bfd7a4fbShyche 964bfd7a4fbShyche fKey.SetObjectID(found.ObjectID()); 965bfd7a4fbShyche fKey.SetOffset(found.Offset()); 966bfd7a4fbShyche if (fKey.Type() != found.Type() && fKey.Type() != BTRFS_KEY_TYPE_ANY) 967bfd7a4fbShyche return B_ENTRY_NOT_FOUND; 968bfd7a4fbShyche 969299aba38Shyche return B_OK; 970299aba38Shyche } 971299aba38Shyche 972299aba38Shyche 973299aba38Shyche status_t 974bfd7a4fbShyche TreeIterator::Find(const btrfs_key& key) 975299aba38Shyche { 976bfd7a4fbShyche if (fIteratorStatus == B_INTERRUPTED) 977bfd7a4fbShyche return fIteratorStatus; 978bfd7a4fbShyche 979bfd7a4fbShyche fKey = key; 980bfd7a4fbShyche fIteratorStatus = B_NO_INIT; 981299aba38Shyche return B_OK; 982299aba38Shyche } 983299aba38Shyche 984299aba38Shyche 985299aba38Shyche void 986299aba38Shyche TreeIterator::Stop() 987299aba38Shyche { 988299aba38Shyche fTree = NULL; 989bfd7a4fbShyche fIteratorStatus = B_INTERRUPTED; 990299aba38Shyche } 991