1 /* 2 * Copyright 2001-2011, 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 BReferenceable { 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(int32* 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 int32* 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 BReferenceable(), 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->AcquireReference(); 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->ReleaseReference(); 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 request->isVIP = (ioRequest->Flags() & B_VIP_IO_REQUEST) != 0; 1232 1233 // send the request 1234 KernelRequestHandler handler(this, DO_IO_REPLY); 1235 DoIOReply* reply; 1236 1237 // TODO: when to notify the io_request? 1238 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 1239 if (error != B_OK) 1240 return error; 1241 RequestReleaser requestReleaser(port, reply); 1242 1243 // process the reply 1244 if (reply->error != B_OK) 1245 return reply->error; 1246 1247 requestRemover.Detach(); 1248 1249 return B_OK; 1250 } 1251 1252 1253 // CancelIO 1254 status_t 1255 Volume::CancelIO(void* _node, void* cookie, io_request* ioRequest) 1256 { 1257 VNode* vnode = (VNode*)_node; 1258 1259 // check capability 1260 if (!HasVNodeCapability(vnode, FS_VNODE_CAPABILITY_CANCEL_IO)) 1261 return B_BAD_VALUE; 1262 1263 // find the request 1264 int32 requestID; 1265 status_t error = _FindIORequest(ioRequest, &requestID); 1266 if (error != B_OK) 1267 return error; 1268 1269 IORequestRemover requestRemover(this, requestID); 1270 1271 // get a free port 1272 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 1273 if (!port) 1274 return B_ERROR; 1275 PortReleaser _(fFileSystem->GetPortPool(), port); 1276 1277 // prepare the request 1278 RequestAllocator allocator(port->GetPort()); 1279 CancelIORequest* request; 1280 error = AllocateRequest(allocator, &request); 1281 if (error != B_OK) 1282 return error; 1283 1284 request->volume = fUserlandVolume; 1285 request->node = vnode->clientNode; 1286 request->fileCookie = cookie; 1287 request->request = requestID; 1288 1289 // send the request 1290 KernelRequestHandler handler(this, CANCEL_IO_REPLY); 1291 CancelIOReply* reply; 1292 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 1293 if (error != B_OK) { 1294 _UnregisterIORequest(requestID); 1295 return error; 1296 } 1297 RequestReleaser requestReleaser(port, reply); 1298 1299 // process the reply 1300 if (reply->error != B_OK) { 1301 _UnregisterIORequest(requestID); 1302 return reply->error; 1303 } 1304 1305 return B_OK; 1306 } 1307 1308 1309 // #pragma mark - nodes 1310 1311 1312 // IOCtl 1313 status_t 1314 Volume::IOCtl(void* _node, void* cookie, uint32 command, void *buffer, 1315 size_t len) 1316 { 1317 VNode* vnode = (VNode*)_node; 1318 1319 // check the command and its parameters 1320 bool isBuffer = false; 1321 int32 bufferSize = 0; 1322 int32 writeSize = 0; 1323 switch (command) { 1324 case IOCTL_FILE_UNCACHED_IO: 1325 buffer = NULL; 1326 break; 1327 case IOCTL_CREATE_TIME: 1328 case IOCTL_MODIFIED_TIME: 1329 isBuffer = 0; 1330 bufferSize = 0; 1331 writeSize = sizeof(bigtime_t); 1332 break; 1333 case USERLANDFS_IOCTL: 1334 area_id area; 1335 area_info info; 1336 PRINT(("Volume::IOCtl(): USERLANDFS_IOCTL\n")); 1337 if ((area = area_for(buffer)) >= 0) { 1338 if (get_area_info(area, &info) == B_OK) { 1339 if ((uint8*)buffer - (uint8*)info.address 1340 + sizeof(userlandfs_ioctl) <= info.size) { 1341 if (strncmp(((userlandfs_ioctl*)buffer)->magic, 1342 kUserlandFSIOCtlMagic, 1343 USERLAND_IOCTL_MAGIC_LENGTH) == 0) { 1344 return _InternalIOCtl((userlandfs_ioctl*)buffer, 1345 bufferSize); 1346 } else 1347 PRINT(("Volume::IOCtl(): bad magic\n")); 1348 } else 1349 PRINT(("Volume::IOCtl(): bad buffer size\n")); 1350 } else 1351 PRINT(("Volume::IOCtl(): failed to get area info\n")); 1352 } else 1353 PRINT(("Volume::IOCtl(): bad area\n")); 1354 // fall through... 1355 default: 1356 { 1357 // We don't know the command. Check whether the FileSystem knows 1358 // about it. 1359 const IOCtlInfo* info = fFileSystem->GetIOCtlInfo(command); 1360 if (!info) { 1361 PRINT(("Volume::IOCtl(): unknown command\n")); 1362 return B_BAD_VALUE; 1363 } 1364 1365 isBuffer = info->isBuffer; 1366 bufferSize = info->bufferSize; 1367 writeSize = info->writeBufferSize; 1368 1369 // If the buffer shall indeed specify a buffer, check it. 1370 if (info->isBuffer) { 1371 if (!buffer) { 1372 PRINT(("Volume::IOCtl(): buffer is NULL\n")); 1373 return B_BAD_VALUE; 1374 } 1375 1376 area_id area = area_for(buffer); 1377 if (area < 0) { 1378 PRINT(("Volume::IOCtl(): bad area\n")); 1379 return B_BAD_VALUE; 1380 } 1381 1382 area_info info; 1383 if (get_area_info(area, &info) != B_OK) { 1384 PRINT(("Volume::IOCtl(): failed to get area info\n")); 1385 return B_BAD_VALUE; 1386 } 1387 1388 int32 areaSize = info.size - ((uint8*)buffer 1389 - (uint8*)info.address); 1390 if (bufferSize > areaSize || writeSize > areaSize) { 1391 PRINT(("Volume::IOCtl(): bad buffer size\n")); 1392 return B_BAD_VALUE; 1393 } 1394 1395 if (writeSize > 0 && !(info.protection & B_WRITE_AREA)) { 1396 PRINT(("Volume::IOCtl(): buffer not writable\n")); 1397 return B_BAD_VALUE; 1398 } 1399 } 1400 break; 1401 } 1402 } 1403 1404 // check capability 1405 if (!HasVNodeCapability(vnode, FS_VNODE_CAPABILITY_IOCTL)) 1406 return B_BAD_VALUE; 1407 1408 // get a free port 1409 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 1410 if (!port) 1411 return B_ERROR; 1412 PortReleaser _(fFileSystem->GetPortPool(), port); 1413 1414 // prepare the request 1415 RequestAllocator allocator(port->GetPort()); 1416 IOCtlRequest* request; 1417 status_t error = AllocateRequest(allocator, &request); 1418 if (error != B_OK) 1419 return error; 1420 1421 request->volume = fUserlandVolume; 1422 request->node = vnode->clientNode; 1423 request->fileCookie = cookie; 1424 request->command = command; 1425 request->bufferParameter = buffer; 1426 request->isBuffer = isBuffer; 1427 request->lenParameter = len; 1428 request->writeSize = writeSize; 1429 1430 if (isBuffer && bufferSize > 0) { 1431 error = allocator.AllocateData(request->buffer, buffer, bufferSize, 8); 1432 if (error != B_OK) 1433 return error; 1434 } 1435 1436 // send the request 1437 KernelRequestHandler handler(this, IOCTL_REPLY); 1438 IOCtlReply* reply; 1439 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 1440 if (error != B_OK) 1441 return error; 1442 RequestReleaser requestReleaser(port, reply); 1443 1444 // process the reply 1445 if (reply->error != B_OK) 1446 return reply->error; 1447 1448 // Copy back the buffer even if the result is not B_OK. The protocol 1449 // is defined by the FS developer and may include writing data into 1450 // the buffer in some error cases. 1451 if (isBuffer && writeSize > 0 && reply->buffer.GetData()) { 1452 if (writeSize > reply->buffer.GetSize()) 1453 writeSize = reply->buffer.GetSize(); 1454 memcpy(buffer, reply->buffer.GetData(), writeSize); 1455 _SendReceiptAck(port); 1456 } 1457 return reply->ioctlError; 1458 } 1459 1460 // SetFlags 1461 status_t 1462 Volume::SetFlags(void* _node, void* cookie, int flags) 1463 { 1464 VNode* vnode = (VNode*)_node; 1465 1466 // check capability 1467 if (!HasVNodeCapability(vnode, FS_VNODE_CAPABILITY_SET_FLAGS)) 1468 return B_BAD_VALUE; 1469 1470 // get a free port 1471 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 1472 if (!port) 1473 return B_ERROR; 1474 PortReleaser _(fFileSystem->GetPortPool(), port); 1475 1476 // prepare the request 1477 RequestAllocator allocator(port->GetPort()); 1478 SetFlagsRequest* request; 1479 status_t error = AllocateRequest(allocator, &request); 1480 if (error != B_OK) 1481 return error; 1482 1483 request->volume = fUserlandVolume; 1484 request->node = vnode->clientNode; 1485 request->fileCookie = cookie; 1486 request->flags = flags; 1487 1488 // send the request 1489 KernelRequestHandler handler(this, SET_FLAGS_REPLY); 1490 SetFlagsReply* reply; 1491 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 1492 if (error != B_OK) 1493 return error; 1494 RequestReleaser requestReleaser(port, reply); 1495 1496 // process the reply 1497 if (reply->error != B_OK) 1498 return reply->error; 1499 return error; 1500 } 1501 1502 // Select 1503 status_t 1504 Volume::Select(void* _node, void* cookie, uint8 event, selectsync* sync) 1505 { 1506 VNode* vnode = (VNode*)_node; 1507 1508 // check capability 1509 if (!HasVNodeCapability(vnode, FS_VNODE_CAPABILITY_SELECT)) { 1510 notify_select_event(sync, event); 1511 return B_OK; 1512 } 1513 1514 // get a free port 1515 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 1516 if (!port) 1517 return B_ERROR; 1518 PortReleaser _(fFileSystem->GetPortPool(), port); 1519 1520 // prepare the request 1521 RequestAllocator allocator(port->GetPort()); 1522 SelectRequest* request; 1523 status_t error = AllocateRequest(allocator, &request); 1524 if (error != B_OK) 1525 return error; 1526 1527 request->volume = fUserlandVolume; 1528 request->node = vnode->clientNode; 1529 request->fileCookie = cookie; 1530 request->event = event; 1531 request->sync = sync; 1532 1533 // add a selectsync entry 1534 error = fFileSystem->AddSelectSyncEntry(sync); 1535 if (error != B_OK) 1536 return error; 1537 1538 // send the request 1539 KernelRequestHandler handler(this, SELECT_REPLY); 1540 SelectReply* reply; 1541 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 1542 if (error != B_OK) { 1543 fFileSystem->RemoveSelectSyncEntry(sync); 1544 return error; 1545 } 1546 RequestReleaser requestReleaser(port, reply); 1547 1548 // process the reply 1549 if (reply->error != B_OK) { 1550 fFileSystem->RemoveSelectSyncEntry(sync); 1551 return reply->error; 1552 } 1553 return error; 1554 } 1555 1556 // Deselect 1557 status_t 1558 Volume::Deselect(void* _node, void* cookie, uint8 event, selectsync* sync) 1559 { 1560 VNode* vnode = (VNode*)_node; 1561 1562 // check capability 1563 if (!HasVNodeCapability(vnode, FS_VNODE_CAPABILITY_DESELECT)) 1564 return B_OK; 1565 1566 struct SyncRemover { 1567 SyncRemover(FileSystem* fs, selectsync* sync) 1568 : fs(fs), sync(sync) {} 1569 ~SyncRemover() { fs->RemoveSelectSyncEntry(sync); } 1570 1571 FileSystem* fs; 1572 selectsync* sync; 1573 } syncRemover(fFileSystem, sync); 1574 1575 // get a free port 1576 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 1577 if (!port) 1578 return B_ERROR; 1579 PortReleaser _(fFileSystem->GetPortPool(), port); 1580 1581 // prepare the request 1582 RequestAllocator allocator(port->GetPort()); 1583 DeselectRequest* request; 1584 status_t error = AllocateRequest(allocator, &request); 1585 if (error != B_OK) 1586 return error; 1587 1588 request->volume = fUserlandVolume; 1589 request->node = vnode->clientNode; 1590 request->fileCookie = cookie; 1591 request->event = event; 1592 request->sync = sync; 1593 1594 // send the request 1595 KernelRequestHandler handler(this, DESELECT_REPLY); 1596 DeselectReply* reply; 1597 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 1598 if (error != B_OK) 1599 return error; 1600 RequestReleaser requestReleaser(port, reply); 1601 1602 // process the reply 1603 if (reply->error != B_OK) 1604 return reply->error; 1605 return error; 1606 } 1607 1608 // FSync 1609 status_t 1610 Volume::FSync(void* _node) 1611 { 1612 VNode* vnode = (VNode*)_node; 1613 1614 // check capability 1615 if (!HasVNodeCapability(vnode, FS_VNODE_CAPABILITY_FSYNC)) 1616 return B_BAD_VALUE; 1617 1618 // get a free port 1619 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 1620 if (!port) 1621 return B_ERROR; 1622 PortReleaser _(fFileSystem->GetPortPool(), port); 1623 1624 // prepare the request 1625 RequestAllocator allocator(port->GetPort()); 1626 FSyncRequest* request; 1627 status_t error = AllocateRequest(allocator, &request); 1628 if (error != B_OK) 1629 return error; 1630 1631 request->volume = fUserlandVolume; 1632 request->node = vnode->clientNode; 1633 1634 // send the request 1635 KernelRequestHandler handler(this, FSYNC_REPLY); 1636 FSyncReply* reply; 1637 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 1638 if (error != B_OK) 1639 return error; 1640 RequestReleaser requestReleaser(port, reply); 1641 1642 // process the reply 1643 if (reply->error != B_OK) 1644 return reply->error; 1645 return error; 1646 } 1647 1648 // ReadSymlink 1649 status_t 1650 Volume::ReadSymlink(void* _node, char* buffer, size_t bufferSize, 1651 size_t* bytesRead) 1652 { 1653 VNode* vnode = (VNode*)_node; 1654 1655 *bytesRead = 0; 1656 1657 // check capability 1658 if (!HasVNodeCapability(vnode, FS_VNODE_CAPABILITY_READ_SYMLINK)) 1659 return B_BAD_VALUE; 1660 1661 // get a free port 1662 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 1663 if (!port) 1664 return B_ERROR; 1665 PortReleaser _(fFileSystem->GetPortPool(), port); 1666 1667 // prepare the request 1668 RequestAllocator allocator(port->GetPort()); 1669 ReadSymlinkRequest* request; 1670 status_t error = AllocateRequest(allocator, &request); 1671 if (error != B_OK) 1672 return error; 1673 1674 request->volume = fUserlandVolume; 1675 request->node = vnode->clientNode; 1676 request->size = bufferSize; 1677 1678 // send the request 1679 KernelRequestHandler handler(this, READ_SYMLINK_REPLY); 1680 ReadSymlinkReply* reply; 1681 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 1682 if (error != B_OK) 1683 return error; 1684 RequestReleaser requestReleaser(port, reply); 1685 1686 // process the reply 1687 if (reply->error != B_OK) 1688 return reply->error; 1689 void* readBuffer = reply->buffer.GetData(); 1690 if (reply->bytesRead > (uint32)reply->buffer.GetSize() 1691 || reply->bytesRead > bufferSize) { 1692 return B_BAD_DATA; 1693 } 1694 if (reply->bytesRead > 0) 1695 memcpy(buffer, readBuffer, reply->bytesRead); 1696 *bytesRead = reply->bytesRead; 1697 _SendReceiptAck(port); 1698 return error; 1699 } 1700 1701 // CreateSymlink 1702 status_t 1703 Volume::CreateSymlink(void* _dir, const char* name, const char* target, 1704 int mode) 1705 { 1706 VNode* vnode = (VNode*)_dir; 1707 1708 // check capability 1709 if (!HasVNodeCapability(vnode, FS_VNODE_CAPABILITY_CREATE_SYMLINK)) 1710 return B_BAD_VALUE; 1711 1712 // get a free port 1713 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 1714 if (!port) 1715 return B_ERROR; 1716 PortReleaser _(fFileSystem->GetPortPool(), port); 1717 1718 // prepare the request 1719 RequestAllocator allocator(port->GetPort()); 1720 CreateSymlinkRequest* request; 1721 status_t error = AllocateRequest(allocator, &request); 1722 if (error != B_OK) 1723 return error; 1724 1725 request->volume = fUserlandVolume; 1726 request->node = vnode->clientNode; 1727 error = allocator.AllocateString(request->name, name); 1728 if (error == B_OK) 1729 error = allocator.AllocateString(request->target, target); 1730 if (error != B_OK) 1731 return error; 1732 request->mode = mode; 1733 1734 // send the request 1735 KernelRequestHandler handler(this, CREATE_SYMLINK_REPLY); 1736 CreateSymlinkReply* reply; 1737 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 1738 if (error != B_OK) 1739 return error; 1740 RequestReleaser requestReleaser(port, reply); 1741 1742 // process the reply 1743 if (reply->error != B_OK) 1744 return reply->error; 1745 return error; 1746 } 1747 1748 // Link 1749 status_t 1750 Volume::Link(void* _dir, const char* name, void* node) 1751 { 1752 VNode* vnode = (VNode*)_dir; 1753 VNode* targetVnode = (VNode*)node; 1754 1755 // check capability 1756 if (!HasVNodeCapability(vnode, FS_VNODE_CAPABILITY_LINK)) 1757 return B_BAD_VALUE; 1758 1759 // get a free port 1760 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 1761 if (!port) 1762 return B_ERROR; 1763 PortReleaser _(fFileSystem->GetPortPool(), port); 1764 1765 // prepare the request 1766 RequestAllocator allocator(port->GetPort()); 1767 LinkRequest* request; 1768 status_t error = AllocateRequest(allocator, &request); 1769 if (error != B_OK) 1770 return error; 1771 1772 request->volume = fUserlandVolume; 1773 request->node = vnode->clientNode; 1774 error = allocator.AllocateString(request->name, name); 1775 request->target = targetVnode->clientNode; 1776 if (error != B_OK) 1777 return error; 1778 1779 // send the request 1780 KernelRequestHandler handler(this, LINK_REPLY); 1781 LinkReply* reply; 1782 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 1783 if (error != B_OK) 1784 return error; 1785 RequestReleaser requestReleaser(port, reply); 1786 1787 // process the reply 1788 if (reply->error != B_OK) 1789 return reply->error; 1790 return error; 1791 } 1792 1793 // Unlink 1794 status_t 1795 Volume::Unlink(void* _dir, const char* name) 1796 { 1797 VNode* vnode = (VNode*)_dir; 1798 1799 // check capability 1800 if (!HasVNodeCapability(vnode, FS_VNODE_CAPABILITY_UNLINK)) 1801 return B_BAD_VALUE; 1802 1803 // get a free port 1804 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 1805 if (!port) 1806 return B_ERROR; 1807 PortReleaser _(fFileSystem->GetPortPool(), port); 1808 1809 // prepare the request 1810 RequestAllocator allocator(port->GetPort()); 1811 UnlinkRequest* request; 1812 status_t error = AllocateRequest(allocator, &request); 1813 if (error != B_OK) 1814 return error; 1815 1816 request->volume = fUserlandVolume; 1817 request->node = vnode->clientNode; 1818 error = allocator.AllocateString(request->name, name); 1819 if (error != B_OK) 1820 return error; 1821 1822 // send the request 1823 KernelRequestHandler handler(this, UNLINK_REPLY); 1824 UnlinkReply* reply; 1825 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 1826 if (error != B_OK) 1827 return error; 1828 RequestReleaser requestReleaser(port, reply); 1829 1830 // process the reply 1831 if (reply->error != B_OK) 1832 return reply->error; 1833 return error; 1834 } 1835 1836 // Rename 1837 status_t 1838 Volume::Rename(void* _oldDir, const char* oldName, void* _newDir, 1839 const char* newName) 1840 { 1841 VNode* oldVNode = (VNode*)_oldDir; 1842 VNode* newVNode = (VNode*)_newDir; 1843 1844 // check capability 1845 if (!HasVNodeCapability(oldVNode, FS_VNODE_CAPABILITY_RENAME)) 1846 return B_BAD_VALUE; 1847 1848 // get a free port 1849 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 1850 if (!port) 1851 return B_ERROR; 1852 PortReleaser _(fFileSystem->GetPortPool(), port); 1853 1854 // prepare the request 1855 RequestAllocator allocator(port->GetPort()); 1856 RenameRequest* request; 1857 status_t error = AllocateRequest(allocator, &request); 1858 if (error != B_OK) 1859 return error; 1860 1861 request->volume = fUserlandVolume; 1862 request->oldDir = oldVNode->clientNode; 1863 request->newDir = newVNode->clientNode; 1864 error = allocator.AllocateString(request->oldName, oldName); 1865 if (error == B_OK) 1866 error = allocator.AllocateString(request->newName, newName); 1867 if (error != B_OK) 1868 return error; 1869 1870 // send the request 1871 KernelRequestHandler handler(this, RENAME_REPLY); 1872 RenameReply* reply; 1873 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 1874 if (error != B_OK) 1875 return error; 1876 RequestReleaser requestReleaser(port, reply); 1877 1878 // process the reply 1879 if (reply->error != B_OK) 1880 return reply->error; 1881 return error; 1882 } 1883 1884 // Access 1885 status_t 1886 Volume::Access(void* _node, int mode) 1887 { 1888 VNode* vnode = (VNode*)_node; 1889 1890 // check capability 1891 if (!HasVNodeCapability(vnode, FS_VNODE_CAPABILITY_ACCESS)) 1892 return B_OK; 1893 1894 // get a free port 1895 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 1896 if (!port) 1897 return B_ERROR; 1898 PortReleaser _(fFileSystem->GetPortPool(), port); 1899 1900 // prepare the request 1901 RequestAllocator allocator(port->GetPort()); 1902 AccessRequest* request; 1903 status_t error = AllocateRequest(allocator, &request); 1904 if (error != B_OK) 1905 return error; 1906 1907 request->volume = fUserlandVolume; 1908 request->node = vnode->clientNode; 1909 request->mode = mode; 1910 1911 // send the request 1912 KernelRequestHandler handler(this, ACCESS_REPLY); 1913 AccessReply* reply; 1914 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 1915 if (error != B_OK) 1916 return error; 1917 RequestReleaser requestReleaser(port, reply); 1918 1919 // process the reply 1920 if (reply->error != B_OK) 1921 return reply->error; 1922 return error; 1923 } 1924 1925 // ReadStat 1926 status_t 1927 Volume::ReadStat(void* node, struct stat* st) 1928 { 1929 // When the connection to the userland server is lost, we serve 1930 // read_stat(fRootNode) requests manually to allow clean unmounting. 1931 status_t error = _ReadStat(node, st); 1932 if (error != B_OK && fFileSystem->GetPortPool()->IsDisconnected() 1933 && node == fRootNode) { 1934 WARN(("Volume::ReadStat(): connection lost, emulating stat for the " 1935 "root node\n")); 1936 1937 st->st_dev = GetID(); 1938 st->st_ino = fRootID; 1939 st->st_mode = ACCESSPERMS; 1940 st->st_nlink = 1; 1941 st->st_uid = 0; 1942 st->st_gid = 0; 1943 st->st_size = 512; 1944 st->st_blksize = 512; 1945 st->st_atime = 0; 1946 st->st_mtime = 0; 1947 st->st_ctime = 0; 1948 st->st_crtime = 0; 1949 1950 error = B_OK; 1951 } 1952 return error; 1953 } 1954 1955 // WriteStat 1956 status_t 1957 Volume::WriteStat(void* _node, const struct stat* st, uint32 mask) 1958 { 1959 VNode* vnode = (VNode*)_node; 1960 1961 // check capability 1962 if (!HasVNodeCapability(vnode, FS_VNODE_CAPABILITY_WRITE_STAT)) 1963 return B_BAD_VALUE; 1964 1965 // get a free port 1966 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 1967 if (!port) 1968 return B_ERROR; 1969 PortReleaser _(fFileSystem->GetPortPool(), port); 1970 1971 // prepare the request 1972 RequestAllocator allocator(port->GetPort()); 1973 WriteStatRequest* request; 1974 status_t error = AllocateRequest(allocator, &request); 1975 if (error != B_OK) 1976 return error; 1977 1978 request->volume = fUserlandVolume; 1979 request->node = vnode->clientNode; 1980 request->st = *st; 1981 request->mask = mask; 1982 1983 // send the request 1984 KernelRequestHandler handler(this, WRITE_STAT_REPLY); 1985 WriteStatReply* reply; 1986 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 1987 if (error != B_OK) 1988 return error; 1989 RequestReleaser requestReleaser(port, reply); 1990 1991 // process the reply 1992 if (reply->error != B_OK) 1993 return reply->error; 1994 return error; 1995 } 1996 1997 1998 // #pragma mark - files 1999 2000 // Create 2001 status_t 2002 Volume::Create(void* _dir, const char* name, int openMode, int mode, 2003 void** cookie, ino_t* vnid) 2004 { 2005 VNode* vnode = (VNode*)_dir; 2006 2007 // check capability 2008 if (!HasVNodeCapability(vnode, FS_VNODE_CAPABILITY_CREATE)) 2009 return B_BAD_VALUE; 2010 2011 // get a free port 2012 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 2013 if (!port) 2014 return B_ERROR; 2015 PortReleaser _(fFileSystem->GetPortPool(), port); 2016 AutoIncrementer incrementer(&fOpenFiles); 2017 2018 // prepare the request 2019 RequestAllocator allocator(port->GetPort()); 2020 CreateRequest* request; 2021 status_t error = AllocateRequest(allocator, &request); 2022 if (error != B_OK) 2023 return error; 2024 2025 request->volume = fUserlandVolume; 2026 request->node = vnode->clientNode; 2027 error = allocator.AllocateString(request->name, name); 2028 request->openMode = openMode; 2029 request->mode = mode; 2030 if (error != B_OK) 2031 return error; 2032 2033 // send the request 2034 KernelRequestHandler handler(this, CREATE_REPLY); 2035 CreateReply* reply; 2036 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 2037 if (error != B_OK) 2038 return error; 2039 RequestReleaser requestReleaser(port, reply); 2040 2041 // process the reply 2042 if (reply->error != B_OK) 2043 return reply->error; 2044 incrementer.Keep(); 2045 *vnid = reply->vnid; 2046 *cookie = reply->fileCookie; 2047 2048 // The VFS will balance the publish_vnode() call for the FS. 2049 if (error == B_OK) 2050 _DecrementVNodeCount(*vnid); 2051 return error; 2052 } 2053 2054 // Open 2055 status_t 2056 Volume::Open(void* _node, int openMode, void** cookie) 2057 { 2058 VNode* vnode = (VNode*)_node; 2059 2060 // check capability 2061 if (!HasVNodeCapability(vnode, FS_VNODE_CAPABILITY_OPEN)) 2062 return B_BAD_VALUE; 2063 2064 // get a free port 2065 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 2066 if (!port) 2067 return B_ERROR; 2068 PortReleaser _(fFileSystem->GetPortPool(), port); 2069 AutoIncrementer incrementer(&fOpenFiles); 2070 2071 // prepare the request 2072 RequestAllocator allocator(port->GetPort()); 2073 OpenRequest* request; 2074 status_t error = AllocateRequest(allocator, &request); 2075 if (error != B_OK) 2076 return error; 2077 request->volume = fUserlandVolume; 2078 request->node = vnode->clientNode; 2079 request->openMode = openMode; 2080 2081 // send the request 2082 KernelRequestHandler handler(this, OPEN_REPLY); 2083 OpenReply* reply; 2084 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 2085 if (error != B_OK) 2086 return error; 2087 RequestReleaser requestReleaser(port, reply); 2088 2089 // process the reply 2090 if (reply->error != B_OK) 2091 return reply->error; 2092 incrementer.Keep(); 2093 *cookie = reply->fileCookie; 2094 return error; 2095 } 2096 2097 // Close 2098 status_t 2099 Volume::Close(void* node, void* cookie) 2100 { 2101 status_t error = _Close(node, cookie); 2102 if (error != B_OK && fFileSystem->GetPortPool()->IsDisconnected()) { 2103 // This isn't really necessary, as the return value is irrelevant to 2104 // the VFS. OBOS ignores it completely. The fsshell returns it to the 2105 // userland, but considers the node closed anyway. 2106 WARN(("Volume::Close(): connection lost, forcing close\n")); 2107 return B_OK; 2108 } 2109 return error; 2110 } 2111 2112 // FreeCookie 2113 status_t 2114 Volume::FreeCookie(void* node, void* cookie) 2115 { 2116 status_t error = _FreeCookie(node, cookie); 2117 bool disconnected = false; 2118 if (error != B_OK && fFileSystem->GetPortPool()->IsDisconnected()) { 2119 // This isn't really necessary, as the return value is irrelevant to 2120 // the VFS. It's completely ignored by OBOS as well as by the fsshell. 2121 WARN(("Volume::FreeCookie(): connection lost, forcing free cookie\n")); 2122 error = B_OK; 2123 disconnected = true; 2124 } 2125 2126 int32 openFiles = atomic_add(&fOpenFiles, -1); 2127 if (openFiles <= 1 && disconnected) 2128 _PutAllPendingVNodes(); 2129 return error; 2130 } 2131 2132 // Read 2133 status_t 2134 Volume::Read(void* _node, void* cookie, off_t pos, void* buffer, 2135 size_t bufferSize, size_t* bytesRead) 2136 { 2137 VNode* vnode = (VNode*)_node; 2138 2139 *bytesRead = 0; 2140 2141 // check capability 2142 if (!HasVNodeCapability(vnode, FS_VNODE_CAPABILITY_READ)) 2143 return B_BAD_VALUE; 2144 2145 // get a free port 2146 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 2147 if (!port) 2148 return B_ERROR; 2149 PortReleaser _(fFileSystem->GetPortPool(), port); 2150 2151 // prepare the request 2152 RequestAllocator allocator(port->GetPort()); 2153 ReadRequest* request; 2154 status_t error = AllocateRequest(allocator, &request); 2155 if (error != B_OK) 2156 return error; 2157 2158 request->volume = fUserlandVolume; 2159 request->node = vnode->clientNode; 2160 request->fileCookie = cookie; 2161 request->pos = pos; 2162 request->size = bufferSize; 2163 2164 // send the request 2165 KernelRequestHandler handler(this, READ_REPLY); 2166 ReadReply* reply; 2167 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 2168 if (error != B_OK) 2169 return error; 2170 RequestReleaser requestReleaser(port, reply); 2171 2172 // process the reply 2173 if (reply->error != B_OK) 2174 return reply->error; 2175 void* readBuffer = reply->buffer.GetData(); 2176 if (reply->bytesRead > (uint32)reply->buffer.GetSize() 2177 || reply->bytesRead > bufferSize) { 2178 return B_BAD_DATA; 2179 } 2180 if (reply->bytesRead > 0) 2181 memcpy(buffer, readBuffer, reply->bytesRead); 2182 *bytesRead = reply->bytesRead; 2183 _SendReceiptAck(port); 2184 return error; 2185 } 2186 2187 // Write 2188 status_t 2189 Volume::Write(void* _node, void* cookie, off_t pos, const void* buffer, 2190 size_t size, size_t* bytesWritten) 2191 { 2192 VNode* vnode = (VNode*)_node; 2193 2194 *bytesWritten = 0; 2195 2196 // check capability 2197 if (!HasVNodeCapability(vnode, FS_VNODE_CAPABILITY_WRITE)) 2198 return B_BAD_VALUE; 2199 2200 // get a free port 2201 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 2202 if (!port) 2203 return B_ERROR; 2204 PortReleaser _(fFileSystem->GetPortPool(), port); 2205 2206 // prepare the request 2207 RequestAllocator allocator(port->GetPort()); 2208 WriteRequest* request; 2209 status_t error = AllocateRequest(allocator, &request); 2210 if (error != B_OK) 2211 return error; 2212 2213 request->volume = fUserlandVolume; 2214 request->node = vnode->clientNode; 2215 request->fileCookie = cookie; 2216 request->pos = pos; 2217 error = allocator.AllocateData(request->buffer, buffer, size, 1); 2218 if (error != B_OK) 2219 return error; 2220 2221 // send the request 2222 KernelRequestHandler handler(this, WRITE_REPLY); 2223 WriteReply* reply; 2224 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 2225 if (error != B_OK) 2226 return error; 2227 RequestReleaser requestReleaser(port, reply); 2228 2229 // process the reply 2230 if (reply->error != B_OK) 2231 return reply->error; 2232 *bytesWritten = reply->bytesWritten; 2233 return error; 2234 } 2235 2236 2237 // #pragma mark - directories 2238 2239 // CreateDir 2240 status_t 2241 Volume::CreateDir(void* _dir, const char* name, int mode) 2242 { 2243 VNode* vnode = (VNode*)_dir; 2244 2245 // check capability 2246 if (!HasVNodeCapability(vnode, FS_VNODE_CAPABILITY_CREATE_DIR)) 2247 return B_BAD_VALUE; 2248 2249 // get a free port 2250 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 2251 if (!port) 2252 return B_ERROR; 2253 PortReleaser _(fFileSystem->GetPortPool(), port); 2254 2255 // prepare the request 2256 RequestAllocator allocator(port->GetPort()); 2257 CreateDirRequest* request; 2258 status_t error = AllocateRequest(allocator, &request); 2259 if (error != B_OK) 2260 return error; 2261 2262 request->volume = fUserlandVolume; 2263 request->node = vnode->clientNode; 2264 error = allocator.AllocateString(request->name, name); 2265 request->mode = mode; 2266 if (error != B_OK) 2267 return error; 2268 2269 // send the request 2270 KernelRequestHandler handler(this, CREATE_DIR_REPLY); 2271 CreateDirReply* reply; 2272 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 2273 if (error != B_OK) 2274 return error; 2275 RequestReleaser requestReleaser(port, reply); 2276 2277 // process the reply 2278 if (reply->error != B_OK) 2279 return reply->error; 2280 return error; 2281 } 2282 2283 // RemoveDir 2284 status_t 2285 Volume::RemoveDir(void* _dir, const char* name) 2286 { 2287 VNode* vnode = (VNode*)_dir; 2288 2289 // check capability 2290 if (!HasVNodeCapability(vnode, FS_VNODE_CAPABILITY_REMOVE_DIR)) 2291 return B_BAD_VALUE; 2292 2293 // get a free port 2294 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 2295 if (!port) 2296 return B_ERROR; 2297 PortReleaser _(fFileSystem->GetPortPool(), port); 2298 2299 // prepare the request 2300 RequestAllocator allocator(port->GetPort()); 2301 RemoveDirRequest* request; 2302 status_t error = AllocateRequest(allocator, &request); 2303 if (error != B_OK) 2304 return error; 2305 2306 request->volume = fUserlandVolume; 2307 request->node = vnode->clientNode; 2308 error = allocator.AllocateString(request->name, name); 2309 if (error != B_OK) 2310 return error; 2311 2312 // send the request 2313 KernelRequestHandler handler(this, REMOVE_DIR_REPLY); 2314 RemoveDirReply* reply; 2315 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 2316 if (error != B_OK) 2317 return error; 2318 RequestReleaser requestReleaser(port, reply); 2319 2320 // process the reply 2321 if (reply->error != B_OK) 2322 return reply->error; 2323 return error; 2324 } 2325 2326 // OpenDir 2327 status_t 2328 Volume::OpenDir(void* _node, void** cookie) 2329 { 2330 VNode* vnode = (VNode*)_node; 2331 2332 // check capability 2333 if (!HasVNodeCapability(vnode, FS_VNODE_CAPABILITY_OPEN_DIR)) 2334 return B_BAD_VALUE; 2335 2336 // get a free port 2337 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 2338 if (!port) 2339 return B_ERROR; 2340 PortReleaser _(fFileSystem->GetPortPool(), port); 2341 AutoIncrementer incrementer(&fOpenDirectories); 2342 2343 // prepare the request 2344 RequestAllocator allocator(port->GetPort()); 2345 OpenDirRequest* request; 2346 status_t error = AllocateRequest(allocator, &request); 2347 if (error != B_OK) 2348 return error; 2349 2350 request->volume = fUserlandVolume; 2351 request->node = vnode->clientNode; 2352 2353 // send the request 2354 KernelRequestHandler handler(this, OPEN_DIR_REPLY); 2355 OpenDirReply* reply; 2356 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 2357 if (error != B_OK) 2358 return error; 2359 RequestReleaser requestReleaser(port, reply); 2360 2361 // process the reply 2362 if (reply->error != B_OK) 2363 return reply->error; 2364 incrementer.Keep(); 2365 *cookie = reply->dirCookie; 2366 return error; 2367 } 2368 2369 // CloseDir 2370 status_t 2371 Volume::CloseDir(void* node, void* cookie) 2372 { 2373 status_t error = _CloseDir(node, cookie); 2374 if (error != B_OK && fFileSystem->GetPortPool()->IsDisconnected()) { 2375 // This isn't really necessary, as the return value is irrelevant to 2376 // the VFS. OBOS ignores it completely. The fsshell returns it to the 2377 // userland, but considers the node closed anyway. 2378 WARN(("Volume::CloseDir(): connection lost, forcing close dir\n")); 2379 return B_OK; 2380 } 2381 return error; 2382 } 2383 2384 // FreeDirCookie 2385 status_t 2386 Volume::FreeDirCookie(void* node, void* cookie) 2387 { 2388 status_t error = _FreeDirCookie(node, cookie); 2389 bool disconnected = false; 2390 if (error != B_OK && fFileSystem->GetPortPool()->IsDisconnected()) { 2391 // This isn't really necessary, as the return value is irrelevant to 2392 // the VFS. It's completely ignored by OBOS as well as by the fsshell. 2393 WARN(("Volume::FreeDirCookie(): connection lost, forcing free dir " 2394 "cookie\n")); 2395 error = B_OK; 2396 disconnected = true; 2397 } 2398 int32 openDirs = atomic_add(&fOpenDirectories, -1); 2399 if (openDirs <= 1 && disconnected) 2400 _PutAllPendingVNodes(); 2401 return error; 2402 } 2403 2404 // ReadDir 2405 status_t 2406 Volume::ReadDir(void* _node, void* cookie, void* buffer, size_t bufferSize, 2407 uint32 count, uint32* countRead) 2408 { 2409 VNode* vnode = (VNode*)_node; 2410 2411 *countRead = 0; 2412 2413 // check capability 2414 if (!HasVNodeCapability(vnode, FS_VNODE_CAPABILITY_READ_DIR)) 2415 return B_BAD_VALUE; 2416 2417 // get a free port 2418 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 2419 if (!port) 2420 return B_ERROR; 2421 PortReleaser _(fFileSystem->GetPortPool(), port); 2422 2423 // prepare the request 2424 RequestAllocator allocator(port->GetPort()); 2425 ReadDirRequest* request; 2426 status_t error = AllocateRequest(allocator, &request); 2427 if (error != B_OK) 2428 return error; 2429 2430 request->volume = fUserlandVolume; 2431 request->node = vnode->clientNode; 2432 request->dirCookie = cookie; 2433 request->bufferSize = bufferSize; 2434 request->count = count; 2435 2436 // send the request 2437 KernelRequestHandler handler(this, READ_DIR_REPLY); 2438 ReadDirReply* reply; 2439 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 2440 if (error != B_OK) 2441 return error; 2442 RequestReleaser requestReleaser(port, reply); 2443 2444 // process the reply 2445 if (reply->error != B_OK) 2446 return reply->error; 2447 if (reply->count < 0 || reply->count > count) 2448 return B_BAD_DATA; 2449 if ((int32)bufferSize < reply->buffer.GetSize()) 2450 return B_BAD_DATA; 2451 PRINT(("Volume::ReadDir(): buffer returned: %ld bytes\n", 2452 reply->buffer.GetSize())); 2453 2454 *countRead = reply->count; 2455 if (*countRead > 0) { 2456 // copy the buffer -- limit the number of bytes to copy 2457 uint32 maxBytes = *countRead 2458 * (sizeof(struct dirent) + B_FILE_NAME_LENGTH); 2459 uint32 copyBytes = reply->buffer.GetSize(); 2460 if (copyBytes > maxBytes) 2461 copyBytes = maxBytes; 2462 memcpy(buffer, reply->buffer.GetData(), copyBytes); 2463 } 2464 _SendReceiptAck(port); 2465 return error; 2466 } 2467 2468 // RewindDir 2469 status_t 2470 Volume::RewindDir(void* _node, void* cookie) 2471 { 2472 VNode* vnode = (VNode*)_node; 2473 2474 // check capability 2475 if (!HasVNodeCapability(vnode, FS_VNODE_CAPABILITY_REWIND_DIR)) 2476 return B_BAD_VALUE; 2477 2478 // get a free port 2479 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 2480 if (!port) 2481 return B_ERROR; 2482 PortReleaser _(fFileSystem->GetPortPool(), port); 2483 2484 // prepare the request 2485 RequestAllocator allocator(port->GetPort()); 2486 RewindDirRequest* request; 2487 status_t error = AllocateRequest(allocator, &request); 2488 if (error != B_OK) 2489 return error; 2490 2491 request->volume = fUserlandVolume; 2492 request->node = vnode->clientNode; 2493 request->dirCookie = cookie; 2494 2495 // send the request 2496 KernelRequestHandler handler(this, REWIND_DIR_REPLY); 2497 RewindDirReply* reply; 2498 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 2499 if (error != B_OK) 2500 return error; 2501 RequestReleaser requestReleaser(port, reply); 2502 2503 // process the reply 2504 if (reply->error != B_OK) 2505 return reply->error; 2506 return error; 2507 } 2508 2509 2510 // #pragma mark - attribute directories 2511 2512 2513 // OpenAttrDir 2514 status_t 2515 Volume::OpenAttrDir(void* _node, void** cookie) 2516 { 2517 VNode* vnode = (VNode*)_node; 2518 2519 // check capability 2520 if (!HasVNodeCapability(vnode, FS_VNODE_CAPABILITY_OPEN_ATTR_DIR)) 2521 return B_BAD_VALUE; 2522 2523 // get a free port 2524 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 2525 if (!port) 2526 return B_ERROR; 2527 PortReleaser _(fFileSystem->GetPortPool(), port); 2528 AutoIncrementer incrementer(&fOpenAttributeDirectories); 2529 2530 // prepare the request 2531 RequestAllocator allocator(port->GetPort()); 2532 OpenAttrDirRequest* request; 2533 status_t error = AllocateRequest(allocator, &request); 2534 if (error != B_OK) 2535 return error; 2536 2537 request->volume = fUserlandVolume; 2538 request->node = vnode->clientNode; 2539 2540 // send the request 2541 KernelRequestHandler handler(this, OPEN_ATTR_DIR_REPLY); 2542 OpenAttrDirReply* reply; 2543 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 2544 if (error != B_OK) 2545 return error; 2546 RequestReleaser requestReleaser(port, reply); 2547 2548 // process the reply 2549 if (reply->error != B_OK) 2550 return reply->error; 2551 incrementer.Keep(); 2552 *cookie = reply->attrDirCookie; 2553 return error; 2554 } 2555 2556 // CloseAttrDir 2557 status_t 2558 Volume::CloseAttrDir(void* node, void* cookie) 2559 { 2560 status_t error = _CloseAttrDir(node, cookie); 2561 if (error != B_OK && fFileSystem->GetPortPool()->IsDisconnected()) { 2562 // This isn't really necessary, as the return value is irrelevant to 2563 // the VFS. OBOS ignores it completely. The fsshell returns it to the 2564 // userland, but considers the node closed anyway. 2565 WARN(("Volume::CloseAttrDir(): connection lost, forcing close attr " 2566 "dir\n")); 2567 return B_OK; 2568 } 2569 return error; 2570 } 2571 2572 // FreeAttrDirCookie 2573 status_t 2574 Volume::FreeAttrDirCookie(void* node, void* cookie) 2575 { 2576 status_t error = _FreeAttrDirCookie(node, cookie); 2577 bool disconnected = false; 2578 if (error != B_OK && fFileSystem->GetPortPool()->IsDisconnected()) { 2579 // This isn't really necessary, as the return value is irrelevant to 2580 // the VFS. It's completely ignored by OBOS as well as by the fsshell. 2581 WARN(("Volume::FreeAttrDirCookie(): connection lost, forcing free attr " 2582 "dir cookie\n")); 2583 error = B_OK; 2584 disconnected = true; 2585 } 2586 2587 int32 openAttrDirs = atomic_add(&fOpenAttributeDirectories, -1); 2588 if (openAttrDirs <= 1 && disconnected) 2589 _PutAllPendingVNodes(); 2590 return error; 2591 } 2592 2593 // ReadAttrDir 2594 status_t 2595 Volume::ReadAttrDir(void* _node, void* cookie, void* buffer, 2596 size_t bufferSize, uint32 count, uint32* countRead) 2597 { 2598 VNode* vnode = (VNode*)_node; 2599 2600 // check capability 2601 if (!HasVNodeCapability(vnode, FS_VNODE_CAPABILITY_READ_ATTR_DIR)) 2602 return B_BAD_VALUE; 2603 2604 *countRead = 0; 2605 // get a free port 2606 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 2607 if (!port) 2608 return B_ERROR; 2609 PortReleaser _(fFileSystem->GetPortPool(), port); 2610 2611 // prepare the request 2612 RequestAllocator allocator(port->GetPort()); 2613 ReadAttrDirRequest* request; 2614 status_t error = AllocateRequest(allocator, &request); 2615 if (error != B_OK) 2616 return error; 2617 2618 request->volume = fUserlandVolume; 2619 request->node = vnode->clientNode; 2620 request->attrDirCookie = cookie; 2621 request->bufferSize = bufferSize; 2622 request->count = count; 2623 2624 // send the request 2625 KernelRequestHandler handler(this, READ_ATTR_DIR_REPLY); 2626 ReadAttrDirReply* reply; 2627 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 2628 if (error != B_OK) 2629 return error; 2630 RequestReleaser requestReleaser(port, reply); 2631 2632 // process the reply 2633 if (reply->error != B_OK) 2634 return reply->error; 2635 if (reply->count < 0 || reply->count > count) 2636 return B_BAD_DATA; 2637 if ((int32)bufferSize < reply->buffer.GetSize()) 2638 return B_BAD_DATA; 2639 2640 *countRead = reply->count; 2641 if (*countRead > 0) { 2642 // copy the buffer -- limit the number of bytes to copy 2643 uint32 maxBytes = *countRead 2644 * (sizeof(struct dirent) + B_ATTR_NAME_LENGTH); 2645 uint32 copyBytes = reply->buffer.GetSize(); 2646 if (copyBytes > maxBytes) 2647 copyBytes = maxBytes; 2648 memcpy(buffer, reply->buffer.GetData(), copyBytes); 2649 } 2650 _SendReceiptAck(port); 2651 return error; 2652 } 2653 2654 // RewindAttrDir 2655 status_t 2656 Volume::RewindAttrDir(void* _node, void* cookie) 2657 { 2658 VNode* vnode = (VNode*)_node; 2659 2660 // check capability 2661 if (!HasVNodeCapability(vnode, FS_VNODE_CAPABILITY_REWIND_ATTR_DIR)) 2662 return B_BAD_VALUE; 2663 2664 // get a free port 2665 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 2666 if (!port) 2667 return B_ERROR; 2668 PortReleaser _(fFileSystem->GetPortPool(), port); 2669 2670 // prepare the request 2671 RequestAllocator allocator(port->GetPort()); 2672 RewindAttrDirRequest* request; 2673 status_t error = AllocateRequest(allocator, &request); 2674 if (error != B_OK) 2675 return error; 2676 2677 request->volume = fUserlandVolume; 2678 request->node = vnode->clientNode; 2679 request->attrDirCookie = cookie; 2680 2681 // send the request 2682 KernelRequestHandler handler(this, REWIND_ATTR_DIR_REPLY); 2683 RewindAttrDirReply* reply; 2684 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 2685 if (error != B_OK) 2686 return error; 2687 RequestReleaser requestReleaser(port, reply); 2688 2689 // process the reply 2690 if (reply->error != B_OK) 2691 return reply->error; 2692 return error; 2693 } 2694 2695 2696 // #pragma mark - attributes 2697 2698 // CreateAttr 2699 status_t 2700 Volume::CreateAttr(void* _node, const char* name, uint32 type, int openMode, 2701 void** cookie) 2702 { 2703 VNode* vnode = (VNode*)_node; 2704 2705 // check capability 2706 if (!HasVNodeCapability(vnode, FS_VNODE_CAPABILITY_CREATE_ATTR)) 2707 return B_BAD_VALUE; 2708 2709 // get a free port 2710 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 2711 if (!port) 2712 return B_ERROR; 2713 PortReleaser _(fFileSystem->GetPortPool(), port); 2714 AutoIncrementer incrementer(&fOpenAttributes); 2715 2716 // prepare the request 2717 RequestAllocator allocator(port->GetPort()); 2718 CreateAttrRequest* request; 2719 status_t error = AllocateRequest(allocator, &request); 2720 if (error != B_OK) 2721 return error; 2722 2723 request->volume = fUserlandVolume; 2724 request->node = vnode->clientNode; 2725 error = allocator.AllocateString(request->name, name); 2726 request->type = type; 2727 request->openMode = openMode; 2728 if (error != B_OK) 2729 return error; 2730 2731 // send the request 2732 KernelRequestHandler handler(this, CREATE_ATTR_REPLY); 2733 CreateAttrReply* reply; 2734 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 2735 if (error != B_OK) 2736 return error; 2737 RequestReleaser requestReleaser(port, reply); 2738 2739 // process the reply 2740 if (reply->error != B_OK) 2741 return reply->error; 2742 incrementer.Keep(); 2743 *cookie = reply->attrCookie; 2744 return error; 2745 } 2746 2747 // OpenAttr 2748 status_t 2749 Volume::OpenAttr(void* _node, const char* name, int openMode, 2750 void** cookie) 2751 { 2752 VNode* vnode = (VNode*)_node; 2753 2754 // check capability 2755 if (!HasVNodeCapability(vnode, FS_VNODE_CAPABILITY_OPEN_ATTR)) 2756 return B_BAD_VALUE; 2757 2758 // get a free port 2759 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 2760 if (!port) 2761 return B_ERROR; 2762 PortReleaser _(fFileSystem->GetPortPool(), port); 2763 AutoIncrementer incrementer(&fOpenAttributes); 2764 2765 // prepare the request 2766 RequestAllocator allocator(port->GetPort()); 2767 OpenAttrRequest* request; 2768 status_t error = AllocateRequest(allocator, &request); 2769 if (error != B_OK) 2770 return error; 2771 2772 request->volume = fUserlandVolume; 2773 request->node = vnode->clientNode; 2774 error = allocator.AllocateString(request->name, name); 2775 request->openMode = openMode; 2776 if (error != B_OK) 2777 return error; 2778 2779 // send the request 2780 KernelRequestHandler handler(this, OPEN_ATTR_REPLY); 2781 OpenAttrReply* reply; 2782 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 2783 if (error != B_OK) 2784 return error; 2785 RequestReleaser requestReleaser(port, reply); 2786 2787 // process the reply 2788 if (reply->error != B_OK) 2789 return reply->error; 2790 incrementer.Keep(); 2791 *cookie = reply->attrCookie; 2792 return error; 2793 } 2794 2795 // CloseAttr 2796 status_t 2797 Volume::CloseAttr(void* node, void* cookie) 2798 { 2799 status_t error = _CloseAttr(node, cookie); 2800 if (error != B_OK && fFileSystem->GetPortPool()->IsDisconnected()) { 2801 // This isn't really necessary, as the return value is irrelevant to 2802 // the VFS. OBOS ignores it completely. The fsshell returns it to the 2803 // userland, but considers the node closed anyway. 2804 WARN(("Volume::CloseAttr(): connection lost, forcing close attr\n")); 2805 return B_OK; 2806 } 2807 return error; 2808 } 2809 2810 // FreeAttrCookie 2811 status_t 2812 Volume::FreeAttrCookie(void* node, void* cookie) 2813 { 2814 status_t error = _FreeAttrCookie(node, cookie); 2815 bool disconnected = false; 2816 if (error != B_OK && fFileSystem->GetPortPool()->IsDisconnected()) { 2817 // This isn't really necessary, as the return value is irrelevant to 2818 // the VFS. It's completely ignored by OBOS as well as by the fsshell. 2819 WARN(("Volume::FreeAttrCookie(): connection lost, forcing free attr " 2820 "cookie\n")); 2821 error = B_OK; 2822 disconnected = true; 2823 } 2824 2825 int32 openAttributes = atomic_add(&fOpenAttributes, -1); 2826 if (openAttributes <= 1 && disconnected) 2827 _PutAllPendingVNodes(); 2828 return error; 2829 } 2830 2831 // ReadAttr 2832 status_t 2833 Volume::ReadAttr(void* _node, void* cookie, off_t pos, 2834 void* buffer, size_t bufferSize, size_t* bytesRead) 2835 { 2836 VNode* vnode = (VNode*)_node; 2837 2838 *bytesRead = 0; 2839 2840 // check capability 2841 if (!HasVNodeCapability(vnode, FS_VNODE_CAPABILITY_READ_ATTR)) 2842 return B_BAD_VALUE; 2843 2844 // get a free port 2845 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 2846 if (!port) 2847 return B_ERROR; 2848 PortReleaser _(fFileSystem->GetPortPool(), port); 2849 2850 // prepare the request 2851 RequestAllocator allocator(port->GetPort()); 2852 ReadAttrRequest* request; 2853 status_t error = AllocateRequest(allocator, &request); 2854 if (error != B_OK) 2855 return error; 2856 2857 request->volume = fUserlandVolume; 2858 request->node = vnode->clientNode; 2859 request->attrCookie = cookie; 2860 request->pos = pos; 2861 request->size = bufferSize; 2862 2863 // send the request 2864 KernelRequestHandler handler(this, READ_ATTR_REPLY); 2865 ReadAttrReply* reply; 2866 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 2867 if (error != B_OK) 2868 return error; 2869 RequestReleaser requestReleaser(port, reply); 2870 2871 // process the reply 2872 if (reply->error != B_OK) 2873 return reply->error; 2874 void* readBuffer = reply->buffer.GetData(); 2875 if (reply->bytesRead > (uint32)reply->buffer.GetSize() 2876 || reply->bytesRead > bufferSize) { 2877 return B_BAD_DATA; 2878 } 2879 if (reply->bytesRead > 0) 2880 memcpy(buffer, readBuffer, reply->bytesRead); 2881 *bytesRead = reply->bytesRead; 2882 _SendReceiptAck(port); 2883 return error; 2884 } 2885 2886 // WriteAttr 2887 status_t 2888 Volume::WriteAttr(void* _node, void* cookie, off_t pos, 2889 const void* buffer, size_t bufferSize, size_t* bytesWritten) 2890 { 2891 VNode* vnode = (VNode*)_node; 2892 2893 *bytesWritten = 0; 2894 2895 // check capability 2896 if (!HasVNodeCapability(vnode, FS_VNODE_CAPABILITY_WRITE_ATTR)) 2897 return B_BAD_VALUE; 2898 2899 // get a free port 2900 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 2901 if (!port) 2902 return B_ERROR; 2903 PortReleaser _(fFileSystem->GetPortPool(), port); 2904 2905 // prepare the request 2906 RequestAllocator allocator(port->GetPort()); 2907 WriteAttrRequest* request; 2908 status_t error = AllocateRequest(allocator, &request); 2909 if (error != B_OK) 2910 return error; 2911 2912 request->volume = fUserlandVolume; 2913 request->node = vnode->clientNode; 2914 request->attrCookie = cookie; 2915 request->pos = pos; 2916 error = allocator.AllocateData(request->buffer, buffer, bufferSize, 1); 2917 if (error != B_OK) 2918 return error; 2919 2920 // send the request 2921 KernelRequestHandler handler(this, WRITE_ATTR_REPLY); 2922 WriteAttrReply* reply; 2923 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 2924 if (error != B_OK) 2925 return error; 2926 RequestReleaser requestReleaser(port, reply); 2927 2928 // process the reply 2929 if (reply->error != B_OK) 2930 return reply->error; 2931 *bytesWritten = reply->bytesWritten; 2932 return error; 2933 } 2934 2935 // ReadAttrStat 2936 status_t 2937 Volume::ReadAttrStat(void* _node, void* cookie, struct stat *st) 2938 { 2939 VNode* vnode = (VNode*)_node; 2940 2941 // check capability 2942 if (!HasVNodeCapability(vnode, FS_VNODE_CAPABILITY_READ_ATTR_STAT)) 2943 return B_BAD_VALUE; 2944 2945 // get a free port 2946 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 2947 if (!port) 2948 return B_ERROR; 2949 PortReleaser _(fFileSystem->GetPortPool(), port); 2950 2951 // prepare the request 2952 RequestAllocator allocator(port->GetPort()); 2953 ReadAttrStatRequest* request; 2954 status_t error = AllocateRequest(allocator, &request); 2955 if (error != B_OK) 2956 return error; 2957 2958 request->volume = fUserlandVolume; 2959 request->node = vnode->clientNode; 2960 request->attrCookie = cookie; 2961 2962 // send the request 2963 KernelRequestHandler handler(this, READ_ATTR_STAT_REPLY); 2964 ReadAttrStatReply* reply; 2965 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 2966 if (error != B_OK) 2967 return error; 2968 RequestReleaser requestReleaser(port, reply); 2969 2970 // process the reply 2971 if (reply->error != B_OK) 2972 return reply->error; 2973 *st = reply->st; 2974 return error; 2975 } 2976 2977 // WriteAttrStat 2978 status_t 2979 Volume::WriteAttrStat(void* _node, void* cookie, const struct stat *st, 2980 int statMask) 2981 { 2982 VNode* vnode = (VNode*)_node; 2983 2984 // check capability 2985 if (!HasVNodeCapability(vnode, FS_VNODE_CAPABILITY_WRITE_ATTR_STAT)) 2986 return B_BAD_VALUE; 2987 2988 // get a free port 2989 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 2990 if (!port) 2991 return B_ERROR; 2992 PortReleaser _(fFileSystem->GetPortPool(), port); 2993 2994 // prepare the request 2995 RequestAllocator allocator(port->GetPort()); 2996 WriteAttrStatRequest* request; 2997 status_t error = AllocateRequest(allocator, &request); 2998 if (error != B_OK) 2999 return error; 3000 3001 request->volume = fUserlandVolume; 3002 request->node = vnode->clientNode; 3003 request->attrCookie = cookie; 3004 request->st = *st; 3005 request->mask = statMask; 3006 3007 // send the request 3008 KernelRequestHandler handler(this, WRITE_ATTR_STAT_REPLY); 3009 WriteAttrStatReply* reply; 3010 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 3011 if (error != B_OK) 3012 return error; 3013 RequestReleaser requestReleaser(port, reply); 3014 3015 // process the reply 3016 if (reply->error != B_OK) 3017 return reply->error; 3018 return error; 3019 } 3020 3021 // RenameAttr 3022 status_t 3023 Volume::RenameAttr(void* _oldNode, const char* oldName, void* _newNode, 3024 const char* newName) 3025 { 3026 VNode* oldVNode = (VNode*)_oldNode; 3027 VNode* newVNode = (VNode*)_newNode; 3028 3029 // check capability 3030 if (!HasVNodeCapability(oldVNode, FS_VNODE_CAPABILITY_RENAME_ATTR)) 3031 return B_BAD_VALUE; 3032 3033 // get a free port 3034 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 3035 if (!port) 3036 return B_ERROR; 3037 PortReleaser _(fFileSystem->GetPortPool(), port); 3038 3039 // prepare the request 3040 RequestAllocator allocator(port->GetPort()); 3041 RenameAttrRequest* request; 3042 status_t error = AllocateRequest(allocator, &request); 3043 if (error != B_OK) 3044 return error; 3045 3046 request->volume = fUserlandVolume; 3047 request->oldNode = oldVNode->clientNode; 3048 request->newNode = newVNode->clientNode; 3049 error = allocator.AllocateString(request->oldName, oldName); 3050 if (error == B_OK) 3051 error = allocator.AllocateString(request->newName, newName); 3052 if (error != B_OK) 3053 return error; 3054 3055 // send the request 3056 KernelRequestHandler handler(this, RENAME_ATTR_REPLY); 3057 RenameAttrReply* reply; 3058 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 3059 if (error != B_OK) 3060 return error; 3061 RequestReleaser requestReleaser(port, reply); 3062 3063 // process the reply 3064 if (reply->error != B_OK) 3065 return reply->error; 3066 return error; 3067 } 3068 3069 // RemoveAttr 3070 status_t 3071 Volume::RemoveAttr(void* _node, const char* name) 3072 { 3073 VNode* vnode = (VNode*)_node; 3074 3075 // check capability 3076 if (!HasVNodeCapability(vnode, FS_VNODE_CAPABILITY_REMOVE_ATTR)) 3077 return B_BAD_VALUE; 3078 3079 // get a free port 3080 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 3081 if (!port) 3082 return B_ERROR; 3083 PortReleaser _(fFileSystem->GetPortPool(), port); 3084 3085 // prepare the request 3086 RequestAllocator allocator(port->GetPort()); 3087 RemoveAttrRequest* request; 3088 status_t error = AllocateRequest(allocator, &request); 3089 if (error != B_OK) 3090 return error; 3091 3092 request->volume = fUserlandVolume; 3093 request->node = vnode->clientNode; 3094 error = allocator.AllocateString(request->name, name); 3095 if (error != B_OK) 3096 return error; 3097 3098 // send the request 3099 KernelRequestHandler handler(this, REMOVE_ATTR_REPLY); 3100 RemoveAttrReply* reply; 3101 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 3102 if (error != B_OK) 3103 return error; 3104 RequestReleaser requestReleaser(port, reply); 3105 3106 // process the reply 3107 if (reply->error != B_OK) 3108 return reply->error; 3109 return error; 3110 } 3111 3112 3113 // #pragma mark - indices 3114 3115 3116 // OpenIndexDir 3117 status_t 3118 Volume::OpenIndexDir(void** cookie) 3119 { 3120 // check capability 3121 if (!HasCapability(FS_VOLUME_CAPABILITY_OPEN_INDEX_DIR)) 3122 return B_BAD_VALUE; 3123 3124 // get a free port 3125 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 3126 if (!port) 3127 return B_ERROR; 3128 PortReleaser _(fFileSystem->GetPortPool(), port); 3129 AutoIncrementer incrementer(&fOpenIndexDirectories); 3130 3131 // prepare the request 3132 RequestAllocator allocator(port->GetPort()); 3133 OpenIndexDirRequest* request; 3134 status_t error = AllocateRequest(allocator, &request); 3135 if (error != B_OK) 3136 return error; 3137 3138 request->volume = fUserlandVolume; 3139 3140 // send the request 3141 KernelRequestHandler handler(this, OPEN_INDEX_DIR_REPLY); 3142 OpenIndexDirReply* reply; 3143 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 3144 if (error != B_OK) 3145 return error; 3146 RequestReleaser requestReleaser(port, reply); 3147 3148 // process the reply 3149 if (reply->error != B_OK) 3150 return reply->error; 3151 incrementer.Keep(); 3152 *cookie = reply->indexDirCookie; 3153 return error; 3154 } 3155 3156 // CloseIndexDir 3157 status_t 3158 Volume::CloseIndexDir(void* cookie) 3159 { 3160 status_t error = _CloseIndexDir(cookie); 3161 if (error != B_OK && fFileSystem->GetPortPool()->IsDisconnected()) { 3162 // This isn't really necessary, as the return value is irrelevant to 3163 // the VFS. OBOS ignores it completely. The fsshell returns it to the 3164 // userland, but considers the node closed anyway. 3165 WARN(("Volume::CloseIndexDir(): connection lost, forcing close " 3166 "index dir\n")); 3167 return B_OK; 3168 } 3169 return error; 3170 } 3171 3172 // FreeIndexDirCookie 3173 status_t 3174 Volume::FreeIndexDirCookie(void* cookie) 3175 { 3176 status_t error = _FreeIndexDirCookie(cookie); 3177 bool disconnected = false; 3178 if (error != B_OK && fFileSystem->GetPortPool()->IsDisconnected()) { 3179 // This isn't really necessary, as the return value is irrelevant to 3180 // the VFS. It's completely ignored by OBOS as well as by the fsshell. 3181 WARN(("Volume::FreeIndexDirCookie(): connection lost, forcing free " 3182 "index dir cookie\n")); 3183 error = B_OK; 3184 disconnected = true; 3185 } 3186 3187 int32 openIndexDirs = atomic_add(&fOpenIndexDirectories, -1); 3188 if (openIndexDirs <= 1 && disconnected) 3189 _PutAllPendingVNodes(); 3190 return error; 3191 } 3192 3193 // ReadIndexDir 3194 status_t 3195 Volume::ReadIndexDir(void* cookie, void* buffer, size_t bufferSize, 3196 uint32 count, uint32* countRead) 3197 { 3198 *countRead = 0; 3199 3200 // check capability 3201 if (!HasCapability(FS_VOLUME_CAPABILITY_READ_INDEX_DIR)) 3202 return B_BAD_VALUE; 3203 3204 // get a free port 3205 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 3206 if (!port) 3207 return B_ERROR; 3208 PortReleaser _(fFileSystem->GetPortPool(), port); 3209 3210 // prepare the request 3211 RequestAllocator allocator(port->GetPort()); 3212 ReadIndexDirRequest* request; 3213 status_t error = AllocateRequest(allocator, &request); 3214 if (error != B_OK) 3215 return error; 3216 3217 request->volume = fUserlandVolume; 3218 request->indexDirCookie = cookie; 3219 request->bufferSize = bufferSize; 3220 request->count = count; 3221 3222 // send the request 3223 KernelRequestHandler handler(this, READ_INDEX_DIR_REPLY); 3224 ReadIndexDirReply* reply; 3225 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 3226 if (error != B_OK) 3227 return error; 3228 RequestReleaser requestReleaser(port, reply); 3229 3230 // process the reply 3231 if (reply->error != B_OK) 3232 return reply->error; 3233 if (reply->count < 0 || reply->count > count) 3234 return B_BAD_DATA; 3235 if ((int32)bufferSize < reply->buffer.GetSize()) 3236 return B_BAD_DATA; 3237 3238 *countRead = reply->count; 3239 if (*countRead > 0) { 3240 // copy the buffer -- limit the number of bytes to copy 3241 uint32 maxBytes = *countRead 3242 * (sizeof(struct dirent) + B_FILE_NAME_LENGTH); 3243 uint32 copyBytes = reply->buffer.GetSize(); 3244 if (copyBytes > maxBytes) 3245 copyBytes = maxBytes; 3246 memcpy(buffer, reply->buffer.GetData(), copyBytes); 3247 } 3248 _SendReceiptAck(port); 3249 return error; 3250 } 3251 3252 // RewindIndexDir 3253 status_t 3254 Volume::RewindIndexDir(void* cookie) 3255 { 3256 // check capability 3257 if (!HasCapability(FS_VOLUME_CAPABILITY_REWIND_INDEX_DIR)) 3258 return B_BAD_VALUE; 3259 3260 // get a free port 3261 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 3262 if (!port) 3263 return B_ERROR; 3264 PortReleaser _(fFileSystem->GetPortPool(), port); 3265 3266 // prepare the request 3267 RequestAllocator allocator(port->GetPort()); 3268 RewindIndexDirRequest* request; 3269 status_t error = AllocateRequest(allocator, &request); 3270 if (error != B_OK) 3271 return error; 3272 3273 request->volume = fUserlandVolume; 3274 request->indexDirCookie = cookie; 3275 3276 // send the request 3277 KernelRequestHandler handler(this, REWIND_INDEX_DIR_REPLY); 3278 RewindIndexDirReply* reply; 3279 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 3280 if (error != B_OK) 3281 return error; 3282 RequestReleaser requestReleaser(port, reply); 3283 3284 // process the reply 3285 if (reply->error != B_OK) 3286 return reply->error; 3287 return error; 3288 } 3289 3290 // CreateIndex 3291 status_t 3292 Volume::CreateIndex(const char* name, uint32 type, uint32 flags) 3293 { 3294 // check capability 3295 if (!HasCapability(FS_VOLUME_CAPABILITY_CREATE_INDEX)) 3296 return B_BAD_VALUE; 3297 3298 // get a free port 3299 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 3300 if (!port) 3301 return B_ERROR; 3302 PortReleaser _(fFileSystem->GetPortPool(), port); 3303 3304 // prepare the request 3305 RequestAllocator allocator(port->GetPort()); 3306 CreateIndexRequest* request; 3307 status_t error = AllocateRequest(allocator, &request); 3308 if (error != B_OK) 3309 return error; 3310 3311 request->volume = fUserlandVolume; 3312 error = allocator.AllocateString(request->name, name); 3313 request->type = type; 3314 request->flags = flags; 3315 if (error != B_OK) 3316 return error; 3317 3318 // send the request 3319 KernelRequestHandler handler(this, CREATE_INDEX_REPLY); 3320 CreateIndexReply* reply; 3321 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 3322 if (error != B_OK) 3323 return error; 3324 RequestReleaser requestReleaser(port, reply); 3325 3326 // process the reply 3327 if (reply->error != B_OK) 3328 return reply->error; 3329 return error; 3330 } 3331 3332 // RemoveIndex 3333 status_t 3334 Volume::RemoveIndex(const char* name) 3335 { 3336 // check capability 3337 if (!HasCapability(FS_VOLUME_CAPABILITY_REMOVE_INDEX)) 3338 return B_BAD_VALUE; 3339 3340 // get a free port 3341 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 3342 if (!port) 3343 return B_ERROR; 3344 PortReleaser _(fFileSystem->GetPortPool(), port); 3345 3346 // prepare the request 3347 RequestAllocator allocator(port->GetPort()); 3348 RemoveIndexRequest* request; 3349 status_t error = AllocateRequest(allocator, &request); 3350 if (error != B_OK) 3351 return error; 3352 3353 request->volume = fUserlandVolume; 3354 error = allocator.AllocateString(request->name, name); 3355 if (error != B_OK) 3356 return error; 3357 3358 // send the request 3359 KernelRequestHandler handler(this, REMOVE_INDEX_REPLY); 3360 RemoveIndexReply* reply; 3361 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 3362 if (error != B_OK) 3363 return error; 3364 RequestReleaser requestReleaser(port, reply); 3365 3366 // process the reply 3367 if (reply->error != B_OK) 3368 return reply->error; 3369 return error; 3370 } 3371 3372 // ReadIndexStat 3373 status_t 3374 Volume::ReadIndexStat(const char* name, struct stat *st) 3375 { 3376 // check capability 3377 if (!HasCapability(FS_VOLUME_CAPABILITY_READ_INDEX_STAT)) 3378 return B_BAD_VALUE; 3379 3380 // get a free port 3381 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 3382 if (!port) 3383 return B_ERROR; 3384 PortReleaser _(fFileSystem->GetPortPool(), port); 3385 3386 // prepare the request 3387 RequestAllocator allocator(port->GetPort()); 3388 ReadIndexStatRequest* request; 3389 status_t error = AllocateRequest(allocator, &request); 3390 if (error != B_OK) 3391 return error; 3392 3393 request->volume = fUserlandVolume; 3394 error = allocator.AllocateString(request->name, name); 3395 if (error != B_OK) 3396 return error; 3397 3398 // send the request 3399 KernelRequestHandler handler(this, READ_INDEX_STAT_REPLY); 3400 ReadIndexStatReply* reply; 3401 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 3402 if (error != B_OK) 3403 return error; 3404 RequestReleaser requestReleaser(port, reply); 3405 3406 // process the reply 3407 if (reply->error != B_OK) 3408 return reply->error; 3409 *st = reply->st; 3410 return error; 3411 } 3412 3413 3414 // #pragma mark - queries 3415 3416 3417 // OpenQuery 3418 status_t 3419 Volume::OpenQuery(const char* queryString, uint32 flags, port_id targetPort, 3420 uint32 token, void** cookie) 3421 { 3422 // check capability 3423 if (!HasCapability(FS_VOLUME_CAPABILITY_OPEN_QUERY)) 3424 return B_BAD_VALUE; 3425 3426 // get a free port 3427 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 3428 if (!port) 3429 return B_ERROR; 3430 PortReleaser _(fFileSystem->GetPortPool(), port); 3431 AutoIncrementer incrementer(&fOpenQueries); 3432 3433 // prepare the request 3434 RequestAllocator allocator(port->GetPort()); 3435 OpenQueryRequest* request; 3436 status_t error = AllocateRequest(allocator, &request); 3437 if (error != B_OK) 3438 return error; 3439 3440 request->volume = fUserlandVolume; 3441 error = allocator.AllocateString(request->queryString, queryString); 3442 if (error != B_OK) 3443 return error; 3444 request->flags = flags; 3445 request->port = targetPort; 3446 request->token = token; 3447 3448 // send the request 3449 KernelRequestHandler handler(this, OPEN_QUERY_REPLY); 3450 OpenQueryReply* reply; 3451 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 3452 if (error != B_OK) 3453 return error; 3454 RequestReleaser requestReleaser(port, reply); 3455 3456 // process the reply 3457 if (reply->error != B_OK) 3458 return reply->error; 3459 incrementer.Keep(); 3460 *cookie = reply->queryCookie; 3461 return error; 3462 } 3463 3464 // CloseQuery 3465 status_t 3466 Volume::CloseQuery(void* cookie) 3467 { 3468 status_t error = _CloseQuery(cookie); 3469 if (error != B_OK && fFileSystem->GetPortPool()->IsDisconnected()) { 3470 // This isn't really necessary, as the return value is irrelevant to 3471 // the VFS. OBOS ignores it completely. The fsshell returns it to the 3472 // userland, but considers the node closed anyway. 3473 WARN(("Volume::CloseQuery(): connection lost, forcing close query\n")); 3474 return B_OK; 3475 } 3476 return error; 3477 } 3478 3479 // FreeQueryCookie 3480 status_t 3481 Volume::FreeQueryCookie(void* cookie) 3482 { 3483 status_t error = _FreeQueryCookie(cookie); 3484 bool disconnected = false; 3485 if (error != B_OK && fFileSystem->GetPortPool()->IsDisconnected()) { 3486 // This isn't really necessary, as the return value is irrelevant to 3487 // the VFS. It's completely ignored by OBOS as well as by the fsshell. 3488 WARN(("Volume::FreeQueryCookie(): connection lost, forcing free " 3489 "query cookie\n")); 3490 error = B_OK; 3491 disconnected = true; 3492 } 3493 3494 int32 openQueries = atomic_add(&fOpenQueries, -1); 3495 if (openQueries <= 1 && disconnected) 3496 _PutAllPendingVNodes(); 3497 return error; 3498 } 3499 3500 // ReadQuery 3501 status_t 3502 Volume::ReadQuery(void* cookie, void* buffer, size_t bufferSize, 3503 uint32 count, uint32* countRead) 3504 { 3505 *countRead = 0; 3506 3507 // check capability 3508 if (!HasCapability(FS_VOLUME_CAPABILITY_READ_QUERY)) 3509 return B_BAD_VALUE; 3510 3511 // get a free port 3512 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 3513 if (!port) 3514 return B_ERROR; 3515 PortReleaser _(fFileSystem->GetPortPool(), port); 3516 3517 // prepare the request 3518 RequestAllocator allocator(port->GetPort()); 3519 ReadQueryRequest* request; 3520 status_t error = AllocateRequest(allocator, &request); 3521 if (error != B_OK) 3522 return error; 3523 3524 request->volume = fUserlandVolume; 3525 request->queryCookie = cookie; 3526 request->bufferSize = bufferSize; 3527 request->count = count; 3528 3529 // send the request 3530 KernelRequestHandler handler(this, READ_QUERY_REPLY); 3531 ReadQueryReply* reply; 3532 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 3533 if (error != B_OK) 3534 return error; 3535 RequestReleaser requestReleaser(port, reply); 3536 3537 // process the reply 3538 if (reply->error != B_OK) 3539 return reply->error; 3540 if (reply->count < 0 || reply->count > count) 3541 return B_BAD_DATA; 3542 if ((int32)bufferSize < reply->buffer.GetSize()) 3543 return B_BAD_DATA; 3544 3545 *countRead = reply->count; 3546 if (*countRead > 0) { 3547 // copy the buffer -- limit the number of bytes to copy 3548 uint32 maxBytes = *countRead 3549 * (sizeof(struct dirent) + B_FILE_NAME_LENGTH); 3550 uint32 copyBytes = reply->buffer.GetSize(); 3551 if (copyBytes > maxBytes) 3552 copyBytes = maxBytes; 3553 memcpy(buffer, reply->buffer.GetData(), copyBytes); 3554 } 3555 _SendReceiptAck(port); 3556 return error; 3557 } 3558 3559 // RewindQuery 3560 status_t 3561 Volume::RewindQuery(void* cookie) 3562 { 3563 // check capability 3564 if (!HasCapability(FS_VOLUME_CAPABILITY_REWIND_QUERY)) 3565 return B_BAD_VALUE; 3566 3567 // get a free port 3568 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 3569 if (!port) 3570 return B_ERROR; 3571 PortReleaser _(fFileSystem->GetPortPool(), port); 3572 3573 // prepare the request 3574 RequestAllocator allocator(port->GetPort()); 3575 RewindQueryRequest* request; 3576 status_t error = AllocateRequest(allocator, &request); 3577 if (error != B_OK) 3578 return error; 3579 3580 request->volume = fUserlandVolume; 3581 request->queryCookie = cookie; 3582 3583 // send the request 3584 KernelRequestHandler handler(this, REWIND_QUERY_REPLY); 3585 RewindQueryReply* reply; 3586 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 3587 if (error != B_OK) 3588 return error; 3589 RequestReleaser requestReleaser(port, reply); 3590 3591 // process the reply 3592 if (reply->error != B_OK) 3593 return reply->error; 3594 return error; 3595 } 3596 3597 // #pragma mark - 3598 // #pragma mark ----- private implementations ----- 3599 3600 3601 // _InitVolumeOps 3602 void 3603 Volume::_InitVolumeOps() 3604 { 3605 memcpy(&fVolumeOps, &gUserlandFSVolumeOps, sizeof(fs_volume_ops)); 3606 3607 #undef CLEAR_UNSUPPORTED 3608 #define CLEAR_UNSUPPORTED(capability, op) \ 3609 if (!fCapabilities.Get(capability)) \ 3610 fVolumeOps.op = NULL 3611 3612 // FS operations 3613 // FS_VOLUME_CAPABILITY_UNMOUNT: unmount 3614 // always needed 3615 3616 // FS_VOLUME_CAPABILITY_READ_FS_INFO: read_fs_info 3617 // always needed 3618 CLEAR_UNSUPPORTED(FS_VOLUME_CAPABILITY_WRITE_FS_INFO, write_fs_info); 3619 CLEAR_UNSUPPORTED(FS_VOLUME_CAPABILITY_SYNC, sync); 3620 3621 // vnode operations 3622 // FS_VOLUME_CAPABILITY_GET_VNODE: get_vnode 3623 // always needed 3624 3625 // index directory & index operations 3626 CLEAR_UNSUPPORTED(FS_VOLUME_CAPABILITY_OPEN_INDEX_DIR, open_index_dir); 3627 // FS_VOLUME_CAPABILITY_CLOSE_INDEX_DIR: close_index_dir 3628 // always needed 3629 // FS_VOLUME_CAPABILITY_FREE_INDEX_DIR_COOKIE: free_index_dir_cookie 3630 // always needed 3631 CLEAR_UNSUPPORTED(FS_VOLUME_CAPABILITY_READ_INDEX_DIR, read_index_dir); 3632 CLEAR_UNSUPPORTED(FS_VOLUME_CAPABILITY_REWIND_INDEX_DIR, rewind_index_dir); 3633 3634 CLEAR_UNSUPPORTED(FS_VOLUME_CAPABILITY_CREATE_INDEX, create_index); 3635 CLEAR_UNSUPPORTED(FS_VOLUME_CAPABILITY_REMOVE_INDEX, remove_index); 3636 CLEAR_UNSUPPORTED(FS_VOLUME_CAPABILITY_READ_INDEX_STAT, read_index_stat); 3637 3638 // query operations 3639 CLEAR_UNSUPPORTED(FS_VOLUME_CAPABILITY_OPEN_QUERY, open_query); 3640 // FS_VOLUME_CAPABILITY_CLOSE_QUERY: close_query 3641 // always needed 3642 // FS_VOLUME_CAPABILITY_FREE_QUERY_COOKIE: free_query_cookie 3643 // always needed 3644 CLEAR_UNSUPPORTED(FS_VOLUME_CAPABILITY_READ_QUERY, read_query); 3645 CLEAR_UNSUPPORTED(FS_VOLUME_CAPABILITY_REWIND_QUERY, rewind_query); 3646 3647 #undef CLEAR_UNSUPPORTED 3648 } 3649 3650 3651 // #pragma mark - 3652 3653 3654 // _Mount 3655 status_t 3656 Volume::_Mount(const char* device, uint32 flags, const char* parameters) 3657 { 3658 // get a free port 3659 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 3660 if (!port) 3661 return B_ERROR; 3662 PortReleaser _(fFileSystem->GetPortPool(), port); 3663 3664 // get the current working directory 3665 char cwd[B_PATH_NAME_LENGTH]; 3666 if (!getcwd(cwd, sizeof(cwd))) 3667 return errno; 3668 3669 // prepare the request 3670 RequestAllocator allocator(port->GetPort()); 3671 MountVolumeRequest* request; 3672 status_t error = AllocateRequest(allocator, &request); 3673 if (error != B_OK) 3674 return error; 3675 3676 request->nsid = GetID(); 3677 error = allocator.AllocateString(request->cwd, cwd); 3678 if (error == B_OK) 3679 error = allocator.AllocateString(request->device, device); 3680 request->flags = flags; 3681 if (error == B_OK) 3682 error = allocator.AllocateString(request->parameters, parameters); 3683 if (error != B_OK) 3684 return error; 3685 3686 // send the request 3687 KernelRequestHandler handler(this, MOUNT_VOLUME_REPLY); 3688 MountVolumeReply* reply; 3689 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 3690 if (error != B_OK) 3691 return error; 3692 RequestReleaser requestReleaser(port, reply); 3693 3694 // process the reply 3695 if (reply->error != B_OK) 3696 return reply->error; 3697 fRootID = reply->rootID; 3698 fUserlandVolume = reply->volume; 3699 fCapabilities = reply->capabilities; 3700 3701 return error; 3702 } 3703 3704 // _Unmount 3705 status_t 3706 Volume::_Unmount() 3707 { 3708 // get a free port 3709 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 3710 if (!port) 3711 return B_ERROR; 3712 PortReleaser _(fFileSystem->GetPortPool(), port); 3713 3714 // prepare the request 3715 RequestAllocator allocator(port->GetPort()); 3716 UnmountVolumeRequest* request; 3717 status_t error = AllocateRequest(allocator, &request); 3718 if (error != B_OK) 3719 return error; 3720 3721 request->volume = fUserlandVolume; 3722 3723 // send the request 3724 KernelRequestHandler handler(this, UNMOUNT_VOLUME_REPLY); 3725 UnmountVolumeReply* reply; 3726 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 3727 if (error != B_OK) 3728 return error; 3729 RequestReleaser requestReleaser(port, reply); 3730 3731 // process the reply 3732 if (reply->error != B_OK) 3733 return reply->error; 3734 return error; 3735 } 3736 3737 // _ReadFSInfo 3738 status_t 3739 Volume::_ReadFSInfo(fs_info* info) 3740 { 3741 // check capability 3742 if (!HasCapability(FS_VOLUME_CAPABILITY_READ_FS_INFO)) 3743 return B_BAD_VALUE; 3744 3745 // get a free port 3746 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 3747 if (!port) 3748 return B_ERROR; 3749 PortReleaser _(fFileSystem->GetPortPool(), port); 3750 3751 // prepare the request 3752 RequestAllocator allocator(port->GetPort()); 3753 ReadFSInfoRequest* request; 3754 status_t error = AllocateRequest(allocator, &request); 3755 if (error != B_OK) 3756 return error; 3757 3758 request->volume = fUserlandVolume; 3759 3760 // send the request 3761 KernelRequestHandler handler(this, READ_FS_INFO_REPLY); 3762 ReadFSInfoReply* reply; 3763 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 3764 if (error != B_OK) 3765 return error; 3766 RequestReleaser requestReleaser(port, reply); 3767 3768 // process the reply 3769 if (reply->error != B_OK) 3770 return reply->error; 3771 *info = reply->info; 3772 return error; 3773 } 3774 3775 // _Lookup 3776 status_t 3777 Volume::_Lookup(void* _dir, const char* entryName, ino_t* vnid) 3778 { 3779 VNode* vnode = (VNode*)_dir; 3780 3781 // get a free port 3782 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 3783 if (!port) 3784 return B_ERROR; 3785 PortReleaser _(fFileSystem->GetPortPool(), port); 3786 3787 // prepare the request 3788 RequestAllocator allocator(port->GetPort()); 3789 LookupRequest* request; 3790 status_t error = AllocateRequest(allocator, &request); 3791 if (error != B_OK) 3792 return error; 3793 request->volume = fUserlandVolume; 3794 request->node = vnode->clientNode; 3795 error = allocator.AllocateString(request->entryName, entryName); 3796 if (error != B_OK) 3797 return error; 3798 3799 // send the request 3800 KernelRequestHandler handler(this, LOOKUP_REPLY); 3801 LookupReply* reply; 3802 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 3803 if (error != B_OK) 3804 return error; 3805 RequestReleaser requestReleaser(port, reply); 3806 3807 // process the reply 3808 if (reply->error != B_OK) 3809 return reply->error; 3810 *vnid = reply->vnid; 3811 3812 // The VFS will balance the get_vnode() call for the FS. 3813 _DecrementVNodeCount(*vnid); 3814 return error; 3815 } 3816 3817 // _WriteVNode 3818 status_t 3819 Volume::_WriteVNode(void* _node, bool reenter) 3820 { 3821 VNode* vnode = (VNode*)_node; 3822 3823 // At any rate remove the vnode from our map and delete it. We don't do that 3824 // right now, though, since we might still need to serve file cache requests 3825 // from the client FS. 3826 VNodeRemover nodeRemover(this, vnode); 3827 3828 void* clientNode = vnode->clientNode; 3829 3830 // get a free port 3831 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 3832 if (!port) 3833 return B_ERROR; 3834 PortReleaser _(fFileSystem->GetPortPool(), port); 3835 3836 // prepare the request 3837 RequestAllocator allocator(port->GetPort()); 3838 WriteVNodeRequest* request; 3839 status_t error = AllocateRequest(allocator, &request); 3840 if (error != B_OK) 3841 return error; 3842 request->volume = fUserlandVolume; 3843 request->node = clientNode; 3844 request->reenter = reenter; 3845 3846 // send the request 3847 KernelRequestHandler handler(this, WRITE_VNODE_REPLY); 3848 WriteVNodeReply* reply; 3849 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 3850 if (error != B_OK) 3851 return error; 3852 RequestReleaser requestReleaser(port, reply); 3853 3854 // process the reply 3855 if (reply->error != B_OK) 3856 return reply->error; 3857 return error; 3858 } 3859 3860 // _ReadStat 3861 status_t 3862 Volume::_ReadStat(void* _node, struct stat* st) 3863 { 3864 VNode* vnode = (VNode*)_node; 3865 3866 // check capability 3867 if (!HasVNodeCapability(vnode, FS_VNODE_CAPABILITY_READ_STAT)) 3868 return B_BAD_VALUE; 3869 3870 // get a free port 3871 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 3872 if (!port) 3873 return B_ERROR; 3874 PortReleaser _(fFileSystem->GetPortPool(), port); 3875 3876 // prepare the request 3877 RequestAllocator allocator(port->GetPort()); 3878 ReadStatRequest* request; 3879 status_t error = AllocateRequest(allocator, &request); 3880 if (error != B_OK) 3881 return error; 3882 3883 request->volume = fUserlandVolume; 3884 request->node = vnode->clientNode; 3885 3886 // send the request 3887 KernelRequestHandler handler(this, READ_STAT_REPLY); 3888 ReadStatReply* reply; 3889 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 3890 if (error != B_OK) 3891 return error; 3892 RequestReleaser requestReleaser(port, reply); 3893 3894 // process the reply 3895 if (reply->error != B_OK) 3896 return reply->error; 3897 *st = reply->st; 3898 return error; 3899 } 3900 3901 // _Close 3902 status_t 3903 Volume::_Close(void* _node, void* cookie) 3904 { 3905 VNode* vnode = (VNode*)_node; 3906 3907 // check capability 3908 if (!HasVNodeCapability(vnode, FS_VNODE_CAPABILITY_CLOSE)) 3909 return B_OK; 3910 3911 // get a free port 3912 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 3913 if (!port) 3914 return B_ERROR; 3915 PortReleaser _(fFileSystem->GetPortPool(), port); 3916 3917 // prepare the request 3918 RequestAllocator allocator(port->GetPort()); 3919 CloseRequest* request; 3920 status_t error = AllocateRequest(allocator, &request); 3921 if (error != B_OK) 3922 return error; 3923 3924 request->volume = fUserlandVolume; 3925 request->node = vnode->clientNode; 3926 request->fileCookie = cookie; 3927 3928 // send the request 3929 KernelRequestHandler handler(this, CLOSE_REPLY); 3930 CloseReply* reply; 3931 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 3932 if (error != B_OK) 3933 return error; 3934 RequestReleaser requestReleaser(port, reply); 3935 3936 // process the reply 3937 if (reply->error != B_OK) 3938 return reply->error; 3939 return error; 3940 } 3941 3942 // _FreeCookie 3943 status_t 3944 Volume::_FreeCookie(void* _node, void* cookie) 3945 { 3946 VNode* vnode = (VNode*)_node; 3947 3948 // check capability 3949 if (!HasVNodeCapability(vnode, FS_VNODE_CAPABILITY_FREE_COOKIE)) 3950 return B_OK; 3951 3952 // get a free port 3953 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 3954 if (!port) 3955 return B_ERROR; 3956 PortReleaser _(fFileSystem->GetPortPool(), port); 3957 3958 // prepare the request 3959 RequestAllocator allocator(port->GetPort()); 3960 FreeCookieRequest* request; 3961 status_t error = AllocateRequest(allocator, &request); 3962 if (error != B_OK) 3963 return error; 3964 3965 request->volume = fUserlandVolume; 3966 request->node = vnode->clientNode; 3967 request->fileCookie = cookie; 3968 3969 // send the request 3970 KernelRequestHandler handler(this, FREE_COOKIE_REPLY); 3971 FreeCookieReply* reply; 3972 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 3973 if (error != B_OK) 3974 return error; 3975 RequestReleaser requestReleaser(port, reply); 3976 3977 // process the reply 3978 if (reply->error != B_OK) 3979 return reply->error; 3980 return error; 3981 } 3982 3983 // _CloseDir 3984 status_t 3985 Volume::_CloseDir(void* _node, void* cookie) 3986 { 3987 VNode* vnode = (VNode*)_node; 3988 3989 // check capability 3990 if (!HasVNodeCapability(vnode, FS_VNODE_CAPABILITY_CLOSE_DIR)) 3991 return B_OK; 3992 3993 // get a free port 3994 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 3995 if (!port) 3996 return B_ERROR; 3997 PortReleaser _(fFileSystem->GetPortPool(), port); 3998 3999 // prepare the request 4000 RequestAllocator allocator(port->GetPort()); 4001 CloseDirRequest* request; 4002 status_t error = AllocateRequest(allocator, &request); 4003 if (error != B_OK) 4004 return error; 4005 4006 request->volume = fUserlandVolume; 4007 request->node = vnode->clientNode; 4008 request->dirCookie = cookie; 4009 4010 // send the request 4011 KernelRequestHandler handler(this, CLOSE_DIR_REPLY); 4012 CloseDirReply* reply; 4013 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 4014 if (error != B_OK) 4015 return error; 4016 RequestReleaser requestReleaser(port, reply); 4017 4018 // process the reply 4019 if (reply->error != B_OK) 4020 return reply->error; 4021 return error; 4022 } 4023 4024 // _FreeDirCookie 4025 status_t 4026 Volume::_FreeDirCookie(void* _node, void* cookie) 4027 { 4028 VNode* vnode = (VNode*)_node; 4029 4030 // check capability 4031 if (!HasVNodeCapability(vnode, FS_VNODE_CAPABILITY_FREE_DIR_COOKIE)) 4032 return B_OK; 4033 4034 // get a free port 4035 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 4036 if (!port) 4037 return B_ERROR; 4038 PortReleaser _(fFileSystem->GetPortPool(), port); 4039 4040 // prepare the request 4041 RequestAllocator allocator(port->GetPort()); 4042 FreeDirCookieRequest* request; 4043 status_t error = AllocateRequest(allocator, &request); 4044 if (error != B_OK) 4045 return error; 4046 4047 request->volume = fUserlandVolume; 4048 request->node = vnode->clientNode; 4049 request->dirCookie = cookie; 4050 4051 // send the request 4052 KernelRequestHandler handler(this, FREE_DIR_COOKIE_REPLY); 4053 FreeDirCookieReply* reply; 4054 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 4055 if (error != B_OK) 4056 return error; 4057 RequestReleaser requestReleaser(port, reply); 4058 4059 // process the reply 4060 if (reply->error != B_OK) 4061 return reply->error; 4062 return error; 4063 } 4064 4065 // _CloseAttrDir 4066 status_t 4067 Volume::_CloseAttrDir(void* _node, void* cookie) 4068 { 4069 VNode* vnode = (VNode*)_node; 4070 4071 // check capability 4072 if (!HasVNodeCapability(vnode, FS_VNODE_CAPABILITY_CLOSE_ATTR_DIR)) 4073 return B_OK; 4074 4075 // get a free port 4076 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 4077 if (!port) 4078 return B_ERROR; 4079 PortReleaser _(fFileSystem->GetPortPool(), port); 4080 4081 // prepare the request 4082 RequestAllocator allocator(port->GetPort()); 4083 CloseAttrDirRequest* request; 4084 status_t error = AllocateRequest(allocator, &request); 4085 if (error != B_OK) 4086 return error; 4087 4088 request->volume = fUserlandVolume; 4089 request->node = vnode->clientNode; 4090 request->attrDirCookie = cookie; 4091 4092 // send the request 4093 KernelRequestHandler handler(this, CLOSE_ATTR_DIR_REPLY); 4094 CloseAttrDirReply* reply; 4095 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 4096 if (error != B_OK) 4097 return error; 4098 RequestReleaser requestReleaser(port, reply); 4099 4100 // process the reply 4101 if (reply->error != B_OK) 4102 return reply->error; 4103 return error; 4104 } 4105 4106 // _FreeAttrDirCookie 4107 status_t 4108 Volume::_FreeAttrDirCookie(void* _node, void* cookie) 4109 { 4110 VNode* vnode = (VNode*)_node; 4111 4112 // check capability 4113 if (!HasVNodeCapability(vnode, FS_VNODE_CAPABILITY_FREE_ATTR_DIR_COOKIE)) 4114 return B_OK; 4115 4116 // get a free port 4117 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 4118 if (!port) 4119 return B_ERROR; 4120 PortReleaser _(fFileSystem->GetPortPool(), port); 4121 4122 // prepare the request 4123 RequestAllocator allocator(port->GetPort()); 4124 FreeAttrDirCookieRequest* request; 4125 status_t error = AllocateRequest(allocator, &request); 4126 if (error != B_OK) 4127 return error; 4128 4129 request->volume = fUserlandVolume; 4130 request->node = vnode->clientNode; 4131 request->attrDirCookie = cookie; 4132 4133 // send the request 4134 KernelRequestHandler handler(this, FREE_ATTR_DIR_COOKIE_REPLY); 4135 FreeAttrDirCookieReply* reply; 4136 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 4137 if (error != B_OK) 4138 return error; 4139 RequestReleaser requestReleaser(port, reply); 4140 4141 // process the reply 4142 if (reply->error != B_OK) 4143 return reply->error; 4144 return error; 4145 } 4146 4147 // _CloseAttr 4148 status_t 4149 Volume::_CloseAttr(void* _node, void* cookie) 4150 { 4151 VNode* vnode = (VNode*)_node; 4152 4153 // check capability 4154 if (!HasVNodeCapability(vnode, FS_VNODE_CAPABILITY_CLOSE_ATTR)) 4155 return B_OK; 4156 4157 // get a free port 4158 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 4159 if (!port) 4160 return B_ERROR; 4161 PortReleaser _(fFileSystem->GetPortPool(), port); 4162 4163 // prepare the request 4164 RequestAllocator allocator(port->GetPort()); 4165 CloseAttrRequest* request; 4166 status_t error = AllocateRequest(allocator, &request); 4167 if (error != B_OK) 4168 return error; 4169 4170 request->volume = fUserlandVolume; 4171 request->node = vnode->clientNode; 4172 request->attrCookie = cookie; 4173 4174 // send the request 4175 KernelRequestHandler handler(this, CLOSE_ATTR_REPLY); 4176 CloseAttrReply* reply; 4177 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 4178 if (error != B_OK) 4179 return error; 4180 RequestReleaser requestReleaser(port, reply); 4181 4182 // process the reply 4183 if (reply->error != B_OK) 4184 return reply->error; 4185 return error; 4186 } 4187 4188 // _FreeAttrCookie 4189 status_t 4190 Volume::_FreeAttrCookie(void* _node, void* cookie) 4191 { 4192 VNode* vnode = (VNode*)_node; 4193 4194 // check capability 4195 if (!HasVNodeCapability(vnode, FS_VNODE_CAPABILITY_FREE_ATTR_COOKIE)) 4196 return B_OK; 4197 4198 // get a free port 4199 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 4200 if (!port) 4201 return B_ERROR; 4202 PortReleaser _(fFileSystem->GetPortPool(), port); 4203 4204 // prepare the request 4205 RequestAllocator allocator(port->GetPort()); 4206 FreeAttrCookieRequest* request; 4207 status_t error = AllocateRequest(allocator, &request); 4208 if (error != B_OK) 4209 return error; 4210 4211 request->volume = fUserlandVolume; 4212 request->node = vnode->clientNode; 4213 request->attrCookie = cookie; 4214 4215 // send the request 4216 KernelRequestHandler handler(this, FREE_ATTR_COOKIE_REPLY); 4217 FreeAttrCookieReply* reply; 4218 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 4219 if (error != B_OK) 4220 return error; 4221 RequestReleaser requestReleaser(port, reply); 4222 4223 // process the reply 4224 if (reply->error != B_OK) 4225 return reply->error; 4226 return error; 4227 } 4228 4229 // _CloseIndexDir 4230 status_t 4231 Volume::_CloseIndexDir(void* cookie) 4232 { 4233 // check capability 4234 if (!HasCapability(FS_VOLUME_CAPABILITY_CLOSE_INDEX_DIR)) 4235 return B_OK; 4236 4237 // get a free port 4238 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 4239 if (!port) 4240 return B_ERROR; 4241 PortReleaser _(fFileSystem->GetPortPool(), port); 4242 4243 // prepare the request 4244 RequestAllocator allocator(port->GetPort()); 4245 CloseIndexDirRequest* request; 4246 status_t error = AllocateRequest(allocator, &request); 4247 if (error != B_OK) 4248 return error; 4249 4250 request->volume = fUserlandVolume; 4251 request->indexDirCookie = cookie; 4252 4253 // send the request 4254 KernelRequestHandler handler(this, CLOSE_INDEX_DIR_REPLY); 4255 CloseIndexDirReply* reply; 4256 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 4257 if (error != B_OK) 4258 return error; 4259 RequestReleaser requestReleaser(port, reply); 4260 4261 // process the reply 4262 if (reply->error != B_OK) 4263 return reply->error; 4264 return error; 4265 } 4266 4267 // _FreeIndexDirCookie 4268 status_t 4269 Volume::_FreeIndexDirCookie(void* cookie) 4270 { 4271 // check capability 4272 if (!HasCapability(FS_VOLUME_CAPABILITY_FREE_INDEX_DIR_COOKIE)) 4273 return B_OK; 4274 4275 // get a free port 4276 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 4277 if (!port) 4278 return B_ERROR; 4279 PortReleaser _(fFileSystem->GetPortPool(), port); 4280 4281 // prepare the request 4282 RequestAllocator allocator(port->GetPort()); 4283 FreeIndexDirCookieRequest* request; 4284 status_t error = AllocateRequest(allocator, &request); 4285 if (error != B_OK) 4286 return error; 4287 4288 request->volume = fUserlandVolume; 4289 request->indexDirCookie = cookie; 4290 4291 // send the request 4292 KernelRequestHandler handler(this, FREE_INDEX_DIR_COOKIE_REPLY); 4293 FreeIndexDirCookieReply* reply; 4294 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 4295 if (error != B_OK) 4296 return error; 4297 RequestReleaser requestReleaser(port, reply); 4298 4299 // process the reply 4300 if (reply->error != B_OK) 4301 return reply->error; 4302 return error; 4303 } 4304 4305 // _CloseQuery 4306 status_t 4307 Volume::_CloseQuery(void* cookie) 4308 { 4309 // check capability 4310 if (!HasCapability(FS_VOLUME_CAPABILITY_CLOSE_QUERY)) 4311 return B_OK; 4312 4313 // get a free port 4314 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 4315 if (!port) 4316 return B_ERROR; 4317 PortReleaser _(fFileSystem->GetPortPool(), port); 4318 4319 // prepare the request 4320 RequestAllocator allocator(port->GetPort()); 4321 CloseQueryRequest* request; 4322 status_t error = AllocateRequest(allocator, &request); 4323 if (error != B_OK) 4324 return error; 4325 4326 request->volume = fUserlandVolume; 4327 request->queryCookie = cookie; 4328 4329 // send the request 4330 KernelRequestHandler handler(this, CLOSE_QUERY_REPLY); 4331 CloseQueryReply* reply; 4332 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 4333 if (error != B_OK) 4334 return error; 4335 RequestReleaser requestReleaser(port, reply); 4336 4337 // process the reply 4338 if (reply->error != B_OK) 4339 return reply->error; 4340 return error; 4341 } 4342 4343 // _FreeQueryCookie 4344 status_t 4345 Volume::_FreeQueryCookie(void* cookie) 4346 { 4347 // check capability 4348 if (!HasCapability(FS_VOLUME_CAPABILITY_FREE_QUERY_COOKIE)) 4349 return B_OK; 4350 4351 // get a free port 4352 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 4353 if (!port) 4354 return B_ERROR; 4355 PortReleaser _(fFileSystem->GetPortPool(), port); 4356 4357 // prepare the request 4358 RequestAllocator allocator(port->GetPort()); 4359 FreeQueryCookieRequest* request; 4360 status_t error = AllocateRequest(allocator, &request); 4361 if (error != B_OK) 4362 return error; 4363 4364 request->volume = fUserlandVolume; 4365 request->queryCookie = cookie; 4366 4367 // send the request 4368 KernelRequestHandler handler(this, FREE_QUERY_COOKIE_REPLY); 4369 FreeQueryCookieReply* reply; 4370 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 4371 if (error != B_OK) 4372 return error; 4373 RequestReleaser requestReleaser(port, reply); 4374 4375 // process the reply 4376 if (reply->error != B_OK) 4377 return reply->error; 4378 return error; 4379 } 4380 4381 // _SendRequest 4382 status_t 4383 Volume::_SendRequest(RequestPort* port, RequestAllocator* allocator, 4384 RequestHandler* handler, Request** reply) 4385 { 4386 // fill in the caller info 4387 KernelRequest* request = static_cast<KernelRequest*>( 4388 allocator->GetRequest()); 4389 Thread* thread = thread_get_current_thread(); 4390 request->team = thread->team->id; 4391 request->thread = thread->id; 4392 request->user = geteuid(); 4393 request->group = getegid(); 4394 4395 if (!fFileSystem->IsUserlandServerThread()) 4396 return port->SendRequest(allocator, handler, reply); 4397 // Here it gets dangerous: a thread of the userland server team being here 4398 // calls for trouble. We try receiving the request with a timeout, and 4399 // close the port -- which will disconnect the whole FS. 4400 status_t error = port->SendRequest(allocator, handler, reply, 4401 kUserlandServerlandPortTimeout); 4402 if (error == B_TIMED_OUT || error == B_WOULD_BLOCK) 4403 port->Close(); 4404 return error; 4405 } 4406 4407 // _SendReceiptAck 4408 status_t 4409 Volume::_SendReceiptAck(RequestPort* port) 4410 { 4411 RequestAllocator allocator(port->GetPort()); 4412 ReceiptAckReply* request; 4413 status_t error = AllocateRequest(allocator, &request); 4414 if (error != B_OK) 4415 return error; 4416 return port->SendRequest(&allocator); 4417 } 4418 4419 // _IncrementVNodeCount 4420 void 4421 Volume::_IncrementVNodeCount(ino_t vnid) 4422 { 4423 MutexLocker _(fLock); 4424 4425 if (!fVNodeCountingEnabled) 4426 return; 4427 4428 VNode* vnode = fVNodes->Lookup(vnid); 4429 if (vnode == NULL) { 4430 ERROR(("Volume::_IncrementVNodeCount(): Node with ID %lld not " 4431 "known!\n", vnid)); 4432 return; 4433 } 4434 4435 vnode->useCount++; 4436 //PRINT(("_IncrementVNodeCount(%Ld): count: %ld, fVNodeCountMap size: %ld\n", vnid, *count, fVNodeCountMap->Size())); 4437 } 4438 4439 4440 // _DecrementVNodeCount 4441 void 4442 Volume::_DecrementVNodeCount(ino_t vnid) 4443 { 4444 MutexLocker _(fLock); 4445 4446 if (!fVNodeCountingEnabled) 4447 return; 4448 4449 VNode* vnode = fVNodes->Lookup(vnid); 4450 if (vnode == NULL) { 4451 ERROR(("Volume::_DecrementVNodeCount(): Node with ID %lld not " 4452 "known!\n", vnid)); 4453 return; 4454 } 4455 4456 vnode->useCount--; 4457 //PRINT(("_DecrementVNodeCount(%Ld): count: %ld, fVNodeCountMap size: %ld\n", vnid, tmpCount, fVNodeCountMap->Size())); 4458 } 4459 4460 4461 // _RemoveInvalidVNode 4462 void 4463 Volume::_RemoveInvalidVNode(ino_t vnid) 4464 { 4465 MutexLocker locker(fLock); 4466 4467 VNode* vnode = fVNodes->Lookup(vnid); 4468 if (vnode == NULL) { 4469 ERROR(("Volume::_RemoveInvalidVNode(): Node with ID %lld not known!\n", 4470 vnid)); 4471 return; 4472 } 4473 4474 fVNodes->Remove(vnode); 4475 locker.Unlock(); 4476 4477 // release all references acquired so far 4478 if (fVNodeCountingEnabled) { 4479 for (; vnode->useCount > 0; vnode->useCount--) 4480 put_vnode(fFSVolume, vnid); 4481 } 4482 4483 vnode->Delete(this); 4484 } 4485 4486 4487 // _InternalIOCtl 4488 status_t 4489 Volume::_InternalIOCtl(userlandfs_ioctl* buffer, int32 bufferSize) 4490 { 4491 if (buffer->version != USERLAND_IOCTL_CURRENT_VERSION) 4492 return B_BAD_VALUE; 4493 status_t result = B_OK; 4494 switch (buffer->command) { 4495 case USERLAND_IOCTL_PUT_ALL_PENDING_VNODES: 4496 result = _PutAllPendingVNodes(); 4497 break; 4498 default: 4499 return B_BAD_VALUE; 4500 } 4501 buffer->error = result; 4502 return B_OK; 4503 } 4504 4505 // _PutAllPendingVNodes 4506 status_t 4507 Volume::_PutAllPendingVNodes() 4508 { 4509 PRINT(("Volume::_PutAllPendingVNodes()\n")); 4510 if (!fFileSystem->GetPortPool()->IsDisconnected()) { 4511 PRINT(("Volume::_PutAllPendingVNodes() failed: still connected\n")); 4512 return USERLAND_IOCTL_STILL_CONNECTED; 4513 } 4514 4515 MutexLocker locker(fLock); 4516 4517 if (!fVNodeCountingEnabled) { 4518 PRINT(("Volume::_PutAllPendingVNodes() failed: vnode counting " 4519 "disabled\n")); 4520 return USERLAND_IOCTL_VNODE_COUNTING_DISABLED; 4521 } 4522 // Check whether there are open entities at the moment. 4523 if (atomic_get(&fOpenFiles) > 0) { 4524 PRINT(("Volume::_PutAllPendingVNodes() failed: open files\n")); 4525 return USERLAND_IOCTL_OPEN_FILES; 4526 } 4527 if (atomic_get(&fOpenDirectories) > 0) { 4528 PRINT(("Volume::_PutAllPendingVNodes() failed: open dirs\n")); 4529 return USERLAND_IOCTL_OPEN_DIRECTORIES; 4530 } 4531 if (atomic_get(&fOpenAttributeDirectories) > 0) { 4532 PRINT(("Volume::_PutAllPendingVNodes() failed: open attr dirs\n")); 4533 return USERLAND_IOCTL_OPEN_ATTRIBUTE_DIRECTORIES; 4534 } 4535 if (atomic_get(&fOpenAttributes) > 0) { 4536 PRINT(("Volume::_PutAllPendingVNodes() failed: open attributes\n")); 4537 return USERLAND_IOCTL_OPEN_ATTRIBUTES; 4538 } 4539 if (atomic_get(&fOpenIndexDirectories) > 0) { 4540 PRINT(("Volume::_PutAllPendingVNodes() failed: open index dirs\n")); 4541 return USERLAND_IOCTL_OPEN_INDEX_DIRECTORIES; 4542 } 4543 if (atomic_get(&fOpenQueries) > 0) { 4544 PRINT(("Volume::_PutAllPendingVNodes() failed: open queries\n")); 4545 return USERLAND_IOCTL_OPEN_QUERIES; 4546 } 4547 // No open entities. Since the port pool is disconnected, no new 4548 // entities can be opened. Disable node counting and put all pending 4549 // vnodes. 4550 fVNodeCountingEnabled = false; 4551 4552 int32 putVNodeCount = 0; 4553 4554 // Since the vnode map can still change, we need to iterate to the first 4555 // node we need to put, drop the lock, put the node, and restart from the 4556 // beginning. 4557 // TODO: Optimize by extracting batches of relevant nodes to an on-stack 4558 // array. 4559 bool nodeFound; 4560 do { 4561 nodeFound = false; 4562 4563 // get the next node to put 4564 for (VNodeMap::Iterator it = fVNodes->GetIterator(); 4565 VNode* vnode = it.Next();) { 4566 if (vnode->useCount > 0) { 4567 ino_t vnid = vnode->id; 4568 int32 count = vnode->useCount; 4569 vnode->useCount = 0; 4570 fs_vnode_ops* ops = vnode->ops->ops; 4571 bool published = vnode->published; 4572 4573 locker.Unlock(); 4574 4575 // If the node has not yet been published, we have to do that 4576 // before putting otherwise the VFS will complain that the node 4577 // is busy when the last reference is gone. 4578 if (!published) 4579 publish_vnode(fFSVolume, vnid, vnode, ops, S_IFDIR, 0); 4580 4581 for (int32 i = 0; i < count; i++) { 4582 PutVNode(vnid); 4583 putVNodeCount++; 4584 } 4585 4586 locker.Lock(); 4587 4588 nodeFound = true; 4589 break; 4590 } 4591 } 4592 } while (nodeFound); 4593 4594 PRINT(("Volume::_PutAllPendingVNodes() successful: Put %ld vnodes\n", 4595 putVNodeCount)); 4596 4597 return B_OK; 4598 } 4599 4600 4601 // _RegisterIORequest 4602 status_t 4603 Volume::_RegisterIORequest(io_request* request, int32* requestID) 4604 { 4605 MutexLocker _(fLock); 4606 4607 // get the next free ID 4608 while (fIORequestInfosByID->Lookup(++fLastIORequestID) != NULL) { 4609 } 4610 4611 // allocate the info 4612 IORequestInfo* info = new(std::nothrow) IORequestInfo(request, 4613 ++fLastIORequestID); 4614 if (info == NULL) 4615 return B_NO_MEMORY; 4616 4617 // add the info to the maps 4618 fIORequestInfosByID->Insert(info); 4619 fIORequestInfosByStruct->Insert(info); 4620 4621 *requestID = info->id; 4622 4623 return B_OK; 4624 } 4625 4626 4627 // _UnregisterIORequest 4628 status_t 4629 Volume::_UnregisterIORequest(int32 requestID) 4630 { 4631 MutexLocker _(fLock); 4632 4633 if (IORequestInfo* info = fIORequestInfosByID->Lookup(requestID)) { 4634 fIORequestInfosByID->Remove(info); 4635 fIORequestInfosByStruct->Remove(info); 4636 return B_OK; 4637 } 4638 4639 return B_ENTRY_NOT_FOUND; 4640 } 4641 4642 4643 // _FindIORequest 4644 status_t 4645 Volume::_FindIORequest(int32 requestID, io_request** request) 4646 { 4647 MutexLocker _(fLock); 4648 4649 if (IORequestInfo* info = fIORequestInfosByID->Lookup(requestID)) { 4650 *request = info->request; 4651 return B_OK; 4652 } 4653 4654 return B_ENTRY_NOT_FOUND; 4655 } 4656 4657 4658 // _FindIORequest 4659 status_t 4660 Volume::_FindIORequest(io_request* request, int32* requestID) 4661 { 4662 MutexLocker _(fLock); 4663 4664 if (IORequestInfo* info = fIORequestInfosByStruct->Lookup(request)) { 4665 *requestID = info->id; 4666 return B_OK; 4667 } 4668 4669 return B_ENTRY_NOT_FOUND; 4670 } 4671 4672 4673 /*static*/ status_t 4674 Volume::_IterativeFDIOGetVecs(void* _cookie, io_request* ioRequest, 4675 off_t offset, size_t size, struct file_io_vec* vecs, size_t* _count) 4676 { 4677 IterativeFDIOCookie* cookie = (IterativeFDIOCookie*)_cookie; 4678 Volume* volume = cookie->volume; 4679 4680 MutexLocker locker(volume->fLock); 4681 4682 // If there are vecs cached in the cookie and the offset matches, return 4683 // those. 4684 if (cookie->vecs != NULL) { 4685 size_t vecCount = 0; 4686 if (offset == cookie->offset) { 4687 // good, copy the vecs 4688 while (size > 0 && vecCount < cookie->vecCount 4689 && vecCount < *_count) { 4690 off_t maxSize = std::min((off_t)size, 4691 cookie->vecs[vecCount].length); 4692 vecs[vecCount].offset = cookie->vecs[vecCount].offset; 4693 vecs[vecCount].length = maxSize; 4694 4695 size -= maxSize; 4696 vecCount++; 4697 } 4698 } 4699 4700 cookie->vecs = NULL; 4701 cookie->vecCount = 0; 4702 4703 // got some vecs? -- then we're done 4704 if (vecCount > 0) { 4705 *_count = vecCount; 4706 return B_OK; 4707 } 4708 } 4709 4710 // we have to ask the client FS 4711 int32 requestID = cookie->requestID; 4712 void* clientCookie = cookie->clientCookie; 4713 locker.Unlock(); 4714 4715 // get a free port 4716 RequestPort* port = volume->fFileSystem->GetPortPool()->AcquirePort(); 4717 if (!port) 4718 return B_ERROR; 4719 PortReleaser _(volume->fFileSystem->GetPortPool(), port); 4720 4721 // prepare the request 4722 RequestAllocator allocator(port->GetPort()); 4723 IterativeIOGetVecsRequest* request; 4724 status_t error = AllocateRequest(allocator, &request); 4725 if (error != B_OK) 4726 return error; 4727 4728 request->volume = volume->fUserlandVolume; 4729 request->cookie = clientCookie; 4730 request->offset = offset; 4731 request->request = requestID; 4732 request->size = size; 4733 size_t maxVecs = std::min(*_count, 4734 (size_t)IterativeIOGetVecsReply::MAX_VECS); 4735 request->vecCount = maxVecs; 4736 4737 // send the request 4738 KernelRequestHandler handler(volume, ITERATIVE_IO_GET_VECS_REPLY); 4739 IterativeIOGetVecsReply* reply; 4740 error = volume->_SendRequest(port, &allocator, &handler, (Request**)&reply); 4741 if (error != B_OK) 4742 return error; 4743 RequestReleaser requestReleaser(port, reply); 4744 4745 // process the reply 4746 if (reply->error != B_OK) 4747 return reply->error; 4748 uint32 vecCount = reply->vecCount; 4749 if (vecCount < 0 || vecCount > maxVecs) 4750 return B_BAD_DATA; 4751 4752 memcpy(vecs, reply->vecs, vecCount * sizeof(file_io_vec)); 4753 *_count = vecCount; 4754 4755 return B_OK; 4756 } 4757 4758 4759 /*static*/ status_t 4760 Volume::_IterativeFDIOFinished(void* _cookie, io_request* ioRequest, 4761 status_t status, bool partialTransfer, size_t bytesTransferred) 4762 { 4763 IterativeFDIOCookie* cookie = (IterativeFDIOCookie*)_cookie; 4764 Volume* volume = cookie->volume; 4765 4766 // At any rate, we're done with the cookie after this call -- it will not 4767 // be used anymore. 4768 BReference<IterativeFDIOCookie> _(cookie, true); 4769 4770 // We also want to dispose of the request. 4771 IORequestRemover _2(volume, cookie->requestID); 4772 4773 // get a free port 4774 RequestPort* port = volume->fFileSystem->GetPortPool()->AcquirePort(); 4775 if (!port) 4776 return B_ERROR; 4777 PortReleaser _3(volume->fFileSystem->GetPortPool(), port); 4778 4779 // prepare the request 4780 RequestAllocator allocator(port->GetPort()); 4781 IterativeIOFinishedRequest* request; 4782 status_t error = AllocateRequest(allocator, &request); 4783 if (error != B_OK) 4784 return error; 4785 4786 request->volume = volume->fUserlandVolume; 4787 request->cookie = cookie->clientCookie; 4788 request->request = cookie->requestID; 4789 request->status = status; 4790 request->partialTransfer = partialTransfer; 4791 request->bytesTransferred = bytesTransferred; 4792 4793 // send the request 4794 KernelRequestHandler handler(volume, ITERATIVE_IO_FINISHED_REPLY); 4795 IterativeIOFinishedReply* reply; 4796 error = volume->_SendRequest(port, &allocator, &handler, (Request**)&reply); 4797 if (error != B_OK) 4798 return error; 4799 RequestReleaser requestReleaser(port, reply); 4800 4801 // process the reply 4802 if (reply->error != B_OK) 4803 return reply->error; 4804 return B_OK; 4805 } 4806