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 = fRootDirectory->Link(NULL); 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 status_t error = NodeRemoved(node); 361 if (error == B_OK) 362 delete node; 363 return error; 364 } 365 366 // UnremoveVNode 367 status_t 368 Volume::UnremoveVNode(Node *node) 369 { 370 return (fMounted ? unremove_vnode(FSVolume(), node->GetID()) : B_BAD_VALUE); 371 } 372 373 // NodeAdded 374 status_t 375 Volume::NodeAdded(Node *node) 376 { 377 status_t error = (node ? B_OK : B_BAD_VALUE); 378 if (error == B_OK) { 379 error = fNodeTable->AddNode(node); 380 // notify listeners 381 if (error == B_OK) { 382 // listeners interested in that node 383 NodeListenerTree::Iterator it; 384 if (fNodeListeners->FindFirst(node, &it)) { 385 for (NodeListenerValue *value = it.GetCurrent(); 386 value && value->node == node; 387 value = it.GetNext()) { 388 if (value->flags & NODE_LISTEN_ADDED) 389 value->listener->NodeAdded(node); 390 } 391 } 392 // listeners interested in any node 393 int32 count = fAnyNodeListeners.CountItems(); 394 for (int32 i = 0; i < count; i++) { 395 const NodeListenerValue &value = fAnyNodeListeners.ItemAt(i); 396 if (value.flags & NODE_LISTEN_ADDED) 397 value.listener->NodeAdded(node); 398 } 399 } 400 } 401 return error; 402 } 403 404 // NodeRemoved 405 status_t 406 Volume::NodeRemoved(Node *node) 407 { 408 status_t error = (node ? B_OK : B_BAD_VALUE); 409 if (error == B_OK) { 410 error = fNodeTable->RemoveNode(node); 411 // notify listeners 412 if (error == B_OK) { 413 // listeners interested in that node 414 NodeListenerTree::Iterator it; 415 if (fNodeListeners->FindFirst(node, &it)) { 416 for (NodeListenerValue *value = it.GetCurrent(); 417 value && value->node == node; 418 value = it.GetNext()) { 419 if (value->flags & NODE_LISTEN_REMOVED) 420 value->listener->NodeRemoved(node); 421 } 422 } 423 // listeners interested in any node 424 int32 count = fAnyNodeListeners.CountItems(); 425 for (int32 i = 0; i < count; i++) { 426 const NodeListenerValue &value = fAnyNodeListeners.ItemAt(i); 427 if (value.flags & NODE_LISTEN_REMOVED) 428 value.listener->NodeRemoved(node); 429 } 430 } 431 } 432 return error; 433 } 434 435 // FindNode 436 /*! \brief Finds the node identified by a ino_t. 437 438 \note The method does not initialize the parent ID for non-directory nodes. 439 440 \param id ID of the node to be found. 441 \param node pointer to a pre-allocated Node* to be set to the found node. 442 \return \c B_OK, if everything went fine. 443 */ 444 status_t 445 Volume::FindNode(ino_t id, Node **node) 446 { 447 status_t error = (node ? B_OK : B_BAD_VALUE); 448 if (error == B_OK) { 449 *node = fNodeTable->GetNode(id); 450 if (!*node) 451 error = B_ENTRY_NOT_FOUND; 452 } 453 return error; 454 } 455 456 // AddNodeListener 457 status_t 458 Volume::AddNodeListener(NodeListener *listener, Node *node, uint32 flags) 459 { 460 // check parameters 461 if (!listener || (!node && !(flags & NODE_LISTEN_ANY_NODE)) 462 || !(flags & NODE_LISTEN_ALL)) { 463 return B_BAD_VALUE; 464 } 465 // add the listener to the right container 466 status_t error = B_OK; 467 NodeListenerValue value(listener, node, flags); 468 if (flags & NODE_LISTEN_ANY_NODE) { 469 if (!fAnyNodeListeners.AddItem(value)) 470 error = B_NO_MEMORY; 471 } else 472 error = fNodeListeners->Insert(value); 473 return error; 474 } 475 476 // RemoveNodeListener 477 status_t 478 Volume::RemoveNodeListener(NodeListener *listener, Node *node) 479 { 480 if (!listener) 481 return B_BAD_VALUE; 482 status_t error = B_OK; 483 if (node) 484 error = fNodeListeners->Remove(node, listener); 485 else { 486 NodeListenerValue value(listener, node, 0); 487 if (!fAnyNodeListeners.RemoveItem(value)) 488 error = B_ENTRY_NOT_FOUND; 489 } 490 return error; 491 } 492 493 // EntryAdded 494 status_t 495 Volume::EntryAdded(ino_t id, Entry *entry) 496 { 497 status_t error = (entry ? B_OK : B_BAD_VALUE); 498 if (error == B_OK) { 499 error = fDirectoryEntryTable->AddEntry(id, entry); 500 if (error == B_OK) { 501 // notify listeners 502 // listeners interested in that entry 503 EntryListenerTree::Iterator it; 504 if (fEntryListeners->FindFirst(entry, &it)) { 505 for (EntryListenerValue *value = it.GetCurrent(); 506 value && value->entry == entry; 507 value = it.GetNext()) { 508 if (value->flags & ENTRY_LISTEN_ADDED) 509 value->listener->EntryAdded(entry); 510 } 511 } 512 // listeners interested in any entry 513 int32 count = fAnyEntryListeners.CountItems(); 514 for (int32 i = 0; i < count; i++) { 515 const EntryListenerValue &value = fAnyEntryListeners.ItemAt(i); 516 if (value.flags & ENTRY_LISTEN_ADDED) 517 value.listener->EntryAdded(entry); 518 } 519 } 520 } 521 return error; 522 } 523 524 // EntryRemoved 525 status_t 526 Volume::EntryRemoved(ino_t id, Entry *entry) 527 { 528 status_t error = (entry ? B_OK : B_BAD_VALUE); 529 if (error == B_OK) { 530 error = fDirectoryEntryTable->RemoveEntry(id, entry); 531 if (error == B_OK) { 532 // notify listeners 533 // listeners interested in that entry 534 EntryListenerTree::Iterator it; 535 if (fEntryListeners->FindFirst(entry, &it)) { 536 for (EntryListenerValue *value = it.GetCurrent(); 537 value && value->entry == entry; 538 value = it.GetNext()) { 539 if (value->flags & ENTRY_LISTEN_REMOVED) 540 value->listener->EntryRemoved(entry); 541 } 542 } 543 // listeners interested in any entry 544 int32 count = fAnyEntryListeners.CountItems(); 545 for (int32 i = 0; i < count; i++) { 546 const EntryListenerValue &value = fAnyEntryListeners.ItemAt(i); 547 if (value.flags & ENTRY_LISTEN_REMOVED) 548 value.listener->EntryRemoved(entry); 549 } 550 } 551 } 552 return error; 553 } 554 555 // FindEntry 556 status_t 557 Volume::FindEntry(ino_t id, const char *name, Entry **entry) 558 { 559 status_t error = (entry ? B_OK : B_BAD_VALUE); 560 if (error == B_OK) { 561 *entry = fDirectoryEntryTable->GetEntry(id, name); 562 if (!*entry) 563 error = B_ENTRY_NOT_FOUND; 564 } 565 return error; 566 } 567 568 // AddEntryListener 569 status_t 570 Volume::AddEntryListener(EntryListener *listener, Entry *entry, uint32 flags) 571 { 572 // check parameters 573 if (!listener || (!entry && !(flags & ENTRY_LISTEN_ANY_ENTRY)) 574 || !(flags & ENTRY_LISTEN_ALL)) { 575 return B_BAD_VALUE; 576 } 577 // add the listener to the right container 578 status_t error = B_OK; 579 EntryListenerValue value(listener, entry, flags); 580 if (flags & ENTRY_LISTEN_ANY_ENTRY) { 581 if (!fAnyEntryListeners.AddItem(value)) 582 error = B_NO_MEMORY; 583 } else 584 error = fEntryListeners->Insert(value); 585 return error; 586 } 587 588 // RemoveEntryListener 589 status_t 590 Volume::RemoveEntryListener(EntryListener *listener, Entry *entry) 591 { 592 if (!listener) 593 return B_BAD_VALUE; 594 status_t error = B_OK; 595 if (entry) 596 error = fEntryListeners->Remove(entry, listener); 597 else { 598 EntryListenerValue value(listener, entry, 0); 599 if (!fAnyEntryListeners.RemoveItem(value)) 600 error = B_ENTRY_NOT_FOUND; 601 } 602 return error; 603 } 604 605 // NodeAttributeAdded 606 status_t 607 Volume::NodeAttributeAdded(ino_t id, Attribute *attribute) 608 { 609 status_t error = (attribute ? B_OK : B_BAD_VALUE); 610 if (error == B_OK) { 611 // notify the respective attribute index 612 if (error == B_OK) { 613 if (AttributeIndex *index = FindAttributeIndex( 614 attribute->GetName(), attribute->GetType())) { 615 index->Added(attribute); 616 } 617 } 618 } 619 return error; 620 } 621 622 // NodeAttributeRemoved 623 status_t 624 Volume::NodeAttributeRemoved(ino_t id, Attribute *attribute) 625 { 626 status_t error = (attribute ? B_OK : B_BAD_VALUE); 627 if (error == B_OK) { 628 // notify the respective attribute index 629 if (error == B_OK) { 630 if (AttributeIndex *index = FindAttributeIndex( 631 attribute->GetName(), attribute->GetType())) { 632 index->Removed(attribute); 633 } 634 } 635 636 // update live queries 637 if (error == B_OK && attribute->GetNode()) { 638 uint8 oldKey[kMaxIndexKeyLength]; 639 size_t oldLength; 640 attribute->GetKey(oldKey, &oldLength); 641 UpdateLiveQueries(NULL, attribute->GetNode(), attribute->GetName(), 642 attribute->GetType(), oldKey, oldLength, NULL, 0); 643 } 644 } 645 return error; 646 } 647 648 // GetNameIndex 649 NameIndex * 650 Volume::GetNameIndex() const 651 { 652 return (fIndexDirectory ? fIndexDirectory->GetNameIndex() : NULL); 653 } 654 655 // GetLastModifiedIndex 656 LastModifiedIndex * 657 Volume::GetLastModifiedIndex() const 658 { 659 return (fIndexDirectory ? fIndexDirectory->GetLastModifiedIndex() : NULL); 660 } 661 662 // GetSizeIndex 663 SizeIndex * 664 Volume::GetSizeIndex() const 665 { 666 return (fIndexDirectory ? fIndexDirectory->GetSizeIndex() : NULL); 667 } 668 669 // FindIndex 670 Index * 671 Volume::FindIndex(const char *name) 672 { 673 return (fIndexDirectory ? fIndexDirectory->FindIndex(name) : NULL); 674 } 675 676 // FindAttributeIndex 677 AttributeIndex * 678 Volume::FindAttributeIndex(const char *name, uint32 type) 679 { 680 return (fIndexDirectory 681 ? fIndexDirectory->FindAttributeIndex(name, type) : NULL); 682 } 683 684 // AddQuery 685 void 686 Volume::AddQuery(Query *query) 687 { 688 RecursiveLocker _(fQueryLocker); 689 690 if (query) 691 fQueries.Insert(query); 692 } 693 694 // RemoveQuery 695 void 696 Volume::RemoveQuery(Query *query) 697 { 698 RecursiveLocker _(fQueryLocker); 699 700 if (query) 701 fQueries.Remove(query); 702 } 703 704 // UpdateLiveQueries 705 void 706 Volume::UpdateLiveQueries(Entry *entry, Node* node, const char *attribute, 707 int32 type, const uint8 *oldKey, size_t oldLength, const uint8 *newKey, 708 size_t newLength) 709 { 710 RecursiveLocker _(fQueryLocker); 711 712 for (Query* query = fQueries.First(); 713 query; 714 query = fQueries.GetNext(query)) { 715 query->LiveUpdate(entry, node, attribute, type, oldKey, oldLength, 716 newKey, newLength); 717 } 718 } 719 720 // GetAllocationInfo 721 void 722 Volume::GetAllocationInfo(AllocationInfo &info) 723 { 724 // tables 725 info.AddOtherAllocation(sizeof(NodeTable)); 726 fNodeTable->GetAllocationInfo(info); 727 info.AddOtherAllocation(sizeof(DirectoryEntryTable)); 728 fDirectoryEntryTable->GetAllocationInfo(info); 729 // node hierarchy 730 fRootDirectory->GetAllocationInfo(info); 731 // name 732 info.AddStringAllocation(fName.GetLength()); 733 } 734 735 // ReadLock 736 bool 737 Volume::ReadLock() 738 { 739 bool ok = rw_lock_read_lock(&fLocker) == B_OK; 740 if (ok && fLocker.owner_count > 1) 741 fAccessTime = system_time(); 742 return ok; 743 } 744 745 // ReadUnlock 746 void 747 Volume::ReadUnlock() 748 { 749 rw_lock_read_unlock(&fLocker); 750 } 751 752 // WriteLock 753 bool 754 Volume::WriteLock() 755 { 756 bool ok = rw_lock_write_lock(&fLocker) == B_OK; 757 if (ok && fLocker.owner_count > 1) 758 fAccessTime = system_time(); 759 return ok; 760 } 761 762 // WriteUnlock 763 void 764 Volume::WriteUnlock() 765 { 766 rw_lock_write_unlock(&fLocker); 767 } 768 769 // IteratorLock 770 bool 771 Volume::IteratorLock() 772 { 773 return recursive_lock_lock(&fIteratorLocker) == B_OK; 774 } 775 776 // IteratorUnlock 777 void 778 Volume::IteratorUnlock() 779 { 780 recursive_lock_unlock(&fIteratorLocker); 781 } 782 783