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