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