1 /* 2 * Copyright 2001-2009, Ingo Weinhold, ingo_weinhold@gmx.de. 3 * Distributed under the terms of the MIT License. 4 */ 5 6 #include "Volume.h" 7 8 #include <errno.h> 9 #include <string.h> 10 #include <unistd.h> 11 #include <sys/stat.h> 12 13 #include <algorithm> 14 15 #include <fs_cache.h> 16 17 #include <util/AutoLock.h> 18 #include <util/OpenHashTable.h> 19 20 #include <fs/fd.h> // kernel private 21 #include <io_requests.h> 22 #include <thread.h> 23 24 #include "IORequest.h" // kernel internal 25 26 #include "Compatibility.h" 27 #include "Debug.h" 28 #include "FileSystem.h" 29 #include "IOCtlInfo.h" 30 #include "kernel_interface.h" 31 #include "KernelRequestHandler.h" 32 #include "PortReleaser.h" 33 #include "RequestAllocator.h" 34 #include "RequestPort.h" 35 #include "Requests.h" 36 #include "userlandfs_ioctl.h" 37 38 // missing ioctl()s 39 // TODO: Place somewhere else. 40 #define IOCTL_FILE_UNCACHED_IO 10000 41 #define IOCTL_CREATE_TIME 10002 42 #define IOCTL_MODIFIED_TIME 10003 43 44 // If a thread of the userland server enters userland FS kernel code and 45 // is sending a request, this is the time after which it shall time out 46 // waiting for a reply. 47 static const bigtime_t kUserlandServerlandPortTimeout = 10000000; // 10s 48 49 50 // VNode 51 struct Volume::VNode { 52 ino_t id; 53 void* clientNode; 54 void* fileCache; 55 VNodeOps* ops; 56 int32 useCount; 57 bool valid; 58 bool published; 59 VNode* hash_link; 60 61 VNode(ino_t id, void* clientNode, VNodeOps* ops) 62 : 63 id(id), 64 clientNode(clientNode), 65 fileCache(NULL), 66 ops(ops), 67 useCount(0), 68 valid(true), 69 published(true) 70 { 71 } 72 73 void Delete(Volume* volume) 74 { 75 if (ops != NULL) 76 volume->GetFileSystem()->PutVNodeOps(ops); 77 delete this; 78 } 79 80 protected: // should be private, but gcc 2.95.3 issues a warning 81 ~VNode() 82 { 83 if (fileCache != NULL) 84 { 85 ERROR(("VNode %lld still has a file cache!\n", id)); 86 file_cache_delete(fileCache); 87 } 88 } 89 }; 90 91 92 // VNodeHashDefinition 93 struct Volume::VNodeHashDefinition { 94 typedef ino_t KeyType; 95 typedef VNode ValueType; 96 97 size_t HashKey(ino_t key) const 98 { return (uint32)key ^ (uint32)(key >> 32); } 99 size_t Hash(const VNode* value) const 100 { return HashKey(value->id); } 101 bool Compare(ino_t key, const VNode* value) const 102 { return value->id == key; } 103 VNode*& GetLink(VNode* value) const 104 { return value->hash_link; } 105 }; 106 107 108 // VNodeMap 109 struct Volume::VNodeMap 110 : public BOpenHashTable<VNodeHashDefinition> { 111 }; 112 113 114 // IORequestInfo 115 struct Volume::IORequestInfo { 116 io_request* request; 117 int32 id; 118 119 IORequestInfo* idLink; 120 IORequestInfo* structLink; 121 122 IORequestInfo(io_request* request, int32 id) 123 : 124 request(request), 125 id(id) 126 { 127 } 128 }; 129 130 131 // IORequestIDHashDefinition 132 struct Volume::IORequestIDHashDefinition { 133 typedef int32 KeyType; 134 typedef IORequestInfo ValueType; 135 136 size_t HashKey(int32 key) const 137 { return key; } 138 size_t Hash(const IORequestInfo* value) const 139 { return HashKey(value->id); } 140 bool Compare(int32 key, const IORequestInfo* value) const 141 { return value->id == key; } 142 IORequestInfo*& GetLink(IORequestInfo* value) const 143 { return value->idLink; } 144 }; 145 146 147 // IORequestStructHashDefinition 148 struct Volume::IORequestStructHashDefinition { 149 typedef io_request* KeyType; 150 typedef IORequestInfo ValueType; 151 152 size_t HashKey(io_request* key) const 153 { return (size_t)(addr_t)key; } 154 size_t Hash(const IORequestInfo* value) const 155 { return HashKey(value->request); } 156 bool Compare(io_request* key, const IORequestInfo* value) const 157 { return value->request == key; } 158 IORequestInfo*& GetLink(IORequestInfo* value) const 159 { return value->structLink; } 160 }; 161 162 163 // IORequestIDMap 164 struct Volume::IORequestIDMap 165 : public BOpenHashTable<IORequestIDHashDefinition> { 166 }; 167 168 169 // IORequestStructMap 170 struct Volume::IORequestStructMap 171 : public BOpenHashTable<IORequestStructHashDefinition> { 172 }; 173 174 175 // IterativeFDIOCookie 176 struct Volume::IterativeFDIOCookie : public Referenceable { 177 Volume* volume; 178 int fd; 179 int32 requestID; 180 void* clientCookie; 181 off_t offset; 182 const file_io_vec* vecs; 183 uint32 vecCount; 184 185 IterativeFDIOCookie(Volume* volume, int fd, int32 requestID, 186 void* clientCookie, off_t offset, const file_io_vec* vecs, 187 uint32 vecCount) 188 : 189 volume(volume), 190 fd(fd), 191 requestID(requestID), 192 clientCookie(clientCookie), 193 offset(offset), 194 vecs(vecs), 195 vecCount(vecCount) 196 { 197 } 198 199 ~IterativeFDIOCookie() 200 { 201 if (fd >= 0) 202 close(fd); 203 } 204 }; 205 206 207 // AutoIncrementer 208 class Volume::AutoIncrementer { 209 public: 210 AutoIncrementer(vint32* variable) 211 : fVariable(variable) 212 { 213 if (fVariable) 214 atomic_add(fVariable, 1); 215 } 216 217 ~AutoIncrementer() 218 { 219 if (fVariable) 220 atomic_add(fVariable, -1); 221 } 222 223 void Keep() 224 { 225 fVariable = NULL; 226 } 227 228 private: 229 vint32* fVariable; 230 }; 231 232 233 // IORequestRemover 234 class Volume::IORequestRemover { 235 public: 236 IORequestRemover(Volume* volume, int32 requestID) 237 : 238 fVolume(volume), 239 fRequestID(requestID) 240 { 241 } 242 243 ~IORequestRemover() 244 { 245 if (fVolume != NULL) 246 fVolume->_UnregisterIORequest(fRequestID); 247 } 248 249 void Detach() 250 { 251 fVolume = NULL; 252 } 253 254 private: 255 Volume* fVolume; 256 int32 fRequestID; 257 }; 258 259 260 // VNodeRemover 261 class Volume::VNodeRemover { 262 public: 263 VNodeRemover(Volume* volume, VNode* node) 264 : 265 fVolume(volume), 266 fNode(node) 267 { 268 } 269 270 ~VNodeRemover() 271 { 272 if (fNode != NULL) { 273 MutexLocker locker(fVolume->fLock); 274 fVolume->fVNodes->Remove(fNode); 275 locker.Unlock(); 276 277 fNode->Delete(fVolume); 278 } 279 } 280 281 private: 282 Volume* fVolume; 283 VNode* fNode; 284 }; 285 286 287 // HasVNodeCapability 288 inline bool 289 Volume::HasVNodeCapability(VNode* vnode, int capability) const 290 { 291 return vnode->ops->capabilities.Get(capability); 292 } 293 294 295 // constructor 296 Volume::Volume(FileSystem* fileSystem, fs_volume* fsVolume) 297 : 298 Referenceable(true), 299 fFileSystem(fileSystem), 300 fFSVolume(fsVolume), 301 fUserlandVolume(NULL), 302 fRootID(0), 303 fRootNode(NULL), 304 fOpenFiles(0), 305 fOpenDirectories(0), 306 fOpenAttributeDirectories(0), 307 fOpenAttributes(0), 308 fOpenIndexDirectories(0), 309 fOpenQueries(0), 310 fVNodes(NULL), 311 fIORequestInfosByID(NULL), 312 fIORequestInfosByStruct(NULL), 313 fLastIORequestID(0), 314 fVNodeCountingEnabled(false) 315 { 316 mutex_init(&fLock, "userlandfs volume"); 317 } 318 319 320 // destructor 321 Volume::~Volume() 322 { 323 mutex_destroy(&fLock); 324 325 delete fIORequestInfosByID; 326 delete fIORequestInfosByStruct; 327 delete fVNodes; 328 } 329 330 331 // #pragma mark - client methods 332 333 // GetVNode 334 status_t 335 Volume::GetVNode(ino_t vnid, void** _node) 336 { 337 PRINT(("get_vnode(%ld, %lld)\n", GetID(), vnid)); 338 void* vnode; 339 status_t error = get_vnode(fFSVolume, vnid, &vnode); 340 if (error == B_OK) { 341 _IncrementVNodeCount(vnid); 342 *_node = ((VNode*)vnode)->clientNode; 343 } 344 345 return error; 346 } 347 348 // PutVNode 349 status_t 350 Volume::PutVNode(ino_t vnid) 351 { 352 PRINT(("put_vnode(%ld, %lld)\n", GetID(), vnid)); 353 // Decrement the count first. We might not have another chance, since 354 // put_vnode() could put the last reference, thus causing the node to be 355 // removed from our map. This is all not very dramatic, but this way we 356 // avoid an erroneous error message from _DecrementVNodeCount(). 357 _DecrementVNodeCount(vnid); 358 359 return put_vnode(fFSVolume, vnid); 360 } 361 362 363 // AcquireVNode 364 status_t 365 Volume::AcquireVNode(ino_t vnid) 366 { 367 PRINT(("acquire_vnode(%ld, %lld)\n", GetID(), vnid)); 368 status_t error = acquire_vnode(fFSVolume, vnid); 369 if (error == B_OK) 370 _IncrementVNodeCount(vnid); 371 return error; 372 } 373 374 375 // NewVNode 376 status_t 377 Volume::NewVNode(ino_t vnid, void* clientNode, 378 const FSVNodeCapabilities& capabilities) 379 { 380 PRINT(("new_vnode(%ld, %lld)\n", GetID(), vnid)); 381 // lookup the node 382 MutexLocker locker(fLock); 383 VNode* node = fVNodes->Lookup(vnid); 384 if (node != NULL) { 385 // The node is already known -- this is an error. 386 RETURN_ERROR(B_BAD_VALUE); 387 } 388 389 // get the ops vector for the node 390 VNodeOps* ops = fFileSystem->GetVNodeOps(capabilities); 391 if (ops == NULL) 392 RETURN_ERROR(B_NO_MEMORY); 393 394 // create the node 395 node = new(std::nothrow) VNode(vnid, clientNode, ops); 396 if (node == NULL) { 397 fFileSystem->PutVNodeOps(ops); 398 RETURN_ERROR(B_NO_MEMORY); 399 } 400 401 node->published = false; 402 403 locker.Unlock(); 404 405 // tell the VFS 406 status_t error = new_vnode(fFSVolume, vnid, node, node->ops->ops); 407 if (error != B_OK) { 408 node->Delete(this); 409 RETURN_ERROR(error); 410 } 411 412 // add the node to our map 413 locker.Lock(); 414 fVNodes->Insert(node); 415 416 // Increment its use count. After new_vnode() the caller has a reference, 417 // but a subsequent publish_vnode() won't get another one. We handle that 418 // there. 419 if (fVNodeCountingEnabled) 420 node->useCount++; 421 422 return B_OK; 423 } 424 425 // PublishVNode 426 status_t 427 Volume::PublishVNode(ino_t vnid, void* clientNode, int type, uint32 flags, 428 const FSVNodeCapabilities& capabilities) 429 { 430 PRINT(("publish_vnode(%ld, %lld, %p)\n", GetID(), vnid, clientNode)); 431 // lookup the node 432 MutexLocker locker(fLock); 433 VNode* node = fVNodes->Lookup(vnid); 434 bool nodeKnown = node != NULL; 435 436 if (nodeKnown) { 437 if (node->published) { 438 WARN(("publish_vnode(): vnode (%ld, %lld) already published!\n", 439 GetID(), vnid)); 440 RETURN_ERROR(B_BAD_VALUE); 441 } 442 } else if (!nodeKnown) { 443 // The node is not yet known -- create it. 444 445 // get the ops vector for the node 446 VNodeOps* ops = fFileSystem->GetVNodeOps(capabilities); 447 if (ops == NULL) 448 RETURN_ERROR(B_NO_MEMORY); 449 450 // create the node 451 node = new(std::nothrow) VNode(vnid, clientNode, ops); 452 if (node == NULL) { 453 fFileSystem->PutVNodeOps(ops); 454 RETURN_ERROR(B_NO_MEMORY); 455 } 456 } 457 458 locker.Unlock(); 459 460 // tell the VFS 461 status_t error = publish_vnode(fFSVolume, vnid, node, node->ops->ops, 462 type, flags); 463 if (error != B_OK) { 464 if (nodeKnown) { 465 // The node was known, i.e. it had been made known via new_vnode() 466 // and thus already had a use count of 1. Decrement that use count 467 // and remove the node completely. 468 _DecrementVNodeCount(vnid); 469 _RemoveInvalidVNode(vnid); 470 } else 471 node->Delete(this); 472 RETURN_ERROR(error); 473 } 474 475 // add the node to our map, if not known yet 476 locker.Lock(); 477 if (nodeKnown) { 478 // The node is now published. Don't increment its use count. It already 479 // has 1 from new_vnode() and this publish_vnode() didn't increment it. 480 node->published = true; 481 } else { 482 // New node: increment its use count and add it to the map. 483 if (fVNodeCountingEnabled) 484 node->useCount++; 485 fVNodes->Insert(node); 486 } 487 488 return B_OK; 489 } 490 491 // RemoveVNode 492 status_t 493 Volume::RemoveVNode(ino_t vnid) 494 { 495 PRINT(("remove_vnode(%ld, %lld)\n", GetID(), vnid)); 496 return remove_vnode(fFSVolume, vnid); 497 } 498 499 // UnremoveVNode 500 status_t 501 Volume::UnremoveVNode(ino_t vnid) 502 { 503 PRINT(("unremove_vnode(%ld, %lld)\n", GetID(), vnid)); 504 return unremove_vnode(fFSVolume, vnid); 505 } 506 507 // GetVNodeRemoved 508 status_t 509 Volume::GetVNodeRemoved(ino_t vnid, bool* removed) 510 { 511 PRINT(("get_vnode_removed(%ld, %lld, %p)\n", GetID(), vnid, removed)); 512 return get_vnode_removed(fFSVolume, vnid, removed); 513 } 514 515 516 // CreateFileCache 517 status_t 518 Volume::CreateFileCache(ino_t vnodeID, off_t size) 519 { 520 // lookup the node 521 MutexLocker locker(fLock); 522 VNode* vnode = fVNodes->Lookup(vnodeID); 523 if (vnode == NULL) 524 RETURN_ERROR(B_BAD_VALUE); 525 526 // does the node already have a file cache? 527 if (vnode->fileCache != NULL) 528 RETURN_ERROR(B_BAD_VALUE); 529 530 // create the file cache 531 locker.Unlock(); 532 void* fileCache = file_cache_create(GetID(), vnodeID, size); 533 locker.Lock(); 534 535 // re-check whether the node still lives 536 vnode = fVNodes->Lookup(vnodeID); 537 if (vnode == NULL) { 538 file_cache_delete(fileCache); 539 RETURN_ERROR(B_BAD_VALUE); 540 } 541 542 vnode->fileCache = fileCache; 543 544 return B_OK; 545 } 546 547 548 // DeleteFileCache 549 status_t 550 Volume::DeleteFileCache(ino_t vnodeID) 551 { 552 // lookup the node 553 MutexLocker locker(fLock); 554 VNode* vnode = fVNodes->Lookup(vnodeID); 555 if (vnode == NULL) 556 RETURN_ERROR(B_BAD_VALUE); 557 558 // does the node have a file cache 559 if (vnode->fileCache == NULL) 560 RETURN_ERROR(B_BAD_VALUE); 561 562 void* fileCache = vnode->fileCache; 563 vnode->fileCache = NULL; 564 565 locker.Unlock(); 566 567 file_cache_delete(fileCache); 568 569 return B_OK; 570 } 571 572 573 // SetFileCacheEnabled 574 status_t 575 Volume::SetFileCacheEnabled(ino_t vnodeID, bool enabled) 576 { 577 // lookup the node 578 MutexLocker locker(fLock); 579 VNode* vnode = fVNodes->Lookup(vnodeID); 580 if (vnode == NULL) 581 RETURN_ERROR(B_BAD_VALUE); 582 583 // does the node have a file cache 584 if (vnode->fileCache == NULL) 585 RETURN_ERROR(B_BAD_VALUE); 586 587 void* fileCache = vnode->fileCache; 588 locker.Unlock(); 589 // TODO: We should use some kind of ref counting to avoid that another thread 590 // deletes the file cache now that we have dropped the lock. Applies to the 591 // other file cache operations as well. 592 593 // enable/disable the file cache 594 if (enabled) { 595 file_cache_enable(fileCache); 596 return B_OK; 597 } 598 599 return file_cache_disable(fileCache); 600 } 601 602 603 // SetFileCacheSize 604 status_t 605 Volume::SetFileCacheSize(ino_t vnodeID, off_t size) 606 { 607 // lookup the node 608 MutexLocker locker(fLock); 609 VNode* vnode = fVNodes->Lookup(vnodeID); 610 if (vnode == NULL) 611 RETURN_ERROR(B_BAD_VALUE); 612 613 // does the node have a file cache 614 if (vnode->fileCache == NULL) 615 RETURN_ERROR(B_BAD_VALUE); 616 617 void* fileCache = vnode->fileCache; 618 locker.Unlock(); 619 620 // set the size 621 return file_cache_set_size(fileCache, size); 622 } 623 624 625 // SyncFileCache 626 status_t 627 Volume::SyncFileCache(ino_t vnodeID) 628 { 629 // lookup the node 630 MutexLocker locker(fLock); 631 VNode* vnode = fVNodes->Lookup(vnodeID); 632 if (vnode == NULL) 633 RETURN_ERROR(B_BAD_VALUE); 634 635 // does the node have a file cache 636 if (vnode->fileCache == NULL) 637 RETURN_ERROR(B_BAD_VALUE); 638 639 void* fileCache = vnode->fileCache; 640 locker.Unlock(); 641 642 // sync 643 return file_cache_sync(fileCache); 644 } 645 646 647 // ReadFileCache 648 status_t 649 Volume::ReadFileCache(ino_t vnodeID, void* cookie, 650 off_t offset, void* buffer, size_t* _size) 651 { 652 // lookup the node 653 MutexLocker locker(fLock); 654 VNode* vnode = fVNodes->Lookup(vnodeID); 655 if (vnode == NULL) 656 RETURN_ERROR(B_BAD_VALUE); 657 658 // does the node have a file cache 659 if (vnode->fileCache == NULL) 660 RETURN_ERROR(B_BAD_VALUE); 661 662 void* fileCache = vnode->fileCache; 663 locker.Unlock(); 664 665 // read 666 return file_cache_read(fileCache, cookie, offset, buffer, _size); 667 } 668 669 670 // WriteFileCache 671 status_t 672 Volume::WriteFileCache(ino_t vnodeID, void* cookie, 673 off_t offset, const void* buffer, size_t* _size) 674 { 675 // lookup the node 676 MutexLocker locker(fLock); 677 VNode* vnode = fVNodes->Lookup(vnodeID); 678 if (vnode == NULL) 679 RETURN_ERROR(B_BAD_VALUE); 680 681 // does the node have a file cache 682 if (vnode->fileCache == NULL) 683 RETURN_ERROR(B_BAD_VALUE); 684 685 void* fileCache = vnode->fileCache; 686 locker.Unlock(); 687 688 // read 689 return file_cache_write(fileCache, cookie, offset, buffer, _size); 690 } 691 692 693 status_t 694 Volume::ReadFromIORequest(int32 requestID, void* buffer, size_t size) 695 { 696 // get the request 697 io_request* request; 698 status_t error = _FindIORequest(requestID, &request); 699 if (error != B_OK) 700 RETURN_ERROR(error); 701 702 return read_from_io_request(request, buffer, size); 703 } 704 705 706 status_t 707 Volume::WriteToIORequest(int32 requestID, const void* buffer, size_t size) 708 { 709 // get the request 710 io_request* request; 711 status_t error = _FindIORequest(requestID, &request); 712 if (error != B_OK) 713 RETURN_ERROR(error); 714 715 return write_to_io_request(request, buffer, size); 716 } 717 718 719 // DoIterativeFDIO 720 status_t 721 Volume::DoIterativeFDIO(int fd, int32 requestID, void* clientCookie, 722 const file_io_vec* vecs, uint32 vecCount) 723 { 724 // get the request 725 io_request* request; 726 status_t error = _FindIORequest(requestID, &request); 727 if (error != B_OK) 728 RETURN_ERROR(error); 729 730 // copy the FD into the kernel 731 fd = dup_foreign_fd(fFileSystem->GetTeam(), fd, true); 732 if (fd < 0) 733 RETURN_ERROR(fd); 734 735 // create a cookie 736 IterativeFDIOCookie* cookie = new(std::nothrow) IterativeFDIOCookie( 737 this, fd, requestID, clientCookie, request->Offset(), vecs, vecCount); 738 if (cookie == NULL) { 739 close(fd); 740 RETURN_ERROR(B_NO_MEMORY); 741 } 742 743 // we need another reference, so we can still access the cookie below 744 cookie->AddReference(); 745 746 // TODO: Up to this point we're responsible for calling the finished hook on 747 // error! 748 // call the kernel function 749 error = do_iterative_fd_io(fd, request, &_IterativeFDIOGetVecs, 750 &_IterativeFDIOFinished, cookie); 751 752 // unset the vecs -- they are on the stack an will become invalid when we 753 // return 754 MutexLocker _(fLock); 755 cookie->vecs = NULL; 756 cookie->vecCount = 0; 757 cookie->RemoveReference(); 758 759 return error; 760 } 761 762 763 status_t 764 Volume::NotifyIORequest(int32 requestID, status_t status) 765 { 766 // get the request 767 io_request* request; 768 status_t error = _FindIORequest(requestID, &request); 769 if (error != B_OK) 770 RETURN_ERROR(error); 771 772 notify_io_request(request, status); 773 return B_OK; 774 } 775 776 777 // #pragma mark - FS 778 779 780 // Mount 781 status_t 782 Volume::Mount(const char* device, uint32 flags, const char* parameters) 783 { 784 // create the maps 785 fVNodes = new(std::nothrow) VNodeMap; 786 fIORequestInfosByID = new(std::nothrow) IORequestIDMap; 787 fIORequestInfosByStruct = new(std::nothrow) IORequestStructMap; 788 789 if (fVNodes == NULL || fIORequestInfosByID == NULL 790 || fIORequestInfosByStruct == NULL 791 || fVNodes->Init() != B_OK 792 || fIORequestInfosByID->Init() != B_OK 793 || fIORequestInfosByStruct->Init() != B_OK) { 794 return B_NO_MEMORY; 795 } 796 797 // enable vnode counting 798 fVNodeCountingEnabled = true; 799 800 // init IORequest ID's 801 fLastIORequestID = 0; 802 803 // mount 804 status_t error = _Mount(device, flags, parameters); 805 if (error != B_OK) 806 RETURN_ERROR(error); 807 808 MutexLocker locker(fLock); 809 // fetch the root node, so that we can serve Walk() requests on it, 810 // after the connection to the userland server is gone 811 fRootNode = fVNodes->Lookup(fRootID); 812 if (fRootNode == NULL) { 813 // The root node was not added while mounting. That's a serious 814 // problem -- not only because we don't have it, but also because 815 // the VFS requires publish_vnode() to be invoked for the root node. 816 ERROR(("Volume::Mount(): new_vnode() was not called for root node! " 817 "Unmounting...\n")); 818 locker.Unlock(); 819 Unmount(); 820 return B_ERROR; 821 } 822 823 // Decrement the root node use count. The publish_vnode() the client FS 824 // did will be balanced by the VFS. 825 if (fVNodeCountingEnabled) 826 fRootNode->useCount--; 827 828 // init the volume ops vector we'll give the VFS 829 _InitVolumeOps(); 830 831 return B_OK; 832 } 833 834 // Unmount 835 status_t 836 Volume::Unmount() 837 { 838 status_t error = _Unmount(); 839 840 // free the memory associated with the maps 841 { 842 // vnodes 843 MutexLocker _(fLock); 844 if (fVNodes != NULL) { 845 VNode* node = fVNodes->Clear(true); 846 while (node != NULL) { 847 VNode* nextNode = node->hash_link; 848 node->Delete(this); 849 node = nextNode; 850 } 851 delete fVNodes; 852 fVNodes = NULL; 853 } 854 855 // io request infos 856 if (fIORequestInfosByID != NULL) { 857 fIORequestInfosByID->Clear(); 858 delete fIORequestInfosByID; 859 fIORequestInfosByID = NULL; 860 } 861 862 if (fIORequestInfosByStruct != NULL) { 863 IORequestInfo* info = fIORequestInfosByStruct->Clear(true); 864 while (info != NULL) { 865 IORequestInfo* nextInfo = info->structLink; 866 delete info; 867 // TODO: We should probably also notify the request, if that 868 // hasn't happened yet. 869 info = nextInfo; 870 } 871 delete fIORequestInfosByStruct; 872 fIORequestInfosByStruct = NULL; 873 } 874 } 875 876 fFileSystem->VolumeUnmounted(this); 877 return error; 878 } 879 880 // Sync 881 status_t 882 Volume::Sync() 883 { 884 // check capability 885 if (!HasCapability(FS_VOLUME_CAPABILITY_SYNC)) 886 return B_BAD_VALUE; 887 888 // get a free port 889 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 890 if (!port) 891 return B_ERROR; 892 PortReleaser _(fFileSystem->GetPortPool(), port); 893 894 // prepare the request 895 RequestAllocator allocator(port->GetPort()); 896 SyncVolumeRequest* request; 897 status_t error = AllocateRequest(allocator, &request); 898 if (error != B_OK) 899 return error; 900 901 request->volume = fUserlandVolume; 902 903 // send the request 904 KernelRequestHandler handler(this, SYNC_VOLUME_REPLY); 905 SyncVolumeReply* reply; 906 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 907 if (error != B_OK) 908 return error; 909 RequestReleaser requestReleaser(port, reply); 910 911 // process the reply 912 if (reply->error != B_OK) 913 return reply->error; 914 return error; 915 } 916 917 // ReadFSInfo 918 status_t 919 Volume::ReadFSInfo(fs_info* info) 920 { 921 // When the connection to the userland server is lost, we serve 922 // read_fs_info() requests manually. 923 status_t error = _ReadFSInfo(info); 924 if (error != B_OK && fFileSystem->GetPortPool()->IsDisconnected()) { 925 WARN(("Volume::ReadFSInfo(): connection lost, emulating lookup `.'\n")); 926 927 info->flags = B_FS_IS_PERSISTENT | B_FS_IS_READONLY; 928 info->block_size = 512; 929 info->io_size = 512; 930 info->total_blocks = 0; 931 info->free_blocks = 0; 932 strlcpy(info->volume_name, fFileSystem->GetName(), 933 sizeof(info->volume_name)); 934 strlcat(info->volume_name, ":disconnected", sizeof(info->volume_name)); 935 936 error = B_OK; 937 } 938 return error; 939 } 940 941 // WriteFSInfo 942 status_t 943 Volume::WriteFSInfo(const struct fs_info *info, uint32 mask) 944 { 945 // check capability 946 if (!HasCapability(FS_VOLUME_CAPABILITY_WRITE_FS_INFO)) 947 return B_BAD_VALUE; 948 949 // get a free port 950 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 951 if (!port) 952 return B_ERROR; 953 PortReleaser _(fFileSystem->GetPortPool(), port); 954 955 // prepare the request 956 RequestAllocator allocator(port->GetPort()); 957 WriteFSInfoRequest* request; 958 status_t error = AllocateRequest(allocator, &request); 959 if (error != B_OK) 960 return error; 961 962 request->volume = fUserlandVolume; 963 request->info = *info; 964 request->mask = mask; 965 966 // send the request 967 KernelRequestHandler handler(this, WRITE_FS_INFO_REPLY); 968 WriteFSInfoReply* reply; 969 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 970 if (error != B_OK) 971 return error; 972 RequestReleaser requestReleaser(port, reply); 973 974 // process the reply 975 if (reply->error != B_OK) 976 return reply->error; 977 return error; 978 } 979 980 981 // #pragma mark - vnodes 982 983 984 // Lookup 985 status_t 986 Volume::Lookup(void* dir, const char* entryName, ino_t* vnid) 987 { 988 // When the connection to the userland server is lost, we serve 989 // lookup(fRootNode, `.') requests manually to allow clean unmounting. 990 status_t error = _Lookup(dir, entryName, vnid); 991 if (error != B_OK && fFileSystem->GetPortPool()->IsDisconnected() 992 && dir == fRootNode && strcmp(entryName, ".") == 0) { 993 WARN(("Volume::Lookup(): connection lost, emulating lookup `.'\n")); 994 void* entryNode; 995 if (GetVNode(fRootID, &entryNode) != B_OK) 996 RETURN_ERROR(B_BAD_VALUE); 997 *vnid = fRootID; 998 // The VFS will balance the get_vnode() call for the FS. 999 _DecrementVNodeCount(*vnid); 1000 return B_OK; 1001 } 1002 return error; 1003 } 1004 1005 // GetVNodeName 1006 status_t 1007 Volume::GetVNodeName(void* _node, char* buffer, size_t bufferSize) 1008 { 1009 // We don't check the capability -- if not implemented by the client FS, 1010 // the functionality is emulated in userland. 1011 1012 VNode* vnode = (VNode*)_node; 1013 1014 // get a free port 1015 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 1016 if (!port) 1017 return B_ERROR; 1018 PortReleaser _(fFileSystem->GetPortPool(), port); 1019 1020 // prepare the request 1021 RequestAllocator allocator(port->GetPort()); 1022 GetVNodeNameRequest* request; 1023 status_t error = AllocateRequest(allocator, &request); 1024 if (error != B_OK) 1025 return error; 1026 1027 request->volume = fUserlandVolume; 1028 request->node = vnode->clientNode; 1029 request->size = bufferSize; 1030 1031 // send the request 1032 KernelRequestHandler handler(this, GET_VNODE_NAME_REPLY); 1033 GetVNodeNameReply* reply; 1034 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 1035 if (error != B_OK) 1036 return error; 1037 RequestReleaser requestReleaser(port, reply); 1038 1039 // process the reply 1040 if (reply->error != B_OK) 1041 return reply->error; 1042 1043 char* readBuffer = (char*)reply->buffer.GetData(); 1044 size_t nameLen = reply->buffer.GetSize(); 1045 nameLen = strnlen(readBuffer, nameLen); 1046 if (nameLen <= 1 || nameLen >= bufferSize) 1047 RETURN_ERROR(B_BAD_DATA); 1048 1049 memcpy(buffer, readBuffer, nameLen); 1050 buffer[nameLen] = '\0'; 1051 1052 _SendReceiptAck(port); 1053 return error; 1054 } 1055 1056 // ReadVNode 1057 status_t 1058 Volume::ReadVNode(ino_t vnid, bool reenter, void** _node, fs_vnode_ops** _ops, 1059 int* type, uint32* flags) 1060 { 1061 // get a free port 1062 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 1063 if (!port) 1064 return B_ERROR; 1065 PortReleaser _(fFileSystem->GetPortPool(), port); 1066 1067 // prepare the request 1068 RequestAllocator allocator(port->GetPort()); 1069 ReadVNodeRequest* request; 1070 status_t error = AllocateRequest(allocator, &request); 1071 if (error != B_OK) 1072 return error; 1073 1074 request->volume = fUserlandVolume; 1075 request->vnid = vnid; 1076 request->reenter = reenter; 1077 1078 // add the uninitialized node to our map 1079 VNode* vnode = new(std::nothrow) VNode(vnid, NULL, NULL); 1080 if (vnode == NULL) 1081 RETURN_ERROR(B_NO_MEMORY); 1082 vnode->valid = false; 1083 1084 MutexLocker locker(fLock); 1085 fVNodes->Insert(vnode); 1086 locker.Unlock(); 1087 1088 // send the request 1089 KernelRequestHandler handler(this, READ_VNODE_REPLY); 1090 ReadVNodeReply* reply; 1091 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 1092 if (error != B_OK) { 1093 _RemoveInvalidVNode(vnid); 1094 return error; 1095 } 1096 RequestReleaser requestReleaser(port, reply); 1097 1098 // process the reply 1099 if (reply->error != B_OK) { 1100 _RemoveInvalidVNode(vnid); 1101 return reply->error; 1102 } 1103 1104 // get the ops vector for the node 1105 VNodeOps* ops = fFileSystem->GetVNodeOps(reply->capabilities); 1106 if (ops == NULL) { 1107 _RemoveInvalidVNode(vnid); 1108 RETURN_ERROR(B_NO_MEMORY); 1109 } 1110 1111 // everything went fine -- mark the node valid 1112 locker.Lock(); 1113 vnode->clientNode = reply->node; 1114 vnode->ops = ops; 1115 vnode->valid = true; 1116 1117 *_node = vnode; 1118 *type = reply->type; 1119 *flags = reply->flags; 1120 *_ops = ops->ops; 1121 return B_OK; 1122 } 1123 1124 // WriteVNode 1125 status_t 1126 Volume::WriteVNode(void* node, bool reenter) 1127 { 1128 status_t error = _WriteVNode(node, reenter); 1129 if (error != B_OK && fFileSystem->GetPortPool()->IsDisconnected()) { 1130 // This isn't really necessary, since the VFS basically ignores the 1131 // return value -- at least Haiku. The fshell panic()s; didn't check 1132 // BeOS. It doesn't harm to appear to behave nicely. :-) 1133 WARN(("Volume::WriteVNode(): connection lost, forcing write vnode\n")); 1134 return B_OK; 1135 } 1136 return error; 1137 } 1138 1139 // RemoveVNode 1140 status_t 1141 Volume::RemoveVNode(void* _node, bool reenter) 1142 { 1143 VNode* vnode = (VNode*)_node; 1144 1145 // At any rate remove the vnode from our map and delete it. We don't do that 1146 // right now, though, since we might still need to serve file cache requests 1147 // from the client FS. 1148 VNodeRemover nodeRemover(this, vnode); 1149 1150 void* clientNode = vnode->clientNode; 1151 1152 // get a free port 1153 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 1154 if (!port) 1155 return B_ERROR; 1156 PortReleaser _(fFileSystem->GetPortPool(), port); 1157 1158 // prepare the request 1159 RequestAllocator allocator(port->GetPort()); 1160 FSRemoveVNodeRequest* request; 1161 status_t error = AllocateRequest(allocator, &request); 1162 if (error != B_OK) 1163 return error; 1164 1165 request->volume = fUserlandVolume; 1166 request->node = clientNode; 1167 request->reenter = reenter; 1168 1169 // send the request 1170 KernelRequestHandler handler(this, FS_REMOVE_VNODE_REPLY); 1171 FSRemoveVNodeReply* reply; 1172 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 1173 if (error != B_OK) 1174 return error; 1175 RequestReleaser requestReleaser(port, reply); 1176 1177 // process the reply 1178 if (reply->error != B_OK) 1179 return reply->error; 1180 return error; 1181 } 1182 1183 1184 // #pragma mark - asynchronous I/O 1185 1186 1187 // DoIO 1188 status_t 1189 Volume::DoIO(void* _node, void* cookie, io_request* ioRequest) 1190 { 1191 VNode* vnode = (VNode*)_node; 1192 1193 // check capability 1194 if (!HasVNodeCapability(vnode, FS_VNODE_CAPABILITY_IO)) 1195 return B_UNSUPPORTED; 1196 1197 // register the IO request 1198 int32 requestID; 1199 status_t error = _RegisterIORequest(ioRequest, &requestID); 1200 if (error != B_OK) { 1201 notify_io_request(ioRequest, error); 1202 return error; 1203 } 1204 1205 IORequestRemover requestRemover(this, requestID); 1206 1207 // get a free port 1208 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 1209 if (!port) { 1210 notify_io_request(ioRequest, B_ERROR); 1211 return B_ERROR; 1212 } 1213 PortReleaser _(fFileSystem->GetPortPool(), port); 1214 1215 // prepare the request 1216 RequestAllocator allocator(port->GetPort()); 1217 DoIORequest* request; 1218 error = AllocateRequest(allocator, &request); 1219 if (error != B_OK) { 1220 notify_io_request(ioRequest, error); 1221 return error; 1222 } 1223 1224 request->volume = fUserlandVolume; 1225 request->node = vnode->clientNode; 1226 request->fileCookie = cookie; 1227 request->request = requestID; 1228 request->offset = ioRequest->Offset(); 1229 request->length = ioRequest->Length(); 1230 request->isWrite = ioRequest->IsWrite(); 1231 1232 // send the request 1233 KernelRequestHandler handler(this, DO_IO_REPLY); 1234 DoIOReply* reply; 1235 1236 // TODO: when to notify the io_request? 1237 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 1238 if (error != B_OK) 1239 return error; 1240 RequestReleaser requestReleaser(port, reply); 1241 1242 // process the reply 1243 if (reply->error != B_OK) 1244 return reply->error; 1245 1246 requestRemover.Detach(); 1247 1248 return B_OK; 1249 } 1250 1251 1252 // CancelIO 1253 status_t 1254 Volume::CancelIO(void* _node, void* cookie, io_request* ioRequest) 1255 { 1256 VNode* vnode = (VNode*)_node; 1257 1258 // check capability 1259 if (!HasVNodeCapability(vnode, FS_VNODE_CAPABILITY_CANCEL_IO)) 1260 return B_BAD_VALUE; 1261 1262 // find the request 1263 int32 requestID; 1264 status_t error = _FindIORequest(ioRequest, &requestID); 1265 if (error != B_OK) 1266 return error; 1267 1268 IORequestRemover requestRemover(this, requestID); 1269 1270 // get a free port 1271 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 1272 if (!port) 1273 return B_ERROR; 1274 PortReleaser _(fFileSystem->GetPortPool(), port); 1275 1276 // prepare the request 1277 RequestAllocator allocator(port->GetPort()); 1278 CancelIORequest* request; 1279 error = AllocateRequest(allocator, &request); 1280 if (error != B_OK) 1281 return error; 1282 1283 request->volume = fUserlandVolume; 1284 request->node = vnode->clientNode; 1285 request->fileCookie = cookie; 1286 request->request = requestID; 1287 1288 // send the request 1289 KernelRequestHandler handler(this, CANCEL_IO_REPLY); 1290 CancelIOReply* reply; 1291 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 1292 if (error != B_OK) { 1293 _UnregisterIORequest(requestID); 1294 return error; 1295 } 1296 RequestReleaser requestReleaser(port, reply); 1297 1298 // process the reply 1299 if (reply->error != B_OK) { 1300 _UnregisterIORequest(requestID); 1301 return reply->error; 1302 } 1303 1304 return B_OK; 1305 } 1306 1307 1308 // #pragma mark - nodes 1309 1310 1311 // IOCtl 1312 status_t 1313 Volume::IOCtl(void* _node, void* cookie, uint32 command, void *buffer, 1314 size_t len) 1315 { 1316 VNode* vnode = (VNode*)_node; 1317 1318 // check the command and its parameters 1319 bool isBuffer = false; 1320 int32 bufferSize = 0; 1321 int32 writeSize = 0; 1322 switch (command) { 1323 case IOCTL_FILE_UNCACHED_IO: 1324 buffer = NULL; 1325 break; 1326 case IOCTL_CREATE_TIME: 1327 case IOCTL_MODIFIED_TIME: 1328 isBuffer = 0; 1329 bufferSize = 0; 1330 writeSize = sizeof(bigtime_t); 1331 break; 1332 case USERLANDFS_IOCTL: 1333 area_id area; 1334 area_info info; 1335 PRINT(("Volume::IOCtl(): USERLANDFS_IOCTL\n")); 1336 if ((area = area_for(buffer)) >= 0) { 1337 if (get_area_info(area, &info) == B_OK) { 1338 if ((uint8*)buffer - (uint8*)info.address 1339 + sizeof(userlandfs_ioctl) <= info.size) { 1340 if (strncmp(((userlandfs_ioctl*)buffer)->magic, 1341 kUserlandFSIOCtlMagic, 1342 USERLAND_IOCTL_MAGIC_LENGTH) == 0) { 1343 return _InternalIOCtl((userlandfs_ioctl*)buffer, 1344 bufferSize); 1345 } else 1346 PRINT(("Volume::IOCtl(): bad magic\n")); 1347 } else 1348 PRINT(("Volume::IOCtl(): bad buffer size\n")); 1349 } else 1350 PRINT(("Volume::IOCtl(): failed to get area info\n")); 1351 } else 1352 PRINT(("Volume::IOCtl(): bad area\n")); 1353 // fall through... 1354 default: 1355 { 1356 // We don't know the command. Check whether the FileSystem knows 1357 // about it. 1358 const IOCtlInfo* info = fFileSystem->GetIOCtlInfo(command); 1359 if (!info) { 1360 PRINT(("Volume::IOCtl(): unknown command\n")); 1361 return B_BAD_VALUE; 1362 } 1363 1364 isBuffer = info->isBuffer; 1365 bufferSize = info->bufferSize; 1366 writeSize = info->writeBufferSize; 1367 1368 // If the buffer shall indeed specify a buffer, check it. 1369 if (info->isBuffer) { 1370 if (!buffer) { 1371 PRINT(("Volume::IOCtl(): buffer is NULL\n")); 1372 return B_BAD_VALUE; 1373 } 1374 1375 area_id area = area_for(buffer); 1376 if (area < 0) { 1377 PRINT(("Volume::IOCtl(): bad area\n")); 1378 return B_BAD_VALUE; 1379 } 1380 1381 area_info info; 1382 if (get_area_info(area, &info) != B_OK) { 1383 PRINT(("Volume::IOCtl(): failed to get area info\n")); 1384 return B_BAD_VALUE; 1385 } 1386 1387 int32 areaSize = info.size - ((uint8*)buffer 1388 - (uint8*)info.address); 1389 if (bufferSize > areaSize || writeSize > areaSize) { 1390 PRINT(("Volume::IOCtl(): bad buffer size\n")); 1391 return B_BAD_VALUE; 1392 } 1393 1394 if (writeSize > 0 && !(info.protection & B_WRITE_AREA)) { 1395 PRINT(("Volume::IOCtl(): buffer not writable\n")); 1396 return B_BAD_VALUE; 1397 } 1398 } 1399 break; 1400 } 1401 } 1402 1403 // check capability 1404 if (!HasVNodeCapability(vnode, FS_VNODE_CAPABILITY_IOCTL)) 1405 return B_BAD_VALUE; 1406 1407 // get a free port 1408 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 1409 if (!port) 1410 return B_ERROR; 1411 PortReleaser _(fFileSystem->GetPortPool(), port); 1412 1413 // prepare the request 1414 RequestAllocator allocator(port->GetPort()); 1415 IOCtlRequest* request; 1416 status_t error = AllocateRequest(allocator, &request); 1417 if (error != B_OK) 1418 return error; 1419 1420 request->volume = fUserlandVolume; 1421 request->node = vnode->clientNode; 1422 request->fileCookie = cookie; 1423 request->command = command; 1424 request->bufferParameter = buffer; 1425 request->isBuffer = isBuffer; 1426 request->lenParameter = len; 1427 request->writeSize = writeSize; 1428 1429 if (isBuffer && bufferSize > 0) { 1430 error = allocator.AllocateData(request->buffer, buffer, bufferSize, 8); 1431 if (error != B_OK) 1432 return error; 1433 } 1434 1435 // send the request 1436 KernelRequestHandler handler(this, IOCTL_REPLY); 1437 IOCtlReply* reply; 1438 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 1439 if (error != B_OK) 1440 return error; 1441 RequestReleaser requestReleaser(port, reply); 1442 1443 // process the reply 1444 if (reply->error != B_OK) 1445 return reply->error; 1446 1447 // Copy back the buffer even if the result is not B_OK. The protocol 1448 // is defined by the FS developer and may include writing data into 1449 // the buffer in some error cases. 1450 if (isBuffer && writeSize > 0 && reply->buffer.GetData()) { 1451 if (writeSize > reply->buffer.GetSize()) 1452 writeSize = reply->buffer.GetSize(); 1453 memcpy(buffer, reply->buffer.GetData(), writeSize); 1454 _SendReceiptAck(port); 1455 } 1456 return reply->ioctlError; 1457 } 1458 1459 // SetFlags 1460 status_t 1461 Volume::SetFlags(void* _node, void* cookie, int flags) 1462 { 1463 VNode* vnode = (VNode*)_node; 1464 1465 // check capability 1466 if (!HasVNodeCapability(vnode, FS_VNODE_CAPABILITY_SET_FLAGS)) 1467 return B_BAD_VALUE; 1468 1469 // get a free port 1470 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 1471 if (!port) 1472 return B_ERROR; 1473 PortReleaser _(fFileSystem->GetPortPool(), port); 1474 1475 // prepare the request 1476 RequestAllocator allocator(port->GetPort()); 1477 SetFlagsRequest* request; 1478 status_t error = AllocateRequest(allocator, &request); 1479 if (error != B_OK) 1480 return error; 1481 1482 request->volume = fUserlandVolume; 1483 request->node = vnode->clientNode; 1484 request->fileCookie = cookie; 1485 request->flags = flags; 1486 1487 // send the request 1488 KernelRequestHandler handler(this, SET_FLAGS_REPLY); 1489 SetFlagsReply* reply; 1490 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 1491 if (error != B_OK) 1492 return error; 1493 RequestReleaser requestReleaser(port, reply); 1494 1495 // process the reply 1496 if (reply->error != B_OK) 1497 return reply->error; 1498 return error; 1499 } 1500 1501 // Select 1502 status_t 1503 Volume::Select(void* _node, void* cookie, uint8 event, selectsync* sync) 1504 { 1505 VNode* vnode = (VNode*)_node; 1506 1507 // check capability 1508 if (!HasVNodeCapability(vnode, FS_VNODE_CAPABILITY_SELECT)) { 1509 notify_select_event(sync, event); 1510 return B_OK; 1511 } 1512 1513 // get a free port 1514 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 1515 if (!port) 1516 return B_ERROR; 1517 PortReleaser _(fFileSystem->GetPortPool(), port); 1518 1519 // prepare the request 1520 RequestAllocator allocator(port->GetPort()); 1521 SelectRequest* request; 1522 status_t error = AllocateRequest(allocator, &request); 1523 if (error != B_OK) 1524 return error; 1525 1526 request->volume = fUserlandVolume; 1527 request->node = vnode->clientNode; 1528 request->fileCookie = cookie; 1529 request->event = event; 1530 request->sync = sync; 1531 1532 // add a selectsync entry 1533 error = fFileSystem->AddSelectSyncEntry(sync); 1534 if (error != B_OK) 1535 return error; 1536 1537 // send the request 1538 KernelRequestHandler handler(this, SELECT_REPLY); 1539 SelectReply* reply; 1540 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 1541 if (error != B_OK) { 1542 fFileSystem->RemoveSelectSyncEntry(sync); 1543 return error; 1544 } 1545 RequestReleaser requestReleaser(port, reply); 1546 1547 // process the reply 1548 if (reply->error != B_OK) { 1549 fFileSystem->RemoveSelectSyncEntry(sync); 1550 return reply->error; 1551 } 1552 return error; 1553 } 1554 1555 // Deselect 1556 status_t 1557 Volume::Deselect(void* _node, void* cookie, uint8 event, selectsync* sync) 1558 { 1559 VNode* vnode = (VNode*)_node; 1560 1561 // check capability 1562 if (!HasVNodeCapability(vnode, FS_VNODE_CAPABILITY_DESELECT)) 1563 return B_OK; 1564 1565 struct SyncRemover { 1566 SyncRemover(FileSystem* fs, selectsync* sync) 1567 : fs(fs), sync(sync) {} 1568 ~SyncRemover() { fs->RemoveSelectSyncEntry(sync); } 1569 1570 FileSystem* fs; 1571 selectsync* sync; 1572 } syncRemover(fFileSystem, sync); 1573 1574 // get a free port 1575 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 1576 if (!port) 1577 return B_ERROR; 1578 PortReleaser _(fFileSystem->GetPortPool(), port); 1579 1580 // prepare the request 1581 RequestAllocator allocator(port->GetPort()); 1582 DeselectRequest* request; 1583 status_t error = AllocateRequest(allocator, &request); 1584 if (error != B_OK) 1585 return error; 1586 1587 request->volume = fUserlandVolume; 1588 request->node = vnode->clientNode; 1589 request->fileCookie = cookie; 1590 request->event = event; 1591 request->sync = sync; 1592 1593 // send the request 1594 KernelRequestHandler handler(this, DESELECT_REPLY); 1595 DeselectReply* reply; 1596 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 1597 if (error != B_OK) 1598 return error; 1599 RequestReleaser requestReleaser(port, reply); 1600 1601 // process the reply 1602 if (reply->error != B_OK) 1603 return reply->error; 1604 return error; 1605 } 1606 1607 // FSync 1608 status_t 1609 Volume::FSync(void* _node) 1610 { 1611 VNode* vnode = (VNode*)_node; 1612 1613 // check capability 1614 if (!HasVNodeCapability(vnode, FS_VNODE_CAPABILITY_FSYNC)) 1615 return B_BAD_VALUE; 1616 1617 // get a free port 1618 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 1619 if (!port) 1620 return B_ERROR; 1621 PortReleaser _(fFileSystem->GetPortPool(), port); 1622 1623 // prepare the request 1624 RequestAllocator allocator(port->GetPort()); 1625 FSyncRequest* request; 1626 status_t error = AllocateRequest(allocator, &request); 1627 if (error != B_OK) 1628 return error; 1629 1630 request->volume = fUserlandVolume; 1631 request->node = vnode->clientNode; 1632 1633 // send the request 1634 KernelRequestHandler handler(this, FSYNC_REPLY); 1635 FSyncReply* reply; 1636 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 1637 if (error != B_OK) 1638 return error; 1639 RequestReleaser requestReleaser(port, reply); 1640 1641 // process the reply 1642 if (reply->error != B_OK) 1643 return reply->error; 1644 return error; 1645 } 1646 1647 // ReadSymlink 1648 status_t 1649 Volume::ReadSymlink(void* _node, char* buffer, size_t bufferSize, 1650 size_t* bytesRead) 1651 { 1652 VNode* vnode = (VNode*)_node; 1653 1654 *bytesRead = 0; 1655 1656 // check capability 1657 if (!HasVNodeCapability(vnode, FS_VNODE_CAPABILITY_READ_SYMLINK)) 1658 return B_BAD_VALUE; 1659 1660 // get a free port 1661 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 1662 if (!port) 1663 return B_ERROR; 1664 PortReleaser _(fFileSystem->GetPortPool(), port); 1665 1666 // prepare the request 1667 RequestAllocator allocator(port->GetPort()); 1668 ReadSymlinkRequest* request; 1669 status_t error = AllocateRequest(allocator, &request); 1670 if (error != B_OK) 1671 return error; 1672 1673 request->volume = fUserlandVolume; 1674 request->node = vnode->clientNode; 1675 request->size = bufferSize; 1676 1677 // send the request 1678 KernelRequestHandler handler(this, READ_SYMLINK_REPLY); 1679 ReadSymlinkReply* reply; 1680 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 1681 if (error != B_OK) 1682 return error; 1683 RequestReleaser requestReleaser(port, reply); 1684 1685 // process the reply 1686 if (reply->error != B_OK) 1687 return reply->error; 1688 void* readBuffer = reply->buffer.GetData(); 1689 if (reply->bytesRead > (uint32)reply->buffer.GetSize() 1690 || reply->bytesRead > bufferSize) { 1691 return B_BAD_DATA; 1692 } 1693 if (reply->bytesRead > 0) 1694 memcpy(buffer, readBuffer, reply->bytesRead); 1695 *bytesRead = reply->bytesRead; 1696 _SendReceiptAck(port); 1697 return error; 1698 } 1699 1700 // CreateSymlink 1701 status_t 1702 Volume::CreateSymlink(void* _dir, const char* name, const char* target, 1703 int mode) 1704 { 1705 VNode* vnode = (VNode*)_dir; 1706 1707 // check capability 1708 if (!HasVNodeCapability(vnode, FS_VNODE_CAPABILITY_CREATE_SYMLINK)) 1709 return B_BAD_VALUE; 1710 1711 // get a free port 1712 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 1713 if (!port) 1714 return B_ERROR; 1715 PortReleaser _(fFileSystem->GetPortPool(), port); 1716 1717 // prepare the request 1718 RequestAllocator allocator(port->GetPort()); 1719 CreateSymlinkRequest* request; 1720 status_t error = AllocateRequest(allocator, &request); 1721 if (error != B_OK) 1722 return error; 1723 1724 request->volume = fUserlandVolume; 1725 request->node = vnode->clientNode; 1726 error = allocator.AllocateString(request->name, name); 1727 if (error == B_OK) 1728 error = allocator.AllocateString(request->target, target); 1729 if (error != B_OK) 1730 return error; 1731 request->mode = mode; 1732 1733 // send the request 1734 KernelRequestHandler handler(this, CREATE_SYMLINK_REPLY); 1735 CreateSymlinkReply* reply; 1736 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 1737 if (error != B_OK) 1738 return error; 1739 RequestReleaser requestReleaser(port, reply); 1740 1741 // process the reply 1742 if (reply->error != B_OK) 1743 return reply->error; 1744 return error; 1745 } 1746 1747 // Link 1748 status_t 1749 Volume::Link(void* _dir, const char* name, void* node) 1750 { 1751 VNode* vnode = (VNode*)_dir; 1752 1753 // check capability 1754 if (!HasVNodeCapability(vnode, FS_VNODE_CAPABILITY_LINK)) 1755 return B_BAD_VALUE; 1756 1757 // get a free port 1758 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 1759 if (!port) 1760 return B_ERROR; 1761 PortReleaser _(fFileSystem->GetPortPool(), port); 1762 1763 // prepare the request 1764 RequestAllocator allocator(port->GetPort()); 1765 LinkRequest* request; 1766 status_t error = AllocateRequest(allocator, &request); 1767 if (error != B_OK) 1768 return error; 1769 1770 request->volume = fUserlandVolume; 1771 request->node = vnode->clientNode; 1772 error = allocator.AllocateString(request->name, name); 1773 request->target = node; 1774 if (error != B_OK) 1775 return error; 1776 1777 // send the request 1778 KernelRequestHandler handler(this, LINK_REPLY); 1779 LinkReply* reply; 1780 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 1781 if (error != B_OK) 1782 return error; 1783 RequestReleaser requestReleaser(port, reply); 1784 1785 // process the reply 1786 if (reply->error != B_OK) 1787 return reply->error; 1788 return error; 1789 } 1790 1791 // Unlink 1792 status_t 1793 Volume::Unlink(void* _dir, const char* name) 1794 { 1795 VNode* vnode = (VNode*)_dir; 1796 1797 // check capability 1798 if (!HasVNodeCapability(vnode, FS_VNODE_CAPABILITY_UNLINK)) 1799 return B_BAD_VALUE; 1800 1801 // get a free port 1802 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 1803 if (!port) 1804 return B_ERROR; 1805 PortReleaser _(fFileSystem->GetPortPool(), port); 1806 1807 // prepare the request 1808 RequestAllocator allocator(port->GetPort()); 1809 UnlinkRequest* request; 1810 status_t error = AllocateRequest(allocator, &request); 1811 if (error != B_OK) 1812 return error; 1813 1814 request->volume = fUserlandVolume; 1815 request->node = vnode->clientNode; 1816 error = allocator.AllocateString(request->name, name); 1817 if (error != B_OK) 1818 return error; 1819 1820 // send the request 1821 KernelRequestHandler handler(this, UNLINK_REPLY); 1822 UnlinkReply* reply; 1823 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 1824 if (error != B_OK) 1825 return error; 1826 RequestReleaser requestReleaser(port, reply); 1827 1828 // process the reply 1829 if (reply->error != B_OK) 1830 return reply->error; 1831 return error; 1832 } 1833 1834 // Rename 1835 status_t 1836 Volume::Rename(void* _oldDir, const char* oldName, void* _newDir, 1837 const char* newName) 1838 { 1839 VNode* oldVNode = (VNode*)_oldDir; 1840 VNode* newVNode = (VNode*)_newDir; 1841 1842 // check capability 1843 if (!HasVNodeCapability(oldVNode, FS_VNODE_CAPABILITY_RENAME)) 1844 return B_BAD_VALUE; 1845 1846 // get a free port 1847 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 1848 if (!port) 1849 return B_ERROR; 1850 PortReleaser _(fFileSystem->GetPortPool(), port); 1851 1852 // prepare the request 1853 RequestAllocator allocator(port->GetPort()); 1854 RenameRequest* request; 1855 status_t error = AllocateRequest(allocator, &request); 1856 if (error != B_OK) 1857 return error; 1858 1859 request->volume = fUserlandVolume; 1860 request->oldDir = oldVNode->clientNode; 1861 request->newDir = newVNode->clientNode; 1862 error = allocator.AllocateString(request->oldName, oldName); 1863 if (error == B_OK) 1864 error = allocator.AllocateString(request->newName, newName); 1865 if (error != B_OK) 1866 return error; 1867 1868 // send the request 1869 KernelRequestHandler handler(this, RENAME_REPLY); 1870 RenameReply* reply; 1871 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 1872 if (error != B_OK) 1873 return error; 1874 RequestReleaser requestReleaser(port, reply); 1875 1876 // process the reply 1877 if (reply->error != B_OK) 1878 return reply->error; 1879 return error; 1880 } 1881 1882 // Access 1883 status_t 1884 Volume::Access(void* _node, int mode) 1885 { 1886 VNode* vnode = (VNode*)_node; 1887 1888 // check capability 1889 if (!HasVNodeCapability(vnode, FS_VNODE_CAPABILITY_ACCESS)) 1890 return B_OK; 1891 1892 // get a free port 1893 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 1894 if (!port) 1895 return B_ERROR; 1896 PortReleaser _(fFileSystem->GetPortPool(), port); 1897 1898 // prepare the request 1899 RequestAllocator allocator(port->GetPort()); 1900 AccessRequest* request; 1901 status_t error = AllocateRequest(allocator, &request); 1902 if (error != B_OK) 1903 return error; 1904 1905 request->volume = fUserlandVolume; 1906 request->node = vnode->clientNode; 1907 request->mode = mode; 1908 1909 // send the request 1910 KernelRequestHandler handler(this, ACCESS_REPLY); 1911 AccessReply* reply; 1912 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 1913 if (error != B_OK) 1914 return error; 1915 RequestReleaser requestReleaser(port, reply); 1916 1917 // process the reply 1918 if (reply->error != B_OK) 1919 return reply->error; 1920 return error; 1921 } 1922 1923 // ReadStat 1924 status_t 1925 Volume::ReadStat(void* node, struct stat* st) 1926 { 1927 // When the connection to the userland server is lost, we serve 1928 // read_stat(fRootNode) requests manually to allow clean unmounting. 1929 status_t error = _ReadStat(node, st); 1930 if (error != B_OK && fFileSystem->GetPortPool()->IsDisconnected() 1931 && node == fRootNode) { 1932 WARN(("Volume::ReadStat(): connection lost, emulating stat for the " 1933 "root node\n")); 1934 1935 st->st_dev = GetID(); 1936 st->st_ino = fRootID; 1937 st->st_mode = ACCESSPERMS; 1938 st->st_nlink = 1; 1939 st->st_uid = 0; 1940 st->st_gid = 0; 1941 st->st_size = 512; 1942 st->st_blksize = 512; 1943 st->st_atime = 0; 1944 st->st_mtime = 0; 1945 st->st_ctime = 0; 1946 st->st_crtime = 0; 1947 1948 error = B_OK; 1949 } 1950 return error; 1951 } 1952 1953 // WriteStat 1954 status_t 1955 Volume::WriteStat(void* _node, const struct stat* st, uint32 mask) 1956 { 1957 VNode* vnode = (VNode*)_node; 1958 1959 // check capability 1960 if (!HasVNodeCapability(vnode, FS_VNODE_CAPABILITY_WRITE_STAT)) 1961 return B_BAD_VALUE; 1962 1963 // get a free port 1964 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 1965 if (!port) 1966 return B_ERROR; 1967 PortReleaser _(fFileSystem->GetPortPool(), port); 1968 1969 // prepare the request 1970 RequestAllocator allocator(port->GetPort()); 1971 WriteStatRequest* request; 1972 status_t error = AllocateRequest(allocator, &request); 1973 if (error != B_OK) 1974 return error; 1975 1976 request->volume = fUserlandVolume; 1977 request->node = vnode->clientNode; 1978 request->st = *st; 1979 request->mask = mask; 1980 1981 // send the request 1982 KernelRequestHandler handler(this, WRITE_STAT_REPLY); 1983 WriteStatReply* reply; 1984 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 1985 if (error != B_OK) 1986 return error; 1987 RequestReleaser requestReleaser(port, reply); 1988 1989 // process the reply 1990 if (reply->error != B_OK) 1991 return reply->error; 1992 return error; 1993 } 1994 1995 1996 // #pragma mark - files 1997 1998 // Create 1999 status_t 2000 Volume::Create(void* _dir, const char* name, int openMode, int mode, 2001 void** cookie, ino_t* vnid) 2002 { 2003 VNode* vnode = (VNode*)_dir; 2004 2005 // check capability 2006 if (!HasVNodeCapability(vnode, FS_VNODE_CAPABILITY_CREATE)) 2007 return B_BAD_VALUE; 2008 2009 // get a free port 2010 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 2011 if (!port) 2012 return B_ERROR; 2013 PortReleaser _(fFileSystem->GetPortPool(), port); 2014 AutoIncrementer incrementer(&fOpenFiles); 2015 2016 // prepare the request 2017 RequestAllocator allocator(port->GetPort()); 2018 CreateRequest* request; 2019 status_t error = AllocateRequest(allocator, &request); 2020 if (error != B_OK) 2021 return error; 2022 2023 request->volume = fUserlandVolume; 2024 request->node = vnode->clientNode; 2025 error = allocator.AllocateString(request->name, name); 2026 request->openMode = openMode; 2027 request->mode = mode; 2028 if (error != B_OK) 2029 return error; 2030 2031 // send the request 2032 KernelRequestHandler handler(this, CREATE_REPLY); 2033 CreateReply* reply; 2034 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 2035 if (error != B_OK) 2036 return error; 2037 RequestReleaser requestReleaser(port, reply); 2038 2039 // process the reply 2040 if (reply->error != B_OK) 2041 return reply->error; 2042 incrementer.Keep(); 2043 *vnid = reply->vnid; 2044 *cookie = reply->fileCookie; 2045 2046 // The VFS will balance the publish_vnode() call for the FS. 2047 if (error == B_OK) 2048 _DecrementVNodeCount(*vnid); 2049 return error; 2050 } 2051 2052 // Open 2053 status_t 2054 Volume::Open(void* _node, int openMode, void** cookie) 2055 { 2056 VNode* vnode = (VNode*)_node; 2057 2058 // check capability 2059 if (!HasVNodeCapability(vnode, FS_VNODE_CAPABILITY_OPEN)) 2060 return B_BAD_VALUE; 2061 2062 // get a free port 2063 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 2064 if (!port) 2065 return B_ERROR; 2066 PortReleaser _(fFileSystem->GetPortPool(), port); 2067 AutoIncrementer incrementer(&fOpenFiles); 2068 2069 // prepare the request 2070 RequestAllocator allocator(port->GetPort()); 2071 OpenRequest* request; 2072 status_t error = AllocateRequest(allocator, &request); 2073 if (error != B_OK) 2074 return error; 2075 request->volume = fUserlandVolume; 2076 request->node = vnode->clientNode; 2077 request->openMode = openMode; 2078 2079 // send the request 2080 KernelRequestHandler handler(this, OPEN_REPLY); 2081 OpenReply* reply; 2082 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 2083 if (error != B_OK) 2084 return error; 2085 RequestReleaser requestReleaser(port, reply); 2086 2087 // process the reply 2088 if (reply->error != B_OK) 2089 return reply->error; 2090 incrementer.Keep(); 2091 *cookie = reply->fileCookie; 2092 return error; 2093 } 2094 2095 // Close 2096 status_t 2097 Volume::Close(void* node, void* cookie) 2098 { 2099 status_t error = _Close(node, cookie); 2100 if (error != B_OK && fFileSystem->GetPortPool()->IsDisconnected()) { 2101 // This isn't really necessary, as the return value is irrelevant to 2102 // the VFS. OBOS ignores it completely. The fsshell returns it to the 2103 // userland, but considers the node closed anyway. 2104 WARN(("Volume::Close(): connection lost, forcing close\n")); 2105 return B_OK; 2106 } 2107 return error; 2108 } 2109 2110 // FreeCookie 2111 status_t 2112 Volume::FreeCookie(void* node, void* cookie) 2113 { 2114 status_t error = _FreeCookie(node, cookie); 2115 bool disconnected = false; 2116 if (error != B_OK && fFileSystem->GetPortPool()->IsDisconnected()) { 2117 // This isn't really necessary, as the return value is irrelevant to 2118 // the VFS. It's completely ignored by OBOS as well as by the fsshell. 2119 WARN(("Volume::FreeCookie(): connection lost, forcing free cookie\n")); 2120 error = B_OK; 2121 disconnected = true; 2122 } 2123 2124 int32 openFiles = atomic_add(&fOpenFiles, -1); 2125 if (openFiles <= 1 && disconnected) 2126 _PutAllPendingVNodes(); 2127 return error; 2128 } 2129 2130 // Read 2131 status_t 2132 Volume::Read(void* _node, void* cookie, off_t pos, void* buffer, 2133 size_t bufferSize, size_t* bytesRead) 2134 { 2135 VNode* vnode = (VNode*)_node; 2136 2137 *bytesRead = 0; 2138 2139 // check capability 2140 if (!HasVNodeCapability(vnode, FS_VNODE_CAPABILITY_READ)) 2141 return B_BAD_VALUE; 2142 2143 // get a free port 2144 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 2145 if (!port) 2146 return B_ERROR; 2147 PortReleaser _(fFileSystem->GetPortPool(), port); 2148 2149 // prepare the request 2150 RequestAllocator allocator(port->GetPort()); 2151 ReadRequest* request; 2152 status_t error = AllocateRequest(allocator, &request); 2153 if (error != B_OK) 2154 return error; 2155 2156 request->volume = fUserlandVolume; 2157 request->node = vnode->clientNode; 2158 request->fileCookie = cookie; 2159 request->pos = pos; 2160 request->size = bufferSize; 2161 2162 // send the request 2163 KernelRequestHandler handler(this, READ_REPLY); 2164 ReadReply* reply; 2165 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 2166 if (error != B_OK) 2167 return error; 2168 RequestReleaser requestReleaser(port, reply); 2169 2170 // process the reply 2171 if (reply->error != B_OK) 2172 return reply->error; 2173 void* readBuffer = reply->buffer.GetData(); 2174 if (reply->bytesRead > (uint32)reply->buffer.GetSize() 2175 || reply->bytesRead > bufferSize) { 2176 return B_BAD_DATA; 2177 } 2178 if (reply->bytesRead > 0) 2179 memcpy(buffer, readBuffer, reply->bytesRead); 2180 *bytesRead = reply->bytesRead; 2181 _SendReceiptAck(port); 2182 return error; 2183 } 2184 2185 // Write 2186 status_t 2187 Volume::Write(void* _node, void* cookie, off_t pos, const void* buffer, 2188 size_t size, size_t* bytesWritten) 2189 { 2190 VNode* vnode = (VNode*)_node; 2191 2192 *bytesWritten = 0; 2193 2194 // check capability 2195 if (!HasVNodeCapability(vnode, FS_VNODE_CAPABILITY_WRITE)) 2196 return B_BAD_VALUE; 2197 2198 // get a free port 2199 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 2200 if (!port) 2201 return B_ERROR; 2202 PortReleaser _(fFileSystem->GetPortPool(), port); 2203 2204 // prepare the request 2205 RequestAllocator allocator(port->GetPort()); 2206 WriteRequest* request; 2207 status_t error = AllocateRequest(allocator, &request); 2208 if (error != B_OK) 2209 return error; 2210 2211 request->volume = fUserlandVolume; 2212 request->node = vnode->clientNode; 2213 request->fileCookie = cookie; 2214 request->pos = pos; 2215 error = allocator.AllocateData(request->buffer, buffer, size, 1); 2216 if (error != B_OK) 2217 return error; 2218 2219 // send the request 2220 KernelRequestHandler handler(this, WRITE_REPLY); 2221 WriteReply* reply; 2222 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 2223 if (error != B_OK) 2224 return error; 2225 RequestReleaser requestReleaser(port, reply); 2226 2227 // process the reply 2228 if (reply->error != B_OK) 2229 return reply->error; 2230 *bytesWritten = reply->bytesWritten; 2231 return error; 2232 } 2233 2234 2235 // #pragma mark - directories 2236 2237 // CreateDir 2238 status_t 2239 Volume::CreateDir(void* _dir, const char* name, int mode) 2240 { 2241 VNode* vnode = (VNode*)_dir; 2242 2243 // check capability 2244 if (!HasVNodeCapability(vnode, FS_VNODE_CAPABILITY_CREATE_DIR)) 2245 return B_BAD_VALUE; 2246 2247 // get a free port 2248 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 2249 if (!port) 2250 return B_ERROR; 2251 PortReleaser _(fFileSystem->GetPortPool(), port); 2252 2253 // prepare the request 2254 RequestAllocator allocator(port->GetPort()); 2255 CreateDirRequest* request; 2256 status_t error = AllocateRequest(allocator, &request); 2257 if (error != B_OK) 2258 return error; 2259 2260 request->volume = fUserlandVolume; 2261 request->node = vnode->clientNode; 2262 error = allocator.AllocateString(request->name, name); 2263 request->mode = mode; 2264 if (error != B_OK) 2265 return error; 2266 2267 // send the request 2268 KernelRequestHandler handler(this, CREATE_DIR_REPLY); 2269 CreateDirReply* reply; 2270 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 2271 if (error != B_OK) 2272 return error; 2273 RequestReleaser requestReleaser(port, reply); 2274 2275 // process the reply 2276 if (reply->error != B_OK) 2277 return reply->error; 2278 return error; 2279 } 2280 2281 // RemoveDir 2282 status_t 2283 Volume::RemoveDir(void* _dir, const char* name) 2284 { 2285 VNode* vnode = (VNode*)_dir; 2286 2287 // check capability 2288 if (!HasVNodeCapability(vnode, FS_VNODE_CAPABILITY_REMOVE_DIR)) 2289 return B_BAD_VALUE; 2290 2291 // get a free port 2292 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 2293 if (!port) 2294 return B_ERROR; 2295 PortReleaser _(fFileSystem->GetPortPool(), port); 2296 2297 // prepare the request 2298 RequestAllocator allocator(port->GetPort()); 2299 RemoveDirRequest* request; 2300 status_t error = AllocateRequest(allocator, &request); 2301 if (error != B_OK) 2302 return error; 2303 2304 request->volume = fUserlandVolume; 2305 request->node = vnode->clientNode; 2306 error = allocator.AllocateString(request->name, name); 2307 if (error != B_OK) 2308 return error; 2309 2310 // send the request 2311 KernelRequestHandler handler(this, REMOVE_DIR_REPLY); 2312 RemoveDirReply* reply; 2313 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 2314 if (error != B_OK) 2315 return error; 2316 RequestReleaser requestReleaser(port, reply); 2317 2318 // process the reply 2319 if (reply->error != B_OK) 2320 return reply->error; 2321 return error; 2322 } 2323 2324 // OpenDir 2325 status_t 2326 Volume::OpenDir(void* _node, void** cookie) 2327 { 2328 VNode* vnode = (VNode*)_node; 2329 2330 // check capability 2331 if (!HasVNodeCapability(vnode, FS_VNODE_CAPABILITY_OPEN_DIR)) 2332 return B_BAD_VALUE; 2333 2334 // get a free port 2335 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 2336 if (!port) 2337 return B_ERROR; 2338 PortReleaser _(fFileSystem->GetPortPool(), port); 2339 AutoIncrementer incrementer(&fOpenDirectories); 2340 2341 // prepare the request 2342 RequestAllocator allocator(port->GetPort()); 2343 OpenDirRequest* request; 2344 status_t error = AllocateRequest(allocator, &request); 2345 if (error != B_OK) 2346 return error; 2347 2348 request->volume = fUserlandVolume; 2349 request->node = vnode->clientNode; 2350 2351 // send the request 2352 KernelRequestHandler handler(this, OPEN_DIR_REPLY); 2353 OpenDirReply* reply; 2354 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 2355 if (error != B_OK) 2356 return error; 2357 RequestReleaser requestReleaser(port, reply); 2358 2359 // process the reply 2360 if (reply->error != B_OK) 2361 return reply->error; 2362 incrementer.Keep(); 2363 *cookie = reply->dirCookie; 2364 return error; 2365 } 2366 2367 // CloseDir 2368 status_t 2369 Volume::CloseDir(void* node, void* cookie) 2370 { 2371 status_t error = _CloseDir(node, cookie); 2372 if (error != B_OK && fFileSystem->GetPortPool()->IsDisconnected()) { 2373 // This isn't really necessary, as the return value is irrelevant to 2374 // the VFS. OBOS ignores it completely. The fsshell returns it to the 2375 // userland, but considers the node closed anyway. 2376 WARN(("Volume::CloseDir(): connection lost, forcing close dir\n")); 2377 return B_OK; 2378 } 2379 return error; 2380 } 2381 2382 // FreeDirCookie 2383 status_t 2384 Volume::FreeDirCookie(void* node, void* cookie) 2385 { 2386 status_t error = _FreeDirCookie(node, cookie); 2387 bool disconnected = false; 2388 if (error != B_OK && fFileSystem->GetPortPool()->IsDisconnected()) { 2389 // This isn't really necessary, as the return value is irrelevant to 2390 // the VFS. It's completely ignored by OBOS as well as by the fsshell. 2391 WARN(("Volume::FreeDirCookie(): connection lost, forcing free dir " 2392 "cookie\n")); 2393 error = B_OK; 2394 disconnected = true; 2395 } 2396 int32 openDirs = atomic_add(&fOpenDirectories, -1); 2397 if (openDirs <= 1 && disconnected) 2398 _PutAllPendingVNodes(); 2399 return error; 2400 } 2401 2402 // ReadDir 2403 status_t 2404 Volume::ReadDir(void* _node, void* cookie, void* buffer, size_t bufferSize, 2405 uint32 count, uint32* countRead) 2406 { 2407 VNode* vnode = (VNode*)_node; 2408 2409 *countRead = 0; 2410 2411 // check capability 2412 if (!HasVNodeCapability(vnode, FS_VNODE_CAPABILITY_READ_DIR)) 2413 return B_BAD_VALUE; 2414 2415 // get a free port 2416 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 2417 if (!port) 2418 return B_ERROR; 2419 PortReleaser _(fFileSystem->GetPortPool(), port); 2420 2421 // prepare the request 2422 RequestAllocator allocator(port->GetPort()); 2423 ReadDirRequest* request; 2424 status_t error = AllocateRequest(allocator, &request); 2425 if (error != B_OK) 2426 return error; 2427 2428 request->volume = fUserlandVolume; 2429 request->node = vnode->clientNode; 2430 request->dirCookie = cookie; 2431 request->bufferSize = bufferSize; 2432 request->count = count; 2433 2434 // send the request 2435 KernelRequestHandler handler(this, READ_DIR_REPLY); 2436 ReadDirReply* reply; 2437 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 2438 if (error != B_OK) 2439 return error; 2440 RequestReleaser requestReleaser(port, reply); 2441 2442 // process the reply 2443 if (reply->error != B_OK) 2444 return reply->error; 2445 if (reply->count < 0 || reply->count > count) 2446 return B_BAD_DATA; 2447 if ((int32)bufferSize < reply->buffer.GetSize()) 2448 return B_BAD_DATA; 2449 PRINT(("Volume::ReadDir(): buffer returned: %ld bytes\n", 2450 reply->buffer.GetSize())); 2451 2452 *countRead = reply->count; 2453 if (*countRead > 0) { 2454 // copy the buffer -- limit the number of bytes to copy 2455 uint32 maxBytes = *countRead 2456 * (sizeof(struct dirent) + B_FILE_NAME_LENGTH); 2457 uint32 copyBytes = reply->buffer.GetSize(); 2458 if (copyBytes > maxBytes) 2459 copyBytes = maxBytes; 2460 memcpy(buffer, reply->buffer.GetData(), copyBytes); 2461 } 2462 _SendReceiptAck(port); 2463 return error; 2464 } 2465 2466 // RewindDir 2467 status_t 2468 Volume::RewindDir(void* _node, void* cookie) 2469 { 2470 VNode* vnode = (VNode*)_node; 2471 2472 // check capability 2473 if (!HasVNodeCapability(vnode, FS_VNODE_CAPABILITY_REWIND_DIR)) 2474 return B_BAD_VALUE; 2475 2476 // get a free port 2477 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 2478 if (!port) 2479 return B_ERROR; 2480 PortReleaser _(fFileSystem->GetPortPool(), port); 2481 2482 // prepare the request 2483 RequestAllocator allocator(port->GetPort()); 2484 RewindDirRequest* request; 2485 status_t error = AllocateRequest(allocator, &request); 2486 if (error != B_OK) 2487 return error; 2488 2489 request->volume = fUserlandVolume; 2490 request->node = vnode->clientNode; 2491 request->dirCookie = cookie; 2492 2493 // send the request 2494 KernelRequestHandler handler(this, REWIND_DIR_REPLY); 2495 RewindDirReply* reply; 2496 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 2497 if (error != B_OK) 2498 return error; 2499 RequestReleaser requestReleaser(port, reply); 2500 2501 // process the reply 2502 if (reply->error != B_OK) 2503 return reply->error; 2504 return error; 2505 } 2506 2507 2508 // #pragma mark - attribute directories 2509 2510 2511 // OpenAttrDir 2512 status_t 2513 Volume::OpenAttrDir(void* _node, void** cookie) 2514 { 2515 VNode* vnode = (VNode*)_node; 2516 2517 // check capability 2518 if (!HasVNodeCapability(vnode, FS_VNODE_CAPABILITY_OPEN_ATTR_DIR)) 2519 return B_BAD_VALUE; 2520 2521 // get a free port 2522 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 2523 if (!port) 2524 return B_ERROR; 2525 PortReleaser _(fFileSystem->GetPortPool(), port); 2526 AutoIncrementer incrementer(&fOpenAttributeDirectories); 2527 2528 // prepare the request 2529 RequestAllocator allocator(port->GetPort()); 2530 OpenAttrDirRequest* request; 2531 status_t error = AllocateRequest(allocator, &request); 2532 if (error != B_OK) 2533 return error; 2534 2535 request->volume = fUserlandVolume; 2536 request->node = vnode->clientNode; 2537 2538 // send the request 2539 KernelRequestHandler handler(this, OPEN_ATTR_DIR_REPLY); 2540 OpenAttrDirReply* reply; 2541 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 2542 if (error != B_OK) 2543 return error; 2544 RequestReleaser requestReleaser(port, reply); 2545 2546 // process the reply 2547 if (reply->error != B_OK) 2548 return reply->error; 2549 incrementer.Keep(); 2550 *cookie = reply->attrDirCookie; 2551 return error; 2552 } 2553 2554 // CloseAttrDir 2555 status_t 2556 Volume::CloseAttrDir(void* node, void* cookie) 2557 { 2558 status_t error = _CloseAttrDir(node, cookie); 2559 if (error != B_OK && fFileSystem->GetPortPool()->IsDisconnected()) { 2560 // This isn't really necessary, as the return value is irrelevant to 2561 // the VFS. OBOS ignores it completely. The fsshell returns it to the 2562 // userland, but considers the node closed anyway. 2563 WARN(("Volume::CloseAttrDir(): connection lost, forcing close attr " 2564 "dir\n")); 2565 return B_OK; 2566 } 2567 return error; 2568 } 2569 2570 // FreeAttrDirCookie 2571 status_t 2572 Volume::FreeAttrDirCookie(void* node, void* cookie) 2573 { 2574 status_t error = _FreeAttrDirCookie(node, cookie); 2575 bool disconnected = false; 2576 if (error != B_OK && fFileSystem->GetPortPool()->IsDisconnected()) { 2577 // This isn't really necessary, as the return value is irrelevant to 2578 // the VFS. It's completely ignored by OBOS as well as by the fsshell. 2579 WARN(("Volume::FreeAttrDirCookie(): connection lost, forcing free attr " 2580 "dir cookie\n")); 2581 error = B_OK; 2582 disconnected = true; 2583 } 2584 2585 int32 openAttrDirs = atomic_add(&fOpenAttributeDirectories, -1); 2586 if (openAttrDirs <= 1 && disconnected) 2587 _PutAllPendingVNodes(); 2588 return error; 2589 } 2590 2591 // ReadAttrDir 2592 status_t 2593 Volume::ReadAttrDir(void* _node, void* cookie, void* buffer, 2594 size_t bufferSize, uint32 count, uint32* countRead) 2595 { 2596 VNode* vnode = (VNode*)_node; 2597 2598 // check capability 2599 if (!HasVNodeCapability(vnode, FS_VNODE_CAPABILITY_READ_ATTR_DIR)) 2600 return B_BAD_VALUE; 2601 2602 *countRead = 0; 2603 // get a free port 2604 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 2605 if (!port) 2606 return B_ERROR; 2607 PortReleaser _(fFileSystem->GetPortPool(), port); 2608 2609 // prepare the request 2610 RequestAllocator allocator(port->GetPort()); 2611 ReadAttrDirRequest* request; 2612 status_t error = AllocateRequest(allocator, &request); 2613 if (error != B_OK) 2614 return error; 2615 2616 request->volume = fUserlandVolume; 2617 request->node = vnode->clientNode; 2618 request->attrDirCookie = cookie; 2619 request->bufferSize = bufferSize; 2620 request->count = count; 2621 2622 // send the request 2623 KernelRequestHandler handler(this, READ_ATTR_DIR_REPLY); 2624 ReadAttrDirReply* reply; 2625 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 2626 if (error != B_OK) 2627 return error; 2628 RequestReleaser requestReleaser(port, reply); 2629 2630 // process the reply 2631 if (reply->error != B_OK) 2632 return reply->error; 2633 if (reply->count < 0 || reply->count > count) 2634 return B_BAD_DATA; 2635 if ((int32)bufferSize < reply->buffer.GetSize()) 2636 return B_BAD_DATA; 2637 2638 *countRead = reply->count; 2639 if (*countRead > 0) { 2640 // copy the buffer -- limit the number of bytes to copy 2641 uint32 maxBytes = *countRead 2642 * (sizeof(struct dirent) + B_ATTR_NAME_LENGTH); 2643 uint32 copyBytes = reply->buffer.GetSize(); 2644 if (copyBytes > maxBytes) 2645 copyBytes = maxBytes; 2646 memcpy(buffer, reply->buffer.GetData(), copyBytes); 2647 } 2648 _SendReceiptAck(port); 2649 return error; 2650 } 2651 2652 // RewindAttrDir 2653 status_t 2654 Volume::RewindAttrDir(void* _node, void* cookie) 2655 { 2656 VNode* vnode = (VNode*)_node; 2657 2658 // check capability 2659 if (!HasVNodeCapability(vnode, FS_VNODE_CAPABILITY_REWIND_ATTR_DIR)) 2660 return B_BAD_VALUE; 2661 2662 // get a free port 2663 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 2664 if (!port) 2665 return B_ERROR; 2666 PortReleaser _(fFileSystem->GetPortPool(), port); 2667 2668 // prepare the request 2669 RequestAllocator allocator(port->GetPort()); 2670 RewindAttrDirRequest* request; 2671 status_t error = AllocateRequest(allocator, &request); 2672 if (error != B_OK) 2673 return error; 2674 2675 request->volume = fUserlandVolume; 2676 request->node = vnode->clientNode; 2677 request->attrDirCookie = cookie; 2678 2679 // send the request 2680 KernelRequestHandler handler(this, REWIND_ATTR_DIR_REPLY); 2681 RewindAttrDirReply* reply; 2682 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 2683 if (error != B_OK) 2684 return error; 2685 RequestReleaser requestReleaser(port, reply); 2686 2687 // process the reply 2688 if (reply->error != B_OK) 2689 return reply->error; 2690 return error; 2691 } 2692 2693 2694 // #pragma mark - attributes 2695 2696 // CreateAttr 2697 status_t 2698 Volume::CreateAttr(void* _node, const char* name, uint32 type, int openMode, 2699 void** cookie) 2700 { 2701 VNode* vnode = (VNode*)_node; 2702 2703 // check capability 2704 if (!HasVNodeCapability(vnode, FS_VNODE_CAPABILITY_CREATE_ATTR)) 2705 return B_BAD_VALUE; 2706 2707 // get a free port 2708 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 2709 if (!port) 2710 return B_ERROR; 2711 PortReleaser _(fFileSystem->GetPortPool(), port); 2712 AutoIncrementer incrementer(&fOpenAttributes); 2713 2714 // prepare the request 2715 RequestAllocator allocator(port->GetPort()); 2716 CreateAttrRequest* request; 2717 status_t error = AllocateRequest(allocator, &request); 2718 if (error != B_OK) 2719 return error; 2720 2721 request->volume = fUserlandVolume; 2722 request->node = vnode->clientNode; 2723 error = allocator.AllocateString(request->name, name); 2724 request->type = type; 2725 request->openMode = openMode; 2726 if (error != B_OK) 2727 return error; 2728 2729 // send the request 2730 KernelRequestHandler handler(this, CREATE_ATTR_REPLY); 2731 CreateAttrReply* reply; 2732 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 2733 if (error != B_OK) 2734 return error; 2735 RequestReleaser requestReleaser(port, reply); 2736 2737 // process the reply 2738 if (reply->error != B_OK) 2739 return reply->error; 2740 incrementer.Keep(); 2741 *cookie = reply->attrCookie; 2742 return error; 2743 } 2744 2745 // OpenAttr 2746 status_t 2747 Volume::OpenAttr(void* _node, const char* name, int openMode, 2748 void** cookie) 2749 { 2750 VNode* vnode = (VNode*)_node; 2751 2752 // check capability 2753 if (!HasVNodeCapability(vnode, FS_VNODE_CAPABILITY_OPEN_ATTR)) 2754 return B_BAD_VALUE; 2755 2756 // get a free port 2757 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 2758 if (!port) 2759 return B_ERROR; 2760 PortReleaser _(fFileSystem->GetPortPool(), port); 2761 AutoIncrementer incrementer(&fOpenAttributes); 2762 2763 // prepare the request 2764 RequestAllocator allocator(port->GetPort()); 2765 OpenAttrRequest* request; 2766 status_t error = AllocateRequest(allocator, &request); 2767 if (error != B_OK) 2768 return error; 2769 2770 request->volume = fUserlandVolume; 2771 request->node = vnode->clientNode; 2772 error = allocator.AllocateString(request->name, name); 2773 request->openMode = openMode; 2774 if (error != B_OK) 2775 return error; 2776 2777 // send the request 2778 KernelRequestHandler handler(this, OPEN_ATTR_REPLY); 2779 OpenAttrReply* reply; 2780 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 2781 if (error != B_OK) 2782 return error; 2783 RequestReleaser requestReleaser(port, reply); 2784 2785 // process the reply 2786 if (reply->error != B_OK) 2787 return reply->error; 2788 incrementer.Keep(); 2789 *cookie = reply->attrCookie; 2790 return error; 2791 } 2792 2793 // CloseAttr 2794 status_t 2795 Volume::CloseAttr(void* node, void* cookie) 2796 { 2797 status_t error = _CloseAttr(node, cookie); 2798 if (error != B_OK && fFileSystem->GetPortPool()->IsDisconnected()) { 2799 // This isn't really necessary, as the return value is irrelevant to 2800 // the VFS. OBOS ignores it completely. The fsshell returns it to the 2801 // userland, but considers the node closed anyway. 2802 WARN(("Volume::CloseAttr(): connection lost, forcing close attr\n")); 2803 return B_OK; 2804 } 2805 return error; 2806 } 2807 2808 // FreeAttrCookie 2809 status_t 2810 Volume::FreeAttrCookie(void* node, void* cookie) 2811 { 2812 status_t error = _FreeAttrCookie(node, cookie); 2813 bool disconnected = false; 2814 if (error != B_OK && fFileSystem->GetPortPool()->IsDisconnected()) { 2815 // This isn't really necessary, as the return value is irrelevant to 2816 // the VFS. It's completely ignored by OBOS as well as by the fsshell. 2817 WARN(("Volume::FreeAttrCookie(): connection lost, forcing free attr " 2818 "cookie\n")); 2819 error = B_OK; 2820 disconnected = true; 2821 } 2822 2823 int32 openAttributes = atomic_add(&fOpenAttributes, -1); 2824 if (openAttributes <= 1 && disconnected) 2825 _PutAllPendingVNodes(); 2826 return error; 2827 } 2828 2829 // ReadAttr 2830 status_t 2831 Volume::ReadAttr(void* _node, void* cookie, off_t pos, 2832 void* buffer, size_t bufferSize, size_t* bytesRead) 2833 { 2834 VNode* vnode = (VNode*)_node; 2835 2836 *bytesRead = 0; 2837 2838 // check capability 2839 if (!HasVNodeCapability(vnode, FS_VNODE_CAPABILITY_READ_ATTR)) 2840 return B_BAD_VALUE; 2841 2842 // get a free port 2843 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 2844 if (!port) 2845 return B_ERROR; 2846 PortReleaser _(fFileSystem->GetPortPool(), port); 2847 2848 // prepare the request 2849 RequestAllocator allocator(port->GetPort()); 2850 ReadAttrRequest* request; 2851 status_t error = AllocateRequest(allocator, &request); 2852 if (error != B_OK) 2853 return error; 2854 2855 request->volume = fUserlandVolume; 2856 request->node = vnode->clientNode; 2857 request->attrCookie = cookie; 2858 request->pos = pos; 2859 request->size = bufferSize; 2860 2861 // send the request 2862 KernelRequestHandler handler(this, READ_ATTR_REPLY); 2863 ReadAttrReply* reply; 2864 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 2865 if (error != B_OK) 2866 return error; 2867 RequestReleaser requestReleaser(port, reply); 2868 2869 // process the reply 2870 if (reply->error != B_OK) 2871 return reply->error; 2872 void* readBuffer = reply->buffer.GetData(); 2873 if (reply->bytesRead > (uint32)reply->buffer.GetSize() 2874 || reply->bytesRead > bufferSize) { 2875 return B_BAD_DATA; 2876 } 2877 if (reply->bytesRead > 0) 2878 memcpy(buffer, readBuffer, reply->bytesRead); 2879 *bytesRead = reply->bytesRead; 2880 _SendReceiptAck(port); 2881 return error; 2882 } 2883 2884 // WriteAttr 2885 status_t 2886 Volume::WriteAttr(void* _node, void* cookie, off_t pos, 2887 const void* buffer, size_t bufferSize, size_t* bytesWritten) 2888 { 2889 VNode* vnode = (VNode*)_node; 2890 2891 *bytesWritten = 0; 2892 2893 // check capability 2894 if (!HasVNodeCapability(vnode, FS_VNODE_CAPABILITY_WRITE_ATTR)) 2895 return B_BAD_VALUE; 2896 2897 // get a free port 2898 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 2899 if (!port) 2900 return B_ERROR; 2901 PortReleaser _(fFileSystem->GetPortPool(), port); 2902 2903 // prepare the request 2904 RequestAllocator allocator(port->GetPort()); 2905 WriteAttrRequest* request; 2906 status_t error = AllocateRequest(allocator, &request); 2907 if (error != B_OK) 2908 return error; 2909 2910 request->volume = fUserlandVolume; 2911 request->node = vnode->clientNode; 2912 request->attrCookie = cookie; 2913 request->pos = pos; 2914 error = allocator.AllocateData(request->buffer, buffer, bufferSize, 1); 2915 if (error != B_OK) 2916 return error; 2917 2918 // send the request 2919 KernelRequestHandler handler(this, WRITE_ATTR_REPLY); 2920 WriteAttrReply* reply; 2921 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 2922 if (error != B_OK) 2923 return error; 2924 RequestReleaser requestReleaser(port, reply); 2925 2926 // process the reply 2927 if (reply->error != B_OK) 2928 return reply->error; 2929 *bytesWritten = reply->bytesWritten; 2930 return error; 2931 } 2932 2933 // ReadAttrStat 2934 status_t 2935 Volume::ReadAttrStat(void* _node, void* cookie, struct stat *st) 2936 { 2937 VNode* vnode = (VNode*)_node; 2938 2939 // check capability 2940 if (!HasVNodeCapability(vnode, FS_VNODE_CAPABILITY_READ_ATTR_STAT)) 2941 return B_BAD_VALUE; 2942 2943 // get a free port 2944 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 2945 if (!port) 2946 return B_ERROR; 2947 PortReleaser _(fFileSystem->GetPortPool(), port); 2948 2949 // prepare the request 2950 RequestAllocator allocator(port->GetPort()); 2951 ReadAttrStatRequest* request; 2952 status_t error = AllocateRequest(allocator, &request); 2953 if (error != B_OK) 2954 return error; 2955 2956 request->volume = fUserlandVolume; 2957 request->node = vnode->clientNode; 2958 request->attrCookie = cookie; 2959 2960 // send the request 2961 KernelRequestHandler handler(this, READ_ATTR_STAT_REPLY); 2962 ReadAttrStatReply* reply; 2963 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 2964 if (error != B_OK) 2965 return error; 2966 RequestReleaser requestReleaser(port, reply); 2967 2968 // process the reply 2969 if (reply->error != B_OK) 2970 return reply->error; 2971 *st = reply->st; 2972 return error; 2973 } 2974 2975 // WriteAttrStat 2976 status_t 2977 Volume::WriteAttrStat(void* _node, void* cookie, const struct stat *st, 2978 int statMask) 2979 { 2980 VNode* vnode = (VNode*)_node; 2981 2982 // check capability 2983 if (!HasVNodeCapability(vnode, FS_VNODE_CAPABILITY_WRITE_ATTR_STAT)) 2984 return B_BAD_VALUE; 2985 2986 // get a free port 2987 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 2988 if (!port) 2989 return B_ERROR; 2990 PortReleaser _(fFileSystem->GetPortPool(), port); 2991 2992 // prepare the request 2993 RequestAllocator allocator(port->GetPort()); 2994 WriteAttrStatRequest* request; 2995 status_t error = AllocateRequest(allocator, &request); 2996 if (error != B_OK) 2997 return error; 2998 2999 request->volume = fUserlandVolume; 3000 request->node = vnode->clientNode; 3001 request->attrCookie = cookie; 3002 request->st = *st; 3003 request->mask = statMask; 3004 3005 // send the request 3006 KernelRequestHandler handler(this, WRITE_ATTR_STAT_REPLY); 3007 WriteAttrStatReply* reply; 3008 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 3009 if (error != B_OK) 3010 return error; 3011 RequestReleaser requestReleaser(port, reply); 3012 3013 // process the reply 3014 if (reply->error != B_OK) 3015 return reply->error; 3016 return error; 3017 } 3018 3019 // RenameAttr 3020 status_t 3021 Volume::RenameAttr(void* _oldNode, const char* oldName, void* _newNode, 3022 const char* newName) 3023 { 3024 VNode* oldVNode = (VNode*)_oldNode; 3025 VNode* newVNode = (VNode*)_newNode; 3026 3027 // check capability 3028 if (!HasVNodeCapability(oldVNode, FS_VNODE_CAPABILITY_RENAME_ATTR)) 3029 return B_BAD_VALUE; 3030 3031 // get a free port 3032 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 3033 if (!port) 3034 return B_ERROR; 3035 PortReleaser _(fFileSystem->GetPortPool(), port); 3036 3037 // prepare the request 3038 RequestAllocator allocator(port->GetPort()); 3039 RenameAttrRequest* request; 3040 status_t error = AllocateRequest(allocator, &request); 3041 if (error != B_OK) 3042 return error; 3043 3044 request->volume = fUserlandVolume; 3045 request->oldNode = oldVNode->clientNode; 3046 request->newNode = newVNode->clientNode; 3047 error = allocator.AllocateString(request->oldName, oldName); 3048 if (error == B_OK) 3049 error = allocator.AllocateString(request->newName, newName); 3050 if (error != B_OK) 3051 return error; 3052 3053 // send the request 3054 KernelRequestHandler handler(this, RENAME_ATTR_REPLY); 3055 RenameAttrReply* reply; 3056 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 3057 if (error != B_OK) 3058 return error; 3059 RequestReleaser requestReleaser(port, reply); 3060 3061 // process the reply 3062 if (reply->error != B_OK) 3063 return reply->error; 3064 return error; 3065 } 3066 3067 // RemoveAttr 3068 status_t 3069 Volume::RemoveAttr(void* _node, const char* name) 3070 { 3071 VNode* vnode = (VNode*)_node; 3072 3073 // check capability 3074 if (!HasVNodeCapability(vnode, FS_VNODE_CAPABILITY_REMOVE_ATTR)) 3075 return B_BAD_VALUE; 3076 3077 // get a free port 3078 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 3079 if (!port) 3080 return B_ERROR; 3081 PortReleaser _(fFileSystem->GetPortPool(), port); 3082 3083 // prepare the request 3084 RequestAllocator allocator(port->GetPort()); 3085 RemoveAttrRequest* request; 3086 status_t error = AllocateRequest(allocator, &request); 3087 if (error != B_OK) 3088 return error; 3089 3090 request->volume = fUserlandVolume; 3091 request->node = vnode->clientNode; 3092 error = allocator.AllocateString(request->name, name); 3093 if (error != B_OK) 3094 return error; 3095 3096 // send the request 3097 KernelRequestHandler handler(this, REMOVE_ATTR_REPLY); 3098 RemoveAttrReply* reply; 3099 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 3100 if (error != B_OK) 3101 return error; 3102 RequestReleaser requestReleaser(port, reply); 3103 3104 // process the reply 3105 if (reply->error != B_OK) 3106 return reply->error; 3107 return error; 3108 } 3109 3110 3111 // #pragma mark - indices 3112 3113 3114 // OpenIndexDir 3115 status_t 3116 Volume::OpenIndexDir(void** cookie) 3117 { 3118 // check capability 3119 if (!HasCapability(FS_VOLUME_CAPABILITY_OPEN_INDEX_DIR)) 3120 return B_BAD_VALUE; 3121 3122 // get a free port 3123 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 3124 if (!port) 3125 return B_ERROR; 3126 PortReleaser _(fFileSystem->GetPortPool(), port); 3127 AutoIncrementer incrementer(&fOpenIndexDirectories); 3128 3129 // prepare the request 3130 RequestAllocator allocator(port->GetPort()); 3131 OpenIndexDirRequest* request; 3132 status_t error = AllocateRequest(allocator, &request); 3133 if (error != B_OK) 3134 return error; 3135 3136 request->volume = fUserlandVolume; 3137 3138 // send the request 3139 KernelRequestHandler handler(this, OPEN_INDEX_DIR_REPLY); 3140 OpenIndexDirReply* reply; 3141 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 3142 if (error != B_OK) 3143 return error; 3144 RequestReleaser requestReleaser(port, reply); 3145 3146 // process the reply 3147 if (reply->error != B_OK) 3148 return reply->error; 3149 incrementer.Keep(); 3150 *cookie = reply->indexDirCookie; 3151 return error; 3152 } 3153 3154 // CloseIndexDir 3155 status_t 3156 Volume::CloseIndexDir(void* cookie) 3157 { 3158 status_t error = _CloseIndexDir(cookie); 3159 if (error != B_OK && fFileSystem->GetPortPool()->IsDisconnected()) { 3160 // This isn't really necessary, as the return value is irrelevant to 3161 // the VFS. OBOS ignores it completely. The fsshell returns it to the 3162 // userland, but considers the node closed anyway. 3163 WARN(("Volume::CloseIndexDir(): connection lost, forcing close " 3164 "index dir\n")); 3165 return B_OK; 3166 } 3167 return error; 3168 } 3169 3170 // FreeIndexDirCookie 3171 status_t 3172 Volume::FreeIndexDirCookie(void* cookie) 3173 { 3174 status_t error = _FreeIndexDirCookie(cookie); 3175 bool disconnected = false; 3176 if (error != B_OK && fFileSystem->GetPortPool()->IsDisconnected()) { 3177 // This isn't really necessary, as the return value is irrelevant to 3178 // the VFS. It's completely ignored by OBOS as well as by the fsshell. 3179 WARN(("Volume::FreeIndexDirCookie(): connection lost, forcing free " 3180 "index dir cookie\n")); 3181 error = B_OK; 3182 disconnected = true; 3183 } 3184 3185 int32 openIndexDirs = atomic_add(&fOpenIndexDirectories, -1); 3186 if (openIndexDirs <= 1 && disconnected) 3187 _PutAllPendingVNodes(); 3188 return error; 3189 } 3190 3191 // ReadIndexDir 3192 status_t 3193 Volume::ReadIndexDir(void* cookie, void* buffer, size_t bufferSize, 3194 uint32 count, uint32* countRead) 3195 { 3196 *countRead = 0; 3197 3198 // check capability 3199 if (!HasCapability(FS_VOLUME_CAPABILITY_READ_INDEX_DIR)) 3200 return B_BAD_VALUE; 3201 3202 // get a free port 3203 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 3204 if (!port) 3205 return B_ERROR; 3206 PortReleaser _(fFileSystem->GetPortPool(), port); 3207 3208 // prepare the request 3209 RequestAllocator allocator(port->GetPort()); 3210 ReadIndexDirRequest* request; 3211 status_t error = AllocateRequest(allocator, &request); 3212 if (error != B_OK) 3213 return error; 3214 3215 request->volume = fUserlandVolume; 3216 request->indexDirCookie = cookie; 3217 request->bufferSize = bufferSize; 3218 request->count = count; 3219 3220 // send the request 3221 KernelRequestHandler handler(this, READ_INDEX_DIR_REPLY); 3222 ReadIndexDirReply* reply; 3223 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 3224 if (error != B_OK) 3225 return error; 3226 RequestReleaser requestReleaser(port, reply); 3227 3228 // process the reply 3229 if (reply->error != B_OK) 3230 return reply->error; 3231 if (reply->count < 0 || reply->count > count) 3232 return B_BAD_DATA; 3233 if ((int32)bufferSize < reply->buffer.GetSize()) 3234 return B_BAD_DATA; 3235 3236 *countRead = reply->count; 3237 if (*countRead > 0) { 3238 // copy the buffer -- limit the number of bytes to copy 3239 uint32 maxBytes = *countRead 3240 * (sizeof(struct dirent) + B_FILE_NAME_LENGTH); 3241 uint32 copyBytes = reply->buffer.GetSize(); 3242 if (copyBytes > maxBytes) 3243 copyBytes = maxBytes; 3244 memcpy(buffer, reply->buffer.GetData(), copyBytes); 3245 } 3246 _SendReceiptAck(port); 3247 return error; 3248 } 3249 3250 // RewindIndexDir 3251 status_t 3252 Volume::RewindIndexDir(void* cookie) 3253 { 3254 // check capability 3255 if (!HasCapability(FS_VOLUME_CAPABILITY_REWIND_INDEX_DIR)) 3256 return B_BAD_VALUE; 3257 3258 // get a free port 3259 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 3260 if (!port) 3261 return B_ERROR; 3262 PortReleaser _(fFileSystem->GetPortPool(), port); 3263 3264 // prepare the request 3265 RequestAllocator allocator(port->GetPort()); 3266 RewindIndexDirRequest* request; 3267 status_t error = AllocateRequest(allocator, &request); 3268 if (error != B_OK) 3269 return error; 3270 3271 request->volume = fUserlandVolume; 3272 request->indexDirCookie = cookie; 3273 3274 // send the request 3275 KernelRequestHandler handler(this, REWIND_INDEX_DIR_REPLY); 3276 RewindIndexDirReply* reply; 3277 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 3278 if (error != B_OK) 3279 return error; 3280 RequestReleaser requestReleaser(port, reply); 3281 3282 // process the reply 3283 if (reply->error != B_OK) 3284 return reply->error; 3285 return error; 3286 } 3287 3288 // CreateIndex 3289 status_t 3290 Volume::CreateIndex(const char* name, uint32 type, uint32 flags) 3291 { 3292 // check capability 3293 if (!HasCapability(FS_VOLUME_CAPABILITY_CREATE_INDEX)) 3294 return B_BAD_VALUE; 3295 3296 // get a free port 3297 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 3298 if (!port) 3299 return B_ERROR; 3300 PortReleaser _(fFileSystem->GetPortPool(), port); 3301 3302 // prepare the request 3303 RequestAllocator allocator(port->GetPort()); 3304 CreateIndexRequest* request; 3305 status_t error = AllocateRequest(allocator, &request); 3306 if (error != B_OK) 3307 return error; 3308 3309 request->volume = fUserlandVolume; 3310 error = allocator.AllocateString(request->name, name); 3311 request->type = type; 3312 request->flags = flags; 3313 if (error != B_OK) 3314 return error; 3315 3316 // send the request 3317 KernelRequestHandler handler(this, CREATE_INDEX_REPLY); 3318 CreateIndexReply* reply; 3319 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 3320 if (error != B_OK) 3321 return error; 3322 RequestReleaser requestReleaser(port, reply); 3323 3324 // process the reply 3325 if (reply->error != B_OK) 3326 return reply->error; 3327 return error; 3328 } 3329 3330 // RemoveIndex 3331 status_t 3332 Volume::RemoveIndex(const char* name) 3333 { 3334 // check capability 3335 if (!HasCapability(FS_VOLUME_CAPABILITY_REMOVE_INDEX)) 3336 return B_BAD_VALUE; 3337 3338 // get a free port 3339 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 3340 if (!port) 3341 return B_ERROR; 3342 PortReleaser _(fFileSystem->GetPortPool(), port); 3343 3344 // prepare the request 3345 RequestAllocator allocator(port->GetPort()); 3346 RemoveIndexRequest* request; 3347 status_t error = AllocateRequest(allocator, &request); 3348 if (error != B_OK) 3349 return error; 3350 3351 request->volume = fUserlandVolume; 3352 error = allocator.AllocateString(request->name, name); 3353 if (error != B_OK) 3354 return error; 3355 3356 // send the request 3357 KernelRequestHandler handler(this, REMOVE_INDEX_REPLY); 3358 RemoveIndexReply* reply; 3359 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 3360 if (error != B_OK) 3361 return error; 3362 RequestReleaser requestReleaser(port, reply); 3363 3364 // process the reply 3365 if (reply->error != B_OK) 3366 return reply->error; 3367 return error; 3368 } 3369 3370 // ReadIndexStat 3371 status_t 3372 Volume::ReadIndexStat(const char* name, struct stat *st) 3373 { 3374 // check capability 3375 if (!HasCapability(FS_VOLUME_CAPABILITY_READ_INDEX_STAT)) 3376 return B_BAD_VALUE; 3377 3378 // get a free port 3379 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 3380 if (!port) 3381 return B_ERROR; 3382 PortReleaser _(fFileSystem->GetPortPool(), port); 3383 3384 // prepare the request 3385 RequestAllocator allocator(port->GetPort()); 3386 ReadIndexStatRequest* request; 3387 status_t error = AllocateRequest(allocator, &request); 3388 if (error != B_OK) 3389 return error; 3390 3391 request->volume = fUserlandVolume; 3392 error = allocator.AllocateString(request->name, name); 3393 if (error != B_OK) 3394 return error; 3395 3396 // send the request 3397 KernelRequestHandler handler(this, READ_INDEX_STAT_REPLY); 3398 ReadIndexStatReply* reply; 3399 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 3400 if (error != B_OK) 3401 return error; 3402 RequestReleaser requestReleaser(port, reply); 3403 3404 // process the reply 3405 if (reply->error != B_OK) 3406 return reply->error; 3407 *st = reply->st; 3408 return error; 3409 } 3410 3411 3412 // #pragma mark - queries 3413 3414 3415 // OpenQuery 3416 status_t 3417 Volume::OpenQuery(const char* queryString, uint32 flags, port_id targetPort, 3418 uint32 token, void** cookie) 3419 { 3420 // check capability 3421 if (!HasCapability(FS_VOLUME_CAPABILITY_OPEN_QUERY)) 3422 return B_BAD_VALUE; 3423 3424 // get a free port 3425 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 3426 if (!port) 3427 return B_ERROR; 3428 PortReleaser _(fFileSystem->GetPortPool(), port); 3429 AutoIncrementer incrementer(&fOpenQueries); 3430 3431 // prepare the request 3432 RequestAllocator allocator(port->GetPort()); 3433 OpenQueryRequest* request; 3434 status_t error = AllocateRequest(allocator, &request); 3435 if (error != B_OK) 3436 return error; 3437 3438 request->volume = fUserlandVolume; 3439 error = allocator.AllocateString(request->queryString, queryString); 3440 if (error != B_OK) 3441 return error; 3442 request->flags = flags; 3443 request->port = targetPort; 3444 request->token = token; 3445 3446 // send the request 3447 KernelRequestHandler handler(this, OPEN_QUERY_REPLY); 3448 OpenQueryReply* reply; 3449 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 3450 if (error != B_OK) 3451 return error; 3452 RequestReleaser requestReleaser(port, reply); 3453 3454 // process the reply 3455 if (reply->error != B_OK) 3456 return reply->error; 3457 incrementer.Keep(); 3458 *cookie = reply->queryCookie; 3459 return error; 3460 } 3461 3462 // CloseQuery 3463 status_t 3464 Volume::CloseQuery(void* cookie) 3465 { 3466 status_t error = _CloseQuery(cookie); 3467 if (error != B_OK && fFileSystem->GetPortPool()->IsDisconnected()) { 3468 // This isn't really necessary, as the return value is irrelevant to 3469 // the VFS. OBOS ignores it completely. The fsshell returns it to the 3470 // userland, but considers the node closed anyway. 3471 WARN(("Volume::CloseQuery(): connection lost, forcing close query\n")); 3472 return B_OK; 3473 } 3474 return error; 3475 } 3476 3477 // FreeQueryCookie 3478 status_t 3479 Volume::FreeQueryCookie(void* cookie) 3480 { 3481 status_t error = _FreeQueryCookie(cookie); 3482 bool disconnected = false; 3483 if (error != B_OK && fFileSystem->GetPortPool()->IsDisconnected()) { 3484 // This isn't really necessary, as the return value is irrelevant to 3485 // the VFS. It's completely ignored by OBOS as well as by the fsshell. 3486 WARN(("Volume::FreeQueryCookie(): connection lost, forcing free " 3487 "query cookie\n")); 3488 error = B_OK; 3489 disconnected = true; 3490 } 3491 3492 int32 openQueries = atomic_add(&fOpenQueries, -1); 3493 if (openQueries <= 1 && disconnected) 3494 _PutAllPendingVNodes(); 3495 return error; 3496 } 3497 3498 // ReadQuery 3499 status_t 3500 Volume::ReadQuery(void* cookie, void* buffer, size_t bufferSize, 3501 uint32 count, uint32* countRead) 3502 { 3503 *countRead = 0; 3504 3505 // check capability 3506 if (!HasCapability(FS_VOLUME_CAPABILITY_READ_QUERY)) 3507 return B_BAD_VALUE; 3508 3509 // get a free port 3510 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 3511 if (!port) 3512 return B_ERROR; 3513 PortReleaser _(fFileSystem->GetPortPool(), port); 3514 3515 // prepare the request 3516 RequestAllocator allocator(port->GetPort()); 3517 ReadQueryRequest* request; 3518 status_t error = AllocateRequest(allocator, &request); 3519 if (error != B_OK) 3520 return error; 3521 3522 request->volume = fUserlandVolume; 3523 request->queryCookie = cookie; 3524 request->bufferSize = bufferSize; 3525 request->count = count; 3526 3527 // send the request 3528 KernelRequestHandler handler(this, READ_QUERY_REPLY); 3529 ReadQueryReply* reply; 3530 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 3531 if (error != B_OK) 3532 return error; 3533 RequestReleaser requestReleaser(port, reply); 3534 3535 // process the reply 3536 if (reply->error != B_OK) 3537 return reply->error; 3538 if (reply->count < 0 || reply->count > count) 3539 return B_BAD_DATA; 3540 if ((int32)bufferSize < reply->buffer.GetSize()) 3541 return B_BAD_DATA; 3542 3543 *countRead = reply->count; 3544 if (*countRead > 0) { 3545 // copy the buffer -- limit the number of bytes to copy 3546 uint32 maxBytes = *countRead 3547 * (sizeof(struct dirent) + B_FILE_NAME_LENGTH); 3548 uint32 copyBytes = reply->buffer.GetSize(); 3549 if (copyBytes > maxBytes) 3550 copyBytes = maxBytes; 3551 memcpy(buffer, reply->buffer.GetData(), copyBytes); 3552 } 3553 _SendReceiptAck(port); 3554 return error; 3555 } 3556 3557 // RewindQuery 3558 status_t 3559 Volume::RewindQuery(void* cookie) 3560 { 3561 // check capability 3562 if (!HasCapability(FS_VOLUME_CAPABILITY_REWIND_QUERY)) 3563 return B_BAD_VALUE; 3564 3565 // get a free port 3566 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 3567 if (!port) 3568 return B_ERROR; 3569 PortReleaser _(fFileSystem->GetPortPool(), port); 3570 3571 // prepare the request 3572 RequestAllocator allocator(port->GetPort()); 3573 RewindQueryRequest* request; 3574 status_t error = AllocateRequest(allocator, &request); 3575 if (error != B_OK) 3576 return error; 3577 3578 request->volume = fUserlandVolume; 3579 request->queryCookie = cookie; 3580 3581 // send the request 3582 KernelRequestHandler handler(this, REWIND_QUERY_REPLY); 3583 RewindQueryReply* reply; 3584 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 3585 if (error != B_OK) 3586 return error; 3587 RequestReleaser requestReleaser(port, reply); 3588 3589 // process the reply 3590 if (reply->error != B_OK) 3591 return reply->error; 3592 return error; 3593 } 3594 3595 // #pragma mark - 3596 // #pragma mark ----- private implementations ----- 3597 3598 3599 // _InitVolumeOps 3600 void 3601 Volume::_InitVolumeOps() 3602 { 3603 memcpy(&fVolumeOps, &gUserlandFSVolumeOps, sizeof(fs_volume_ops)); 3604 3605 #undef CLEAR_UNSUPPORTED 3606 #define CLEAR_UNSUPPORTED(capability, op) \ 3607 if (!fCapabilities.Get(capability)) \ 3608 fVolumeOps.op = NULL 3609 3610 // FS operations 3611 // FS_VOLUME_CAPABILITY_UNMOUNT: unmount 3612 // always needed 3613 3614 // FS_VOLUME_CAPABILITY_READ_FS_INFO: read_fs_info 3615 // always needed 3616 CLEAR_UNSUPPORTED(FS_VOLUME_CAPABILITY_WRITE_FS_INFO, write_fs_info); 3617 CLEAR_UNSUPPORTED(FS_VOLUME_CAPABILITY_SYNC, sync); 3618 3619 // vnode operations 3620 // FS_VOLUME_CAPABILITY_GET_VNODE: get_vnode 3621 // always needed 3622 3623 // index directory & index operations 3624 CLEAR_UNSUPPORTED(FS_VOLUME_CAPABILITY_OPEN_INDEX_DIR, open_index_dir); 3625 // FS_VOLUME_CAPABILITY_CLOSE_INDEX_DIR: close_index_dir 3626 // always needed 3627 // FS_VOLUME_CAPABILITY_FREE_INDEX_DIR_COOKIE: free_index_dir_cookie 3628 // always needed 3629 CLEAR_UNSUPPORTED(FS_VOLUME_CAPABILITY_READ_INDEX_DIR, read_index_dir); 3630 CLEAR_UNSUPPORTED(FS_VOLUME_CAPABILITY_REWIND_INDEX_DIR, rewind_index_dir); 3631 3632 CLEAR_UNSUPPORTED(FS_VOLUME_CAPABILITY_CREATE_INDEX, create_index); 3633 CLEAR_UNSUPPORTED(FS_VOLUME_CAPABILITY_REMOVE_INDEX, remove_index); 3634 CLEAR_UNSUPPORTED(FS_VOLUME_CAPABILITY_READ_INDEX_STAT, read_index_stat); 3635 3636 // query operations 3637 CLEAR_UNSUPPORTED(FS_VOLUME_CAPABILITY_OPEN_QUERY, open_query); 3638 // FS_VOLUME_CAPABILITY_CLOSE_QUERY: close_query 3639 // always needed 3640 // FS_VOLUME_CAPABILITY_FREE_QUERY_COOKIE: free_query_cookie 3641 // always needed 3642 CLEAR_UNSUPPORTED(FS_VOLUME_CAPABILITY_READ_QUERY, read_query); 3643 CLEAR_UNSUPPORTED(FS_VOLUME_CAPABILITY_REWIND_QUERY, rewind_query); 3644 3645 #undef CLEAR_UNSUPPORTED 3646 } 3647 3648 3649 // #pragma mark - 3650 3651 3652 // _Mount 3653 status_t 3654 Volume::_Mount(const char* device, uint32 flags, const char* parameters) 3655 { 3656 // get a free port 3657 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 3658 if (!port) 3659 return B_ERROR; 3660 PortReleaser _(fFileSystem->GetPortPool(), port); 3661 3662 // get the current working directory 3663 char cwd[B_PATH_NAME_LENGTH]; 3664 if (!getcwd(cwd, sizeof(cwd))) 3665 return errno; 3666 3667 // prepare the request 3668 RequestAllocator allocator(port->GetPort()); 3669 MountVolumeRequest* request; 3670 status_t error = AllocateRequest(allocator, &request); 3671 if (error != B_OK) 3672 return error; 3673 3674 request->nsid = GetID(); 3675 error = allocator.AllocateString(request->cwd, cwd); 3676 if (error == B_OK) 3677 error = allocator.AllocateString(request->device, device); 3678 request->flags = flags; 3679 if (error == B_OK) 3680 error = allocator.AllocateString(request->parameters, parameters); 3681 if (error != B_OK) 3682 return error; 3683 3684 // send the request 3685 KernelRequestHandler handler(this, MOUNT_VOLUME_REPLY); 3686 MountVolumeReply* reply; 3687 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 3688 if (error != B_OK) 3689 return error; 3690 RequestReleaser requestReleaser(port, reply); 3691 3692 // process the reply 3693 if (reply->error != B_OK) 3694 return reply->error; 3695 fRootID = reply->rootID; 3696 fUserlandVolume = reply->volume; 3697 fCapabilities = reply->capabilities; 3698 3699 return error; 3700 } 3701 3702 // _Unmount 3703 status_t 3704 Volume::_Unmount() 3705 { 3706 // get a free port 3707 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 3708 if (!port) 3709 return B_ERROR; 3710 PortReleaser _(fFileSystem->GetPortPool(), port); 3711 3712 // prepare the request 3713 RequestAllocator allocator(port->GetPort()); 3714 UnmountVolumeRequest* request; 3715 status_t error = AllocateRequest(allocator, &request); 3716 if (error != B_OK) 3717 return error; 3718 3719 request->volume = fUserlandVolume; 3720 3721 // send the request 3722 KernelRequestHandler handler(this, UNMOUNT_VOLUME_REPLY); 3723 UnmountVolumeReply* reply; 3724 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 3725 if (error != B_OK) 3726 return error; 3727 RequestReleaser requestReleaser(port, reply); 3728 3729 // process the reply 3730 if (reply->error != B_OK) 3731 return reply->error; 3732 return error; 3733 } 3734 3735 // _ReadFSInfo 3736 status_t 3737 Volume::_ReadFSInfo(fs_info* info) 3738 { 3739 // check capability 3740 if (!HasCapability(FS_VOLUME_CAPABILITY_READ_FS_INFO)) 3741 return B_BAD_VALUE; 3742 3743 // get a free port 3744 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 3745 if (!port) 3746 return B_ERROR; 3747 PortReleaser _(fFileSystem->GetPortPool(), port); 3748 3749 // prepare the request 3750 RequestAllocator allocator(port->GetPort()); 3751 ReadFSInfoRequest* request; 3752 status_t error = AllocateRequest(allocator, &request); 3753 if (error != B_OK) 3754 return error; 3755 3756 request->volume = fUserlandVolume; 3757 3758 // send the request 3759 KernelRequestHandler handler(this, READ_FS_INFO_REPLY); 3760 ReadFSInfoReply* reply; 3761 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 3762 if (error != B_OK) 3763 return error; 3764 RequestReleaser requestReleaser(port, reply); 3765 3766 // process the reply 3767 if (reply->error != B_OK) 3768 return reply->error; 3769 *info = reply->info; 3770 return error; 3771 } 3772 3773 // _Lookup 3774 status_t 3775 Volume::_Lookup(void* _dir, const char* entryName, ino_t* vnid) 3776 { 3777 VNode* vnode = (VNode*)_dir; 3778 3779 // get a free port 3780 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 3781 if (!port) 3782 return B_ERROR; 3783 PortReleaser _(fFileSystem->GetPortPool(), port); 3784 3785 // prepare the request 3786 RequestAllocator allocator(port->GetPort()); 3787 LookupRequest* request; 3788 status_t error = AllocateRequest(allocator, &request); 3789 if (error != B_OK) 3790 return error; 3791 request->volume = fUserlandVolume; 3792 request->node = vnode->clientNode; 3793 error = allocator.AllocateString(request->entryName, entryName); 3794 if (error != B_OK) 3795 return error; 3796 3797 // send the request 3798 KernelRequestHandler handler(this, LOOKUP_REPLY); 3799 LookupReply* reply; 3800 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 3801 if (error != B_OK) 3802 return error; 3803 RequestReleaser requestReleaser(port, reply); 3804 3805 // process the reply 3806 if (reply->error != B_OK) 3807 return reply->error; 3808 *vnid = reply->vnid; 3809 3810 // The VFS will balance the get_vnode() call for the FS. 3811 _DecrementVNodeCount(*vnid); 3812 return error; 3813 } 3814 3815 // _WriteVNode 3816 status_t 3817 Volume::_WriteVNode(void* _node, bool reenter) 3818 { 3819 VNode* vnode = (VNode*)_node; 3820 3821 // At any rate remove the vnode from our map and delete it. We don't do that 3822 // right now, though, since we might still need to serve file cache requests 3823 // from the client FS. 3824 VNodeRemover nodeRemover(this, vnode); 3825 3826 void* clientNode = vnode->clientNode; 3827 3828 // get a free port 3829 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 3830 if (!port) 3831 return B_ERROR; 3832 PortReleaser _(fFileSystem->GetPortPool(), port); 3833 3834 // prepare the request 3835 RequestAllocator allocator(port->GetPort()); 3836 WriteVNodeRequest* request; 3837 status_t error = AllocateRequest(allocator, &request); 3838 if (error != B_OK) 3839 return error; 3840 request->volume = fUserlandVolume; 3841 request->node = clientNode; 3842 request->reenter = reenter; 3843 3844 // send the request 3845 KernelRequestHandler handler(this, WRITE_VNODE_REPLY); 3846 WriteVNodeReply* reply; 3847 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 3848 if (error != B_OK) 3849 return error; 3850 RequestReleaser requestReleaser(port, reply); 3851 3852 // process the reply 3853 if (reply->error != B_OK) 3854 return reply->error; 3855 return error; 3856 } 3857 3858 // _ReadStat 3859 status_t 3860 Volume::_ReadStat(void* _node, struct stat* st) 3861 { 3862 VNode* vnode = (VNode*)_node; 3863 3864 // check capability 3865 if (!HasVNodeCapability(vnode, FS_VNODE_CAPABILITY_READ_STAT)) 3866 return B_BAD_VALUE; 3867 3868 // get a free port 3869 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 3870 if (!port) 3871 return B_ERROR; 3872 PortReleaser _(fFileSystem->GetPortPool(), port); 3873 3874 // prepare the request 3875 RequestAllocator allocator(port->GetPort()); 3876 ReadStatRequest* request; 3877 status_t error = AllocateRequest(allocator, &request); 3878 if (error != B_OK) 3879 return error; 3880 3881 request->volume = fUserlandVolume; 3882 request->node = vnode->clientNode; 3883 3884 // send the request 3885 KernelRequestHandler handler(this, READ_STAT_REPLY); 3886 ReadStatReply* reply; 3887 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 3888 if (error != B_OK) 3889 return error; 3890 RequestReleaser requestReleaser(port, reply); 3891 3892 // process the reply 3893 if (reply->error != B_OK) 3894 return reply->error; 3895 *st = reply->st; 3896 return error; 3897 } 3898 3899 // _Close 3900 status_t 3901 Volume::_Close(void* _node, void* cookie) 3902 { 3903 VNode* vnode = (VNode*)_node; 3904 3905 // check capability 3906 if (!HasVNodeCapability(vnode, FS_VNODE_CAPABILITY_CLOSE)) 3907 return B_OK; 3908 3909 // get a free port 3910 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 3911 if (!port) 3912 return B_ERROR; 3913 PortReleaser _(fFileSystem->GetPortPool(), port); 3914 3915 // prepare the request 3916 RequestAllocator allocator(port->GetPort()); 3917 CloseRequest* request; 3918 status_t error = AllocateRequest(allocator, &request); 3919 if (error != B_OK) 3920 return error; 3921 3922 request->volume = fUserlandVolume; 3923 request->node = vnode->clientNode; 3924 request->fileCookie = cookie; 3925 3926 // send the request 3927 KernelRequestHandler handler(this, CLOSE_REPLY); 3928 CloseReply* reply; 3929 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 3930 if (error != B_OK) 3931 return error; 3932 RequestReleaser requestReleaser(port, reply); 3933 3934 // process the reply 3935 if (reply->error != B_OK) 3936 return reply->error; 3937 return error; 3938 } 3939 3940 // _FreeCookie 3941 status_t 3942 Volume::_FreeCookie(void* _node, void* cookie) 3943 { 3944 VNode* vnode = (VNode*)_node; 3945 3946 // check capability 3947 if (!HasVNodeCapability(vnode, FS_VNODE_CAPABILITY_FREE_COOKIE)) 3948 return B_OK; 3949 3950 // get a free port 3951 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 3952 if (!port) 3953 return B_ERROR; 3954 PortReleaser _(fFileSystem->GetPortPool(), port); 3955 3956 // prepare the request 3957 RequestAllocator allocator(port->GetPort()); 3958 FreeCookieRequest* request; 3959 status_t error = AllocateRequest(allocator, &request); 3960 if (error != B_OK) 3961 return error; 3962 3963 request->volume = fUserlandVolume; 3964 request->node = vnode->clientNode; 3965 request->fileCookie = cookie; 3966 3967 // send the request 3968 KernelRequestHandler handler(this, FREE_COOKIE_REPLY); 3969 FreeCookieReply* reply; 3970 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 3971 if (error != B_OK) 3972 return error; 3973 RequestReleaser requestReleaser(port, reply); 3974 3975 // process the reply 3976 if (reply->error != B_OK) 3977 return reply->error; 3978 return error; 3979 } 3980 3981 // _CloseDir 3982 status_t 3983 Volume::_CloseDir(void* _node, void* cookie) 3984 { 3985 VNode* vnode = (VNode*)_node; 3986 3987 // check capability 3988 if (!HasVNodeCapability(vnode, FS_VNODE_CAPABILITY_CLOSE_DIR)) 3989 return B_OK; 3990 3991 // get a free port 3992 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 3993 if (!port) 3994 return B_ERROR; 3995 PortReleaser _(fFileSystem->GetPortPool(), port); 3996 3997 // prepare the request 3998 RequestAllocator allocator(port->GetPort()); 3999 CloseDirRequest* request; 4000 status_t error = AllocateRequest(allocator, &request); 4001 if (error != B_OK) 4002 return error; 4003 4004 request->volume = fUserlandVolume; 4005 request->node = vnode->clientNode; 4006 request->dirCookie = cookie; 4007 4008 // send the request 4009 KernelRequestHandler handler(this, CLOSE_DIR_REPLY); 4010 CloseDirReply* reply; 4011 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 4012 if (error != B_OK) 4013 return error; 4014 RequestReleaser requestReleaser(port, reply); 4015 4016 // process the reply 4017 if (reply->error != B_OK) 4018 return reply->error; 4019 return error; 4020 } 4021 4022 // _FreeDirCookie 4023 status_t 4024 Volume::_FreeDirCookie(void* _node, void* cookie) 4025 { 4026 VNode* vnode = (VNode*)_node; 4027 4028 // check capability 4029 if (!HasVNodeCapability(vnode, FS_VNODE_CAPABILITY_FREE_DIR_COOKIE)) 4030 return B_OK; 4031 4032 // get a free port 4033 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 4034 if (!port) 4035 return B_ERROR; 4036 PortReleaser _(fFileSystem->GetPortPool(), port); 4037 4038 // prepare the request 4039 RequestAllocator allocator(port->GetPort()); 4040 FreeDirCookieRequest* request; 4041 status_t error = AllocateRequest(allocator, &request); 4042 if (error != B_OK) 4043 return error; 4044 4045 request->volume = fUserlandVolume; 4046 request->node = vnode->clientNode; 4047 request->dirCookie = cookie; 4048 4049 // send the request 4050 KernelRequestHandler handler(this, FREE_DIR_COOKIE_REPLY); 4051 FreeDirCookieReply* reply; 4052 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 4053 if (error != B_OK) 4054 return error; 4055 RequestReleaser requestReleaser(port, reply); 4056 4057 // process the reply 4058 if (reply->error != B_OK) 4059 return reply->error; 4060 return error; 4061 } 4062 4063 // _CloseAttrDir 4064 status_t 4065 Volume::_CloseAttrDir(void* _node, void* cookie) 4066 { 4067 VNode* vnode = (VNode*)_node; 4068 4069 // check capability 4070 if (!HasVNodeCapability(vnode, FS_VNODE_CAPABILITY_CLOSE_ATTR_DIR)) 4071 return B_OK; 4072 4073 // get a free port 4074 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 4075 if (!port) 4076 return B_ERROR; 4077 PortReleaser _(fFileSystem->GetPortPool(), port); 4078 4079 // prepare the request 4080 RequestAllocator allocator(port->GetPort()); 4081 CloseAttrDirRequest* request; 4082 status_t error = AllocateRequest(allocator, &request); 4083 if (error != B_OK) 4084 return error; 4085 4086 request->volume = fUserlandVolume; 4087 request->node = vnode->clientNode; 4088 request->attrDirCookie = cookie; 4089 4090 // send the request 4091 KernelRequestHandler handler(this, CLOSE_ATTR_DIR_REPLY); 4092 CloseAttrDirReply* reply; 4093 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 4094 if (error != B_OK) 4095 return error; 4096 RequestReleaser requestReleaser(port, reply); 4097 4098 // process the reply 4099 if (reply->error != B_OK) 4100 return reply->error; 4101 return error; 4102 } 4103 4104 // _FreeAttrDirCookie 4105 status_t 4106 Volume::_FreeAttrDirCookie(void* _node, void* cookie) 4107 { 4108 VNode* vnode = (VNode*)_node; 4109 4110 // check capability 4111 if (!HasVNodeCapability(vnode, FS_VNODE_CAPABILITY_FREE_ATTR_DIR_COOKIE)) 4112 return B_OK; 4113 4114 // get a free port 4115 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 4116 if (!port) 4117 return B_ERROR; 4118 PortReleaser _(fFileSystem->GetPortPool(), port); 4119 4120 // prepare the request 4121 RequestAllocator allocator(port->GetPort()); 4122 FreeAttrDirCookieRequest* request; 4123 status_t error = AllocateRequest(allocator, &request); 4124 if (error != B_OK) 4125 return error; 4126 4127 request->volume = fUserlandVolume; 4128 request->node = vnode->clientNode; 4129 request->attrDirCookie = cookie; 4130 4131 // send the request 4132 KernelRequestHandler handler(this, FREE_ATTR_DIR_COOKIE_REPLY); 4133 FreeAttrDirCookieReply* reply; 4134 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 4135 if (error != B_OK) 4136 return error; 4137 RequestReleaser requestReleaser(port, reply); 4138 4139 // process the reply 4140 if (reply->error != B_OK) 4141 return reply->error; 4142 return error; 4143 } 4144 4145 // _CloseAttr 4146 status_t 4147 Volume::_CloseAttr(void* _node, void* cookie) 4148 { 4149 VNode* vnode = (VNode*)_node; 4150 4151 // check capability 4152 if (!HasVNodeCapability(vnode, FS_VNODE_CAPABILITY_CLOSE_ATTR)) 4153 return B_OK; 4154 4155 // get a free port 4156 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 4157 if (!port) 4158 return B_ERROR; 4159 PortReleaser _(fFileSystem->GetPortPool(), port); 4160 4161 // prepare the request 4162 RequestAllocator allocator(port->GetPort()); 4163 CloseAttrRequest* request; 4164 status_t error = AllocateRequest(allocator, &request); 4165 if (error != B_OK) 4166 return error; 4167 4168 request->volume = fUserlandVolume; 4169 request->node = vnode->clientNode; 4170 request->attrCookie = cookie; 4171 4172 // send the request 4173 KernelRequestHandler handler(this, CLOSE_ATTR_REPLY); 4174 CloseAttrReply* reply; 4175 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 4176 if (error != B_OK) 4177 return error; 4178 RequestReleaser requestReleaser(port, reply); 4179 4180 // process the reply 4181 if (reply->error != B_OK) 4182 return reply->error; 4183 return error; 4184 } 4185 4186 // _FreeAttrCookie 4187 status_t 4188 Volume::_FreeAttrCookie(void* _node, void* cookie) 4189 { 4190 VNode* vnode = (VNode*)_node; 4191 4192 // check capability 4193 if (!HasVNodeCapability(vnode, FS_VNODE_CAPABILITY_FREE_ATTR_COOKIE)) 4194 return B_OK; 4195 4196 // get a free port 4197 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 4198 if (!port) 4199 return B_ERROR; 4200 PortReleaser _(fFileSystem->GetPortPool(), port); 4201 4202 // prepare the request 4203 RequestAllocator allocator(port->GetPort()); 4204 FreeAttrCookieRequest* request; 4205 status_t error = AllocateRequest(allocator, &request); 4206 if (error != B_OK) 4207 return error; 4208 4209 request->volume = fUserlandVolume; 4210 request->node = vnode->clientNode; 4211 request->attrCookie = cookie; 4212 4213 // send the request 4214 KernelRequestHandler handler(this, FREE_ATTR_COOKIE_REPLY); 4215 FreeAttrCookieReply* reply; 4216 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 4217 if (error != B_OK) 4218 return error; 4219 RequestReleaser requestReleaser(port, reply); 4220 4221 // process the reply 4222 if (reply->error != B_OK) 4223 return reply->error; 4224 return error; 4225 } 4226 4227 // _CloseIndexDir 4228 status_t 4229 Volume::_CloseIndexDir(void* cookie) 4230 { 4231 // check capability 4232 if (!HasCapability(FS_VOLUME_CAPABILITY_CLOSE_INDEX_DIR)) 4233 return B_OK; 4234 4235 // get a free port 4236 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 4237 if (!port) 4238 return B_ERROR; 4239 PortReleaser _(fFileSystem->GetPortPool(), port); 4240 4241 // prepare the request 4242 RequestAllocator allocator(port->GetPort()); 4243 CloseIndexDirRequest* request; 4244 status_t error = AllocateRequest(allocator, &request); 4245 if (error != B_OK) 4246 return error; 4247 4248 request->volume = fUserlandVolume; 4249 request->indexDirCookie = cookie; 4250 4251 // send the request 4252 KernelRequestHandler handler(this, CLOSE_INDEX_DIR_REPLY); 4253 CloseIndexDirReply* reply; 4254 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 4255 if (error != B_OK) 4256 return error; 4257 RequestReleaser requestReleaser(port, reply); 4258 4259 // process the reply 4260 if (reply->error != B_OK) 4261 return reply->error; 4262 return error; 4263 } 4264 4265 // _FreeIndexDirCookie 4266 status_t 4267 Volume::_FreeIndexDirCookie(void* cookie) 4268 { 4269 // check capability 4270 if (!HasCapability(FS_VOLUME_CAPABILITY_FREE_INDEX_DIR_COOKIE)) 4271 return B_OK; 4272 4273 // get a free port 4274 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 4275 if (!port) 4276 return B_ERROR; 4277 PortReleaser _(fFileSystem->GetPortPool(), port); 4278 4279 // prepare the request 4280 RequestAllocator allocator(port->GetPort()); 4281 FreeIndexDirCookieRequest* request; 4282 status_t error = AllocateRequest(allocator, &request); 4283 if (error != B_OK) 4284 return error; 4285 4286 request->volume = fUserlandVolume; 4287 request->indexDirCookie = cookie; 4288 4289 // send the request 4290 KernelRequestHandler handler(this, FREE_INDEX_DIR_COOKIE_REPLY); 4291 FreeIndexDirCookieReply* reply; 4292 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 4293 if (error != B_OK) 4294 return error; 4295 RequestReleaser requestReleaser(port, reply); 4296 4297 // process the reply 4298 if (reply->error != B_OK) 4299 return reply->error; 4300 return error; 4301 } 4302 4303 // _CloseQuery 4304 status_t 4305 Volume::_CloseQuery(void* cookie) 4306 { 4307 // check capability 4308 if (!HasCapability(FS_VOLUME_CAPABILITY_CLOSE_QUERY)) 4309 return B_OK; 4310 4311 // get a free port 4312 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 4313 if (!port) 4314 return B_ERROR; 4315 PortReleaser _(fFileSystem->GetPortPool(), port); 4316 4317 // prepare the request 4318 RequestAllocator allocator(port->GetPort()); 4319 CloseQueryRequest* request; 4320 status_t error = AllocateRequest(allocator, &request); 4321 if (error != B_OK) 4322 return error; 4323 4324 request->volume = fUserlandVolume; 4325 request->queryCookie = cookie; 4326 4327 // send the request 4328 KernelRequestHandler handler(this, CLOSE_QUERY_REPLY); 4329 CloseQueryReply* reply; 4330 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 4331 if (error != B_OK) 4332 return error; 4333 RequestReleaser requestReleaser(port, reply); 4334 4335 // process the reply 4336 if (reply->error != B_OK) 4337 return reply->error; 4338 return error; 4339 } 4340 4341 // _FreeQueryCookie 4342 status_t 4343 Volume::_FreeQueryCookie(void* cookie) 4344 { 4345 // check capability 4346 if (!HasCapability(FS_VOLUME_CAPABILITY_FREE_QUERY_COOKIE)) 4347 return B_OK; 4348 4349 // get a free port 4350 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 4351 if (!port) 4352 return B_ERROR; 4353 PortReleaser _(fFileSystem->GetPortPool(), port); 4354 4355 // prepare the request 4356 RequestAllocator allocator(port->GetPort()); 4357 FreeQueryCookieRequest* request; 4358 status_t error = AllocateRequest(allocator, &request); 4359 if (error != B_OK) 4360 return error; 4361 4362 request->volume = fUserlandVolume; 4363 request->queryCookie = cookie; 4364 4365 // send the request 4366 KernelRequestHandler handler(this, FREE_QUERY_COOKIE_REPLY); 4367 FreeQueryCookieReply* reply; 4368 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 4369 if (error != B_OK) 4370 return error; 4371 RequestReleaser requestReleaser(port, reply); 4372 4373 // process the reply 4374 if (reply->error != B_OK) 4375 return reply->error; 4376 return error; 4377 } 4378 4379 // _SendRequest 4380 status_t 4381 Volume::_SendRequest(RequestPort* port, RequestAllocator* allocator, 4382 RequestHandler* handler, Request** reply) 4383 { 4384 // fill in the caller info 4385 KernelRequest* request = static_cast<KernelRequest*>( 4386 allocator->GetRequest()); 4387 struct thread* thread = thread_get_current_thread(); 4388 request->team = thread->team->id; 4389 request->thread = thread->id; 4390 request->user = geteuid(); 4391 request->group = getegid(); 4392 4393 if (!fFileSystem->IsUserlandServerThread()) 4394 return port->SendRequest(allocator, handler, reply); 4395 // Here it gets dangerous: a thread of the userland server team being here 4396 // calls for trouble. We try receiving the request with a timeout, and 4397 // close the port -- which will disconnect the whole FS. 4398 status_t error = port->SendRequest(allocator, handler, reply, 4399 kUserlandServerlandPortTimeout); 4400 if (error == B_TIMED_OUT || error == B_WOULD_BLOCK) 4401 port->Close(); 4402 return error; 4403 } 4404 4405 // _SendReceiptAck 4406 status_t 4407 Volume::_SendReceiptAck(RequestPort* port) 4408 { 4409 RequestAllocator allocator(port->GetPort()); 4410 ReceiptAckReply* request; 4411 status_t error = AllocateRequest(allocator, &request); 4412 if (error != B_OK) 4413 return error; 4414 return port->SendRequest(&allocator); 4415 } 4416 4417 // _IncrementVNodeCount 4418 void 4419 Volume::_IncrementVNodeCount(ino_t vnid) 4420 { 4421 MutexLocker _(fLock); 4422 4423 if (!fVNodeCountingEnabled) 4424 return; 4425 4426 VNode* vnode = fVNodes->Lookup(vnid); 4427 if (vnode == NULL) { 4428 ERROR(("Volume::_IncrementVNodeCount(): Node with ID %lld not " 4429 "known!\n", vnid)); 4430 return; 4431 } 4432 4433 vnode->useCount++; 4434 //PRINT(("_IncrementVNodeCount(%Ld): count: %ld, fVNodeCountMap size: %ld\n", vnid, *count, fVNodeCountMap->Size())); 4435 } 4436 4437 4438 // _DecrementVNodeCount 4439 void 4440 Volume::_DecrementVNodeCount(ino_t vnid) 4441 { 4442 MutexLocker _(fLock); 4443 4444 if (!fVNodeCountingEnabled) 4445 return; 4446 4447 VNode* vnode = fVNodes->Lookup(vnid); 4448 if (vnode == NULL) { 4449 ERROR(("Volume::_DecrementVNodeCount(): Node with ID %lld not " 4450 "known!\n", vnid)); 4451 return; 4452 } 4453 4454 vnode->useCount--; 4455 //PRINT(("_DecrementVNodeCount(%Ld): count: %ld, fVNodeCountMap size: %ld\n", vnid, tmpCount, fVNodeCountMap->Size())); 4456 } 4457 4458 4459 // _RemoveInvalidVNode 4460 void 4461 Volume::_RemoveInvalidVNode(ino_t vnid) 4462 { 4463 MutexLocker locker(fLock); 4464 4465 VNode* vnode = fVNodes->Lookup(vnid); 4466 if (vnode == NULL) { 4467 ERROR(("Volume::_RemoveInvalidVNode(): Node with ID %lld not known!\n", 4468 vnid)); 4469 return; 4470 } 4471 4472 fVNodes->Remove(vnode); 4473 locker.Unlock(); 4474 4475 // release all references acquired so far 4476 if (fVNodeCountingEnabled) { 4477 for (; vnode->useCount > 0; vnode->useCount--) 4478 put_vnode(fFSVolume, vnid); 4479 } 4480 4481 vnode->Delete(this); 4482 } 4483 4484 4485 // _InternalIOCtl 4486 status_t 4487 Volume::_InternalIOCtl(userlandfs_ioctl* buffer, int32 bufferSize) 4488 { 4489 if (buffer->version != USERLAND_IOCTL_CURRENT_VERSION) 4490 return B_BAD_VALUE; 4491 status_t result = B_OK; 4492 switch (buffer->command) { 4493 case USERLAND_IOCTL_PUT_ALL_PENDING_VNODES: 4494 result = _PutAllPendingVNodes(); 4495 break; 4496 default: 4497 return B_BAD_VALUE; 4498 } 4499 buffer->error = result; 4500 return B_OK; 4501 } 4502 4503 // _PutAllPendingVNodes 4504 status_t 4505 Volume::_PutAllPendingVNodes() 4506 { 4507 PRINT(("Volume::_PutAllPendingVNodes()\n")); 4508 if (!fFileSystem->GetPortPool()->IsDisconnected()) { 4509 PRINT(("Volume::_PutAllPendingVNodes() failed: still connected\n")); 4510 return USERLAND_IOCTL_STILL_CONNECTED; 4511 } 4512 4513 MutexLocker locker(fLock); 4514 4515 if (!fVNodeCountingEnabled) { 4516 PRINT(("Volume::_PutAllPendingVNodes() failed: vnode counting " 4517 "disabled\n")); 4518 return USERLAND_IOCTL_VNODE_COUNTING_DISABLED; 4519 } 4520 // Check whether there are open entities at the moment. 4521 if (fOpenFiles > 0) { 4522 PRINT(("Volume::_PutAllPendingVNodes() failed: open files\n")); 4523 return USERLAND_IOCTL_OPEN_FILES; 4524 } 4525 if (fOpenDirectories > 0) { 4526 PRINT(("Volume::_PutAllPendingVNodes() failed: open dirs\n")); 4527 return USERLAND_IOCTL_OPEN_DIRECTORIES; 4528 } 4529 if (fOpenAttributeDirectories > 0) { 4530 PRINT(("Volume::_PutAllPendingVNodes() failed: open attr dirs\n")); 4531 return USERLAND_IOCTL_OPEN_ATTRIBUTE_DIRECTORIES; 4532 } 4533 if (fOpenAttributes > 0) { 4534 PRINT(("Volume::_PutAllPendingVNodes() failed: open attributes\n")); 4535 return USERLAND_IOCTL_OPEN_ATTRIBUTES; 4536 } 4537 if (fOpenIndexDirectories > 0) { 4538 PRINT(("Volume::_PutAllPendingVNodes() failed: open index dirs\n")); 4539 return USERLAND_IOCTL_OPEN_INDEX_DIRECTORIES; 4540 } 4541 if (fOpenQueries > 0) { 4542 PRINT(("Volume::_PutAllPendingVNodes() failed: open queries\n")); 4543 return USERLAND_IOCTL_OPEN_QUERIES; 4544 } 4545 // No open entities. Since the port pool is disconnected, no new 4546 // entities can be opened. Disable node counting and put all pending 4547 // vnodes. 4548 fVNodeCountingEnabled = false; 4549 4550 int32 putVNodeCount = 0; 4551 4552 // Since the vnode map can still change, we need to iterate to the first 4553 // node we need to put, drop the lock, put the node, and restart from the 4554 // beginning. 4555 // TODO: Optimize by extracting batches of relevant nodes to an on-stack 4556 // array. 4557 bool nodeFound; 4558 do { 4559 nodeFound = false; 4560 4561 // get the next node to put 4562 for (VNodeMap::Iterator it = fVNodes->GetIterator(); 4563 VNode* vnode = it.Next();) { 4564 if (vnode->useCount > 0) { 4565 ino_t vnid = vnode->id; 4566 int32 count = vnode->useCount; 4567 vnode->useCount = 0; 4568 fs_vnode_ops* ops = vnode->ops->ops; 4569 bool published = vnode->published; 4570 4571 locker.Unlock(); 4572 4573 // If the node has not yet been published, we have to do that 4574 // before putting otherwise the VFS will complain that the node 4575 // is busy when the last reference is gone. 4576 if (!published) 4577 publish_vnode(fFSVolume, vnid, vnode, ops, S_IFDIR, 0); 4578 4579 for (int32 i = 0; i < count; i++) { 4580 PutVNode(vnid); 4581 putVNodeCount++; 4582 } 4583 4584 locker.Lock(); 4585 4586 nodeFound = true; 4587 break; 4588 } 4589 } 4590 } while (nodeFound); 4591 4592 PRINT(("Volume::_PutAllPendingVNodes() successful: Put %ld vnodes\n", 4593 putVNodeCount)); 4594 4595 return B_OK; 4596 } 4597 4598 4599 // _RegisterIORequest 4600 status_t 4601 Volume::_RegisterIORequest(io_request* request, int32* requestID) 4602 { 4603 MutexLocker _(fLock); 4604 4605 // get the next free ID 4606 while (fIORequestInfosByID->Lookup(++fLastIORequestID) != NULL) { 4607 } 4608 4609 // allocate the info 4610 IORequestInfo* info = new(std::nothrow) IORequestInfo(request, 4611 ++fLastIORequestID); 4612 if (info == NULL) 4613 return B_NO_MEMORY; 4614 4615 // add the info to the maps 4616 fIORequestInfosByID->Insert(info); 4617 fIORequestInfosByStruct->Insert(info); 4618 4619 *requestID = info->id; 4620 4621 return B_OK; 4622 } 4623 4624 4625 // _UnregisterIORequest 4626 status_t 4627 Volume::_UnregisterIORequest(int32 requestID) 4628 { 4629 MutexLocker _(fLock); 4630 4631 if (IORequestInfo* info = fIORequestInfosByID->Lookup(requestID)) { 4632 fIORequestInfosByID->Remove(info); 4633 fIORequestInfosByStruct->Remove(info); 4634 return B_OK; 4635 } 4636 4637 return B_ENTRY_NOT_FOUND; 4638 } 4639 4640 4641 // _FindIORequest 4642 status_t 4643 Volume::_FindIORequest(int32 requestID, io_request** request) 4644 { 4645 MutexLocker _(fLock); 4646 4647 if (IORequestInfo* info = fIORequestInfosByID->Lookup(requestID)) { 4648 *request = info->request; 4649 return B_OK; 4650 } 4651 4652 return B_ENTRY_NOT_FOUND; 4653 } 4654 4655 4656 // _FindIORequest 4657 status_t 4658 Volume::_FindIORequest(io_request* request, int32* requestID) 4659 { 4660 MutexLocker _(fLock); 4661 4662 if (IORequestInfo* info = fIORequestInfosByStruct->Lookup(request)) { 4663 *requestID = info->id; 4664 return B_OK; 4665 } 4666 4667 return B_ENTRY_NOT_FOUND; 4668 } 4669 4670 4671 /*static*/ status_t 4672 Volume::_IterativeFDIOGetVecs(void* _cookie, io_request* ioRequest, 4673 off_t offset, size_t size, struct file_io_vec* vecs, size_t* _count) 4674 { 4675 IterativeFDIOCookie* cookie = (IterativeFDIOCookie*)_cookie; 4676 Volume* volume = cookie->volume; 4677 4678 MutexLocker locker(volume->fLock); 4679 4680 // If there are vecs cached in the cookie and the offset matches, return 4681 // those. 4682 if (cookie->vecs != NULL) { 4683 size_t vecCount = 0; 4684 if (offset == cookie->offset) { 4685 // good, copy the vecs 4686 while (size > 0 && vecCount < cookie->vecCount 4687 && vecCount < *_count) { 4688 off_t maxSize = std::min((off_t)size, 4689 cookie->vecs[vecCount].length); 4690 vecs[vecCount].offset = cookie->vecs[vecCount].offset; 4691 vecs[vecCount].length = maxSize; 4692 4693 size -= maxSize; 4694 vecCount++; 4695 } 4696 } 4697 4698 cookie->vecs = NULL; 4699 cookie->vecCount = 0; 4700 4701 // got some vecs? -- then we're done 4702 if (vecCount > 0) { 4703 *_count = vecCount; 4704 return B_OK; 4705 } 4706 } 4707 4708 // we have to ask the client FS 4709 int32 requestID = cookie->requestID; 4710 void* clientCookie = cookie->clientCookie; 4711 locker.Unlock(); 4712 4713 // get a free port 4714 RequestPort* port = volume->fFileSystem->GetPortPool()->AcquirePort(); 4715 if (!port) 4716 return B_ERROR; 4717 PortReleaser _(volume->fFileSystem->GetPortPool(), port); 4718 4719 // prepare the request 4720 RequestAllocator allocator(port->GetPort()); 4721 IterativeIOGetVecsRequest* request; 4722 status_t error = AllocateRequest(allocator, &request); 4723 if (error != B_OK) 4724 return error; 4725 4726 request->volume = volume->fUserlandVolume; 4727 request->cookie = clientCookie; 4728 request->offset = offset; 4729 request->request = requestID; 4730 request->size = size; 4731 size_t maxVecs = std::min(*_count, 4732 (size_t)IterativeIOGetVecsReply::MAX_VECS); 4733 request->vecCount = maxVecs; 4734 4735 // send the request 4736 KernelRequestHandler handler(volume, ITERATIVE_IO_GET_VECS_REPLY); 4737 IterativeIOGetVecsReply* reply; 4738 error = volume->_SendRequest(port, &allocator, &handler, (Request**)&reply); 4739 if (error != B_OK) 4740 return error; 4741 RequestReleaser requestReleaser(port, reply); 4742 4743 // process the reply 4744 if (reply->error != B_OK) 4745 return reply->error; 4746 uint32 vecCount = reply->vecCount; 4747 if (vecCount < 0 || vecCount > maxVecs) 4748 return B_BAD_DATA; 4749 4750 memcpy(vecs, reply->vecs, vecCount * sizeof(file_io_vec)); 4751 *_count = vecCount; 4752 4753 return B_OK; 4754 } 4755 4756 4757 /*static*/ status_t 4758 Volume::_IterativeFDIOFinished(void* _cookie, io_request* ioRequest, 4759 status_t status, bool partialTransfer, size_t bytesTransferred) 4760 { 4761 IterativeFDIOCookie* cookie = (IterativeFDIOCookie*)_cookie; 4762 Volume* volume = cookie->volume; 4763 4764 // At any rate, we're done with the cookie after this call -- it will not 4765 // be used anymore. 4766 Reference<IterativeFDIOCookie> _(cookie, true); 4767 4768 // We also want to dispose of the request. 4769 IORequestRemover _2(volume, cookie->requestID); 4770 4771 // get a free port 4772 RequestPort* port = volume->fFileSystem->GetPortPool()->AcquirePort(); 4773 if (!port) 4774 return B_ERROR; 4775 PortReleaser _3(volume->fFileSystem->GetPortPool(), port); 4776 4777 // prepare the request 4778 RequestAllocator allocator(port->GetPort()); 4779 IterativeIOFinishedRequest* request; 4780 status_t error = AllocateRequest(allocator, &request); 4781 if (error != B_OK) 4782 return error; 4783 4784 request->volume = volume->fUserlandVolume; 4785 request->cookie = cookie->clientCookie; 4786 request->request = cookie->requestID; 4787 request->status = status; 4788 request->partialTransfer = partialTransfer; 4789 request->bytesTransferred = bytesTransferred; 4790 4791 // send the request 4792 KernelRequestHandler handler(volume, ITERATIVE_IO_FINISHED_REPLY); 4793 IterativeIOFinishedReply* reply; 4794 error = volume->_SendRequest(port, &allocator, &handler, (Request**)&reply); 4795 if (error != B_OK) 4796 return error; 4797 RequestReleaser requestReleaser(port, reply); 4798 4799 // process the reply 4800 if (reply->error != B_OK) 4801 return reply->error; 4802 return B_OK; 4803 } 4804