1 // Volume.cpp 2 // 3 // Copyright (c) 2003, Ingo Weinhold (bonefish@cs.tu-berlin.de) 4 // 5 // This program is free software; you can redistribute it and/or modify 6 // it under the terms of the GNU General Public License as published by 7 // the Free Software Foundation; either version 2 of the License, or 8 // (at your option) any later version. 9 // 10 // This program is distributed in the hope that it will be useful, 11 // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 // GNU General Public License for more details. 14 // 15 // You should have received a copy of the GNU General Public License 16 // along with this program; if not, write to the Free Software 17 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 18 // 19 // You can alternatively use *this file* under the terms of the the MIT 20 // license included in this package. 21 22 #include <errno.h> 23 #include <fcntl.h> 24 #include <stdio.h> 25 #include <stdlib.h> 26 #include <string.h> 27 #include <unistd.h> 28 29 #include <vm/vm_page.h> 30 31 #include "DebugSupport.h" 32 #include "Directory.h" 33 #include "DirectoryEntryTable.h" 34 #include "Entry.h" 35 #include "EntryListener.h" 36 #include "IndexDirectory.h" 37 #include "Locking.h" 38 #include "Misc.h" 39 #include "NameIndex.h" 40 #include "Node.h" 41 #include "NodeListener.h" 42 #include "NodeTable.h" 43 #include "TwoKeyAVLTree.h" 44 #include "Volume.h" 45 46 // default volume name 47 static const char *kDefaultVolumeName = "RAM FS"; 48 49 // NodeListenerGetPrimaryKey 50 class NodeListenerGetPrimaryKey { 51 public: 52 inline Node *operator()(const NodeListenerValue &a) 53 { 54 return a.node; 55 } 56 57 inline Node *operator()(const NodeListenerValue &a) const 58 { 59 return a.node; 60 } 61 }; 62 63 // NodeListenerGetSecondaryKey 64 class NodeListenerGetSecondaryKey { 65 public: 66 inline NodeListener *operator()(const NodeListenerValue &a) 67 { 68 return a.listener; 69 } 70 71 inline NodeListener *operator()(const NodeListenerValue &a) const 72 { 73 return a.listener; 74 } 75 }; 76 77 // NodeListenerTree 78 typedef TwoKeyAVLTree<NodeListenerValue, Node*, 79 TwoKeyAVLTreeStandardCompare<Node*>, 80 NodeListenerGetPrimaryKey, NodeListener*, 81 TwoKeyAVLTreeStandardCompare<NodeListener*>, 82 NodeListenerGetSecondaryKey > _NodeListenerTree; 83 class NodeListenerTree : public _NodeListenerTree {}; 84 85 // EntryListenerGetPrimaryKey 86 class EntryListenerGetPrimaryKey { 87 public: 88 inline Entry *operator()(const EntryListenerValue &a) 89 { 90 return a.entry; 91 } 92 93 inline Entry *operator()(const EntryListenerValue &a) const 94 { 95 return a.entry; 96 } 97 }; 98 99 // EntryListenerGetSecondaryKey 100 class EntryListenerGetSecondaryKey { 101 public: 102 inline EntryListener *operator()(const EntryListenerValue &a) 103 { 104 return a.listener; 105 } 106 107 inline EntryListener *operator()(const EntryListenerValue &a) const 108 { 109 return a.listener; 110 } 111 }; 112 113 // EntryListenerTree 114 typedef TwoKeyAVLTree<EntryListenerValue, Entry*, 115 TwoKeyAVLTreeStandardCompare<Entry*>, 116 EntryListenerGetPrimaryKey, EntryListener*, 117 TwoKeyAVLTreeStandardCompare<EntryListener*>, 118 EntryListenerGetSecondaryKey > _EntryListenerTree; 119 class EntryListenerTree : public _EntryListenerTree {}; 120 121 122 /*! 123 \class Volume 124 \brief Represents a volume. 125 */ 126 127 // constructor 128 Volume::Volume(fs_volume* volume) 129 : 130 fVolume(volume), 131 fNextNodeID(kRootParentID + 1), 132 fNodeTable(NULL), 133 fDirectoryEntryTable(NULL), 134 fIndexDirectory(NULL), 135 fRootDirectory(NULL), 136 fName(kDefaultVolumeName), 137 fNodeListeners(NULL), 138 fAnyNodeListeners(), 139 fEntryListeners(NULL), 140 fAnyEntryListeners(), 141 fAccessTime(0), 142 fMounted(false) 143 { 144 rw_lock_init(&fLocker, "ramfs volume"); 145 recursive_lock_init(&fIteratorLocker, "ramfs iterators"); 146 recursive_lock_init(&fQueryLocker, "ramfs queries"); 147 } 148 149 150 // destructor 151 Volume::~Volume() 152 { 153 Unmount(); 154 155 recursive_lock_destroy(&fIteratorLocker); 156 recursive_lock_destroy(&fQueryLocker); 157 rw_lock_destroy(&fLocker); 158 } 159 160 161 // Mount 162 status_t 163 Volume::Mount(uint32 flags) 164 { 165 Unmount(); 166 167 status_t error = B_OK; 168 // create the listener trees 169 if (error == B_OK) { 170 fNodeListeners = new(nothrow) NodeListenerTree; 171 if (!fNodeListeners) 172 error = B_NO_MEMORY; 173 } 174 if (error == B_OK) { 175 fEntryListeners = new(nothrow) EntryListenerTree; 176 if (!fEntryListeners) 177 error = B_NO_MEMORY; 178 } 179 // create the node table 180 if (error == B_OK) { 181 fNodeTable = new(nothrow) NodeTable; 182 if (fNodeTable) 183 error = fNodeTable->InitCheck(); 184 else 185 SET_ERROR(error, B_NO_MEMORY); 186 } 187 // create the directory entry table 188 if (error == B_OK) { 189 fDirectoryEntryTable = new(nothrow) DirectoryEntryTable; 190 if (fDirectoryEntryTable) 191 error = fDirectoryEntryTable->InitCheck(); 192 else 193 SET_ERROR(error, B_NO_MEMORY); 194 } 195 // create the index directory 196 if (error == B_OK) { 197 fIndexDirectory = new(nothrow) IndexDirectory(this); 198 if (!fIndexDirectory) 199 SET_ERROR(error, B_NO_MEMORY); 200 } 201 // create the root dir 202 if (error == B_OK) { 203 fRootDirectory = new(nothrow) Directory(this); 204 if (fRootDirectory) { 205 // set permissions: -rwxr-xr-x 206 fRootDirectory->SetMode( 207 S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH); 208 error = PublishVNode(fRootDirectory); 209 } else 210 SET_ERROR(error, B_NO_MEMORY); 211 } 212 // set mounted flag / cleanup on error 213 if (error == B_OK) 214 fMounted = true; 215 else 216 Unmount(); 217 RETURN_ERROR(error); 218 } 219 220 // Unmount 221 status_t 222 Volume::Unmount() 223 { 224 fMounted = false; 225 // delete the root directory 226 if (fRootDirectory) { 227 // deleting the root directory destroys the complete hierarchy 228 delete fRootDirectory; 229 fRootDirectory = NULL; 230 } 231 // delete the index directory 232 if (fIndexDirectory) { 233 delete fIndexDirectory; 234 fIndexDirectory = NULL; 235 } 236 // delete the listener trees 237 if (fEntryListeners) { 238 delete fEntryListeners; 239 fEntryListeners = NULL; 240 } 241 if (fNodeListeners) { 242 delete fNodeListeners; 243 fNodeListeners = NULL; 244 } 245 // delete the tables 246 if (fDirectoryEntryTable) { 247 delete fDirectoryEntryTable; 248 fDirectoryEntryTable = NULL; 249 } 250 if (fNodeTable) { 251 delete fNodeTable; 252 fNodeTable = NULL; 253 } 254 return B_OK; 255 } 256 257 // CountBlocks 258 off_t 259 Volume::CountBlocks() const 260 { 261 // TODO: Compute how many pages we are using across all DataContainers. 262 return 0; 263 } 264 265 // CountFreeBlocks 266 off_t 267 Volume::CountFreeBlocks() const 268 { 269 return vm_page_num_free_pages(); 270 } 271 272 // SetName 273 status_t 274 Volume::SetName(const char *name) 275 { 276 status_t error = (name ? B_OK : B_BAD_VALUE); 277 if (error == B_OK) { 278 if (!fName.SetTo(name)) 279 SET_ERROR(error, B_NO_MEMORY); 280 } 281 return error; 282 } 283 284 // GetName 285 const char * 286 Volume::GetName() const 287 { 288 return fName.GetString(); 289 } 290 291 // NewVNode 292 status_t 293 Volume::NewVNode(Node *node) 294 { 295 status_t error = NodeAdded(node); 296 if (error == B_OK) { 297 error = new_vnode(FSVolume(), node->GetID(), node, &gRamFSVnodeOps); 298 if (error != B_OK) 299 NodeRemoved(node); 300 } 301 return error; 302 } 303 304 // PublishVNode 305 status_t 306 Volume::PublishVNode(Node *node) 307 { 308 status_t error = NodeAdded(node); 309 if (error == B_OK) { 310 error = publish_vnode(FSVolume(), node->GetID(), node, &gRamFSVnodeOps, 311 node->GetMode(), 0); 312 if (error != B_OK) 313 NodeRemoved(node); 314 } 315 return error; 316 } 317 318 // GetVNode 319 status_t 320 Volume::GetVNode(ino_t id, Node **node) 321 { 322 return (fMounted ? get_vnode(FSVolume(), id, (void**)node) : B_BAD_VALUE); 323 } 324 325 // GetVNode 326 status_t 327 Volume::GetVNode(Node *node) 328 { 329 Node *dummy = NULL; 330 status_t error = (fMounted ? GetVNode(node->GetID(), &dummy) 331 : B_BAD_VALUE ); 332 if (error == B_OK && dummy != node) { 333 FATAL("Two Nodes have the same ID: %" B_PRIdINO "!\n", node->GetID()); 334 PutVNode(dummy); 335 error = B_ERROR; 336 } 337 return error; 338 } 339 340 // PutVNode 341 status_t 342 Volume::PutVNode(ino_t id) 343 { 344 return (fMounted ? put_vnode(FSVolume(), id) : B_BAD_VALUE); 345 } 346 347 // PutVNode 348 status_t 349 Volume::PutVNode(Node *node) 350 { 351 return (fMounted ? put_vnode(FSVolume(), node->GetID()) : B_BAD_VALUE); 352 } 353 354 // RemoveVNode 355 status_t 356 Volume::RemoveVNode(Node *node) 357 { 358 if (fMounted) 359 return remove_vnode(FSVolume(), node->GetID()); 360 361 status_t error = NodeRemoved(node); 362 if (error == B_OK) 363 delete node; 364 return error; 365 } 366 367 // UnremoveVNode 368 status_t 369 Volume::UnremoveVNode(Node *node) 370 { 371 return (fMounted ? unremove_vnode(FSVolume(), node->GetID()) : B_BAD_VALUE); 372 } 373 374 // NodeAdded 375 status_t 376 Volume::NodeAdded(Node *node) 377 { 378 status_t error = (node ? B_OK : B_BAD_VALUE); 379 if (error == B_OK) { 380 error = fNodeTable->AddNode(node); 381 // notify listeners 382 if (error == B_OK) { 383 // listeners interested in that node 384 NodeListenerTree::Iterator it; 385 if (fNodeListeners->FindFirst(node, &it)) { 386 for (NodeListenerValue *value = it.GetCurrent(); 387 value && value->node == node; 388 value = it.GetNext()) { 389 if (value->flags & NODE_LISTEN_ADDED) 390 value->listener->NodeAdded(node); 391 } 392 } 393 // listeners interested in any node 394 int32 count = fAnyNodeListeners.CountItems(); 395 for (int32 i = 0; i < count; i++) { 396 const NodeListenerValue &value = fAnyNodeListeners.ItemAt(i); 397 if (value.flags & NODE_LISTEN_ADDED) 398 value.listener->NodeAdded(node); 399 } 400 } 401 } 402 return error; 403 } 404 405 // NodeRemoved 406 status_t 407 Volume::NodeRemoved(Node *node) 408 { 409 status_t error = (node ? B_OK : B_BAD_VALUE); 410 if (error == B_OK) { 411 error = fNodeTable->RemoveNode(node); 412 // notify listeners 413 if (error == B_OK) { 414 // listeners interested in that node 415 NodeListenerTree::Iterator it; 416 if (fNodeListeners->FindFirst(node, &it)) { 417 for (NodeListenerValue *value = it.GetCurrent(); 418 value && value->node == node; 419 value = it.GetNext()) { 420 if (value->flags & NODE_LISTEN_REMOVED) 421 value->listener->NodeRemoved(node); 422 } 423 } 424 // listeners interested in any node 425 int32 count = fAnyNodeListeners.CountItems(); 426 for (int32 i = 0; i < count; i++) { 427 const NodeListenerValue &value = fAnyNodeListeners.ItemAt(i); 428 if (value.flags & NODE_LISTEN_REMOVED) 429 value.listener->NodeRemoved(node); 430 } 431 } 432 } 433 return error; 434 } 435 436 // FindNode 437 /*! \brief Finds the node identified by a ino_t. 438 439 \note The method does not initialize the parent ID for non-directory nodes. 440 441 \param id ID of the node to be found. 442 \param node pointer to a pre-allocated Node* to be set to the found node. 443 \return \c B_OK, if everything went fine. 444 */ 445 status_t 446 Volume::FindNode(ino_t id, Node **node) 447 { 448 status_t error = (node ? B_OK : B_BAD_VALUE); 449 if (error == B_OK) { 450 *node = fNodeTable->GetNode(id); 451 if (!*node) 452 error = B_ENTRY_NOT_FOUND; 453 } 454 return error; 455 } 456 457 // AddNodeListener 458 status_t 459 Volume::AddNodeListener(NodeListener *listener, Node *node, uint32 flags) 460 { 461 // check parameters 462 if (!listener || (!node && !(flags & NODE_LISTEN_ANY_NODE)) 463 || !(flags & NODE_LISTEN_ALL)) { 464 return B_BAD_VALUE; 465 } 466 // add the listener to the right container 467 status_t error = B_OK; 468 NodeListenerValue value(listener, node, flags); 469 if (flags & NODE_LISTEN_ANY_NODE) { 470 if (!fAnyNodeListeners.AddItem(value)) 471 error = B_NO_MEMORY; 472 } else 473 error = fNodeListeners->Insert(value); 474 return error; 475 } 476 477 // RemoveNodeListener 478 status_t 479 Volume::RemoveNodeListener(NodeListener *listener, Node *node) 480 { 481 if (!listener) 482 return B_BAD_VALUE; 483 status_t error = B_OK; 484 if (node) 485 error = fNodeListeners->Remove(node, listener); 486 else { 487 NodeListenerValue value(listener, node, 0); 488 if (!fAnyNodeListeners.RemoveItem(value)) 489 error = B_ENTRY_NOT_FOUND; 490 } 491 return error; 492 } 493 494 // EntryAdded 495 status_t 496 Volume::EntryAdded(ino_t id, Entry *entry) 497 { 498 status_t error = (entry ? B_OK : B_BAD_VALUE); 499 if (error == B_OK) { 500 error = fDirectoryEntryTable->AddEntry(id, entry); 501 if (error == B_OK) { 502 // notify listeners 503 // listeners interested in that entry 504 EntryListenerTree::Iterator it; 505 if (fEntryListeners->FindFirst(entry, &it)) { 506 for (EntryListenerValue *value = it.GetCurrent(); 507 value && value->entry == entry; 508 value = it.GetNext()) { 509 if (value->flags & ENTRY_LISTEN_ADDED) 510 value->listener->EntryAdded(entry); 511 } 512 } 513 // listeners interested in any entry 514 int32 count = fAnyEntryListeners.CountItems(); 515 for (int32 i = 0; i < count; i++) { 516 const EntryListenerValue &value = fAnyEntryListeners.ItemAt(i); 517 if (value.flags & ENTRY_LISTEN_ADDED) 518 value.listener->EntryAdded(entry); 519 } 520 } 521 } 522 return error; 523 } 524 525 // EntryRemoved 526 status_t 527 Volume::EntryRemoved(ino_t id, Entry *entry) 528 { 529 status_t error = (entry ? B_OK : B_BAD_VALUE); 530 if (error == B_OK) { 531 error = fDirectoryEntryTable->RemoveEntry(id, entry); 532 if (error == B_OK) { 533 // notify listeners 534 // listeners interested in that entry 535 EntryListenerTree::Iterator it; 536 if (fEntryListeners->FindFirst(entry, &it)) { 537 for (EntryListenerValue *value = it.GetCurrent(); 538 value && value->entry == entry; 539 value = it.GetNext()) { 540 if (value->flags & ENTRY_LISTEN_REMOVED) 541 value->listener->EntryRemoved(entry); 542 } 543 } 544 // listeners interested in any entry 545 int32 count = fAnyEntryListeners.CountItems(); 546 for (int32 i = 0; i < count; i++) { 547 const EntryListenerValue &value = fAnyEntryListeners.ItemAt(i); 548 if (value.flags & ENTRY_LISTEN_REMOVED) 549 value.listener->EntryRemoved(entry); 550 } 551 } 552 } 553 return error; 554 } 555 556 // FindEntry 557 status_t 558 Volume::FindEntry(ino_t id, const char *name, Entry **entry) 559 { 560 status_t error = (entry ? B_OK : B_BAD_VALUE); 561 if (error == B_OK) { 562 *entry = fDirectoryEntryTable->GetEntry(id, name); 563 if (!*entry) 564 error = B_ENTRY_NOT_FOUND; 565 } 566 return error; 567 } 568 569 // AddEntryListener 570 status_t 571 Volume::AddEntryListener(EntryListener *listener, Entry *entry, uint32 flags) 572 { 573 // check parameters 574 if (!listener || (!entry && !(flags & ENTRY_LISTEN_ANY_ENTRY)) 575 || !(flags & ENTRY_LISTEN_ALL)) { 576 return B_BAD_VALUE; 577 } 578 // add the listener to the right container 579 status_t error = B_OK; 580 EntryListenerValue value(listener, entry, flags); 581 if (flags & ENTRY_LISTEN_ANY_ENTRY) { 582 if (!fAnyEntryListeners.AddItem(value)) 583 error = B_NO_MEMORY; 584 } else 585 error = fEntryListeners->Insert(value); 586 return error; 587 } 588 589 // RemoveEntryListener 590 status_t 591 Volume::RemoveEntryListener(EntryListener *listener, Entry *entry) 592 { 593 if (!listener) 594 return B_BAD_VALUE; 595 status_t error = B_OK; 596 if (entry) 597 error = fEntryListeners->Remove(entry, listener); 598 else { 599 EntryListenerValue value(listener, entry, 0); 600 if (!fAnyEntryListeners.RemoveItem(value)) 601 error = B_ENTRY_NOT_FOUND; 602 } 603 return error; 604 } 605 606 // NodeAttributeAdded 607 status_t 608 Volume::NodeAttributeAdded(ino_t id, Attribute *attribute) 609 { 610 status_t error = (attribute ? B_OK : B_BAD_VALUE); 611 if (error == B_OK) { 612 // notify the respective attribute index 613 if (error == B_OK) { 614 if (AttributeIndex *index = FindAttributeIndex( 615 attribute->GetName(), attribute->GetType())) { 616 index->Added(attribute); 617 } 618 } 619 } 620 return error; 621 } 622 623 // NodeAttributeRemoved 624 status_t 625 Volume::NodeAttributeRemoved(ino_t id, Attribute *attribute) 626 { 627 status_t error = (attribute ? B_OK : B_BAD_VALUE); 628 if (error == B_OK) { 629 // notify the respective attribute index 630 if (error == B_OK) { 631 if (AttributeIndex *index = FindAttributeIndex( 632 attribute->GetName(), attribute->GetType())) { 633 index->Removed(attribute); 634 } 635 } 636 637 // update live queries 638 if (error == B_OK && attribute->GetNode()) { 639 uint8 oldKey[kMaxIndexKeyLength]; 640 size_t oldLength; 641 attribute->GetKey(oldKey, &oldLength); 642 UpdateLiveQueries(NULL, attribute->GetNode(), attribute->GetName(), 643 attribute->GetType(), oldKey, oldLength, NULL, 0); 644 } 645 } 646 return error; 647 } 648 649 // GetNameIndex 650 NameIndex * 651 Volume::GetNameIndex() const 652 { 653 return (fIndexDirectory ? fIndexDirectory->GetNameIndex() : NULL); 654 } 655 656 // GetLastModifiedIndex 657 LastModifiedIndex * 658 Volume::GetLastModifiedIndex() const 659 { 660 return (fIndexDirectory ? fIndexDirectory->GetLastModifiedIndex() : NULL); 661 } 662 663 // GetSizeIndex 664 SizeIndex * 665 Volume::GetSizeIndex() const 666 { 667 return (fIndexDirectory ? fIndexDirectory->GetSizeIndex() : NULL); 668 } 669 670 // FindIndex 671 Index * 672 Volume::FindIndex(const char *name) 673 { 674 return (fIndexDirectory ? fIndexDirectory->FindIndex(name) : NULL); 675 } 676 677 // FindAttributeIndex 678 AttributeIndex * 679 Volume::FindAttributeIndex(const char *name, uint32 type) 680 { 681 return (fIndexDirectory 682 ? fIndexDirectory->FindAttributeIndex(name, type) : NULL); 683 } 684 685 // AddQuery 686 void 687 Volume::AddQuery(Query *query) 688 { 689 RecursiveLocker _(fQueryLocker); 690 691 if (query) 692 fQueries.Insert(query); 693 } 694 695 // RemoveQuery 696 void 697 Volume::RemoveQuery(Query *query) 698 { 699 RecursiveLocker _(fQueryLocker); 700 701 if (query) 702 fQueries.Remove(query); 703 } 704 705 // UpdateLiveQueries 706 void 707 Volume::UpdateLiveQueries(Entry *entry, Node* node, const char *attribute, 708 int32 type, const uint8 *oldKey, size_t oldLength, const uint8 *newKey, 709 size_t newLength) 710 { 711 RecursiveLocker _(fQueryLocker); 712 713 for (Query* query = fQueries.First(); 714 query; 715 query = fQueries.GetNext(query)) { 716 query->LiveUpdate(entry, node, attribute, type, oldKey, oldLength, 717 newKey, newLength); 718 } 719 } 720 721 // GetAllocationInfo 722 void 723 Volume::GetAllocationInfo(AllocationInfo &info) 724 { 725 // tables 726 info.AddOtherAllocation(sizeof(NodeTable)); 727 fNodeTable->GetAllocationInfo(info); 728 info.AddOtherAllocation(sizeof(DirectoryEntryTable)); 729 fDirectoryEntryTable->GetAllocationInfo(info); 730 // node hierarchy 731 fRootDirectory->GetAllocationInfo(info); 732 // name 733 info.AddStringAllocation(fName.GetLength()); 734 } 735 736 // ReadLock 737 bool 738 Volume::ReadLock() 739 { 740 bool ok = rw_lock_read_lock(&fLocker) == B_OK; 741 if (ok && fLocker.owner_count > 1) 742 fAccessTime = system_time(); 743 return ok; 744 } 745 746 // ReadUnlock 747 void 748 Volume::ReadUnlock() 749 { 750 rw_lock_read_unlock(&fLocker); 751 } 752 753 // WriteLock 754 bool 755 Volume::WriteLock() 756 { 757 bool ok = rw_lock_write_lock(&fLocker) == B_OK; 758 if (ok && fLocker.owner_count > 1) 759 fAccessTime = system_time(); 760 return ok; 761 } 762 763 // WriteUnlock 764 void 765 Volume::WriteUnlock() 766 { 767 rw_lock_write_unlock(&fLocker); 768 } 769 770 // IteratorLock 771 bool 772 Volume::IteratorLock() 773 { 774 return recursive_lock_lock(&fIteratorLocker) == B_OK; 775 } 776 777 // IteratorUnlock 778 void 779 Volume::IteratorUnlock() 780 { 781 recursive_lock_unlock(&fIteratorLocker); 782 } 783 784