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