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