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