1 // Volume.cpp 2 3 #include "Volume.h" 4 5 #include <errno.h> 6 #include <string.h> 7 #include <unistd.h> 8 #include <sys/stat.h> 9 10 #include "AutoLocker.h" 11 #include "Compatibility.h" 12 #include "Debug.h" 13 #include "FileSystem.h" 14 #include "HashMap.h" 15 #include "IOCtlInfo.h" 16 #include "KernelRequestHandler.h" 17 #include "PortReleaser.h" 18 #include "RequestAllocator.h" 19 #include "RequestPort.h" 20 #include "Requests.h" 21 #include "userlandfs_ioctl.h" 22 23 // missing ioctl()s 24 // TODO: Place somewhere else. 25 #define IOCTL_FILE_UNCACHED_IO 10000 26 #define IOCTL_CREATE_TIME 10002 27 #define IOCTL_MODIFIED_TIME 10003 28 29 // If a thread of the userland server enters userland FS kernel code and 30 // is sending a request, this is the time after which it shall time out 31 // waiting for a reply. 32 static const bigtime_t kUserlandServerlandPortTimeout = 10000000; // 10s 33 34 // MountVNodeMap 35 struct Volume::MountVNodeMap : public HashMap<HashKey64<ino_t>, void*> { 36 }; 37 38 // VNodeCountMap 39 struct Volume::VNodeCountMap 40 : public SynchronizedHashMap<HashKey64<ino_t>, int32*> { 41 }; 42 43 // AutoIncrementer 44 class Volume::AutoIncrementer { 45 public: 46 AutoIncrementer(vint32* variable) 47 : fVariable(variable) 48 { 49 if (fVariable) 50 atomic_add(fVariable, 1); 51 } 52 53 ~AutoIncrementer() 54 { 55 if (fVariable) 56 atomic_add(fVariable, -1); 57 } 58 59 void Keep() 60 { 61 fVariable = NULL; 62 } 63 64 private: 65 vint32* fVariable; 66 }; 67 68 // constructor 69 Volume::Volume(FileSystem* fileSystem, dev_t id) 70 : Referencable(true), 71 fFileSystem(fileSystem), 72 fID(id), 73 fUserlandVolume(NULL), 74 fRootID(0), 75 fRootNode(NULL), 76 fMountVNodes(NULL), 77 fOpenFiles(0), 78 fOpenDirectories(0), 79 fOpenAttributeDirectories(0), 80 fOpenAttributes(0), 81 fOpenIndexDirectories(0), 82 fOpenQueries(0), 83 fVNodeCountMap(NULL), 84 fVNodeCountingEnabled(false) 85 { 86 } 87 88 // destructor 89 Volume::~Volume() 90 { 91 } 92 93 // GetFileSystem 94 FileSystem* 95 Volume::GetFileSystem() const 96 { 97 return fFileSystem; 98 } 99 100 // GetID 101 dev_t 102 Volume::GetID() const 103 { 104 return fID; 105 } 106 107 // GetUserlandVolume 108 void* 109 Volume::GetUserlandVolume() const 110 { 111 return fUserlandVolume; 112 } 113 114 // GetRootID 115 ino_t 116 Volume::GetRootID() const 117 { 118 return fRootID; 119 } 120 121 // IsMounting 122 bool 123 Volume::IsMounting() const 124 { 125 return fMountVNodes; 126 } 127 128 129 // #pragma mark - client methods 130 131 // GetVNode 132 status_t 133 Volume::GetVNode(ino_t vnid, fs_vnode* node) 134 { 135 PRINT(("get_vnode(%ld, %lld)\n", fID, vnid)); 136 if (IsMounting() && !fMountVNodes->ContainsKey(vnid)) { 137 ERROR(("Volume::GetVNode(): get_vnode() invoked for unknown vnode " 138 "while mounting!\n")); 139 } 140 status_t error = get_vnode(fID, vnid, node); 141 if (error == B_OK) 142 _IncrementVNodeCount(vnid); 143 return error; 144 } 145 146 // PutVNode 147 status_t 148 Volume::PutVNode(ino_t vnid) 149 { 150 PRINT(("put_vnode(%ld, %lld)\n", fID, vnid)); 151 status_t error = put_vnode(fID, vnid); 152 if (error == B_OK) 153 _DecrementVNodeCount(vnid); 154 return error; 155 } 156 157 // NewVNode 158 status_t 159 Volume::NewVNode(ino_t vnid, fs_vnode node) 160 { 161 PRINT(("new_vnode(%ld, %lld)\n", fID, vnid)); 162 status_t error = new_vnode(fID, vnid, node); 163 if (error == B_OK) { 164 if (IsMounting()) { 165 error = fMountVNodes->Put(vnid, node); 166 if (error != B_OK) { 167 ERROR(("Volume::NewVNode(): Failed to add vnode to mount " 168 "vnode map!\n")); 169 publish_vnode(fID, vnid, node); 170 put_vnode(fID, vnid); 171 return error; 172 } 173 } 174 // TODO: Check what we need to do according to the new semantics. 175 // _IncrementVNodeCount(vnid); 176 } 177 return error; 178 } 179 180 // PublishVNode 181 status_t 182 Volume::PublishVNode(ino_t vnid, fs_vnode node) 183 { 184 PRINT(("publish_vnode(%ld, %lld, %p)\n", fID, vnid, node)); 185 status_t error = publish_vnode(fID, vnid, node); 186 if (error == B_OK) { 187 if (IsMounting()) { 188 error = fMountVNodes->Put(vnid, node); 189 if (error != B_OK) { 190 ERROR(("Volume::PublishVNode(): Failed to add vnode to mount " 191 "vnode map!\n")); 192 put_vnode(fID, vnid); 193 return error; 194 } 195 } 196 _IncrementVNodeCount(vnid); 197 } 198 return error; 199 } 200 201 // RemoveVNode 202 status_t 203 Volume::RemoveVNode(ino_t vnid) 204 { 205 PRINT(("remove_vnode(%ld, %lld)\n", fID, vnid)); 206 return remove_vnode(fID, vnid); 207 } 208 209 // UnremoveVNode 210 status_t 211 Volume::UnremoveVNode(ino_t vnid) 212 { 213 PRINT(("unremove_vnode(%ld, %lld)\n", fID, vnid)); 214 return unremove_vnode(fID, vnid); 215 } 216 217 // GetVNodeRemoved 218 status_t 219 Volume::GetVNodeRemoved(ino_t vnid, bool* removed) 220 { 221 PRINT(("get_vnode_removed(%ld, %lld, %p)\n", fID, vnid, removed)); 222 return get_vnode_removed(fID, vnid, removed); 223 } 224 225 226 // #pragma mark - FS 227 228 229 // Mount 230 status_t 231 Volume::Mount(const char* device, uint32 flags, const char* parameters) 232 { 233 // Create a map that holds ino_t->void* mappings of all vnodes 234 // created while mounting. We need it to get the root node. 235 MountVNodeMap vnodeMap; 236 status_t error = vnodeMap.InitCheck(); 237 if (error != B_OK) 238 RETURN_ERROR(error); 239 240 fMountVNodes = &vnodeMap; 241 error = _Mount(device, flags, parameters); 242 fMountVNodes = NULL; 243 if (error == B_OK) { 244 // fetch the root node, so that we can serve Walk() requests on it, 245 // after the connection to the userland server is gone 246 if (!vnodeMap.ContainsKey(fRootID)) { 247 // The root node was not added while mounting. That's a serious 248 // problem -- not only because we don't have it, but also because 249 // the VFS requires new_vnode() to be invoked for the root node. 250 ERROR(("Volume::Mount(): new_vnode() was not called for root node! " 251 "Unmounting...\n")); 252 Unmount(); 253 return B_ERROR; 254 } 255 fRootNode = vnodeMap.Get(fRootID); 256 } 257 return error; 258 } 259 260 // Unmount 261 status_t 262 Volume::Unmount() 263 { 264 status_t error = _Unmount(); 265 // free the memory associated with the vnode count map 266 if (fVNodeCountMap) { 267 AutoLocker<VNodeCountMap> _(fVNodeCountMap); 268 fVNodeCountingEnabled = false; 269 for (VNodeCountMap::Iterator it = fVNodeCountMap->GetIterator(); 270 it.HasNext();) { 271 VNodeCountMap::Entry entry = it.Next(); 272 delete entry.value; 273 } 274 delete fVNodeCountMap; 275 fVNodeCountMap = NULL; 276 } 277 fFileSystem->VolumeUnmounted(this); 278 return error; 279 } 280 281 // Sync 282 status_t 283 Volume::Sync() 284 { 285 // check capability 286 if (!fFileSystem->HasCapability(FS_CAPABILITY_SYNC)) 287 return B_BAD_VALUE; 288 289 // get a free port 290 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 291 if (!port) 292 return B_ERROR; 293 PortReleaser _(fFileSystem->GetPortPool(), port); 294 295 // prepare the request 296 RequestAllocator allocator(port->GetPort()); 297 SyncVolumeRequest* request; 298 status_t error = AllocateRequest(allocator, &request); 299 if (error != B_OK) 300 return error; 301 302 request->volume = fUserlandVolume; 303 304 // send the request 305 KernelRequestHandler handler(this, SYNC_VOLUME_REPLY); 306 SyncVolumeReply* reply; 307 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 308 if (error != B_OK) 309 return error; 310 RequestReleaser requestReleaser(port, reply); 311 312 // process the reply 313 if (reply->error != B_OK) 314 return reply->error; 315 return error; 316 } 317 318 // ReadFSInfo 319 status_t 320 Volume::ReadFSInfo(fs_info* info) 321 { 322 // When the connection to the userland server is lost, we serve 323 // read_fs_info() requests manually. 324 status_t error = _ReadFSInfo(info); 325 if (error != B_OK && fFileSystem->GetPortPool()->IsDisconnected()) { 326 WARN(("Volume::Lookup(): connection lost, emulating lookup `.'\n")); 327 328 info->flags = B_FS_IS_PERSISTENT | B_FS_IS_READONLY; 329 info->block_size = 512; 330 info->io_size = 512; 331 info->total_blocks = 0; 332 info->free_blocks = 0; 333 strlcpy(info->volume_name, fFileSystem->GetName(), 334 sizeof(info->volume_name)); 335 strlcat(info->volume_name, ":disconnected", sizeof(info->volume_name)); 336 337 error = B_OK; 338 } 339 return error; 340 } 341 342 // WriteFSInfo 343 status_t 344 Volume::WriteFSInfo(const struct fs_info *info, uint32 mask) 345 { 346 // check capability 347 if (!fFileSystem->HasCapability(FS_CAPABILITY_WRITE_FS_INFO)) 348 return B_BAD_VALUE; 349 350 // get a free port 351 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 352 if (!port) 353 return B_ERROR; 354 PortReleaser _(fFileSystem->GetPortPool(), port); 355 356 // prepare the request 357 RequestAllocator allocator(port->GetPort()); 358 WriteFSInfoRequest* request; 359 status_t error = AllocateRequest(allocator, &request); 360 if (error != B_OK) 361 return error; 362 363 request->volume = fUserlandVolume; 364 request->info = *info; 365 request->mask = mask; 366 367 // send the request 368 KernelRequestHandler handler(this, WRITE_FS_INFO_REPLY); 369 WriteFSInfoReply* reply; 370 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 371 if (error != B_OK) 372 return error; 373 RequestReleaser requestReleaser(port, reply); 374 375 // process the reply 376 if (reply->error != B_OK) 377 return reply->error; 378 return error; 379 } 380 381 382 // #pragma mark - vnodes 383 384 385 // Lookup 386 status_t 387 Volume::Lookup(fs_vnode dir, const char* entryName, ino_t* vnid, int* type) 388 { 389 // When the connection to the userland server is lost, we serve 390 // lookup(fRootNode, `.') requests manually to allow clean unmounting. 391 status_t error = _Lookup(dir, entryName, vnid, type); 392 if (error != B_OK && fFileSystem->GetPortPool()->IsDisconnected() 393 && dir == fRootNode && strcmp(entryName, ".") == 0) { 394 WARN(("Volume::Lookup(): connection lost, emulating lookup `.'\n")); 395 void* entryNode; 396 if (GetVNode(fRootID, &entryNode) != B_OK) 397 RETURN_ERROR(B_BAD_VALUE); 398 *vnid = fRootID; 399 *type = S_IFDIR; 400 // The VFS will balance the get_vnode() call for the FS. 401 _DecrementVNodeCount(*vnid); 402 return B_OK; 403 } 404 return error; 405 } 406 407 // GetVNodeName 408 status_t 409 Volume::GetVNodeName(fs_vnode node, char* buffer, size_t bufferSize) 410 { 411 // We don't check the capability -- if not implemented by the client FS, 412 // the functionality is emulated in userland. 413 414 // get a free port 415 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 416 if (!port) 417 return B_ERROR; 418 PortReleaser _(fFileSystem->GetPortPool(), port); 419 420 // prepare the request 421 RequestAllocator allocator(port->GetPort()); 422 GetVNodeNameRequest* request; 423 status_t error = AllocateRequest(allocator, &request); 424 if (error != B_OK) 425 return error; 426 427 request->volume = fUserlandVolume; 428 request->node = node; 429 request->size = bufferSize; 430 431 // send the request 432 KernelRequestHandler handler(this, GET_VNODE_NAME_REPLY); 433 GetVNodeNameReply* reply; 434 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 435 if (error != B_OK) 436 return error; 437 RequestReleaser requestReleaser(port, reply); 438 439 // process the reply 440 if (reply->error != B_OK) 441 return reply->error; 442 443 char* readBuffer = (char*)reply->buffer.GetData(); 444 size_t nameLen = reply->buffer.GetSize(); 445 nameLen = strnlen(readBuffer, nameLen); 446 if (nameLen <= 1 || nameLen >= bufferSize) 447 RETURN_ERROR(B_BAD_DATA); 448 449 memcpy(buffer, readBuffer, nameLen); 450 buffer[nameLen] = '\0'; 451 452 _SendReceiptAck(port); 453 return error; 454 } 455 456 // ReadVNode 457 status_t 458 Volume::ReadVNode(ino_t vnid, bool reenter, fs_vnode* node) 459 { 460 // get a free port 461 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 462 if (!port) 463 return B_ERROR; 464 PortReleaser _(fFileSystem->GetPortPool(), port); 465 466 // prepare the request 467 RequestAllocator allocator(port->GetPort()); 468 ReadVNodeRequest* request; 469 status_t error = AllocateRequest(allocator, &request); 470 if (error != B_OK) 471 return error; 472 473 request->volume = fUserlandVolume; 474 request->vnid = vnid; 475 request->reenter = reenter; 476 477 // send the request 478 KernelRequestHandler handler(this, READ_VNODE_REPLY); 479 ReadVNodeReply* reply; 480 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 481 if (error != B_OK) 482 return error; 483 RequestReleaser requestReleaser(port, reply); 484 485 // process the reply 486 if (reply->error != B_OK) 487 return reply->error; 488 *node = reply->node; 489 return error; 490 } 491 492 // WriteVNode 493 status_t 494 Volume::WriteVNode(fs_vnode node, bool reenter) 495 { 496 status_t error = _WriteVNode(node, reenter); 497 if (error != B_OK && fFileSystem->GetPortPool()->IsDisconnected()) { 498 // This isn't really necessary, since the VFS basically ignores the 499 // return value -- at least OBOS. The fshell panic()s; didn't check 500 // BeOS. It doesn't harm to appear to behave nicely. :-) 501 WARN(("Volume::WriteVNode(): connection lost, forcing write vnode\n")); 502 return B_OK; 503 } 504 return error; 505 } 506 507 // RemoveVNode 508 status_t 509 Volume::RemoveVNode(fs_vnode node, bool reenter) 510 { 511 // get a free port 512 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 513 if (!port) 514 return B_ERROR; 515 PortReleaser _(fFileSystem->GetPortPool(), port); 516 517 // prepare the request 518 RequestAllocator allocator(port->GetPort()); 519 FSRemoveVNodeRequest* request; 520 status_t error = AllocateRequest(allocator, &request); 521 if (error != B_OK) 522 return error; 523 524 request->volume = fUserlandVolume; 525 request->node = node; 526 request->reenter = reenter; 527 528 // send the request 529 KernelRequestHandler handler(this, FS_REMOVE_VNODE_REPLY); 530 FSRemoveVNodeReply* reply; 531 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 532 if (error != B_OK) 533 return error; 534 RequestReleaser requestReleaser(port, reply); 535 536 // process the reply 537 if (reply->error != B_OK) 538 return reply->error; 539 return error; 540 } 541 542 543 // #pragma mark - nodes 544 545 546 // IOCtl 547 status_t 548 Volume::IOCtl(fs_vnode node, fs_cookie cookie, uint32 command, void *buffer, 549 size_t len) 550 { 551 // check the command and its parameters 552 bool isBuffer = false; 553 int32 bufferSize = 0; 554 int32 writeSize = 0; 555 switch (command) { 556 case IOCTL_FILE_UNCACHED_IO: 557 buffer = NULL; 558 break; 559 case IOCTL_CREATE_TIME: 560 case IOCTL_MODIFIED_TIME: 561 isBuffer = 0; 562 bufferSize = 0; 563 writeSize = sizeof(bigtime_t); 564 break; 565 case USERLANDFS_IOCTL: 566 area_id area; 567 area_info info; 568 PRINT(("Volume::IOCtl(): USERLANDFS_IOCTL\n")); 569 if ((area = area_for(buffer)) >= 0) { 570 if (get_area_info(area, &info) == B_OK) { 571 if ((uint8*)buffer - (uint8*)info.address 572 + sizeof(userlandfs_ioctl) <= info.size) { 573 if (strncmp(((userlandfs_ioctl*)buffer)->magic, 574 kUserlandFSIOCtlMagic, 575 USERLAND_IOCTL_MAGIC_LENGTH) == 0) { 576 return _InternalIOCtl((userlandfs_ioctl*)buffer, 577 bufferSize); 578 } else 579 PRINT(("Volume::IOCtl(): bad magic\n")); 580 } else 581 PRINT(("Volume::IOCtl(): bad buffer size\n")); 582 } else 583 PRINT(("Volume::IOCtl(): failed to get area info\n")); 584 } else 585 PRINT(("Volume::IOCtl(): bad area\n")); 586 // fall through... 587 default: 588 { 589 // We don't know the command. Check whether the FileSystem knows 590 // about it. 591 const IOCtlInfo* info = fFileSystem->GetIOCtlInfo(command); 592 if (!info) { 593 PRINT(("Volume::IOCtl(): unknown command\n")); 594 return B_BAD_VALUE; 595 } 596 597 isBuffer = info->isBuffer; 598 bufferSize = info->bufferSize; 599 writeSize = info->writeBufferSize; 600 601 // If the buffer shall indeed specify a buffer, check it. 602 if (info->isBuffer) { 603 if (!buffer) { 604 PRINT(("Volume::IOCtl(): buffer is NULL\n")); 605 return B_BAD_VALUE; 606 } 607 608 area_id area = area_for(buffer); 609 if (area < 0) { 610 PRINT(("Volume::IOCtl(): bad area\n")); 611 return B_BAD_VALUE; 612 } 613 614 area_info info; 615 if (get_area_info(area, &info) != B_OK) { 616 PRINT(("Volume::IOCtl(): failed to get area info\n")); 617 return B_BAD_VALUE; 618 } 619 620 int32 areaSize = info.size - ((uint8*)buffer 621 - (uint8*)info.address); 622 if (bufferSize > areaSize || writeSize > areaSize) { 623 PRINT(("Volume::IOCtl(): bad buffer size\n")); 624 return B_BAD_VALUE; 625 } 626 627 if (writeSize > 0 && !(info.protection & B_WRITE_AREA)) { 628 PRINT(("Volume::IOCtl(): buffer not writable\n")); 629 return B_BAD_VALUE; 630 } 631 } 632 break; 633 } 634 } 635 636 // check capability 637 if (!fFileSystem->HasCapability(FS_CAPABILITY_IOCTL)) 638 return B_BAD_VALUE; 639 640 // get a free port 641 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 642 if (!port) 643 return B_ERROR; 644 PortReleaser _(fFileSystem->GetPortPool(), port); 645 646 // prepare the request 647 RequestAllocator allocator(port->GetPort()); 648 IOCtlRequest* request; 649 status_t error = AllocateRequest(allocator, &request); 650 if (error != B_OK) 651 return error; 652 653 request->volume = fUserlandVolume; 654 request->node = node; 655 request->fileCookie = cookie; 656 request->command = command; 657 request->bufferParameter = buffer; 658 request->isBuffer = isBuffer; 659 request->lenParameter = len; 660 request->writeSize = writeSize; 661 662 if (isBuffer && bufferSize > 0) { 663 error = allocator.AllocateData(request->buffer, buffer, bufferSize, 8); 664 if (error != B_OK) 665 return error; 666 } 667 668 // send the request 669 KernelRequestHandler handler(this, IOCTL_REPLY); 670 IOCtlReply* reply; 671 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 672 if (error != B_OK) 673 return error; 674 RequestReleaser requestReleaser(port, reply); 675 676 // process the reply 677 if (reply->error != B_OK) 678 return reply->error; 679 680 // Copy back the buffer even if the result is not B_OK. The protocol 681 // is defined by the FS developer and may include writing data into 682 // the buffer in some error cases. 683 if (isBuffer && writeSize > 0 && reply->buffer.GetData()) { 684 if (writeSize > reply->buffer.GetSize()) 685 writeSize = reply->buffer.GetSize(); 686 memcpy(buffer, reply->buffer.GetData(), writeSize); 687 _SendReceiptAck(port); 688 } 689 return reply->ioctlError; 690 } 691 692 // SetFlags 693 status_t 694 Volume::SetFlags(fs_vnode node, fs_cookie cookie, int flags) 695 { 696 // check capability 697 if (!fFileSystem->HasCapability(FS_CAPABILITY_SET_FLAGS)) 698 return B_BAD_VALUE; 699 700 // get a free port 701 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 702 if (!port) 703 return B_ERROR; 704 PortReleaser _(fFileSystem->GetPortPool(), port); 705 706 // prepare the request 707 RequestAllocator allocator(port->GetPort()); 708 SetFlagsRequest* request; 709 status_t error = AllocateRequest(allocator, &request); 710 if (error != B_OK) 711 return error; 712 713 request->volume = fUserlandVolume; 714 request->node = node; 715 request->fileCookie = cookie; 716 request->flags = flags; 717 718 // send the request 719 KernelRequestHandler handler(this, SET_FLAGS_REPLY); 720 SetFlagsReply* reply; 721 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 722 if (error != B_OK) 723 return error; 724 RequestReleaser requestReleaser(port, reply); 725 726 // process the reply 727 if (reply->error != B_OK) 728 return reply->error; 729 return error; 730 } 731 732 // Select 733 status_t 734 Volume::Select(fs_vnode node, fs_cookie cookie, uint8 event, uint32 ref, 735 selectsync* sync) 736 { 737 // check capability 738 if (!fFileSystem->HasCapability(FS_CAPABILITY_SELECT)) { 739 notify_select_event(sync, ref, event); 740 return B_OK; 741 } 742 743 // get a free port 744 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 745 if (!port) 746 return B_ERROR; 747 PortReleaser _(fFileSystem->GetPortPool(), port); 748 749 // prepare the request 750 RequestAllocator allocator(port->GetPort()); 751 SelectRequest* request; 752 status_t error = AllocateRequest(allocator, &request); 753 if (error != B_OK) 754 return error; 755 756 request->volume = fUserlandVolume; 757 request->node = node; 758 request->fileCookie = cookie; 759 request->event = event; 760 request->ref = ref; 761 request->sync = sync; 762 763 // add a selectsync entry 764 error = fFileSystem->AddSelectSyncEntry(sync); 765 if (error != B_OK) 766 return error; 767 768 // send the request 769 KernelRequestHandler handler(this, SELECT_REPLY); 770 SelectReply* reply; 771 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 772 if (error != B_OK) { 773 fFileSystem->RemoveSelectSyncEntry(sync); 774 return error; 775 } 776 RequestReleaser requestReleaser(port, reply); 777 778 // process the reply 779 if (reply->error != B_OK) { 780 fFileSystem->RemoveSelectSyncEntry(sync); 781 return reply->error; 782 } 783 return error; 784 } 785 786 // Deselect 787 status_t 788 Volume::Deselect(fs_vnode node, fs_cookie cookie, uint8 event, selectsync* sync) 789 { 790 // check capability 791 if (!fFileSystem->HasCapability(FS_CAPABILITY_DESELECT)) 792 return B_OK; 793 794 struct SyncRemover { 795 SyncRemover(FileSystem* fs, selectsync* sync) 796 : fs(fs), sync(sync) {} 797 ~SyncRemover() { fs->RemoveSelectSyncEntry(sync); } 798 799 FileSystem* fs; 800 selectsync* sync; 801 } syncRemover(fFileSystem, sync); 802 803 // get a free port 804 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 805 if (!port) 806 return B_ERROR; 807 PortReleaser _(fFileSystem->GetPortPool(), port); 808 809 // prepare the request 810 RequestAllocator allocator(port->GetPort()); 811 DeselectRequest* request; 812 status_t error = AllocateRequest(allocator, &request); 813 if (error != B_OK) 814 return error; 815 816 request->volume = fUserlandVolume; 817 request->node = node; 818 request->fileCookie = cookie; 819 request->event = event; 820 request->sync = sync; 821 822 // send the request 823 KernelRequestHandler handler(this, DESELECT_REPLY); 824 DeselectReply* reply; 825 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 826 if (error != B_OK) 827 return error; 828 RequestReleaser requestReleaser(port, reply); 829 830 // process the reply 831 if (reply->error != B_OK) 832 return reply->error; 833 return error; 834 } 835 836 // FSync 837 status_t 838 Volume::FSync(fs_vnode node) 839 { 840 // check capability 841 if (!fFileSystem->HasCapability(FS_CAPABILITY_FSYNC)) 842 return B_BAD_VALUE; 843 844 // get a free port 845 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 846 if (!port) 847 return B_ERROR; 848 PortReleaser _(fFileSystem->GetPortPool(), port); 849 850 // prepare the request 851 RequestAllocator allocator(port->GetPort()); 852 FSyncRequest* request; 853 status_t error = AllocateRequest(allocator, &request); 854 if (error != B_OK) 855 return error; 856 857 request->volume = fUserlandVolume; 858 request->node = node; 859 860 // send the request 861 KernelRequestHandler handler(this, FSYNC_REPLY); 862 FSyncReply* reply; 863 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 864 if (error != B_OK) 865 return error; 866 RequestReleaser requestReleaser(port, reply); 867 868 // process the reply 869 if (reply->error != B_OK) 870 return reply->error; 871 return error; 872 } 873 874 // ReadSymlink 875 status_t 876 Volume::ReadSymlink(fs_vnode node, char* buffer, size_t bufferSize, 877 size_t* bytesRead) 878 { 879 *bytesRead = 0; 880 881 // check capability 882 if (!fFileSystem->HasCapability(FS_CAPABILITY_READ_SYMLINK)) 883 return B_BAD_VALUE; 884 885 // get a free port 886 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 887 if (!port) 888 return B_ERROR; 889 PortReleaser _(fFileSystem->GetPortPool(), port); 890 891 // prepare the request 892 RequestAllocator allocator(port->GetPort()); 893 ReadSymlinkRequest* request; 894 status_t error = AllocateRequest(allocator, &request); 895 if (error != B_OK) 896 return error; 897 898 request->volume = fUserlandVolume; 899 request->node = node; 900 request->size = bufferSize; 901 902 // send the request 903 KernelRequestHandler handler(this, READ_SYMLINK_REPLY); 904 ReadSymlinkReply* reply; 905 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 906 if (error != B_OK) 907 return error; 908 RequestReleaser requestReleaser(port, reply); 909 910 // process the reply 911 if (reply->error != B_OK) 912 return reply->error; 913 void* readBuffer = reply->buffer.GetData(); 914 if (reply->bytesRead > (uint32)reply->buffer.GetSize() 915 || reply->bytesRead > bufferSize) { 916 return B_BAD_DATA; 917 } 918 if (reply->bytesRead > 0) 919 memcpy(buffer, readBuffer, reply->bytesRead); 920 *bytesRead = reply->bytesRead; 921 _SendReceiptAck(port); 922 return error; 923 } 924 925 // CreateSymlink 926 status_t 927 Volume::CreateSymlink(fs_vnode dir, const char* name, const char* target, 928 int mode) 929 { 930 // check capability 931 if (!fFileSystem->HasCapability(FS_CAPABILITY_CREATE_SYMLINK)) 932 return B_BAD_VALUE; 933 934 // get a free port 935 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 936 if (!port) 937 return B_ERROR; 938 PortReleaser _(fFileSystem->GetPortPool(), port); 939 940 // prepare the request 941 RequestAllocator allocator(port->GetPort()); 942 CreateSymlinkRequest* request; 943 status_t error = AllocateRequest(allocator, &request); 944 if (error != B_OK) 945 return error; 946 947 request->volume = fUserlandVolume; 948 request->node = dir; 949 error = allocator.AllocateString(request->name, name); 950 if (error == B_OK) 951 error = allocator.AllocateString(request->target, target); 952 if (error != B_OK) 953 return error; 954 request->mode = mode; 955 956 // send the request 957 KernelRequestHandler handler(this, CREATE_SYMLINK_REPLY); 958 CreateSymlinkReply* reply; 959 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 960 if (error != B_OK) 961 return error; 962 RequestReleaser requestReleaser(port, reply); 963 964 // process the reply 965 if (reply->error != B_OK) 966 return reply->error; 967 return error; 968 } 969 970 // Link 971 status_t 972 Volume::Link(fs_vnode dir, const char* name, fs_vnode node) 973 { 974 // check capability 975 if (!fFileSystem->HasCapability(FS_CAPABILITY_LINK)) 976 return B_BAD_VALUE; 977 978 // get a free port 979 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 980 if (!port) 981 return B_ERROR; 982 PortReleaser _(fFileSystem->GetPortPool(), port); 983 984 // prepare the request 985 RequestAllocator allocator(port->GetPort()); 986 LinkRequest* request; 987 status_t error = AllocateRequest(allocator, &request); 988 if (error != B_OK) 989 return error; 990 991 request->volume = fUserlandVolume; 992 request->node = dir; 993 error = allocator.AllocateString(request->name, name); 994 request->target = node; 995 if (error != B_OK) 996 return error; 997 998 // send the request 999 KernelRequestHandler handler(this, LINK_REPLY); 1000 LinkReply* reply; 1001 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 1002 if (error != B_OK) 1003 return error; 1004 RequestReleaser requestReleaser(port, reply); 1005 1006 // process the reply 1007 if (reply->error != B_OK) 1008 return reply->error; 1009 return error; 1010 } 1011 1012 // Unlink 1013 status_t 1014 Volume::Unlink(fs_vnode dir, const char* name) 1015 { 1016 // check capability 1017 if (!fFileSystem->HasCapability(FS_CAPABILITY_UNLINK)) 1018 return B_BAD_VALUE; 1019 1020 // get a free port 1021 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 1022 if (!port) 1023 return B_ERROR; 1024 PortReleaser _(fFileSystem->GetPortPool(), port); 1025 1026 // prepare the request 1027 RequestAllocator allocator(port->GetPort()); 1028 UnlinkRequest* request; 1029 status_t error = AllocateRequest(allocator, &request); 1030 if (error != B_OK) 1031 return error; 1032 1033 request->volume = fUserlandVolume; 1034 request->node = dir; 1035 error = allocator.AllocateString(request->name, name); 1036 if (error != B_OK) 1037 return error; 1038 1039 // send the request 1040 KernelRequestHandler handler(this, UNLINK_REPLY); 1041 UnlinkReply* reply; 1042 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 1043 if (error != B_OK) 1044 return error; 1045 RequestReleaser requestReleaser(port, reply); 1046 1047 // process the reply 1048 if (reply->error != B_OK) 1049 return reply->error; 1050 return error; 1051 } 1052 1053 // Rename 1054 status_t 1055 Volume::Rename(fs_vnode oldDir, const char* oldName, fs_vnode newDir, 1056 const char* newName) 1057 { 1058 // check capability 1059 if (!fFileSystem->HasCapability(FS_CAPABILITY_RENAME)) 1060 return B_BAD_VALUE; 1061 1062 // get a free port 1063 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 1064 if (!port) 1065 return B_ERROR; 1066 PortReleaser _(fFileSystem->GetPortPool(), port); 1067 1068 // prepare the request 1069 RequestAllocator allocator(port->GetPort()); 1070 RenameRequest* request; 1071 status_t error = AllocateRequest(allocator, &request); 1072 if (error != B_OK) 1073 return error; 1074 1075 request->volume = fUserlandVolume; 1076 request->oldDir = oldDir; 1077 request->newDir = newDir; 1078 error = allocator.AllocateString(request->oldName, oldName); 1079 if (error == B_OK) 1080 error = allocator.AllocateString(request->newName, newName); 1081 if (error != B_OK) 1082 return error; 1083 1084 // send the request 1085 KernelRequestHandler handler(this, RENAME_REPLY); 1086 RenameReply* reply; 1087 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 1088 if (error != B_OK) 1089 return error; 1090 RequestReleaser requestReleaser(port, reply); 1091 1092 // process the reply 1093 if (reply->error != B_OK) 1094 return reply->error; 1095 return error; 1096 } 1097 1098 // Access 1099 status_t 1100 Volume::Access(fs_vnode node, int mode) 1101 { 1102 // check capability 1103 if (!fFileSystem->HasCapability(FS_CAPABILITY_ACCESS)) 1104 return B_OK; 1105 1106 // get a free port 1107 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 1108 if (!port) 1109 return B_ERROR; 1110 PortReleaser _(fFileSystem->GetPortPool(), port); 1111 1112 // prepare the request 1113 RequestAllocator allocator(port->GetPort()); 1114 AccessRequest* request; 1115 status_t error = AllocateRequest(allocator, &request); 1116 if (error != B_OK) 1117 return error; 1118 1119 request->volume = fUserlandVolume; 1120 request->node = node; 1121 request->mode = mode; 1122 1123 // send the request 1124 KernelRequestHandler handler(this, ACCESS_REPLY); 1125 AccessReply* reply; 1126 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 1127 if (error != B_OK) 1128 return error; 1129 RequestReleaser requestReleaser(port, reply); 1130 1131 // process the reply 1132 if (reply->error != B_OK) 1133 return reply->error; 1134 return error; 1135 } 1136 1137 // ReadStat 1138 status_t 1139 Volume::ReadStat(fs_vnode node, struct stat* st) 1140 { 1141 // When the connection to the userland server is lost, we serve 1142 // read_stat(fRootNode) requests manually to allow clean unmounting. 1143 status_t error = _ReadStat(node, st); 1144 if (error != B_OK && fFileSystem->GetPortPool()->IsDisconnected() 1145 && node == fRootNode) { 1146 WARN(("Volume::ReadStat(): connection lost, emulating stat for the " 1147 "root node\n")); 1148 1149 st->st_dev = fID; 1150 st->st_ino = fRootID; 1151 st->st_mode = ACCESSPERMS; 1152 st->st_nlink = 1; 1153 st->st_uid = 0; 1154 st->st_gid = 0; 1155 st->st_size = 512; 1156 st->st_blksize = 512; 1157 st->st_atime = 0; 1158 st->st_mtime = 0; 1159 st->st_ctime = 0; 1160 st->st_crtime = 0; 1161 1162 error = B_OK; 1163 } 1164 return error; 1165 } 1166 1167 // WriteStat 1168 status_t 1169 Volume::WriteStat(fs_vnode node, const struct stat* st, uint32 mask) 1170 { 1171 // check capability 1172 if (!fFileSystem->HasCapability(FS_CAPABILITY_WRITE_STAT)) 1173 return B_BAD_VALUE; 1174 1175 // get a free port 1176 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 1177 if (!port) 1178 return B_ERROR; 1179 PortReleaser _(fFileSystem->GetPortPool(), port); 1180 1181 // prepare the request 1182 RequestAllocator allocator(port->GetPort()); 1183 WriteStatRequest* request; 1184 status_t error = AllocateRequest(allocator, &request); 1185 if (error != B_OK) 1186 return error; 1187 1188 request->volume = fUserlandVolume; 1189 request->node = node; 1190 request->st = *st; 1191 request->mask = mask; 1192 1193 // send the request 1194 KernelRequestHandler handler(this, WRITE_STAT_REPLY); 1195 WriteStatReply* reply; 1196 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 1197 if (error != B_OK) 1198 return error; 1199 RequestReleaser requestReleaser(port, reply); 1200 1201 // process the reply 1202 if (reply->error != B_OK) 1203 return reply->error; 1204 return error; 1205 } 1206 1207 1208 // #pragma mark - files 1209 1210 // Create 1211 status_t 1212 Volume::Create(fs_vnode dir, const char* name, int openMode, int mode, 1213 void** cookie, ino_t* vnid) 1214 { 1215 // check capability 1216 if (!fFileSystem->HasCapability(FS_CAPABILITY_CREATE)) 1217 return B_BAD_VALUE; 1218 1219 // get a free port 1220 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 1221 if (!port) 1222 return B_ERROR; 1223 PortReleaser _(fFileSystem->GetPortPool(), port); 1224 AutoIncrementer incrementer(&fOpenFiles); 1225 1226 // prepare the request 1227 RequestAllocator allocator(port->GetPort()); 1228 CreateRequest* request; 1229 status_t error = AllocateRequest(allocator, &request); 1230 if (error != B_OK) 1231 return error; 1232 1233 request->volume = fUserlandVolume; 1234 request->node = dir; 1235 error = allocator.AllocateString(request->name, name); 1236 request->openMode = openMode; 1237 request->mode = mode; 1238 if (error != B_OK) 1239 return error; 1240 1241 // send the request 1242 KernelRequestHandler handler(this, CREATE_REPLY); 1243 CreateReply* reply; 1244 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 1245 if (error != B_OK) 1246 return error; 1247 RequestReleaser requestReleaser(port, reply); 1248 1249 // process the reply 1250 if (reply->error != B_OK) 1251 return reply->error; 1252 incrementer.Keep(); 1253 *vnid = reply->vnid; 1254 *cookie = reply->fileCookie; 1255 // The VFS will balance the new_vnode() call for the FS. 1256 if (error == B_OK) 1257 _DecrementVNodeCount(*vnid); 1258 return error; 1259 } 1260 1261 // Open 1262 status_t 1263 Volume::Open(fs_vnode node, int openMode, fs_cookie* cookie) 1264 { 1265 // check capability 1266 if (!fFileSystem->HasCapability(FS_CAPABILITY_OPEN)) 1267 return B_BAD_VALUE; 1268 1269 // get a free port 1270 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 1271 if (!port) 1272 return B_ERROR; 1273 PortReleaser _(fFileSystem->GetPortPool(), port); 1274 AutoIncrementer incrementer(&fOpenFiles); 1275 1276 // prepare the request 1277 RequestAllocator allocator(port->GetPort()); 1278 OpenRequest* request; 1279 status_t error = AllocateRequest(allocator, &request); 1280 if (error != B_OK) 1281 return error; 1282 request->volume = fUserlandVolume; 1283 request->node = node; 1284 request->openMode = openMode; 1285 1286 // send the request 1287 KernelRequestHandler handler(this, OPEN_REPLY); 1288 OpenReply* reply; 1289 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 1290 if (error != B_OK) 1291 return error; 1292 RequestReleaser requestReleaser(port, reply); 1293 1294 // process the reply 1295 if (reply->error != B_OK) 1296 return reply->error; 1297 incrementer.Keep(); 1298 *cookie = reply->fileCookie; 1299 return error; 1300 } 1301 1302 // Close 1303 status_t 1304 Volume::Close(fs_vnode node, fs_cookie cookie) 1305 { 1306 status_t error = _Close(node, cookie); 1307 if (error != B_OK && fFileSystem->GetPortPool()->IsDisconnected()) { 1308 // This isn't really necessary, as the return value is irrelevant to 1309 // the VFS. OBOS ignores it completely. The fsshell returns it to the 1310 // userland, but considers the node closed anyway. 1311 WARN(("Volume::Close(): connection lost, forcing close\n")); 1312 return B_OK; 1313 } 1314 return error; 1315 } 1316 1317 // FreeCookie 1318 status_t 1319 Volume::FreeCookie(fs_vnode node, fs_cookie cookie) 1320 { 1321 status_t error = _FreeCookie(node, cookie); 1322 bool disconnected = false; 1323 if (error != B_OK && fFileSystem->GetPortPool()->IsDisconnected()) { 1324 // This isn't really necessary, as the return value is irrelevant to 1325 // the VFS. It's completely ignored by OBOS as well as by the fsshell. 1326 WARN(("Volume::FreeCookie(): connection lost, forcing free cookie\n")); 1327 error = B_OK; 1328 disconnected = true; 1329 } 1330 1331 int32 openFiles = atomic_add(&fOpenFiles, -1); 1332 if (openFiles <= 1 && disconnected) 1333 _PutAllPendingVNodes(); 1334 return error; 1335 } 1336 1337 // Read 1338 status_t 1339 Volume::Read(fs_vnode node, fs_cookie cookie, off_t pos, void* buffer, 1340 size_t bufferSize, size_t* bytesRead) 1341 { 1342 *bytesRead = 0; 1343 1344 // check capability 1345 if (!fFileSystem->HasCapability(FS_CAPABILITY_READ)) 1346 return B_BAD_VALUE; 1347 1348 // get a free port 1349 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 1350 if (!port) 1351 return B_ERROR; 1352 PortReleaser _(fFileSystem->GetPortPool(), port); 1353 1354 // prepare the request 1355 RequestAllocator allocator(port->GetPort()); 1356 ReadRequest* request; 1357 status_t error = AllocateRequest(allocator, &request); 1358 if (error != B_OK) 1359 return error; 1360 1361 request->volume = fUserlandVolume; 1362 request->node = node; 1363 request->fileCookie = cookie; 1364 request->pos = pos; 1365 request->size = bufferSize; 1366 1367 // send the request 1368 KernelRequestHandler handler(this, READ_REPLY); 1369 ReadReply* reply; 1370 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 1371 if (error != B_OK) 1372 return error; 1373 RequestReleaser requestReleaser(port, reply); 1374 1375 // process the reply 1376 if (reply->error != B_OK) 1377 return reply->error; 1378 void* readBuffer = reply->buffer.GetData(); 1379 if (reply->bytesRead > (uint32)reply->buffer.GetSize() 1380 || reply->bytesRead > bufferSize) { 1381 return B_BAD_DATA; 1382 } 1383 if (reply->bytesRead > 0) 1384 memcpy(buffer, readBuffer, reply->bytesRead); 1385 *bytesRead = reply->bytesRead; 1386 _SendReceiptAck(port); 1387 return error; 1388 } 1389 1390 // Write 1391 status_t 1392 Volume::Write(fs_vnode node, fs_cookie cookie, off_t pos, const void* buffer, 1393 size_t size, size_t* bytesWritten) 1394 { 1395 *bytesWritten = 0; 1396 1397 // check capability 1398 if (!fFileSystem->HasCapability(FS_CAPABILITY_WRITE)) 1399 return B_BAD_VALUE; 1400 1401 // get a free port 1402 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 1403 if (!port) 1404 return B_ERROR; 1405 PortReleaser _(fFileSystem->GetPortPool(), port); 1406 1407 // prepare the request 1408 RequestAllocator allocator(port->GetPort()); 1409 WriteRequest* request; 1410 status_t error = AllocateRequest(allocator, &request); 1411 if (error != B_OK) 1412 return error; 1413 1414 request->volume = fUserlandVolume; 1415 request->node = node; 1416 request->fileCookie = cookie; 1417 request->pos = pos; 1418 error = allocator.AllocateData(request->buffer, buffer, size, 1); 1419 if (error != B_OK) 1420 return error; 1421 1422 // send the request 1423 KernelRequestHandler handler(this, WRITE_REPLY); 1424 WriteReply* reply; 1425 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 1426 if (error != B_OK) 1427 return error; 1428 RequestReleaser requestReleaser(port, reply); 1429 1430 // process the reply 1431 if (reply->error != B_OK) 1432 return reply->error; 1433 *bytesWritten = reply->bytesWritten; 1434 return error; 1435 } 1436 1437 1438 // #pragma mark - directories 1439 1440 // CreateDir 1441 status_t 1442 Volume::CreateDir(fs_vnode dir, const char* name, int mode, ino_t *newDir) 1443 { 1444 // check capability 1445 if (!fFileSystem->HasCapability(FS_CAPABILITY_CREATE_DIR)) 1446 return B_BAD_VALUE; 1447 1448 // get a free port 1449 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 1450 if (!port) 1451 return B_ERROR; 1452 PortReleaser _(fFileSystem->GetPortPool(), port); 1453 1454 // prepare the request 1455 RequestAllocator allocator(port->GetPort()); 1456 CreateDirRequest* request; 1457 status_t error = AllocateRequest(allocator, &request); 1458 if (error != B_OK) 1459 return error; 1460 1461 request->volume = fUserlandVolume; 1462 request->node = dir; 1463 error = allocator.AllocateString(request->name, name); 1464 request->mode = mode; 1465 if (error != B_OK) 1466 return error; 1467 1468 // send the request 1469 KernelRequestHandler handler(this, CREATE_DIR_REPLY); 1470 CreateDirReply* reply; 1471 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 1472 if (error != B_OK) 1473 return error; 1474 RequestReleaser requestReleaser(port, reply); 1475 1476 // process the reply 1477 if (reply->error != B_OK) 1478 return reply->error; 1479 *newDir = reply->newDir; 1480 return error; 1481 } 1482 1483 // RemoveDir 1484 status_t 1485 Volume::RemoveDir(fs_vnode dir, const char* name) 1486 { 1487 // check capability 1488 if (!fFileSystem->HasCapability(FS_CAPABILITY_REMOVE_DIR)) 1489 return B_BAD_VALUE; 1490 1491 // get a free port 1492 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 1493 if (!port) 1494 return B_ERROR; 1495 PortReleaser _(fFileSystem->GetPortPool(), port); 1496 1497 // prepare the request 1498 RequestAllocator allocator(port->GetPort()); 1499 RemoveDirRequest* request; 1500 status_t error = AllocateRequest(allocator, &request); 1501 if (error != B_OK) 1502 return error; 1503 1504 request->volume = fUserlandVolume; 1505 request->node = dir; 1506 error = allocator.AllocateString(request->name, name); 1507 if (error != B_OK) 1508 return error; 1509 1510 // send the request 1511 KernelRequestHandler handler(this, REMOVE_DIR_REPLY); 1512 RemoveDirReply* reply; 1513 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 1514 if (error != B_OK) 1515 return error; 1516 RequestReleaser requestReleaser(port, reply); 1517 1518 // process the reply 1519 if (reply->error != B_OK) 1520 return reply->error; 1521 return error; 1522 } 1523 1524 // OpenDir 1525 status_t 1526 Volume::OpenDir(fs_vnode node, fs_cookie* cookie) 1527 { 1528 // check capability 1529 if (!fFileSystem->HasCapability(FS_CAPABILITY_OPEN_DIR)) 1530 return B_BAD_VALUE; 1531 1532 // get a free port 1533 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 1534 if (!port) 1535 return B_ERROR; 1536 PortReleaser _(fFileSystem->GetPortPool(), port); 1537 AutoIncrementer incrementer(&fOpenDirectories); 1538 1539 // prepare the request 1540 RequestAllocator allocator(port->GetPort()); 1541 OpenDirRequest* request; 1542 status_t error = AllocateRequest(allocator, &request); 1543 if (error != B_OK) 1544 return error; 1545 1546 request->volume = fUserlandVolume; 1547 request->node = node; 1548 1549 // send the request 1550 KernelRequestHandler handler(this, OPEN_DIR_REPLY); 1551 OpenDirReply* reply; 1552 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 1553 if (error != B_OK) 1554 return error; 1555 RequestReleaser requestReleaser(port, reply); 1556 1557 // process the reply 1558 if (reply->error != B_OK) 1559 return reply->error; 1560 incrementer.Keep(); 1561 *cookie = reply->dirCookie; 1562 return error; 1563 } 1564 1565 // CloseDir 1566 status_t 1567 Volume::CloseDir(fs_vnode node, fs_vnode cookie) 1568 { 1569 status_t error = _CloseDir(node, cookie); 1570 if (error != B_OK && fFileSystem->GetPortPool()->IsDisconnected()) { 1571 // This isn't really necessary, as the return value is irrelevant to 1572 // the VFS. OBOS ignores it completely. The fsshell returns it to the 1573 // userland, but considers the node closed anyway. 1574 WARN(("Volume::CloseDir(): connection lost, forcing close dir\n")); 1575 return B_OK; 1576 } 1577 return error; 1578 } 1579 1580 // FreeDirCookie 1581 status_t 1582 Volume::FreeDirCookie(void* node, void* cookie) 1583 { 1584 status_t error = _FreeDirCookie(node, cookie); 1585 bool disconnected = false; 1586 if (error != B_OK && fFileSystem->GetPortPool()->IsDisconnected()) { 1587 // This isn't really necessary, as the return value is irrelevant to 1588 // the VFS. It's completely ignored by OBOS as well as by the fsshell. 1589 WARN(("Volume::FreeDirCookie(): connection lost, forcing free dir " 1590 "cookie\n")); 1591 error = B_OK; 1592 disconnected = true; 1593 } 1594 int32 openDirs = atomic_add(&fOpenDirectories, -1); 1595 if (openDirs <= 1 && disconnected) 1596 _PutAllPendingVNodes(); 1597 return error; 1598 } 1599 1600 // ReadDir 1601 status_t 1602 Volume::ReadDir(fs_vnode node, fs_vnode cookie, void* buffer, size_t bufferSize, 1603 uint32 count, uint32* countRead) 1604 { 1605 *countRead = 0; 1606 1607 // check capability 1608 if (!fFileSystem->HasCapability(FS_CAPABILITY_READ_DIR)) 1609 return B_BAD_VALUE; 1610 1611 // get a free port 1612 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 1613 if (!port) 1614 return B_ERROR; 1615 PortReleaser _(fFileSystem->GetPortPool(), port); 1616 1617 // prepare the request 1618 RequestAllocator allocator(port->GetPort()); 1619 ReadDirRequest* request; 1620 status_t error = AllocateRequest(allocator, &request); 1621 if (error != B_OK) 1622 return error; 1623 1624 request->volume = fUserlandVolume; 1625 request->node = node; 1626 request->dirCookie = cookie; 1627 request->bufferSize = bufferSize; 1628 request->count = count; 1629 1630 // send the request 1631 KernelRequestHandler handler(this, READ_DIR_REPLY); 1632 ReadDirReply* reply; 1633 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 1634 if (error != B_OK) 1635 return error; 1636 RequestReleaser requestReleaser(port, reply); 1637 1638 // process the reply 1639 if (reply->error != B_OK) 1640 return reply->error; 1641 if (reply->count < 0 || reply->count > count) 1642 return B_BAD_DATA; 1643 if ((int32)bufferSize < reply->buffer.GetSize()) 1644 return B_BAD_DATA; 1645 PRINT(("Volume::ReadDir(): buffer returned: %ld bytes\n", 1646 reply->buffer.GetSize())); 1647 1648 *countRead = reply->count; 1649 if (*countRead > 0) { 1650 // copy the buffer -- limit the number of bytes to copy 1651 uint32 maxBytes = *countRead 1652 * (sizeof(struct dirent) + B_FILE_NAME_LENGTH); 1653 uint32 copyBytes = reply->buffer.GetSize(); 1654 if (copyBytes > maxBytes) 1655 copyBytes = maxBytes; 1656 memcpy(buffer, reply->buffer.GetData(), copyBytes); 1657 } 1658 _SendReceiptAck(port); 1659 return error; 1660 } 1661 1662 // RewindDir 1663 status_t 1664 Volume::RewindDir(fs_vnode node, fs_vnode cookie) 1665 { 1666 // check capability 1667 if (!fFileSystem->HasCapability(FS_CAPABILITY_REWIND_DIR)) 1668 return B_BAD_VALUE; 1669 1670 // get a free port 1671 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 1672 if (!port) 1673 return B_ERROR; 1674 PortReleaser _(fFileSystem->GetPortPool(), port); 1675 1676 // prepare the request 1677 RequestAllocator allocator(port->GetPort()); 1678 RewindDirRequest* request; 1679 status_t error = AllocateRequest(allocator, &request); 1680 if (error != B_OK) 1681 return error; 1682 1683 request->volume = fUserlandVolume; 1684 request->node = node; 1685 request->dirCookie = cookie; 1686 1687 // send the request 1688 KernelRequestHandler handler(this, REWIND_DIR_REPLY); 1689 RewindDirReply* reply; 1690 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 1691 if (error != B_OK) 1692 return error; 1693 RequestReleaser requestReleaser(port, reply); 1694 1695 // process the reply 1696 if (reply->error != B_OK) 1697 return reply->error; 1698 return error; 1699 } 1700 1701 1702 // #pragma mark - attribute directories 1703 1704 1705 // OpenAttrDir 1706 status_t 1707 Volume::OpenAttrDir(fs_vnode node, fs_cookie *cookie) 1708 { 1709 // check capability 1710 if (!fFileSystem->HasCapability(FS_CAPABILITY_OPEN_ATTR_DIR)) 1711 return B_BAD_VALUE; 1712 1713 // get a free port 1714 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 1715 if (!port) 1716 return B_ERROR; 1717 PortReleaser _(fFileSystem->GetPortPool(), port); 1718 AutoIncrementer incrementer(&fOpenAttributeDirectories); 1719 1720 // prepare the request 1721 RequestAllocator allocator(port->GetPort()); 1722 OpenAttrDirRequest* request; 1723 status_t error = AllocateRequest(allocator, &request); 1724 if (error != B_OK) 1725 return error; 1726 1727 request->volume = fUserlandVolume; 1728 request->node = node; 1729 1730 // send the request 1731 KernelRequestHandler handler(this, OPEN_ATTR_DIR_REPLY); 1732 OpenAttrDirReply* reply; 1733 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 1734 if (error != B_OK) 1735 return error; 1736 RequestReleaser requestReleaser(port, reply); 1737 1738 // process the reply 1739 if (reply->error != B_OK) 1740 return reply->error; 1741 incrementer.Keep(); 1742 *cookie = reply->attrDirCookie; 1743 return error; 1744 } 1745 1746 // CloseAttrDir 1747 status_t 1748 Volume::CloseAttrDir(fs_vnode node, fs_cookie cookie) 1749 { 1750 status_t error = _CloseAttrDir(node, cookie); 1751 if (error != B_OK && fFileSystem->GetPortPool()->IsDisconnected()) { 1752 // This isn't really necessary, as the return value is irrelevant to 1753 // the VFS. OBOS ignores it completely. The fsshell returns it to the 1754 // userland, but considers the node closed anyway. 1755 WARN(("Volume::CloseAttrDir(): connection lost, forcing close attr " 1756 "dir\n")); 1757 return B_OK; 1758 } 1759 return error; 1760 } 1761 1762 // FreeAttrDirCookie 1763 status_t 1764 Volume::FreeAttrDirCookie(void* node, void* cookie) 1765 { 1766 status_t error = _FreeAttrDirCookie(node, cookie); 1767 bool disconnected = false; 1768 if (error != B_OK && fFileSystem->GetPortPool()->IsDisconnected()) { 1769 // This isn't really necessary, as the return value is irrelevant to 1770 // the VFS. It's completely ignored by OBOS as well as by the fsshell. 1771 WARN(("Volume::FreeAttrDirCookie(): connection lost, forcing free attr " 1772 "dir cookie\n")); 1773 error = B_OK; 1774 disconnected = true; 1775 } 1776 1777 int32 openAttrDirs = atomic_add(&fOpenAttributeDirectories, -1); 1778 if (openAttrDirs <= 1 && disconnected) 1779 _PutAllPendingVNodes(); 1780 return error; 1781 } 1782 1783 // ReadAttrDir 1784 status_t 1785 Volume::ReadAttrDir(fs_vnode node, fs_cookie cookie, void* buffer, 1786 size_t bufferSize, uint32 count, uint32* countRead) 1787 { 1788 // check capability 1789 if (!fFileSystem->HasCapability(FS_CAPABILITY_READ_ATTR_DIR)) 1790 return B_BAD_VALUE; 1791 1792 *countRead = 0; 1793 // get a free port 1794 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 1795 if (!port) 1796 return B_ERROR; 1797 PortReleaser _(fFileSystem->GetPortPool(), port); 1798 1799 // prepare the request 1800 RequestAllocator allocator(port->GetPort()); 1801 ReadAttrDirRequest* request; 1802 status_t error = AllocateRequest(allocator, &request); 1803 if (error != B_OK) 1804 return error; 1805 1806 request->volume = fUserlandVolume; 1807 request->node = node; 1808 request->attrDirCookie = cookie; 1809 request->bufferSize = bufferSize; 1810 request->count = count; 1811 1812 // send the request 1813 KernelRequestHandler handler(this, READ_ATTR_DIR_REPLY); 1814 ReadAttrDirReply* reply; 1815 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 1816 if (error != B_OK) 1817 return error; 1818 RequestReleaser requestReleaser(port, reply); 1819 1820 // process the reply 1821 if (reply->error != B_OK) 1822 return reply->error; 1823 if (reply->count < 0 || reply->count > count) 1824 return B_BAD_DATA; 1825 if ((int32)bufferSize < reply->buffer.GetSize()) 1826 return B_BAD_DATA; 1827 1828 *countRead = reply->count; 1829 if (*countRead > 0) { 1830 // copy the buffer -- limit the number of bytes to copy 1831 uint32 maxBytes = *countRead 1832 * (sizeof(struct dirent) + B_ATTR_NAME_LENGTH); 1833 uint32 copyBytes = reply->buffer.GetSize(); 1834 if (copyBytes > maxBytes) 1835 copyBytes = maxBytes; 1836 memcpy(buffer, reply->buffer.GetData(), copyBytes); 1837 } 1838 _SendReceiptAck(port); 1839 return error; 1840 } 1841 1842 // RewindAttrDir 1843 status_t 1844 Volume::RewindAttrDir(fs_vnode node, fs_cookie cookie) 1845 { 1846 // check capability 1847 if (!fFileSystem->HasCapability(FS_CAPABILITY_REWIND_ATTR_DIR)) 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 RewindAttrDirRequest* request; 1859 status_t error = AllocateRequest(allocator, &request); 1860 if (error != B_OK) 1861 return error; 1862 1863 request->volume = fUserlandVolume; 1864 request->node = node; 1865 request->attrDirCookie = cookie; 1866 1867 // send the request 1868 KernelRequestHandler handler(this, REWIND_ATTR_DIR_REPLY); 1869 RewindAttrDirReply* reply; 1870 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 1871 if (error != B_OK) 1872 return error; 1873 RequestReleaser requestReleaser(port, reply); 1874 1875 // process the reply 1876 if (reply->error != B_OK) 1877 return reply->error; 1878 return error; 1879 } 1880 1881 1882 // #pragma mark - attributes 1883 1884 // CreateAttr 1885 status_t 1886 Volume::CreateAttr(fs_vnode node, const char* name, uint32 type, int openMode, 1887 fs_cookie* cookie) 1888 { 1889 // check capability 1890 if (!fFileSystem->HasCapability(FS_CAPABILITY_CREATE_ATTR)) 1891 return B_BAD_VALUE; 1892 1893 // get a free port 1894 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 1895 if (!port) 1896 return B_ERROR; 1897 PortReleaser _(fFileSystem->GetPortPool(), port); 1898 AutoIncrementer incrementer(&fOpenAttributes); 1899 1900 // prepare the request 1901 RequestAllocator allocator(port->GetPort()); 1902 CreateAttrRequest* request; 1903 status_t error = AllocateRequest(allocator, &request); 1904 if (error != B_OK) 1905 return error; 1906 1907 request->volume = fUserlandVolume; 1908 request->node = node; 1909 error = allocator.AllocateString(request->name, name); 1910 request->type = type; 1911 request->openMode = openMode; 1912 if (error != B_OK) 1913 return error; 1914 1915 // send the request 1916 KernelRequestHandler handler(this, CREATE_ATTR_REPLY); 1917 CreateAttrReply* reply; 1918 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 1919 if (error != B_OK) 1920 return error; 1921 RequestReleaser requestReleaser(port, reply); 1922 1923 // process the reply 1924 if (reply->error != B_OK) 1925 return reply->error; 1926 incrementer.Keep(); 1927 *cookie = reply->attrCookie; 1928 return error; 1929 } 1930 1931 // OpenAttr 1932 status_t 1933 Volume::OpenAttr(fs_vnode node, const char* name, int openMode, 1934 fs_cookie* cookie) 1935 { 1936 // check capability 1937 if (!fFileSystem->HasCapability(FS_CAPABILITY_OPEN_ATTR)) 1938 return B_BAD_VALUE; 1939 1940 // get a free port 1941 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 1942 if (!port) 1943 return B_ERROR; 1944 PortReleaser _(fFileSystem->GetPortPool(), port); 1945 AutoIncrementer incrementer(&fOpenAttributes); 1946 1947 // prepare the request 1948 RequestAllocator allocator(port->GetPort()); 1949 OpenAttrRequest* request; 1950 status_t error = AllocateRequest(allocator, &request); 1951 if (error != B_OK) 1952 return error; 1953 1954 request->volume = fUserlandVolume; 1955 request->node = node; 1956 error = allocator.AllocateString(request->name, name); 1957 request->openMode = openMode; 1958 if (error != B_OK) 1959 return error; 1960 1961 // send the request 1962 KernelRequestHandler handler(this, OPEN_ATTR_REPLY); 1963 OpenAttrReply* reply; 1964 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 1965 if (error != B_OK) 1966 return error; 1967 RequestReleaser requestReleaser(port, reply); 1968 1969 // process the reply 1970 if (reply->error != B_OK) 1971 return reply->error; 1972 incrementer.Keep(); 1973 *cookie = reply->attrCookie; 1974 return error; 1975 } 1976 1977 // CloseAttr 1978 status_t 1979 Volume::CloseAttr(fs_vnode node, fs_cookie cookie) 1980 { 1981 status_t error = _CloseAttr(node, cookie); 1982 if (error != B_OK && fFileSystem->GetPortPool()->IsDisconnected()) { 1983 // This isn't really necessary, as the return value is irrelevant to 1984 // the VFS. OBOS ignores it completely. The fsshell returns it to the 1985 // userland, but considers the node closed anyway. 1986 WARN(("Volume::CloseAttr(): connection lost, forcing close attr\n")); 1987 return B_OK; 1988 } 1989 return error; 1990 } 1991 1992 // FreeAttrCookie 1993 status_t 1994 Volume::FreeAttrCookie(fs_vnode node, fs_cookie cookie) 1995 { 1996 status_t error = _FreeAttrCookie(node, cookie); 1997 bool disconnected = false; 1998 if (error != B_OK && fFileSystem->GetPortPool()->IsDisconnected()) { 1999 // This isn't really necessary, as the return value is irrelevant to 2000 // the VFS. It's completely ignored by OBOS as well as by the fsshell. 2001 WARN(("Volume::FreeAttrCookie(): connection lost, forcing free attr " 2002 "cookie\n")); 2003 error = B_OK; 2004 disconnected = true; 2005 } 2006 2007 int32 openAttributes = atomic_add(&fOpenAttributes, -1); 2008 if (openAttributes <= 1 && disconnected) 2009 _PutAllPendingVNodes(); 2010 return error; 2011 } 2012 2013 // ReadAttr 2014 status_t 2015 Volume::ReadAttr(fs_vnode node, fs_cookie cookie, off_t pos, 2016 void* buffer, size_t bufferSize, size_t* bytesRead) 2017 { 2018 *bytesRead = 0; 2019 2020 // check capability 2021 if (!fFileSystem->HasCapability(FS_CAPABILITY_READ_ATTR)) 2022 return B_BAD_VALUE; 2023 2024 // get a free port 2025 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 2026 if (!port) 2027 return B_ERROR; 2028 PortReleaser _(fFileSystem->GetPortPool(), port); 2029 2030 // prepare the request 2031 RequestAllocator allocator(port->GetPort()); 2032 ReadAttrRequest* request; 2033 status_t error = AllocateRequest(allocator, &request); 2034 if (error != B_OK) 2035 return error; 2036 2037 request->volume = fUserlandVolume; 2038 request->node = node; 2039 request->attrCookie = cookie; 2040 request->pos = pos; 2041 request->size = bufferSize; 2042 2043 // send the request 2044 KernelRequestHandler handler(this, READ_ATTR_REPLY); 2045 ReadAttrReply* reply; 2046 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 2047 if (error != B_OK) 2048 return error; 2049 RequestReleaser requestReleaser(port, reply); 2050 2051 // process the reply 2052 if (reply->error != B_OK) 2053 return reply->error; 2054 void* readBuffer = reply->buffer.GetData(); 2055 if (reply->bytesRead > (uint32)reply->buffer.GetSize() 2056 || reply->bytesRead > bufferSize) { 2057 return B_BAD_DATA; 2058 } 2059 if (reply->bytesRead > 0) 2060 memcpy(buffer, readBuffer, reply->bytesRead); 2061 *bytesRead = reply->bytesRead; 2062 _SendReceiptAck(port); 2063 return error; 2064 } 2065 2066 // WriteAttr 2067 status_t 2068 Volume::WriteAttr(fs_vnode node, fs_cookie cookie, off_t pos, 2069 const void* buffer, size_t bufferSize, size_t* bytesWritten) 2070 { 2071 *bytesWritten = 0; 2072 2073 // check capability 2074 if (!fFileSystem->HasCapability(FS_CAPABILITY_WRITE_ATTR)) 2075 return B_BAD_VALUE; 2076 2077 // get a free port 2078 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 2079 if (!port) 2080 return B_ERROR; 2081 PortReleaser _(fFileSystem->GetPortPool(), port); 2082 2083 // prepare the request 2084 RequestAllocator allocator(port->GetPort()); 2085 WriteAttrRequest* request; 2086 status_t error = AllocateRequest(allocator, &request); 2087 if (error != B_OK) 2088 return error; 2089 2090 request->volume = fUserlandVolume; 2091 request->node = node; 2092 request->attrCookie = cookie; 2093 request->pos = pos; 2094 error = allocator.AllocateData(request->buffer, buffer, bufferSize, 1); 2095 if (error != B_OK) 2096 return error; 2097 2098 // send the request 2099 KernelRequestHandler handler(this, WRITE_ATTR_REPLY); 2100 WriteAttrReply* reply; 2101 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 2102 if (error != B_OK) 2103 return error; 2104 RequestReleaser requestReleaser(port, reply); 2105 2106 // process the reply 2107 if (reply->error != B_OK) 2108 return reply->error; 2109 *bytesWritten = reply->bytesWritten; 2110 return error; 2111 } 2112 2113 // ReadAttrStat 2114 status_t 2115 Volume::ReadAttrStat(fs_vnode node, fs_cookie cookie, struct stat *st) 2116 { 2117 // check capability 2118 if (!fFileSystem->HasCapability(FS_CAPABILITY_READ_ATTR_STAT)) 2119 return B_BAD_VALUE; 2120 2121 // get a free port 2122 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 2123 if (!port) 2124 return B_ERROR; 2125 PortReleaser _(fFileSystem->GetPortPool(), port); 2126 2127 // prepare the request 2128 RequestAllocator allocator(port->GetPort()); 2129 ReadAttrStatRequest* request; 2130 status_t error = AllocateRequest(allocator, &request); 2131 if (error != B_OK) 2132 return error; 2133 2134 request->volume = fUserlandVolume; 2135 request->node = node; 2136 request->attrCookie = cookie; 2137 2138 // send the request 2139 KernelRequestHandler handler(this, READ_ATTR_STAT_REPLY); 2140 ReadAttrStatReply* reply; 2141 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 2142 if (error != B_OK) 2143 return error; 2144 RequestReleaser requestReleaser(port, reply); 2145 2146 // process the reply 2147 if (reply->error != B_OK) 2148 return reply->error; 2149 *st = reply->st; 2150 return error; 2151 } 2152 2153 // WriteAttrStat 2154 status_t 2155 Volume::WriteAttrStat(fs_vnode node, fs_cookie cookie, const struct stat *st, 2156 int statMask) 2157 { 2158 // check capability 2159 if (!fFileSystem->HasCapability(FS_CAPABILITY_WRITE_ATTR_STAT)) 2160 return B_BAD_VALUE; 2161 2162 // get a free port 2163 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 2164 if (!port) 2165 return B_ERROR; 2166 PortReleaser _(fFileSystem->GetPortPool(), port); 2167 2168 // prepare the request 2169 RequestAllocator allocator(port->GetPort()); 2170 WriteAttrStatRequest* request; 2171 status_t error = AllocateRequest(allocator, &request); 2172 if (error != B_OK) 2173 return error; 2174 2175 request->volume = fUserlandVolume; 2176 request->node = node; 2177 request->attrCookie = cookie; 2178 request->st = *st; 2179 request->mask = statMask; 2180 2181 // send the request 2182 KernelRequestHandler handler(this, WRITE_ATTR_STAT_REPLY); 2183 WriteAttrStatReply* reply; 2184 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 2185 if (error != B_OK) 2186 return error; 2187 RequestReleaser requestReleaser(port, reply); 2188 2189 // process the reply 2190 if (reply->error != B_OK) 2191 return reply->error; 2192 return error; 2193 } 2194 2195 // RenameAttr 2196 status_t 2197 Volume::RenameAttr(fs_vnode oldNode, const char* oldName, fs_vnode newNode, 2198 const char* newName) 2199 { 2200 // check capability 2201 if (!fFileSystem->HasCapability(FS_CAPABILITY_RENAME_ATTR)) 2202 return B_BAD_VALUE; 2203 2204 // get a free port 2205 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 2206 if (!port) 2207 return B_ERROR; 2208 PortReleaser _(fFileSystem->GetPortPool(), port); 2209 2210 // prepare the request 2211 RequestAllocator allocator(port->GetPort()); 2212 RenameAttrRequest* request; 2213 status_t error = AllocateRequest(allocator, &request); 2214 if (error != B_OK) 2215 return error; 2216 2217 request->volume = fUserlandVolume; 2218 request->oldNode = oldNode; 2219 request->newNode = newNode; 2220 error = allocator.AllocateString(request->oldName, oldName); 2221 if (error == B_OK) 2222 error = allocator.AllocateString(request->newName, newName); 2223 if (error != B_OK) 2224 return error; 2225 2226 // send the request 2227 KernelRequestHandler handler(this, RENAME_ATTR_REPLY); 2228 RenameAttrReply* 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 return error; 2238 } 2239 2240 // RemoveAttr 2241 status_t 2242 Volume::RemoveAttr(fs_vnode node, const char* name) 2243 { 2244 // check capability 2245 if (!fFileSystem->HasCapability(FS_CAPABILITY_REMOVE_ATTR)) 2246 return B_BAD_VALUE; 2247 2248 // get a free port 2249 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 2250 if (!port) 2251 return B_ERROR; 2252 PortReleaser _(fFileSystem->GetPortPool(), port); 2253 2254 // prepare the request 2255 RequestAllocator allocator(port->GetPort()); 2256 RemoveAttrRequest* request; 2257 status_t error = AllocateRequest(allocator, &request); 2258 if (error != B_OK) 2259 return error; 2260 2261 request->volume = fUserlandVolume; 2262 request->node = node; 2263 error = allocator.AllocateString(request->name, name); 2264 if (error != B_OK) 2265 return error; 2266 2267 // send the request 2268 KernelRequestHandler handler(this, REMOVE_ATTR_REPLY); 2269 RemoveAttrReply* reply; 2270 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 2271 if (error != B_OK) 2272 return error; 2273 RequestReleaser requestReleaser(port, reply); 2274 2275 // process the reply 2276 if (reply->error != B_OK) 2277 return reply->error; 2278 return error; 2279 } 2280 2281 2282 // #pragma mark - indices 2283 2284 2285 // OpenIndexDir 2286 status_t 2287 Volume::OpenIndexDir(fs_cookie *cookie) 2288 { 2289 // check capability 2290 if (!fFileSystem->HasCapability(FS_CAPABILITY_OPEN_INDEX_DIR)) 2291 return B_BAD_VALUE; 2292 2293 // get a free port 2294 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 2295 if (!port) 2296 return B_ERROR; 2297 PortReleaser _(fFileSystem->GetPortPool(), port); 2298 AutoIncrementer incrementer(&fOpenIndexDirectories); 2299 2300 // prepare the request 2301 RequestAllocator allocator(port->GetPort()); 2302 OpenIndexDirRequest* request; 2303 status_t error = AllocateRequest(allocator, &request); 2304 if (error != B_OK) 2305 return error; 2306 2307 request->volume = fUserlandVolume; 2308 2309 // send the request 2310 KernelRequestHandler handler(this, OPEN_INDEX_DIR_REPLY); 2311 OpenIndexDirReply* reply; 2312 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 2313 if (error != B_OK) 2314 return error; 2315 RequestReleaser requestReleaser(port, reply); 2316 2317 // process the reply 2318 if (reply->error != B_OK) 2319 return reply->error; 2320 incrementer.Keep(); 2321 *cookie = reply->indexDirCookie; 2322 return error; 2323 } 2324 2325 // CloseIndexDir 2326 status_t 2327 Volume::CloseIndexDir(fs_cookie cookie) 2328 { 2329 status_t error = _CloseIndexDir(cookie); 2330 if (error != B_OK && fFileSystem->GetPortPool()->IsDisconnected()) { 2331 // This isn't really necessary, as the return value is irrelevant to 2332 // the VFS. OBOS ignores it completely. The fsshell returns it to the 2333 // userland, but considers the node closed anyway. 2334 WARN(("Volume::CloseIndexDir(): connection lost, forcing close " 2335 "index dir\n")); 2336 return B_OK; 2337 } 2338 return error; 2339 } 2340 2341 // FreeIndexDirCookie 2342 status_t 2343 Volume::FreeIndexDirCookie(fs_cookie cookie) 2344 { 2345 status_t error = _FreeIndexDirCookie(cookie); 2346 bool disconnected = false; 2347 if (error != B_OK && fFileSystem->GetPortPool()->IsDisconnected()) { 2348 // This isn't really necessary, as the return value is irrelevant to 2349 // the VFS. It's completely ignored by OBOS as well as by the fsshell. 2350 WARN(("Volume::FreeIndexDirCookie(): connection lost, forcing free " 2351 "index dir cookie\n")); 2352 error = B_OK; 2353 disconnected = true; 2354 } 2355 2356 int32 openIndexDirs = atomic_add(&fOpenIndexDirectories, -1); 2357 if (openIndexDirs <= 1 && disconnected) 2358 _PutAllPendingVNodes(); 2359 return error; 2360 } 2361 2362 // ReadIndexDir 2363 status_t 2364 Volume::ReadIndexDir(fs_cookie cookie, void* buffer, size_t bufferSize, 2365 uint32 count, uint32* countRead) 2366 { 2367 *countRead = 0; 2368 2369 // check capability 2370 if (!fFileSystem->HasCapability(FS_CAPABILITY_READ_INDEX_DIR)) 2371 return B_BAD_VALUE; 2372 2373 // get a free port 2374 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 2375 if (!port) 2376 return B_ERROR; 2377 PortReleaser _(fFileSystem->GetPortPool(), port); 2378 2379 // prepare the request 2380 RequestAllocator allocator(port->GetPort()); 2381 ReadIndexDirRequest* request; 2382 status_t error = AllocateRequest(allocator, &request); 2383 if (error != B_OK) 2384 return error; 2385 2386 request->volume = fUserlandVolume; 2387 request->indexDirCookie = cookie; 2388 request->bufferSize = bufferSize; 2389 request->count = count; 2390 2391 // send the request 2392 KernelRequestHandler handler(this, READ_INDEX_DIR_REPLY); 2393 ReadIndexDirReply* reply; 2394 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 2395 if (error != B_OK) 2396 return error; 2397 RequestReleaser requestReleaser(port, reply); 2398 2399 // process the reply 2400 if (reply->error != B_OK) 2401 return reply->error; 2402 if (reply->count < 0 || reply->count > count) 2403 return B_BAD_DATA; 2404 if ((int32)bufferSize < reply->buffer.GetSize()) 2405 return B_BAD_DATA; 2406 2407 *countRead = reply->count; 2408 if (*countRead > 0) { 2409 // copy the buffer -- limit the number of bytes to copy 2410 uint32 maxBytes = *countRead 2411 * (sizeof(struct dirent) + B_FILE_NAME_LENGTH); 2412 uint32 copyBytes = reply->buffer.GetSize(); 2413 if (copyBytes > maxBytes) 2414 copyBytes = maxBytes; 2415 memcpy(buffer, reply->buffer.GetData(), copyBytes); 2416 } 2417 _SendReceiptAck(port); 2418 return error; 2419 } 2420 2421 // RewindIndexDir 2422 status_t 2423 Volume::RewindIndexDir(fs_cookie cookie) 2424 { 2425 // check capability 2426 if (!fFileSystem->HasCapability(FS_CAPABILITY_REWIND_INDEX_DIR)) 2427 return B_BAD_VALUE; 2428 2429 // get a free port 2430 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 2431 if (!port) 2432 return B_ERROR; 2433 PortReleaser _(fFileSystem->GetPortPool(), port); 2434 2435 // prepare the request 2436 RequestAllocator allocator(port->GetPort()); 2437 RewindIndexDirRequest* request; 2438 status_t error = AllocateRequest(allocator, &request); 2439 if (error != B_OK) 2440 return error; 2441 2442 request->volume = fUserlandVolume; 2443 request->indexDirCookie = cookie; 2444 2445 // send the request 2446 KernelRequestHandler handler(this, REWIND_INDEX_DIR_REPLY); 2447 RewindIndexDirReply* reply; 2448 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 2449 if (error != B_OK) 2450 return error; 2451 RequestReleaser requestReleaser(port, reply); 2452 2453 // process the reply 2454 if (reply->error != B_OK) 2455 return reply->error; 2456 return error; 2457 } 2458 2459 // CreateIndex 2460 status_t 2461 Volume::CreateIndex(const char* name, uint32 type, uint32 flags) 2462 { 2463 // check capability 2464 if (!fFileSystem->HasCapability(FS_CAPABILITY_CREATE_INDEX)) 2465 return B_BAD_VALUE; 2466 2467 // get a free port 2468 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 2469 if (!port) 2470 return B_ERROR; 2471 PortReleaser _(fFileSystem->GetPortPool(), port); 2472 2473 // prepare the request 2474 RequestAllocator allocator(port->GetPort()); 2475 CreateIndexRequest* request; 2476 status_t error = AllocateRequest(allocator, &request); 2477 if (error != B_OK) 2478 return error; 2479 2480 request->volume = fUserlandVolume; 2481 error = allocator.AllocateString(request->name, name); 2482 request->type = type; 2483 request->flags = flags; 2484 if (error != B_OK) 2485 return error; 2486 2487 // send the request 2488 KernelRequestHandler handler(this, CREATE_INDEX_REPLY); 2489 CreateIndexReply* reply; 2490 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 2491 if (error != B_OK) 2492 return error; 2493 RequestReleaser requestReleaser(port, reply); 2494 2495 // process the reply 2496 if (reply->error != B_OK) 2497 return reply->error; 2498 return error; 2499 } 2500 2501 // RemoveIndex 2502 status_t 2503 Volume::RemoveIndex(const char* name) 2504 { 2505 // check capability 2506 if (!fFileSystem->HasCapability(FS_CAPABILITY_REMOVE_INDEX)) 2507 return B_BAD_VALUE; 2508 2509 // get a free port 2510 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 2511 if (!port) 2512 return B_ERROR; 2513 PortReleaser _(fFileSystem->GetPortPool(), port); 2514 2515 // prepare the request 2516 RequestAllocator allocator(port->GetPort()); 2517 RemoveIndexRequest* request; 2518 status_t error = AllocateRequest(allocator, &request); 2519 if (error != B_OK) 2520 return error; 2521 2522 request->volume = fUserlandVolume; 2523 error = allocator.AllocateString(request->name, name); 2524 if (error != B_OK) 2525 return error; 2526 2527 // send the request 2528 KernelRequestHandler handler(this, REMOVE_INDEX_REPLY); 2529 RemoveIndexReply* reply; 2530 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 2531 if (error != B_OK) 2532 return error; 2533 RequestReleaser requestReleaser(port, reply); 2534 2535 // process the reply 2536 if (reply->error != B_OK) 2537 return reply->error; 2538 return error; 2539 } 2540 2541 // ReadIndexStat 2542 status_t 2543 Volume::ReadIndexStat(const char* name, struct stat *st) 2544 { 2545 // check capability 2546 if (!fFileSystem->HasCapability(FS_CAPABILITY_READ_INDEX_STAT)) 2547 return B_BAD_VALUE; 2548 2549 // get a free port 2550 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 2551 if (!port) 2552 return B_ERROR; 2553 PortReleaser _(fFileSystem->GetPortPool(), port); 2554 2555 // prepare the request 2556 RequestAllocator allocator(port->GetPort()); 2557 ReadIndexStatRequest* request; 2558 status_t error = AllocateRequest(allocator, &request); 2559 if (error != B_OK) 2560 return error; 2561 2562 request->volume = fUserlandVolume; 2563 error = allocator.AllocateString(request->name, name); 2564 if (error != B_OK) 2565 return error; 2566 2567 // send the request 2568 KernelRequestHandler handler(this, READ_INDEX_STAT_REPLY); 2569 ReadIndexStatReply* reply; 2570 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 2571 if (error != B_OK) 2572 return error; 2573 RequestReleaser requestReleaser(port, reply); 2574 2575 // process the reply 2576 if (reply->error != B_OK) 2577 return reply->error; 2578 *st = reply->st; 2579 return error; 2580 } 2581 2582 2583 // #pragma mark - queries 2584 2585 2586 // OpenQuery 2587 status_t 2588 Volume::OpenQuery(const char* queryString, uint32 flags, port_id targetPort, 2589 uint32 token, fs_cookie *cookie) 2590 { 2591 // check capability 2592 if (!fFileSystem->HasCapability(FS_CAPABILITY_OPEN_QUERY)) 2593 return B_BAD_VALUE; 2594 2595 // get a free port 2596 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 2597 if (!port) 2598 return B_ERROR; 2599 PortReleaser _(fFileSystem->GetPortPool(), port); 2600 AutoIncrementer incrementer(&fOpenQueries); 2601 2602 // prepare the request 2603 RequestAllocator allocator(port->GetPort()); 2604 OpenQueryRequest* request; 2605 status_t error = AllocateRequest(allocator, &request); 2606 if (error != B_OK) 2607 return error; 2608 2609 request->volume = fUserlandVolume; 2610 error = allocator.AllocateString(request->queryString, queryString); 2611 if (error != B_OK) 2612 return error; 2613 request->flags = flags; 2614 request->port = targetPort; 2615 request->token = token; 2616 2617 // send the request 2618 KernelRequestHandler handler(this, OPEN_QUERY_REPLY); 2619 OpenQueryReply* reply; 2620 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 2621 if (error != B_OK) 2622 return error; 2623 RequestReleaser requestReleaser(port, reply); 2624 2625 // process the reply 2626 if (reply->error != B_OK) 2627 return reply->error; 2628 incrementer.Keep(); 2629 *cookie = reply->queryCookie; 2630 return error; 2631 } 2632 2633 // CloseQuery 2634 status_t 2635 Volume::CloseQuery(fs_cookie cookie) 2636 { 2637 status_t error = _CloseQuery(cookie); 2638 if (error != B_OK && fFileSystem->GetPortPool()->IsDisconnected()) { 2639 // This isn't really necessary, as the return value is irrelevant to 2640 // the VFS. OBOS ignores it completely. The fsshell returns it to the 2641 // userland, but considers the node closed anyway. 2642 WARN(("Volume::CloseQuery(): connection lost, forcing close query\n")); 2643 return B_OK; 2644 } 2645 return error; 2646 } 2647 2648 // FreeQueryCookie 2649 status_t 2650 Volume::FreeQueryCookie(fs_cookie cookie) 2651 { 2652 status_t error = _FreeQueryCookie(cookie); 2653 bool disconnected = false; 2654 if (error != B_OK && fFileSystem->GetPortPool()->IsDisconnected()) { 2655 // This isn't really necessary, as the return value is irrelevant to 2656 // the VFS. It's completely ignored by OBOS as well as by the fsshell. 2657 WARN(("Volume::FreeQueryCookie(): connection lost, forcing free " 2658 "query cookie\n")); 2659 error = B_OK; 2660 disconnected = true; 2661 } 2662 2663 int32 openQueries = atomic_add(&fOpenQueries, -1); 2664 if (openQueries <= 1 && disconnected) 2665 _PutAllPendingVNodes(); 2666 return error; 2667 } 2668 2669 // ReadQuery 2670 status_t 2671 Volume::ReadQuery(fs_cookie cookie, void* buffer, size_t bufferSize, 2672 uint32 count, uint32* countRead) 2673 { 2674 *countRead = 0; 2675 2676 // check capability 2677 if (!fFileSystem->HasCapability(FS_CAPABILITY_READ_QUERY)) 2678 return B_BAD_VALUE; 2679 2680 // get a free port 2681 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 2682 if (!port) 2683 return B_ERROR; 2684 PortReleaser _(fFileSystem->GetPortPool(), port); 2685 2686 // prepare the request 2687 RequestAllocator allocator(port->GetPort()); 2688 ReadQueryRequest* request; 2689 status_t error = AllocateRequest(allocator, &request); 2690 if (error != B_OK) 2691 return error; 2692 2693 request->volume = fUserlandVolume; 2694 request->queryCookie = cookie; 2695 request->bufferSize = bufferSize; 2696 request->count = count; 2697 2698 // send the request 2699 KernelRequestHandler handler(this, READ_QUERY_REPLY); 2700 ReadQueryReply* reply; 2701 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 2702 if (error != B_OK) 2703 return error; 2704 RequestReleaser requestReleaser(port, reply); 2705 2706 // process the reply 2707 if (reply->error != B_OK) 2708 return reply->error; 2709 if (reply->count < 0 || reply->count > count) 2710 return B_BAD_DATA; 2711 if ((int32)bufferSize < reply->buffer.GetSize()) 2712 return B_BAD_DATA; 2713 2714 *countRead = reply->count; 2715 if (*countRead > 0) { 2716 // copy the buffer -- limit the number of bytes to copy 2717 uint32 maxBytes = *countRead 2718 * (sizeof(struct dirent) + B_FILE_NAME_LENGTH); 2719 uint32 copyBytes = reply->buffer.GetSize(); 2720 if (copyBytes > maxBytes) 2721 copyBytes = maxBytes; 2722 memcpy(buffer, reply->buffer.GetData(), copyBytes); 2723 } 2724 _SendReceiptAck(port); 2725 return error; 2726 } 2727 2728 // RewindQuery 2729 status_t 2730 Volume::RewindQuery(fs_cookie cookie) 2731 { 2732 // check capability 2733 if (!fFileSystem->HasCapability(FS_CAPABILITY_REWIND_QUERY)) 2734 return B_BAD_VALUE; 2735 2736 // get a free port 2737 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 2738 if (!port) 2739 return B_ERROR; 2740 PortReleaser _(fFileSystem->GetPortPool(), port); 2741 2742 // prepare the request 2743 RequestAllocator allocator(port->GetPort()); 2744 RewindQueryRequest* request; 2745 status_t error = AllocateRequest(allocator, &request); 2746 if (error != B_OK) 2747 return error; 2748 2749 request->volume = fUserlandVolume; 2750 request->queryCookie = cookie; 2751 2752 // send the request 2753 KernelRequestHandler handler(this, REWIND_QUERY_REPLY); 2754 RewindQueryReply* reply; 2755 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 2756 if (error != B_OK) 2757 return error; 2758 RequestReleaser requestReleaser(port, reply); 2759 2760 // process the reply 2761 if (reply->error != B_OK) 2762 return reply->error; 2763 return error; 2764 } 2765 2766 // #pragma mark - 2767 // #pragma mark ----- private implementations ----- 2768 2769 // _Mount 2770 status_t 2771 Volume::_Mount(const char* device, uint32 flags, const char* parameters) 2772 { 2773 // get a free port 2774 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 2775 if (!port) 2776 return B_ERROR; 2777 PortReleaser _(fFileSystem->GetPortPool(), port); 2778 2779 // get the current working directory 2780 char cwd[B_PATH_NAME_LENGTH]; 2781 if (!getcwd(cwd, sizeof(cwd))) 2782 return errno; 2783 2784 // prepare the request 2785 RequestAllocator allocator(port->GetPort()); 2786 MountVolumeRequest* request; 2787 status_t error = AllocateRequest(allocator, &request); 2788 if (error != B_OK) 2789 return error; 2790 2791 request->nsid = fID; 2792 error = allocator.AllocateString(request->cwd, cwd); 2793 if (error == B_OK) 2794 error = allocator.AllocateString(request->device, device); 2795 request->flags = flags; 2796 if (error == B_OK) 2797 error = allocator.AllocateString(request->parameters, parameters); 2798 if (error != B_OK) 2799 return error; 2800 2801 // send the request 2802 KernelRequestHandler handler(this, MOUNT_VOLUME_REPLY); 2803 MountVolumeReply* reply; 2804 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 2805 if (error != B_OK) 2806 return error; 2807 RequestReleaser requestReleaser(port, reply); 2808 2809 // process the reply 2810 if (reply->error != B_OK) 2811 return reply->error; 2812 fRootID = reply->rootID; 2813 fUserlandVolume = reply->volume; 2814 2815 // enable vnode counting 2816 fVNodeCountMap = new(nothrow) VNodeCountMap; 2817 if (fVNodeCountMap) 2818 fVNodeCountingEnabled = true; 2819 else 2820 ERROR(("Failed to allocate vnode count map.")); 2821 return error; 2822 } 2823 2824 // _Unmount 2825 status_t 2826 Volume::_Unmount() 2827 { 2828 // get a free port 2829 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 2830 if (!port) 2831 return B_ERROR; 2832 PortReleaser _(fFileSystem->GetPortPool(), port); 2833 2834 // prepare the request 2835 RequestAllocator allocator(port->GetPort()); 2836 UnmountVolumeRequest* request; 2837 status_t error = AllocateRequest(allocator, &request); 2838 if (error != B_OK) 2839 return error; 2840 2841 request->volume = fUserlandVolume; 2842 2843 // send the request 2844 KernelRequestHandler handler(this, UNMOUNT_VOLUME_REPLY); 2845 UnmountVolumeReply* reply; 2846 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 2847 if (error != B_OK) 2848 return error; 2849 RequestReleaser requestReleaser(port, reply); 2850 2851 // process the reply 2852 if (reply->error != B_OK) 2853 return reply->error; 2854 return error; 2855 } 2856 2857 // _ReadFSInfo 2858 status_t 2859 Volume::_ReadFSInfo(fs_info* info) 2860 { 2861 // check capability 2862 if (!fFileSystem->HasCapability(FS_CAPABILITY_READ_FS_INFO)) 2863 return B_BAD_VALUE; 2864 2865 // get a free port 2866 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 2867 if (!port) 2868 return B_ERROR; 2869 PortReleaser _(fFileSystem->GetPortPool(), port); 2870 2871 // prepare the request 2872 RequestAllocator allocator(port->GetPort()); 2873 ReadFSInfoRequest* request; 2874 status_t error = AllocateRequest(allocator, &request); 2875 if (error != B_OK) 2876 return error; 2877 2878 request->volume = fUserlandVolume; 2879 2880 // send the request 2881 KernelRequestHandler handler(this, READ_FS_INFO_REPLY); 2882 ReadFSInfoReply* reply; 2883 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 2884 if (error != B_OK) 2885 return error; 2886 RequestReleaser requestReleaser(port, reply); 2887 2888 // process the reply 2889 if (reply->error != B_OK) 2890 return reply->error; 2891 *info = reply->info; 2892 return error; 2893 } 2894 2895 // _Lookup 2896 status_t 2897 Volume::_Lookup(fs_vnode dir, const char* entryName, ino_t* vnid, int* type) 2898 { 2899 // get a free port 2900 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 2901 if (!port) 2902 return B_ERROR; 2903 PortReleaser _(fFileSystem->GetPortPool(), port); 2904 2905 // prepare the request 2906 RequestAllocator allocator(port->GetPort()); 2907 LookupRequest* request; 2908 status_t error = AllocateRequest(allocator, &request); 2909 if (error != B_OK) 2910 return error; 2911 request->volume = fUserlandVolume; 2912 request->node = dir; 2913 error = allocator.AllocateString(request->entryName, entryName); 2914 if (error != B_OK) 2915 return error; 2916 2917 // send the request 2918 KernelRequestHandler handler(this, LOOKUP_REPLY); 2919 LookupReply* reply; 2920 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 2921 if (error != B_OK) 2922 return error; 2923 RequestReleaser requestReleaser(port, reply); 2924 2925 // process the reply 2926 if (reply->error != B_OK) 2927 return reply->error; 2928 *vnid = reply->vnid; 2929 *type = reply->type; 2930 2931 // The VFS will balance the get_vnode() call for the FS. 2932 _DecrementVNodeCount(*vnid); 2933 return error; 2934 } 2935 2936 // _WriteVNode 2937 status_t 2938 Volume::_WriteVNode(fs_vnode node, bool reenter) 2939 { 2940 // get a free port 2941 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 2942 if (!port) 2943 return B_ERROR; 2944 PortReleaser _(fFileSystem->GetPortPool(), port); 2945 2946 // prepare the request 2947 RequestAllocator allocator(port->GetPort()); 2948 WriteVNodeRequest* request; 2949 status_t error = AllocateRequest(allocator, &request); 2950 if (error != B_OK) 2951 return error; 2952 request->volume = fUserlandVolume; 2953 request->node = node; 2954 request->reenter = reenter; 2955 2956 // send the request 2957 KernelRequestHandler handler(this, WRITE_VNODE_REPLY); 2958 WriteVNodeReply* reply; 2959 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 2960 if (error != B_OK) 2961 return error; 2962 RequestReleaser requestReleaser(port, reply); 2963 2964 // process the reply 2965 if (reply->error != B_OK) 2966 return reply->error; 2967 return error; 2968 } 2969 2970 // _ReadStat 2971 status_t 2972 Volume::_ReadStat(fs_vnode node, struct stat* st) 2973 { 2974 // check capability 2975 if (!fFileSystem->HasCapability(FS_CAPABILITY_READ_STAT)) 2976 return B_BAD_VALUE; 2977 2978 // get a free port 2979 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 2980 if (!port) 2981 return B_ERROR; 2982 PortReleaser _(fFileSystem->GetPortPool(), port); 2983 2984 // prepare the request 2985 RequestAllocator allocator(port->GetPort()); 2986 ReadStatRequest* request; 2987 status_t error = AllocateRequest(allocator, &request); 2988 if (error != B_OK) 2989 return error; 2990 2991 request->volume = fUserlandVolume; 2992 request->node = node; 2993 2994 // send the request 2995 KernelRequestHandler handler(this, READ_STAT_REPLY); 2996 ReadStatReply* reply; 2997 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 2998 if (error != B_OK) 2999 return error; 3000 RequestReleaser requestReleaser(port, reply); 3001 3002 // process the reply 3003 if (reply->error != B_OK) 3004 return reply->error; 3005 *st = reply->st; 3006 return error; 3007 } 3008 3009 // _Close 3010 status_t 3011 Volume::_Close(fs_vnode node, fs_cookie cookie) 3012 { 3013 // check capability 3014 if (!fFileSystem->HasCapability(FS_CAPABILITY_CLOSE)) 3015 return B_OK; 3016 3017 // get a free port 3018 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 3019 if (!port) 3020 return B_ERROR; 3021 PortReleaser _(fFileSystem->GetPortPool(), port); 3022 3023 // prepare the request 3024 RequestAllocator allocator(port->GetPort()); 3025 CloseRequest* request; 3026 status_t error = AllocateRequest(allocator, &request); 3027 if (error != B_OK) 3028 return error; 3029 3030 request->volume = fUserlandVolume; 3031 request->node = node; 3032 request->fileCookie = cookie; 3033 3034 // send the request 3035 KernelRequestHandler handler(this, CLOSE_REPLY); 3036 CloseReply* reply; 3037 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 3038 if (error != B_OK) 3039 return error; 3040 RequestReleaser requestReleaser(port, reply); 3041 3042 // process the reply 3043 if (reply->error != B_OK) 3044 return reply->error; 3045 return error; 3046 } 3047 3048 // _FreeCookie 3049 status_t 3050 Volume::_FreeCookie(fs_vnode node, fs_cookie cookie) 3051 { 3052 // check capability 3053 if (!fFileSystem->HasCapability(FS_CAPABILITY_FREE_COOKIE)) 3054 return B_OK; 3055 3056 // get a free port 3057 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 3058 if (!port) 3059 return B_ERROR; 3060 PortReleaser _(fFileSystem->GetPortPool(), port); 3061 3062 // prepare the request 3063 RequestAllocator allocator(port->GetPort()); 3064 FreeCookieRequest* request; 3065 status_t error = AllocateRequest(allocator, &request); 3066 if (error != B_OK) 3067 return error; 3068 3069 request->volume = fUserlandVolume; 3070 request->node = node; 3071 request->fileCookie = cookie; 3072 3073 // send the request 3074 KernelRequestHandler handler(this, FREE_COOKIE_REPLY); 3075 FreeCookieReply* reply; 3076 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 3077 if (error != B_OK) 3078 return error; 3079 RequestReleaser requestReleaser(port, reply); 3080 3081 // process the reply 3082 if (reply->error != B_OK) 3083 return reply->error; 3084 return error; 3085 } 3086 3087 // _CloseDir 3088 status_t 3089 Volume::_CloseDir(fs_vnode node, fs_vnode cookie) 3090 { 3091 // check capability 3092 if (!fFileSystem->HasCapability(FS_CAPABILITY_CLOSE_DIR)) 3093 return B_OK; 3094 3095 // get a free port 3096 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 3097 if (!port) 3098 return B_ERROR; 3099 PortReleaser _(fFileSystem->GetPortPool(), port); 3100 3101 // prepare the request 3102 RequestAllocator allocator(port->GetPort()); 3103 CloseDirRequest* request; 3104 status_t error = AllocateRequest(allocator, &request); 3105 if (error != B_OK) 3106 return error; 3107 3108 request->volume = fUserlandVolume; 3109 request->node = node; 3110 request->dirCookie = cookie; 3111 3112 // send the request 3113 KernelRequestHandler handler(this, CLOSE_DIR_REPLY); 3114 CloseDirReply* reply; 3115 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 3116 if (error != B_OK) 3117 return error; 3118 RequestReleaser requestReleaser(port, reply); 3119 3120 // process the reply 3121 if (reply->error != B_OK) 3122 return reply->error; 3123 return error; 3124 } 3125 3126 // _FreeDirCookie 3127 status_t 3128 Volume::_FreeDirCookie(fs_vnode node, fs_vnode cookie) 3129 { 3130 // check capability 3131 if (!fFileSystem->HasCapability(FS_CAPABILITY_FREE_DIR_COOKIE)) 3132 return B_OK; 3133 3134 // get a free port 3135 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 3136 if (!port) 3137 return B_ERROR; 3138 PortReleaser _(fFileSystem->GetPortPool(), port); 3139 3140 // prepare the request 3141 RequestAllocator allocator(port->GetPort()); 3142 FreeDirCookieRequest* request; 3143 status_t error = AllocateRequest(allocator, &request); 3144 if (error != B_OK) 3145 return error; 3146 3147 request->volume = fUserlandVolume; 3148 request->node = node; 3149 request->dirCookie = cookie; 3150 3151 // send the request 3152 KernelRequestHandler handler(this, FREE_DIR_COOKIE_REPLY); 3153 FreeDirCookieReply* reply; 3154 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 3155 if (error != B_OK) 3156 return error; 3157 RequestReleaser requestReleaser(port, reply); 3158 3159 // process the reply 3160 if (reply->error != B_OK) 3161 return reply->error; 3162 return error; 3163 } 3164 3165 // _CloseAttrDir 3166 status_t 3167 Volume::_CloseAttrDir(fs_vnode node, fs_cookie cookie) 3168 { 3169 // check capability 3170 if (!fFileSystem->HasCapability(FS_CAPABILITY_CLOSE_ATTR_DIR)) 3171 return B_OK; 3172 3173 // get a free port 3174 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 3175 if (!port) 3176 return B_ERROR; 3177 PortReleaser _(fFileSystem->GetPortPool(), port); 3178 3179 // prepare the request 3180 RequestAllocator allocator(port->GetPort()); 3181 CloseAttrDirRequest* request; 3182 status_t error = AllocateRequest(allocator, &request); 3183 if (error != B_OK) 3184 return error; 3185 3186 request->volume = fUserlandVolume; 3187 request->node = node; 3188 request->attrDirCookie = cookie; 3189 3190 // send the request 3191 KernelRequestHandler handler(this, CLOSE_ATTR_DIR_REPLY); 3192 CloseAttrDirReply* reply; 3193 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 3194 if (error != B_OK) 3195 return error; 3196 RequestReleaser requestReleaser(port, reply); 3197 3198 // process the reply 3199 if (reply->error != B_OK) 3200 return reply->error; 3201 return error; 3202 } 3203 3204 // _FreeAttrDirCookie 3205 status_t 3206 Volume::_FreeAttrDirCookie(fs_vnode node, fs_cookie cookie) 3207 { 3208 // check capability 3209 if (!fFileSystem->HasCapability(FS_CAPABILITY_FREE_ATTR_DIR_COOKIE)) 3210 return B_OK; 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 FreeAttrDirCookieRequest* request; 3221 status_t error = AllocateRequest(allocator, &request); 3222 if (error != B_OK) 3223 return error; 3224 3225 request->volume = fUserlandVolume; 3226 request->node = node; 3227 request->attrDirCookie = cookie; 3228 3229 // send the request 3230 KernelRequestHandler handler(this, FREE_ATTR_DIR_COOKIE_REPLY); 3231 FreeAttrDirCookieReply* reply; 3232 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 3233 if (error != B_OK) 3234 return error; 3235 RequestReleaser requestReleaser(port, reply); 3236 3237 // process the reply 3238 if (reply->error != B_OK) 3239 return reply->error; 3240 return error; 3241 } 3242 3243 // _CloseAttr 3244 status_t 3245 Volume::_CloseAttr(fs_vnode node, fs_cookie cookie) 3246 { 3247 // check capability 3248 if (!fFileSystem->HasCapability(FS_CAPABILITY_CLOSE_ATTR)) 3249 return B_OK; 3250 3251 // get a free port 3252 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 3253 if (!port) 3254 return B_ERROR; 3255 PortReleaser _(fFileSystem->GetPortPool(), port); 3256 3257 // prepare the request 3258 RequestAllocator allocator(port->GetPort()); 3259 CloseAttrRequest* request; 3260 status_t error = AllocateRequest(allocator, &request); 3261 if (error != B_OK) 3262 return error; 3263 3264 request->volume = fUserlandVolume; 3265 request->node = node; 3266 request->attrCookie = cookie; 3267 3268 // send the request 3269 KernelRequestHandler handler(this, CLOSE_ATTR_REPLY); 3270 CloseAttrReply* reply; 3271 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 3272 if (error != B_OK) 3273 return error; 3274 RequestReleaser requestReleaser(port, reply); 3275 3276 // process the reply 3277 if (reply->error != B_OK) 3278 return reply->error; 3279 return error; 3280 } 3281 3282 // _FreeAttrCookie 3283 status_t 3284 Volume::_FreeAttrCookie(fs_vnode node, fs_cookie cookie) 3285 { 3286 // check capability 3287 if (!fFileSystem->HasCapability(FS_CAPABILITY_FREE_ATTR_COOKIE)) 3288 return B_OK; 3289 3290 // get a free port 3291 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 3292 if (!port) 3293 return B_ERROR; 3294 PortReleaser _(fFileSystem->GetPortPool(), port); 3295 3296 // prepare the request 3297 RequestAllocator allocator(port->GetPort()); 3298 FreeAttrCookieRequest* request; 3299 status_t error = AllocateRequest(allocator, &request); 3300 if (error != B_OK) 3301 return error; 3302 3303 request->volume = fUserlandVolume; 3304 request->node = node; 3305 request->attrCookie = cookie; 3306 3307 // send the request 3308 KernelRequestHandler handler(this, FREE_ATTR_COOKIE_REPLY); 3309 FreeAttrCookieReply* reply; 3310 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 3311 if (error != B_OK) 3312 return error; 3313 RequestReleaser requestReleaser(port, reply); 3314 3315 // process the reply 3316 if (reply->error != B_OK) 3317 return reply->error; 3318 return error; 3319 } 3320 3321 // _CloseIndexDir 3322 status_t 3323 Volume::_CloseIndexDir(fs_cookie cookie) 3324 { 3325 // check capability 3326 if (!fFileSystem->HasCapability(FS_CAPABILITY_CLOSE_INDEX_DIR)) 3327 return B_OK; 3328 3329 // get a free port 3330 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 3331 if (!port) 3332 return B_ERROR; 3333 PortReleaser _(fFileSystem->GetPortPool(), port); 3334 3335 // prepare the request 3336 RequestAllocator allocator(port->GetPort()); 3337 CloseIndexDirRequest* request; 3338 status_t error = AllocateRequest(allocator, &request); 3339 if (error != B_OK) 3340 return error; 3341 3342 request->volume = fUserlandVolume; 3343 request->indexDirCookie = cookie; 3344 3345 // send the request 3346 KernelRequestHandler handler(this, CLOSE_INDEX_DIR_REPLY); 3347 CloseIndexDirReply* reply; 3348 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 3349 if (error != B_OK) 3350 return error; 3351 RequestReleaser requestReleaser(port, reply); 3352 3353 // process the reply 3354 if (reply->error != B_OK) 3355 return reply->error; 3356 return error; 3357 } 3358 3359 // _FreeIndexDirCookie 3360 status_t 3361 Volume::_FreeIndexDirCookie(fs_cookie cookie) 3362 { 3363 // check capability 3364 if (!fFileSystem->HasCapability(FS_CAPABILITY_FREE_INDEX_DIR_COOKIE)) 3365 return B_OK; 3366 3367 // get a free port 3368 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 3369 if (!port) 3370 return B_ERROR; 3371 PortReleaser _(fFileSystem->GetPortPool(), port); 3372 3373 // prepare the request 3374 RequestAllocator allocator(port->GetPort()); 3375 FreeIndexDirCookieRequest* request; 3376 status_t error = AllocateRequest(allocator, &request); 3377 if (error != B_OK) 3378 return error; 3379 3380 request->volume = fUserlandVolume; 3381 request->indexDirCookie = cookie; 3382 3383 // send the request 3384 KernelRequestHandler handler(this, FREE_INDEX_DIR_COOKIE_REPLY); 3385 FreeIndexDirCookieReply* reply; 3386 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 3387 if (error != B_OK) 3388 return error; 3389 RequestReleaser requestReleaser(port, reply); 3390 3391 // process the reply 3392 if (reply->error != B_OK) 3393 return reply->error; 3394 return error; 3395 } 3396 3397 // _CloseQuery 3398 status_t 3399 Volume::_CloseQuery(fs_cookie cookie) 3400 { 3401 // check capability 3402 if (!fFileSystem->HasCapability(FS_CAPABILITY_CLOSE_QUERY)) 3403 return B_OK; 3404 3405 // get a free port 3406 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 3407 if (!port) 3408 return B_ERROR; 3409 PortReleaser _(fFileSystem->GetPortPool(), port); 3410 3411 // prepare the request 3412 RequestAllocator allocator(port->GetPort()); 3413 CloseQueryRequest* request; 3414 status_t error = AllocateRequest(allocator, &request); 3415 if (error != B_OK) 3416 return error; 3417 3418 request->volume = fUserlandVolume; 3419 request->queryCookie = cookie; 3420 3421 // send the request 3422 KernelRequestHandler handler(this, CLOSE_QUERY_REPLY); 3423 CloseQueryReply* reply; 3424 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 3425 if (error != B_OK) 3426 return error; 3427 RequestReleaser requestReleaser(port, reply); 3428 3429 // process the reply 3430 if (reply->error != B_OK) 3431 return reply->error; 3432 return error; 3433 } 3434 3435 // _FreeQueryCookie 3436 status_t 3437 Volume::_FreeQueryCookie(fs_cookie cookie) 3438 { 3439 // check capability 3440 if (!fFileSystem->HasCapability(FS_CAPABILITY_FREE_QUERY_COOKIE)) 3441 return B_OK; 3442 3443 // get a free port 3444 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 3445 if (!port) 3446 return B_ERROR; 3447 PortReleaser _(fFileSystem->GetPortPool(), port); 3448 3449 // prepare the request 3450 RequestAllocator allocator(port->GetPort()); 3451 FreeQueryCookieRequest* request; 3452 status_t error = AllocateRequest(allocator, &request); 3453 if (error != B_OK) 3454 return error; 3455 3456 request->volume = fUserlandVolume; 3457 request->queryCookie = cookie; 3458 3459 // send the request 3460 KernelRequestHandler handler(this, FREE_QUERY_COOKIE_REPLY); 3461 FreeQueryCookieReply* reply; 3462 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 3463 if (error != B_OK) 3464 return error; 3465 RequestReleaser requestReleaser(port, reply); 3466 3467 // process the reply 3468 if (reply->error != B_OK) 3469 return reply->error; 3470 return error; 3471 } 3472 3473 // _SendRequest 3474 status_t 3475 Volume::_SendRequest(RequestPort* port, RequestAllocator* allocator, 3476 RequestHandler* handler, Request** reply) 3477 { 3478 if (!fFileSystem->IsUserlandServerThread()) 3479 return port->SendRequest(allocator, handler, reply); 3480 // Here it gets dangerous: a thread of the userland server team being here 3481 // calls for trouble. We try receiving the request with a timeout, and 3482 // close the port -- which will disconnect the whole FS. 3483 status_t error = port->SendRequest(allocator, handler, reply, 3484 kUserlandServerlandPortTimeout); 3485 if (error == B_TIMED_OUT || error == B_WOULD_BLOCK) 3486 port->Close(); 3487 return error; 3488 } 3489 3490 // _SendReceiptAck 3491 status_t 3492 Volume::_SendReceiptAck(RequestPort* port) 3493 { 3494 RequestAllocator allocator(port->GetPort()); 3495 ReceiptAckReply* request; 3496 status_t error = AllocateRequest(allocator, &request); 3497 if (error != B_OK) 3498 return error; 3499 return port->SendRequest(&allocator); 3500 } 3501 3502 // _IncrementVNodeCount 3503 void 3504 Volume::_IncrementVNodeCount(ino_t vnid) 3505 { 3506 if (!fVNodeCountingEnabled) 3507 return; 3508 AutoLocker<VNodeCountMap> _(fVNodeCountMap); 3509 if (!fVNodeCountingEnabled) // someone may have changed it 3510 return; 3511 // get the counter 3512 int32* count = fVNodeCountMap->Get(vnid); 3513 if (!count) { 3514 // vnode not known yet: create and add a new counter 3515 count = new(nothrow) int32(0); 3516 if (!count) { 3517 ERROR(("Volume::_IncrementVNodeCount(): Failed to allocate " 3518 "counter. Disabling vnode counting.\n")); 3519 fVNodeCountingEnabled = false; 3520 return; 3521 } 3522 if (fVNodeCountMap->Put(vnid, count) != B_OK) { 3523 ERROR(("Volume::_IncrementVNodeCount(): Failed to add counter. " 3524 "Disabling vnode counting.\n")); 3525 delete count; 3526 fVNodeCountingEnabled = false; 3527 return; 3528 } 3529 } 3530 // increment the counter 3531 (*count)++; 3532 //PRINT(("_IncrementVNodeCount(%Ld): count: %ld, fVNodeCountMap size: %ld\n", vnid, *count, fVNodeCountMap->Size())); 3533 } 3534 3535 // _DecrementVNodeCount 3536 void 3537 Volume::_DecrementVNodeCount(ino_t vnid) 3538 { 3539 if (!fVNodeCountingEnabled) 3540 return; 3541 AutoLocker<VNodeCountMap> _(fVNodeCountMap); 3542 if (!fVNodeCountingEnabled) // someone may have changed it 3543 return; 3544 int32* count = fVNodeCountMap->Get(vnid); 3545 if (!count) { 3546 // that should never happen 3547 ERROR(("Volume::_DecrementVNodeCount(): Failed to get counter. " 3548 "Disabling vnode counting.\n")); 3549 fVNodeCountingEnabled = false; 3550 return; 3551 } 3552 (*count)--; 3553 //int32 tmpCount = *count; 3554 if (*count == 0) 3555 fVNodeCountMap->Remove(vnid); 3556 //PRINT(("_DecrementVNodeCount(%Ld): count: %ld, fVNodeCountMap size: %ld\n", vnid, tmpCount, fVNodeCountMap->Size())); 3557 } 3558 3559 // _InternalIOCtl 3560 status_t 3561 Volume::_InternalIOCtl(userlandfs_ioctl* buffer, int32 bufferSize) 3562 { 3563 if (buffer->version != USERLAND_IOCTL_CURRENT_VERSION) 3564 return B_BAD_VALUE; 3565 status_t result = B_OK; 3566 switch (buffer->command) { 3567 case USERLAND_IOCTL_PUT_ALL_PENDING_VNODES: 3568 result = _PutAllPendingVNodes(); 3569 break; 3570 default: 3571 return B_BAD_VALUE; 3572 } 3573 buffer->error = result; 3574 return B_OK; 3575 } 3576 3577 // _PutAllPendingVNodes 3578 status_t 3579 Volume::_PutAllPendingVNodes() 3580 { 3581 PRINT(("Volume::_PutAllPendingVNodes()\n")); 3582 if (!fFileSystem->GetPortPool()->IsDisconnected()) { 3583 PRINT(("Volume::_PutAllPendingVNodes() failed: still connected\n")); 3584 return USERLAND_IOCTL_STILL_CONNECTED; 3585 } 3586 if (!fVNodeCountingEnabled) { 3587 PRINT(("Volume::_PutAllPendingVNodes() failed: vnode counting " 3588 "disabled\n")); 3589 return USERLAND_IOCTL_VNODE_COUNTING_DISABLED; 3590 } 3591 { 3592 AutoLocker<VNodeCountMap> _(fVNodeCountMap); 3593 if (!fVNodeCountingEnabled) {// someone may have changed it 3594 PRINT(("Volume::_PutAllPendingVNodes() failed: vnode counting " 3595 "disabled\n")); 3596 return USERLAND_IOCTL_VNODE_COUNTING_DISABLED; 3597 } 3598 // Check whether there are open entities at the moment. 3599 if (fOpenFiles > 0) { 3600 PRINT(("Volume::_PutAllPendingVNodes() failed: open files\n")); 3601 return USERLAND_IOCTL_OPEN_FILES; 3602 } 3603 if (fOpenDirectories > 0) { 3604 PRINT(("Volume::_PutAllPendingVNodes() failed: open dirs\n")); 3605 return USERLAND_IOCTL_OPEN_DIRECTORIES; 3606 } 3607 if (fOpenAttributeDirectories > 0) { 3608 PRINT(("Volume::_PutAllPendingVNodes() failed: open attr dirs\n")); 3609 return USERLAND_IOCTL_OPEN_ATTRIBUTE_DIRECTORIES; 3610 } 3611 if (fOpenAttributes > 0) { 3612 PRINT(("Volume::_PutAllPendingVNodes() failed: open attributes\n")); 3613 return USERLAND_IOCTL_OPEN_ATTRIBUTES; 3614 } 3615 if (fOpenIndexDirectories > 0) { 3616 PRINT(("Volume::_PutAllPendingVNodes() failed: open index dirs\n")); 3617 return USERLAND_IOCTL_OPEN_INDEX_DIRECTORIES; 3618 } 3619 if (fOpenQueries > 0) { 3620 PRINT(("Volume::_PutAllPendingVNodes() failed: open queries\n")); 3621 return USERLAND_IOCTL_OPEN_QUERIES; 3622 } 3623 // No open entities. Since the port pool is disconnected, no new 3624 // entities can be opened. Disable node counting and put all pending 3625 // vnodes. 3626 fVNodeCountingEnabled = false; 3627 } 3628 int32 putVNodeCount = 0; 3629 for (VNodeCountMap::Iterator it = fVNodeCountMap->GetIterator(); 3630 it.HasNext();) { 3631 VNodeCountMap::Entry entry = it.Next(); 3632 int32 count = *entry.value; 3633 for (int32 i = 0; i < count; i++) { 3634 PutVNode(entry.key.value); 3635 putVNodeCount++; 3636 } 3637 } 3638 PRINT(("Volume::_PutAllPendingVNodes() successful: Put %ld vnodes\n", 3639 putVNodeCount)); 3640 return B_OK; 3641 } 3642 3643