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, 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->sync = sync; 761 762 // add a selectsync entry 763 error = fFileSystem->AddSelectSyncEntry(sync); 764 if (error != B_OK) 765 return error; 766 767 // send the request 768 KernelRequestHandler handler(this, SELECT_REPLY); 769 SelectReply* reply; 770 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 771 if (error != B_OK) { 772 fFileSystem->RemoveSelectSyncEntry(sync); 773 return error; 774 } 775 RequestReleaser requestReleaser(port, reply); 776 777 // process the reply 778 if (reply->error != B_OK) { 779 fFileSystem->RemoveSelectSyncEntry(sync); 780 return reply->error; 781 } 782 return error; 783 } 784 785 // Deselect 786 status_t 787 Volume::Deselect(fs_vnode node, fs_cookie cookie, uint8 event, selectsync* sync) 788 { 789 // check capability 790 if (!fFileSystem->HasCapability(FS_CAPABILITY_DESELECT)) 791 return B_OK; 792 793 struct SyncRemover { 794 SyncRemover(FileSystem* fs, selectsync* sync) 795 : fs(fs), sync(sync) {} 796 ~SyncRemover() { fs->RemoveSelectSyncEntry(sync); } 797 798 FileSystem* fs; 799 selectsync* sync; 800 } syncRemover(fFileSystem, sync); 801 802 // get a free port 803 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 804 if (!port) 805 return B_ERROR; 806 PortReleaser _(fFileSystem->GetPortPool(), port); 807 808 // prepare the request 809 RequestAllocator allocator(port->GetPort()); 810 DeselectRequest* request; 811 status_t error = AllocateRequest(allocator, &request); 812 if (error != B_OK) 813 return error; 814 815 request->volume = fUserlandVolume; 816 request->node = node; 817 request->fileCookie = cookie; 818 request->event = event; 819 request->sync = sync; 820 821 // send the request 822 KernelRequestHandler handler(this, DESELECT_REPLY); 823 DeselectReply* reply; 824 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 825 if (error != B_OK) 826 return error; 827 RequestReleaser requestReleaser(port, reply); 828 829 // process the reply 830 if (reply->error != B_OK) 831 return reply->error; 832 return error; 833 } 834 835 // FSync 836 status_t 837 Volume::FSync(fs_vnode node) 838 { 839 // check capability 840 if (!fFileSystem->HasCapability(FS_CAPABILITY_FSYNC)) 841 return B_BAD_VALUE; 842 843 // get a free port 844 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 845 if (!port) 846 return B_ERROR; 847 PortReleaser _(fFileSystem->GetPortPool(), port); 848 849 // prepare the request 850 RequestAllocator allocator(port->GetPort()); 851 FSyncRequest* request; 852 status_t error = AllocateRequest(allocator, &request); 853 if (error != B_OK) 854 return error; 855 856 request->volume = fUserlandVolume; 857 request->node = node; 858 859 // send the request 860 KernelRequestHandler handler(this, FSYNC_REPLY); 861 FSyncReply* reply; 862 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 863 if (error != B_OK) 864 return error; 865 RequestReleaser requestReleaser(port, reply); 866 867 // process the reply 868 if (reply->error != B_OK) 869 return reply->error; 870 return error; 871 } 872 873 // ReadSymlink 874 status_t 875 Volume::ReadSymlink(fs_vnode node, char* buffer, size_t bufferSize, 876 size_t* bytesRead) 877 { 878 *bytesRead = 0; 879 880 // check capability 881 if (!fFileSystem->HasCapability(FS_CAPABILITY_READ_SYMLINK)) 882 return B_BAD_VALUE; 883 884 // get a free port 885 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 886 if (!port) 887 return B_ERROR; 888 PortReleaser _(fFileSystem->GetPortPool(), port); 889 890 // prepare the request 891 RequestAllocator allocator(port->GetPort()); 892 ReadSymlinkRequest* request; 893 status_t error = AllocateRequest(allocator, &request); 894 if (error != B_OK) 895 return error; 896 897 request->volume = fUserlandVolume; 898 request->node = node; 899 request->size = bufferSize; 900 901 // send the request 902 KernelRequestHandler handler(this, READ_SYMLINK_REPLY); 903 ReadSymlinkReply* reply; 904 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 905 if (error != B_OK) 906 return error; 907 RequestReleaser requestReleaser(port, reply); 908 909 // process the reply 910 if (reply->error != B_OK) 911 return reply->error; 912 void* readBuffer = reply->buffer.GetData(); 913 if (reply->bytesRead > (uint32)reply->buffer.GetSize() 914 || reply->bytesRead > bufferSize) { 915 return B_BAD_DATA; 916 } 917 if (reply->bytesRead > 0) 918 memcpy(buffer, readBuffer, reply->bytesRead); 919 *bytesRead = reply->bytesRead; 920 _SendReceiptAck(port); 921 return error; 922 } 923 924 // CreateSymlink 925 status_t 926 Volume::CreateSymlink(fs_vnode dir, const char* name, const char* target, 927 int mode) 928 { 929 // check capability 930 if (!fFileSystem->HasCapability(FS_CAPABILITY_CREATE_SYMLINK)) 931 return B_BAD_VALUE; 932 933 // get a free port 934 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 935 if (!port) 936 return B_ERROR; 937 PortReleaser _(fFileSystem->GetPortPool(), port); 938 939 // prepare the request 940 RequestAllocator allocator(port->GetPort()); 941 CreateSymlinkRequest* request; 942 status_t error = AllocateRequest(allocator, &request); 943 if (error != B_OK) 944 return error; 945 946 request->volume = fUserlandVolume; 947 request->node = dir; 948 error = allocator.AllocateString(request->name, name); 949 if (error == B_OK) 950 error = allocator.AllocateString(request->target, target); 951 if (error != B_OK) 952 return error; 953 request->mode = mode; 954 955 // send the request 956 KernelRequestHandler handler(this, CREATE_SYMLINK_REPLY); 957 CreateSymlinkReply* reply; 958 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 959 if (error != B_OK) 960 return error; 961 RequestReleaser requestReleaser(port, reply); 962 963 // process the reply 964 if (reply->error != B_OK) 965 return reply->error; 966 return error; 967 } 968 969 // Link 970 status_t 971 Volume::Link(fs_vnode dir, const char* name, fs_vnode node) 972 { 973 // check capability 974 if (!fFileSystem->HasCapability(FS_CAPABILITY_LINK)) 975 return B_BAD_VALUE; 976 977 // get a free port 978 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 979 if (!port) 980 return B_ERROR; 981 PortReleaser _(fFileSystem->GetPortPool(), port); 982 983 // prepare the request 984 RequestAllocator allocator(port->GetPort()); 985 LinkRequest* request; 986 status_t error = AllocateRequest(allocator, &request); 987 if (error != B_OK) 988 return error; 989 990 request->volume = fUserlandVolume; 991 request->node = dir; 992 error = allocator.AllocateString(request->name, name); 993 request->target = node; 994 if (error != B_OK) 995 return error; 996 997 // send the request 998 KernelRequestHandler handler(this, LINK_REPLY); 999 LinkReply* reply; 1000 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 1001 if (error != B_OK) 1002 return error; 1003 RequestReleaser requestReleaser(port, reply); 1004 1005 // process the reply 1006 if (reply->error != B_OK) 1007 return reply->error; 1008 return error; 1009 } 1010 1011 // Unlink 1012 status_t 1013 Volume::Unlink(fs_vnode dir, const char* name) 1014 { 1015 // check capability 1016 if (!fFileSystem->HasCapability(FS_CAPABILITY_UNLINK)) 1017 return B_BAD_VALUE; 1018 1019 // get a free port 1020 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 1021 if (!port) 1022 return B_ERROR; 1023 PortReleaser _(fFileSystem->GetPortPool(), port); 1024 1025 // prepare the request 1026 RequestAllocator allocator(port->GetPort()); 1027 UnlinkRequest* request; 1028 status_t error = AllocateRequest(allocator, &request); 1029 if (error != B_OK) 1030 return error; 1031 1032 request->volume = fUserlandVolume; 1033 request->node = dir; 1034 error = allocator.AllocateString(request->name, name); 1035 if (error != B_OK) 1036 return error; 1037 1038 // send the request 1039 KernelRequestHandler handler(this, UNLINK_REPLY); 1040 UnlinkReply* reply; 1041 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 1042 if (error != B_OK) 1043 return error; 1044 RequestReleaser requestReleaser(port, reply); 1045 1046 // process the reply 1047 if (reply->error != B_OK) 1048 return reply->error; 1049 return error; 1050 } 1051 1052 // Rename 1053 status_t 1054 Volume::Rename(fs_vnode oldDir, const char* oldName, fs_vnode newDir, 1055 const char* newName) 1056 { 1057 // check capability 1058 if (!fFileSystem->HasCapability(FS_CAPABILITY_RENAME)) 1059 return B_BAD_VALUE; 1060 1061 // get a free port 1062 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 1063 if (!port) 1064 return B_ERROR; 1065 PortReleaser _(fFileSystem->GetPortPool(), port); 1066 1067 // prepare the request 1068 RequestAllocator allocator(port->GetPort()); 1069 RenameRequest* request; 1070 status_t error = AllocateRequest(allocator, &request); 1071 if (error != B_OK) 1072 return error; 1073 1074 request->volume = fUserlandVolume; 1075 request->oldDir = oldDir; 1076 request->newDir = newDir; 1077 error = allocator.AllocateString(request->oldName, oldName); 1078 if (error == B_OK) 1079 error = allocator.AllocateString(request->newName, newName); 1080 if (error != B_OK) 1081 return error; 1082 1083 // send the request 1084 KernelRequestHandler handler(this, RENAME_REPLY); 1085 RenameReply* reply; 1086 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 1087 if (error != B_OK) 1088 return error; 1089 RequestReleaser requestReleaser(port, reply); 1090 1091 // process the reply 1092 if (reply->error != B_OK) 1093 return reply->error; 1094 return error; 1095 } 1096 1097 // Access 1098 status_t 1099 Volume::Access(fs_vnode node, int mode) 1100 { 1101 // check capability 1102 if (!fFileSystem->HasCapability(FS_CAPABILITY_ACCESS)) 1103 return B_OK; 1104 1105 // get a free port 1106 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 1107 if (!port) 1108 return B_ERROR; 1109 PortReleaser _(fFileSystem->GetPortPool(), port); 1110 1111 // prepare the request 1112 RequestAllocator allocator(port->GetPort()); 1113 AccessRequest* request; 1114 status_t error = AllocateRequest(allocator, &request); 1115 if (error != B_OK) 1116 return error; 1117 1118 request->volume = fUserlandVolume; 1119 request->node = node; 1120 request->mode = mode; 1121 1122 // send the request 1123 KernelRequestHandler handler(this, ACCESS_REPLY); 1124 AccessReply* reply; 1125 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 1126 if (error != B_OK) 1127 return error; 1128 RequestReleaser requestReleaser(port, reply); 1129 1130 // process the reply 1131 if (reply->error != B_OK) 1132 return reply->error; 1133 return error; 1134 } 1135 1136 // ReadStat 1137 status_t 1138 Volume::ReadStat(fs_vnode node, struct stat* st) 1139 { 1140 // When the connection to the userland server is lost, we serve 1141 // read_stat(fRootNode) requests manually to allow clean unmounting. 1142 status_t error = _ReadStat(node, st); 1143 if (error != B_OK && fFileSystem->GetPortPool()->IsDisconnected() 1144 && node == fRootNode) { 1145 WARN(("Volume::ReadStat(): connection lost, emulating stat for the " 1146 "root node\n")); 1147 1148 st->st_dev = fID; 1149 st->st_ino = fRootID; 1150 st->st_mode = ACCESSPERMS; 1151 st->st_nlink = 1; 1152 st->st_uid = 0; 1153 st->st_gid = 0; 1154 st->st_size = 512; 1155 st->st_blksize = 512; 1156 st->st_atime = 0; 1157 st->st_mtime = 0; 1158 st->st_ctime = 0; 1159 st->st_crtime = 0; 1160 1161 error = B_OK; 1162 } 1163 return error; 1164 } 1165 1166 // WriteStat 1167 status_t 1168 Volume::WriteStat(fs_vnode node, const struct stat* st, uint32 mask) 1169 { 1170 // check capability 1171 if (!fFileSystem->HasCapability(FS_CAPABILITY_WRITE_STAT)) 1172 return B_BAD_VALUE; 1173 1174 // get a free port 1175 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 1176 if (!port) 1177 return B_ERROR; 1178 PortReleaser _(fFileSystem->GetPortPool(), port); 1179 1180 // prepare the request 1181 RequestAllocator allocator(port->GetPort()); 1182 WriteStatRequest* request; 1183 status_t error = AllocateRequest(allocator, &request); 1184 if (error != B_OK) 1185 return error; 1186 1187 request->volume = fUserlandVolume; 1188 request->node = node; 1189 request->st = *st; 1190 request->mask = mask; 1191 1192 // send the request 1193 KernelRequestHandler handler(this, WRITE_STAT_REPLY); 1194 WriteStatReply* reply; 1195 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 1196 if (error != B_OK) 1197 return error; 1198 RequestReleaser requestReleaser(port, reply); 1199 1200 // process the reply 1201 if (reply->error != B_OK) 1202 return reply->error; 1203 return error; 1204 } 1205 1206 1207 // #pragma mark - files 1208 1209 // Create 1210 status_t 1211 Volume::Create(fs_vnode dir, const char* name, int openMode, int mode, 1212 void** cookie, ino_t* vnid) 1213 { 1214 // check capability 1215 if (!fFileSystem->HasCapability(FS_CAPABILITY_CREATE)) 1216 return B_BAD_VALUE; 1217 1218 // get a free port 1219 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 1220 if (!port) 1221 return B_ERROR; 1222 PortReleaser _(fFileSystem->GetPortPool(), port); 1223 AutoIncrementer incrementer(&fOpenFiles); 1224 1225 // prepare the request 1226 RequestAllocator allocator(port->GetPort()); 1227 CreateRequest* request; 1228 status_t error = AllocateRequest(allocator, &request); 1229 if (error != B_OK) 1230 return error; 1231 1232 request->volume = fUserlandVolume; 1233 request->node = dir; 1234 error = allocator.AllocateString(request->name, name); 1235 request->openMode = openMode; 1236 request->mode = mode; 1237 if (error != B_OK) 1238 return error; 1239 1240 // send the request 1241 KernelRequestHandler handler(this, CREATE_REPLY); 1242 CreateReply* reply; 1243 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 1244 if (error != B_OK) 1245 return error; 1246 RequestReleaser requestReleaser(port, reply); 1247 1248 // process the reply 1249 if (reply->error != B_OK) 1250 return reply->error; 1251 incrementer.Keep(); 1252 *vnid = reply->vnid; 1253 *cookie = reply->fileCookie; 1254 // The VFS will balance the new_vnode() call for the FS. 1255 if (error == B_OK) 1256 _DecrementVNodeCount(*vnid); 1257 return error; 1258 } 1259 1260 // Open 1261 status_t 1262 Volume::Open(fs_vnode node, int openMode, fs_cookie* cookie) 1263 { 1264 // check capability 1265 if (!fFileSystem->HasCapability(FS_CAPABILITY_OPEN)) 1266 return B_BAD_VALUE; 1267 1268 // get a free port 1269 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 1270 if (!port) 1271 return B_ERROR; 1272 PortReleaser _(fFileSystem->GetPortPool(), port); 1273 AutoIncrementer incrementer(&fOpenFiles); 1274 1275 // prepare the request 1276 RequestAllocator allocator(port->GetPort()); 1277 OpenRequest* request; 1278 status_t error = AllocateRequest(allocator, &request); 1279 if (error != B_OK) 1280 return error; 1281 request->volume = fUserlandVolume; 1282 request->node = node; 1283 request->openMode = openMode; 1284 1285 // send the request 1286 KernelRequestHandler handler(this, OPEN_REPLY); 1287 OpenReply* reply; 1288 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 1289 if (error != B_OK) 1290 return error; 1291 RequestReleaser requestReleaser(port, reply); 1292 1293 // process the reply 1294 if (reply->error != B_OK) 1295 return reply->error; 1296 incrementer.Keep(); 1297 *cookie = reply->fileCookie; 1298 return error; 1299 } 1300 1301 // Close 1302 status_t 1303 Volume::Close(fs_vnode node, fs_cookie cookie) 1304 { 1305 status_t error = _Close(node, cookie); 1306 if (error != B_OK && fFileSystem->GetPortPool()->IsDisconnected()) { 1307 // This isn't really necessary, as the return value is irrelevant to 1308 // the VFS. OBOS ignores it completely. The fsshell returns it to the 1309 // userland, but considers the node closed anyway. 1310 WARN(("Volume::Close(): connection lost, forcing close\n")); 1311 return B_OK; 1312 } 1313 return error; 1314 } 1315 1316 // FreeCookie 1317 status_t 1318 Volume::FreeCookie(fs_vnode node, fs_cookie cookie) 1319 { 1320 status_t error = _FreeCookie(node, cookie); 1321 bool disconnected = false; 1322 if (error != B_OK && fFileSystem->GetPortPool()->IsDisconnected()) { 1323 // This isn't really necessary, as the return value is irrelevant to 1324 // the VFS. It's completely ignored by OBOS as well as by the fsshell. 1325 WARN(("Volume::FreeCookie(): connection lost, forcing free cookie\n")); 1326 error = B_OK; 1327 disconnected = true; 1328 } 1329 1330 int32 openFiles = atomic_add(&fOpenFiles, -1); 1331 if (openFiles <= 1 && disconnected) 1332 _PutAllPendingVNodes(); 1333 return error; 1334 } 1335 1336 // Read 1337 status_t 1338 Volume::Read(fs_vnode node, fs_cookie cookie, off_t pos, void* buffer, 1339 size_t bufferSize, size_t* bytesRead) 1340 { 1341 *bytesRead = 0; 1342 1343 // check capability 1344 if (!fFileSystem->HasCapability(FS_CAPABILITY_READ)) 1345 return B_BAD_VALUE; 1346 1347 // get a free port 1348 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 1349 if (!port) 1350 return B_ERROR; 1351 PortReleaser _(fFileSystem->GetPortPool(), port); 1352 1353 // prepare the request 1354 RequestAllocator allocator(port->GetPort()); 1355 ReadRequest* request; 1356 status_t error = AllocateRequest(allocator, &request); 1357 if (error != B_OK) 1358 return error; 1359 1360 request->volume = fUserlandVolume; 1361 request->node = node; 1362 request->fileCookie = cookie; 1363 request->pos = pos; 1364 request->size = bufferSize; 1365 1366 // send the request 1367 KernelRequestHandler handler(this, READ_REPLY); 1368 ReadReply* reply; 1369 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 1370 if (error != B_OK) 1371 return error; 1372 RequestReleaser requestReleaser(port, reply); 1373 1374 // process the reply 1375 if (reply->error != B_OK) 1376 return reply->error; 1377 void* readBuffer = reply->buffer.GetData(); 1378 if (reply->bytesRead > (uint32)reply->buffer.GetSize() 1379 || reply->bytesRead > bufferSize) { 1380 return B_BAD_DATA; 1381 } 1382 if (reply->bytesRead > 0) 1383 memcpy(buffer, readBuffer, reply->bytesRead); 1384 *bytesRead = reply->bytesRead; 1385 _SendReceiptAck(port); 1386 return error; 1387 } 1388 1389 // Write 1390 status_t 1391 Volume::Write(fs_vnode node, fs_cookie cookie, off_t pos, const void* buffer, 1392 size_t size, size_t* bytesWritten) 1393 { 1394 *bytesWritten = 0; 1395 1396 // check capability 1397 if (!fFileSystem->HasCapability(FS_CAPABILITY_WRITE)) 1398 return B_BAD_VALUE; 1399 1400 // get a free port 1401 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 1402 if (!port) 1403 return B_ERROR; 1404 PortReleaser _(fFileSystem->GetPortPool(), port); 1405 1406 // prepare the request 1407 RequestAllocator allocator(port->GetPort()); 1408 WriteRequest* request; 1409 status_t error = AllocateRequest(allocator, &request); 1410 if (error != B_OK) 1411 return error; 1412 1413 request->volume = fUserlandVolume; 1414 request->node = node; 1415 request->fileCookie = cookie; 1416 request->pos = pos; 1417 error = allocator.AllocateData(request->buffer, buffer, size, 1); 1418 if (error != B_OK) 1419 return error; 1420 1421 // send the request 1422 KernelRequestHandler handler(this, WRITE_REPLY); 1423 WriteReply* reply; 1424 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 1425 if (error != B_OK) 1426 return error; 1427 RequestReleaser requestReleaser(port, reply); 1428 1429 // process the reply 1430 if (reply->error != B_OK) 1431 return reply->error; 1432 *bytesWritten = reply->bytesWritten; 1433 return error; 1434 } 1435 1436 1437 // #pragma mark - directories 1438 1439 // CreateDir 1440 status_t 1441 Volume::CreateDir(fs_vnode dir, const char* name, int mode, ino_t *newDir) 1442 { 1443 // check capability 1444 if (!fFileSystem->HasCapability(FS_CAPABILITY_CREATE_DIR)) 1445 return B_BAD_VALUE; 1446 1447 // get a free port 1448 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 1449 if (!port) 1450 return B_ERROR; 1451 PortReleaser _(fFileSystem->GetPortPool(), port); 1452 1453 // prepare the request 1454 RequestAllocator allocator(port->GetPort()); 1455 CreateDirRequest* request; 1456 status_t error = AllocateRequest(allocator, &request); 1457 if (error != B_OK) 1458 return error; 1459 1460 request->volume = fUserlandVolume; 1461 request->node = dir; 1462 error = allocator.AllocateString(request->name, name); 1463 request->mode = mode; 1464 if (error != B_OK) 1465 return error; 1466 1467 // send the request 1468 KernelRequestHandler handler(this, CREATE_DIR_REPLY); 1469 CreateDirReply* reply; 1470 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 1471 if (error != B_OK) 1472 return error; 1473 RequestReleaser requestReleaser(port, reply); 1474 1475 // process the reply 1476 if (reply->error != B_OK) 1477 return reply->error; 1478 *newDir = reply->newDir; 1479 return error; 1480 } 1481 1482 // RemoveDir 1483 status_t 1484 Volume::RemoveDir(fs_vnode dir, const char* name) 1485 { 1486 // check capability 1487 if (!fFileSystem->HasCapability(FS_CAPABILITY_REMOVE_DIR)) 1488 return B_BAD_VALUE; 1489 1490 // get a free port 1491 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 1492 if (!port) 1493 return B_ERROR; 1494 PortReleaser _(fFileSystem->GetPortPool(), port); 1495 1496 // prepare the request 1497 RequestAllocator allocator(port->GetPort()); 1498 RemoveDirRequest* request; 1499 status_t error = AllocateRequest(allocator, &request); 1500 if (error != B_OK) 1501 return error; 1502 1503 request->volume = fUserlandVolume; 1504 request->node = dir; 1505 error = allocator.AllocateString(request->name, name); 1506 if (error != B_OK) 1507 return error; 1508 1509 // send the request 1510 KernelRequestHandler handler(this, REMOVE_DIR_REPLY); 1511 RemoveDirReply* reply; 1512 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 1513 if (error != B_OK) 1514 return error; 1515 RequestReleaser requestReleaser(port, reply); 1516 1517 // process the reply 1518 if (reply->error != B_OK) 1519 return reply->error; 1520 return error; 1521 } 1522 1523 // OpenDir 1524 status_t 1525 Volume::OpenDir(fs_vnode node, fs_cookie* cookie) 1526 { 1527 // check capability 1528 if (!fFileSystem->HasCapability(FS_CAPABILITY_OPEN_DIR)) 1529 return B_BAD_VALUE; 1530 1531 // get a free port 1532 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 1533 if (!port) 1534 return B_ERROR; 1535 PortReleaser _(fFileSystem->GetPortPool(), port); 1536 AutoIncrementer incrementer(&fOpenDirectories); 1537 1538 // prepare the request 1539 RequestAllocator allocator(port->GetPort()); 1540 OpenDirRequest* request; 1541 status_t error = AllocateRequest(allocator, &request); 1542 if (error != B_OK) 1543 return error; 1544 1545 request->volume = fUserlandVolume; 1546 request->node = node; 1547 1548 // send the request 1549 KernelRequestHandler handler(this, OPEN_DIR_REPLY); 1550 OpenDirReply* reply; 1551 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 1552 if (error != B_OK) 1553 return error; 1554 RequestReleaser requestReleaser(port, reply); 1555 1556 // process the reply 1557 if (reply->error != B_OK) 1558 return reply->error; 1559 incrementer.Keep(); 1560 *cookie = reply->dirCookie; 1561 return error; 1562 } 1563 1564 // CloseDir 1565 status_t 1566 Volume::CloseDir(fs_vnode node, fs_vnode cookie) 1567 { 1568 status_t error = _CloseDir(node, cookie); 1569 if (error != B_OK && fFileSystem->GetPortPool()->IsDisconnected()) { 1570 // This isn't really necessary, as the return value is irrelevant to 1571 // the VFS. OBOS ignores it completely. The fsshell returns it to the 1572 // userland, but considers the node closed anyway. 1573 WARN(("Volume::CloseDir(): connection lost, forcing close dir\n")); 1574 return B_OK; 1575 } 1576 return error; 1577 } 1578 1579 // FreeDirCookie 1580 status_t 1581 Volume::FreeDirCookie(void* node, void* cookie) 1582 { 1583 status_t error = _FreeDirCookie(node, cookie); 1584 bool disconnected = false; 1585 if (error != B_OK && fFileSystem->GetPortPool()->IsDisconnected()) { 1586 // This isn't really necessary, as the return value is irrelevant to 1587 // the VFS. It's completely ignored by OBOS as well as by the fsshell. 1588 WARN(("Volume::FreeDirCookie(): connection lost, forcing free dir " 1589 "cookie\n")); 1590 error = B_OK; 1591 disconnected = true; 1592 } 1593 int32 openDirs = atomic_add(&fOpenDirectories, -1); 1594 if (openDirs <= 1 && disconnected) 1595 _PutAllPendingVNodes(); 1596 return error; 1597 } 1598 1599 // ReadDir 1600 status_t 1601 Volume::ReadDir(fs_vnode node, fs_vnode cookie, void* buffer, size_t bufferSize, 1602 uint32 count, uint32* countRead) 1603 { 1604 *countRead = 0; 1605 1606 // check capability 1607 if (!fFileSystem->HasCapability(FS_CAPABILITY_READ_DIR)) 1608 return B_BAD_VALUE; 1609 1610 // get a free port 1611 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 1612 if (!port) 1613 return B_ERROR; 1614 PortReleaser _(fFileSystem->GetPortPool(), port); 1615 1616 // prepare the request 1617 RequestAllocator allocator(port->GetPort()); 1618 ReadDirRequest* request; 1619 status_t error = AllocateRequest(allocator, &request); 1620 if (error != B_OK) 1621 return error; 1622 1623 request->volume = fUserlandVolume; 1624 request->node = node; 1625 request->dirCookie = cookie; 1626 request->bufferSize = bufferSize; 1627 request->count = count; 1628 1629 // send the request 1630 KernelRequestHandler handler(this, READ_DIR_REPLY); 1631 ReadDirReply* reply; 1632 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 1633 if (error != B_OK) 1634 return error; 1635 RequestReleaser requestReleaser(port, reply); 1636 1637 // process the reply 1638 if (reply->error != B_OK) 1639 return reply->error; 1640 if (reply->count < 0 || reply->count > count) 1641 return B_BAD_DATA; 1642 if ((int32)bufferSize < reply->buffer.GetSize()) 1643 return B_BAD_DATA; 1644 PRINT(("Volume::ReadDir(): buffer returned: %ld bytes\n", 1645 reply->buffer.GetSize())); 1646 1647 *countRead = reply->count; 1648 if (*countRead > 0) { 1649 // copy the buffer -- limit the number of bytes to copy 1650 uint32 maxBytes = *countRead 1651 * (sizeof(struct dirent) + B_FILE_NAME_LENGTH); 1652 uint32 copyBytes = reply->buffer.GetSize(); 1653 if (copyBytes > maxBytes) 1654 copyBytes = maxBytes; 1655 memcpy(buffer, reply->buffer.GetData(), copyBytes); 1656 } 1657 _SendReceiptAck(port); 1658 return error; 1659 } 1660 1661 // RewindDir 1662 status_t 1663 Volume::RewindDir(fs_vnode node, fs_vnode cookie) 1664 { 1665 // check capability 1666 if (!fFileSystem->HasCapability(FS_CAPABILITY_REWIND_DIR)) 1667 return B_BAD_VALUE; 1668 1669 // get a free port 1670 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 1671 if (!port) 1672 return B_ERROR; 1673 PortReleaser _(fFileSystem->GetPortPool(), port); 1674 1675 // prepare the request 1676 RequestAllocator allocator(port->GetPort()); 1677 RewindDirRequest* request; 1678 status_t error = AllocateRequest(allocator, &request); 1679 if (error != B_OK) 1680 return error; 1681 1682 request->volume = fUserlandVolume; 1683 request->node = node; 1684 request->dirCookie = cookie; 1685 1686 // send the request 1687 KernelRequestHandler handler(this, REWIND_DIR_REPLY); 1688 RewindDirReply* reply; 1689 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 1690 if (error != B_OK) 1691 return error; 1692 RequestReleaser requestReleaser(port, reply); 1693 1694 // process the reply 1695 if (reply->error != B_OK) 1696 return reply->error; 1697 return error; 1698 } 1699 1700 1701 // #pragma mark - attribute directories 1702 1703 1704 // OpenAttrDir 1705 status_t 1706 Volume::OpenAttrDir(fs_vnode node, fs_cookie *cookie) 1707 { 1708 // check capability 1709 if (!fFileSystem->HasCapability(FS_CAPABILITY_OPEN_ATTR_DIR)) 1710 return B_BAD_VALUE; 1711 1712 // get a free port 1713 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 1714 if (!port) 1715 return B_ERROR; 1716 PortReleaser _(fFileSystem->GetPortPool(), port); 1717 AutoIncrementer incrementer(&fOpenAttributeDirectories); 1718 1719 // prepare the request 1720 RequestAllocator allocator(port->GetPort()); 1721 OpenAttrDirRequest* request; 1722 status_t error = AllocateRequest(allocator, &request); 1723 if (error != B_OK) 1724 return error; 1725 1726 request->volume = fUserlandVolume; 1727 request->node = node; 1728 1729 // send the request 1730 KernelRequestHandler handler(this, OPEN_ATTR_DIR_REPLY); 1731 OpenAttrDirReply* reply; 1732 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 1733 if (error != B_OK) 1734 return error; 1735 RequestReleaser requestReleaser(port, reply); 1736 1737 // process the reply 1738 if (reply->error != B_OK) 1739 return reply->error; 1740 incrementer.Keep(); 1741 *cookie = reply->attrDirCookie; 1742 return error; 1743 } 1744 1745 // CloseAttrDir 1746 status_t 1747 Volume::CloseAttrDir(fs_vnode node, fs_cookie cookie) 1748 { 1749 status_t error = _CloseAttrDir(node, cookie); 1750 if (error != B_OK && fFileSystem->GetPortPool()->IsDisconnected()) { 1751 // This isn't really necessary, as the return value is irrelevant to 1752 // the VFS. OBOS ignores it completely. The fsshell returns it to the 1753 // userland, but considers the node closed anyway. 1754 WARN(("Volume::CloseAttrDir(): connection lost, forcing close attr " 1755 "dir\n")); 1756 return B_OK; 1757 } 1758 return error; 1759 } 1760 1761 // FreeAttrDirCookie 1762 status_t 1763 Volume::FreeAttrDirCookie(void* node, void* cookie) 1764 { 1765 status_t error = _FreeAttrDirCookie(node, cookie); 1766 bool disconnected = false; 1767 if (error != B_OK && fFileSystem->GetPortPool()->IsDisconnected()) { 1768 // This isn't really necessary, as the return value is irrelevant to 1769 // the VFS. It's completely ignored by OBOS as well as by the fsshell. 1770 WARN(("Volume::FreeAttrDirCookie(): connection lost, forcing free attr " 1771 "dir cookie\n")); 1772 error = B_OK; 1773 disconnected = true; 1774 } 1775 1776 int32 openAttrDirs = atomic_add(&fOpenAttributeDirectories, -1); 1777 if (openAttrDirs <= 1 && disconnected) 1778 _PutAllPendingVNodes(); 1779 return error; 1780 } 1781 1782 // ReadAttrDir 1783 status_t 1784 Volume::ReadAttrDir(fs_vnode node, fs_cookie cookie, void* buffer, 1785 size_t bufferSize, uint32 count, uint32* countRead) 1786 { 1787 // check capability 1788 if (!fFileSystem->HasCapability(FS_CAPABILITY_READ_ATTR_DIR)) 1789 return B_BAD_VALUE; 1790 1791 *countRead = 0; 1792 // get a free port 1793 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 1794 if (!port) 1795 return B_ERROR; 1796 PortReleaser _(fFileSystem->GetPortPool(), port); 1797 1798 // prepare the request 1799 RequestAllocator allocator(port->GetPort()); 1800 ReadAttrDirRequest* request; 1801 status_t error = AllocateRequest(allocator, &request); 1802 if (error != B_OK) 1803 return error; 1804 1805 request->volume = fUserlandVolume; 1806 request->node = node; 1807 request->attrDirCookie = cookie; 1808 request->bufferSize = bufferSize; 1809 request->count = count; 1810 1811 // send the request 1812 KernelRequestHandler handler(this, READ_ATTR_DIR_REPLY); 1813 ReadAttrDirReply* reply; 1814 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 1815 if (error != B_OK) 1816 return error; 1817 RequestReleaser requestReleaser(port, reply); 1818 1819 // process the reply 1820 if (reply->error != B_OK) 1821 return reply->error; 1822 if (reply->count < 0 || reply->count > count) 1823 return B_BAD_DATA; 1824 if ((int32)bufferSize < reply->buffer.GetSize()) 1825 return B_BAD_DATA; 1826 1827 *countRead = reply->count; 1828 if (*countRead > 0) { 1829 // copy the buffer -- limit the number of bytes to copy 1830 uint32 maxBytes = *countRead 1831 * (sizeof(struct dirent) + B_ATTR_NAME_LENGTH); 1832 uint32 copyBytes = reply->buffer.GetSize(); 1833 if (copyBytes > maxBytes) 1834 copyBytes = maxBytes; 1835 memcpy(buffer, reply->buffer.GetData(), copyBytes); 1836 } 1837 _SendReceiptAck(port); 1838 return error; 1839 } 1840 1841 // RewindAttrDir 1842 status_t 1843 Volume::RewindAttrDir(fs_vnode node, fs_cookie cookie) 1844 { 1845 // check capability 1846 if (!fFileSystem->HasCapability(FS_CAPABILITY_REWIND_ATTR_DIR)) 1847 return B_BAD_VALUE; 1848 1849 // get a free port 1850 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 1851 if (!port) 1852 return B_ERROR; 1853 PortReleaser _(fFileSystem->GetPortPool(), port); 1854 1855 // prepare the request 1856 RequestAllocator allocator(port->GetPort()); 1857 RewindAttrDirRequest* request; 1858 status_t error = AllocateRequest(allocator, &request); 1859 if (error != B_OK) 1860 return error; 1861 1862 request->volume = fUserlandVolume; 1863 request->node = node; 1864 request->attrDirCookie = cookie; 1865 1866 // send the request 1867 KernelRequestHandler handler(this, REWIND_ATTR_DIR_REPLY); 1868 RewindAttrDirReply* reply; 1869 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 1870 if (error != B_OK) 1871 return error; 1872 RequestReleaser requestReleaser(port, reply); 1873 1874 // process the reply 1875 if (reply->error != B_OK) 1876 return reply->error; 1877 return error; 1878 } 1879 1880 1881 // #pragma mark - attributes 1882 1883 // CreateAttr 1884 status_t 1885 Volume::CreateAttr(fs_vnode node, const char* name, uint32 type, int openMode, 1886 fs_cookie* cookie) 1887 { 1888 // check capability 1889 if (!fFileSystem->HasCapability(FS_CAPABILITY_CREATE_ATTR)) 1890 return B_BAD_VALUE; 1891 1892 // get a free port 1893 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 1894 if (!port) 1895 return B_ERROR; 1896 PortReleaser _(fFileSystem->GetPortPool(), port); 1897 AutoIncrementer incrementer(&fOpenAttributes); 1898 1899 // prepare the request 1900 RequestAllocator allocator(port->GetPort()); 1901 CreateAttrRequest* request; 1902 status_t error = AllocateRequest(allocator, &request); 1903 if (error != B_OK) 1904 return error; 1905 1906 request->volume = fUserlandVolume; 1907 request->node = node; 1908 error = allocator.AllocateString(request->name, name); 1909 request->type = type; 1910 request->openMode = openMode; 1911 if (error != B_OK) 1912 return error; 1913 1914 // send the request 1915 KernelRequestHandler handler(this, CREATE_ATTR_REPLY); 1916 CreateAttrReply* reply; 1917 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 1918 if (error != B_OK) 1919 return error; 1920 RequestReleaser requestReleaser(port, reply); 1921 1922 // process the reply 1923 if (reply->error != B_OK) 1924 return reply->error; 1925 incrementer.Keep(); 1926 *cookie = reply->attrCookie; 1927 return error; 1928 } 1929 1930 // OpenAttr 1931 status_t 1932 Volume::OpenAttr(fs_vnode node, const char* name, int openMode, 1933 fs_cookie* cookie) 1934 { 1935 // check capability 1936 if (!fFileSystem->HasCapability(FS_CAPABILITY_OPEN_ATTR)) 1937 return B_BAD_VALUE; 1938 1939 // get a free port 1940 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 1941 if (!port) 1942 return B_ERROR; 1943 PortReleaser _(fFileSystem->GetPortPool(), port); 1944 AutoIncrementer incrementer(&fOpenAttributes); 1945 1946 // prepare the request 1947 RequestAllocator allocator(port->GetPort()); 1948 OpenAttrRequest* request; 1949 status_t error = AllocateRequest(allocator, &request); 1950 if (error != B_OK) 1951 return error; 1952 1953 request->volume = fUserlandVolume; 1954 request->node = node; 1955 error = allocator.AllocateString(request->name, name); 1956 request->openMode = openMode; 1957 if (error != B_OK) 1958 return error; 1959 1960 // send the request 1961 KernelRequestHandler handler(this, OPEN_ATTR_REPLY); 1962 OpenAttrReply* reply; 1963 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 1964 if (error != B_OK) 1965 return error; 1966 RequestReleaser requestReleaser(port, reply); 1967 1968 // process the reply 1969 if (reply->error != B_OK) 1970 return reply->error; 1971 incrementer.Keep(); 1972 *cookie = reply->attrCookie; 1973 return error; 1974 } 1975 1976 // CloseAttr 1977 status_t 1978 Volume::CloseAttr(fs_vnode node, fs_cookie cookie) 1979 { 1980 status_t error = _CloseAttr(node, cookie); 1981 if (error != B_OK && fFileSystem->GetPortPool()->IsDisconnected()) { 1982 // This isn't really necessary, as the return value is irrelevant to 1983 // the VFS. OBOS ignores it completely. The fsshell returns it to the 1984 // userland, but considers the node closed anyway. 1985 WARN(("Volume::CloseAttr(): connection lost, forcing close attr\n")); 1986 return B_OK; 1987 } 1988 return error; 1989 } 1990 1991 // FreeAttrCookie 1992 status_t 1993 Volume::FreeAttrCookie(fs_vnode node, fs_cookie cookie) 1994 { 1995 status_t error = _FreeAttrCookie(node, cookie); 1996 bool disconnected = false; 1997 if (error != B_OK && fFileSystem->GetPortPool()->IsDisconnected()) { 1998 // This isn't really necessary, as the return value is irrelevant to 1999 // the VFS. It's completely ignored by OBOS as well as by the fsshell. 2000 WARN(("Volume::FreeAttrCookie(): connection lost, forcing free attr " 2001 "cookie\n")); 2002 error = B_OK; 2003 disconnected = true; 2004 } 2005 2006 int32 openAttributes = atomic_add(&fOpenAttributes, -1); 2007 if (openAttributes <= 1 && disconnected) 2008 _PutAllPendingVNodes(); 2009 return error; 2010 } 2011 2012 // ReadAttr 2013 status_t 2014 Volume::ReadAttr(fs_vnode node, fs_cookie cookie, off_t pos, 2015 void* buffer, size_t bufferSize, size_t* bytesRead) 2016 { 2017 *bytesRead = 0; 2018 2019 // check capability 2020 if (!fFileSystem->HasCapability(FS_CAPABILITY_READ_ATTR)) 2021 return B_BAD_VALUE; 2022 2023 // get a free port 2024 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 2025 if (!port) 2026 return B_ERROR; 2027 PortReleaser _(fFileSystem->GetPortPool(), port); 2028 2029 // prepare the request 2030 RequestAllocator allocator(port->GetPort()); 2031 ReadAttrRequest* request; 2032 status_t error = AllocateRequest(allocator, &request); 2033 if (error != B_OK) 2034 return error; 2035 2036 request->volume = fUserlandVolume; 2037 request->node = node; 2038 request->attrCookie = cookie; 2039 request->pos = pos; 2040 request->size = bufferSize; 2041 2042 // send the request 2043 KernelRequestHandler handler(this, READ_ATTR_REPLY); 2044 ReadAttrReply* reply; 2045 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 2046 if (error != B_OK) 2047 return error; 2048 RequestReleaser requestReleaser(port, reply); 2049 2050 // process the reply 2051 if (reply->error != B_OK) 2052 return reply->error; 2053 void* readBuffer = reply->buffer.GetData(); 2054 if (reply->bytesRead > (uint32)reply->buffer.GetSize() 2055 || reply->bytesRead > bufferSize) { 2056 return B_BAD_DATA; 2057 } 2058 if (reply->bytesRead > 0) 2059 memcpy(buffer, readBuffer, reply->bytesRead); 2060 *bytesRead = reply->bytesRead; 2061 _SendReceiptAck(port); 2062 return error; 2063 } 2064 2065 // WriteAttr 2066 status_t 2067 Volume::WriteAttr(fs_vnode node, fs_cookie cookie, off_t pos, 2068 const void* buffer, size_t bufferSize, size_t* bytesWritten) 2069 { 2070 *bytesWritten = 0; 2071 2072 // check capability 2073 if (!fFileSystem->HasCapability(FS_CAPABILITY_WRITE_ATTR)) 2074 return B_BAD_VALUE; 2075 2076 // get a free port 2077 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 2078 if (!port) 2079 return B_ERROR; 2080 PortReleaser _(fFileSystem->GetPortPool(), port); 2081 2082 // prepare the request 2083 RequestAllocator allocator(port->GetPort()); 2084 WriteAttrRequest* request; 2085 status_t error = AllocateRequest(allocator, &request); 2086 if (error != B_OK) 2087 return error; 2088 2089 request->volume = fUserlandVolume; 2090 request->node = node; 2091 request->attrCookie = cookie; 2092 request->pos = pos; 2093 error = allocator.AllocateData(request->buffer, buffer, bufferSize, 1); 2094 if (error != B_OK) 2095 return error; 2096 2097 // send the request 2098 KernelRequestHandler handler(this, WRITE_ATTR_REPLY); 2099 WriteAttrReply* reply; 2100 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 2101 if (error != B_OK) 2102 return error; 2103 RequestReleaser requestReleaser(port, reply); 2104 2105 // process the reply 2106 if (reply->error != B_OK) 2107 return reply->error; 2108 *bytesWritten = reply->bytesWritten; 2109 return error; 2110 } 2111 2112 // ReadAttrStat 2113 status_t 2114 Volume::ReadAttrStat(fs_vnode node, fs_cookie cookie, struct stat *st) 2115 { 2116 // check capability 2117 if (!fFileSystem->HasCapability(FS_CAPABILITY_READ_ATTR_STAT)) 2118 return B_BAD_VALUE; 2119 2120 // get a free port 2121 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 2122 if (!port) 2123 return B_ERROR; 2124 PortReleaser _(fFileSystem->GetPortPool(), port); 2125 2126 // prepare the request 2127 RequestAllocator allocator(port->GetPort()); 2128 ReadAttrStatRequest* request; 2129 status_t error = AllocateRequest(allocator, &request); 2130 if (error != B_OK) 2131 return error; 2132 2133 request->volume = fUserlandVolume; 2134 request->node = node; 2135 request->attrCookie = cookie; 2136 2137 // send the request 2138 KernelRequestHandler handler(this, READ_ATTR_STAT_REPLY); 2139 ReadAttrStatReply* reply; 2140 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 2141 if (error != B_OK) 2142 return error; 2143 RequestReleaser requestReleaser(port, reply); 2144 2145 // process the reply 2146 if (reply->error != B_OK) 2147 return reply->error; 2148 *st = reply->st; 2149 return error; 2150 } 2151 2152 // WriteAttrStat 2153 status_t 2154 Volume::WriteAttrStat(fs_vnode node, fs_cookie cookie, const struct stat *st, 2155 int statMask) 2156 { 2157 // check capability 2158 if (!fFileSystem->HasCapability(FS_CAPABILITY_WRITE_ATTR_STAT)) 2159 return B_BAD_VALUE; 2160 2161 // get a free port 2162 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 2163 if (!port) 2164 return B_ERROR; 2165 PortReleaser _(fFileSystem->GetPortPool(), port); 2166 2167 // prepare the request 2168 RequestAllocator allocator(port->GetPort()); 2169 WriteAttrStatRequest* request; 2170 status_t error = AllocateRequest(allocator, &request); 2171 if (error != B_OK) 2172 return error; 2173 2174 request->volume = fUserlandVolume; 2175 request->node = node; 2176 request->attrCookie = cookie; 2177 request->st = *st; 2178 request->mask = statMask; 2179 2180 // send the request 2181 KernelRequestHandler handler(this, WRITE_ATTR_STAT_REPLY); 2182 WriteAttrStatReply* reply; 2183 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 2184 if (error != B_OK) 2185 return error; 2186 RequestReleaser requestReleaser(port, reply); 2187 2188 // process the reply 2189 if (reply->error != B_OK) 2190 return reply->error; 2191 return error; 2192 } 2193 2194 // RenameAttr 2195 status_t 2196 Volume::RenameAttr(fs_vnode oldNode, const char* oldName, fs_vnode newNode, 2197 const char* newName) 2198 { 2199 // check capability 2200 if (!fFileSystem->HasCapability(FS_CAPABILITY_RENAME_ATTR)) 2201 return B_BAD_VALUE; 2202 2203 // get a free port 2204 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 2205 if (!port) 2206 return B_ERROR; 2207 PortReleaser _(fFileSystem->GetPortPool(), port); 2208 2209 // prepare the request 2210 RequestAllocator allocator(port->GetPort()); 2211 RenameAttrRequest* request; 2212 status_t error = AllocateRequest(allocator, &request); 2213 if (error != B_OK) 2214 return error; 2215 2216 request->volume = fUserlandVolume; 2217 request->oldNode = oldNode; 2218 request->newNode = newNode; 2219 error = allocator.AllocateString(request->oldName, oldName); 2220 if (error == B_OK) 2221 error = allocator.AllocateString(request->newName, newName); 2222 if (error != B_OK) 2223 return error; 2224 2225 // send the request 2226 KernelRequestHandler handler(this, RENAME_ATTR_REPLY); 2227 RenameAttrReply* reply; 2228 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 2229 if (error != B_OK) 2230 return error; 2231 RequestReleaser requestReleaser(port, reply); 2232 2233 // process the reply 2234 if (reply->error != B_OK) 2235 return reply->error; 2236 return error; 2237 } 2238 2239 // RemoveAttr 2240 status_t 2241 Volume::RemoveAttr(fs_vnode node, const char* name) 2242 { 2243 // check capability 2244 if (!fFileSystem->HasCapability(FS_CAPABILITY_REMOVE_ATTR)) 2245 return B_BAD_VALUE; 2246 2247 // get a free port 2248 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 2249 if (!port) 2250 return B_ERROR; 2251 PortReleaser _(fFileSystem->GetPortPool(), port); 2252 2253 // prepare the request 2254 RequestAllocator allocator(port->GetPort()); 2255 RemoveAttrRequest* request; 2256 status_t error = AllocateRequest(allocator, &request); 2257 if (error != B_OK) 2258 return error; 2259 2260 request->volume = fUserlandVolume; 2261 request->node = node; 2262 error = allocator.AllocateString(request->name, name); 2263 if (error != B_OK) 2264 return error; 2265 2266 // send the request 2267 KernelRequestHandler handler(this, REMOVE_ATTR_REPLY); 2268 RemoveAttrReply* reply; 2269 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 2270 if (error != B_OK) 2271 return error; 2272 RequestReleaser requestReleaser(port, reply); 2273 2274 // process the reply 2275 if (reply->error != B_OK) 2276 return reply->error; 2277 return error; 2278 } 2279 2280 2281 // #pragma mark - indices 2282 2283 2284 // OpenIndexDir 2285 status_t 2286 Volume::OpenIndexDir(fs_cookie *cookie) 2287 { 2288 // check capability 2289 if (!fFileSystem->HasCapability(FS_CAPABILITY_OPEN_INDEX_DIR)) 2290 return B_BAD_VALUE; 2291 2292 // get a free port 2293 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 2294 if (!port) 2295 return B_ERROR; 2296 PortReleaser _(fFileSystem->GetPortPool(), port); 2297 AutoIncrementer incrementer(&fOpenIndexDirectories); 2298 2299 // prepare the request 2300 RequestAllocator allocator(port->GetPort()); 2301 OpenIndexDirRequest* request; 2302 status_t error = AllocateRequest(allocator, &request); 2303 if (error != B_OK) 2304 return error; 2305 2306 request->volume = fUserlandVolume; 2307 2308 // send the request 2309 KernelRequestHandler handler(this, OPEN_INDEX_DIR_REPLY); 2310 OpenIndexDirReply* reply; 2311 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 2312 if (error != B_OK) 2313 return error; 2314 RequestReleaser requestReleaser(port, reply); 2315 2316 // process the reply 2317 if (reply->error != B_OK) 2318 return reply->error; 2319 incrementer.Keep(); 2320 *cookie = reply->indexDirCookie; 2321 return error; 2322 } 2323 2324 // CloseIndexDir 2325 status_t 2326 Volume::CloseIndexDir(fs_cookie cookie) 2327 { 2328 status_t error = _CloseIndexDir(cookie); 2329 if (error != B_OK && fFileSystem->GetPortPool()->IsDisconnected()) { 2330 // This isn't really necessary, as the return value is irrelevant to 2331 // the VFS. OBOS ignores it completely. The fsshell returns it to the 2332 // userland, but considers the node closed anyway. 2333 WARN(("Volume::CloseIndexDir(): connection lost, forcing close " 2334 "index dir\n")); 2335 return B_OK; 2336 } 2337 return error; 2338 } 2339 2340 // FreeIndexDirCookie 2341 status_t 2342 Volume::FreeIndexDirCookie(fs_cookie cookie) 2343 { 2344 status_t error = _FreeIndexDirCookie(cookie); 2345 bool disconnected = false; 2346 if (error != B_OK && fFileSystem->GetPortPool()->IsDisconnected()) { 2347 // This isn't really necessary, as the return value is irrelevant to 2348 // the VFS. It's completely ignored by OBOS as well as by the fsshell. 2349 WARN(("Volume::FreeIndexDirCookie(): connection lost, forcing free " 2350 "index dir cookie\n")); 2351 error = B_OK; 2352 disconnected = true; 2353 } 2354 2355 int32 openIndexDirs = atomic_add(&fOpenIndexDirectories, -1); 2356 if (openIndexDirs <= 1 && disconnected) 2357 _PutAllPendingVNodes(); 2358 return error; 2359 } 2360 2361 // ReadIndexDir 2362 status_t 2363 Volume::ReadIndexDir(fs_cookie cookie, void* buffer, size_t bufferSize, 2364 uint32 count, uint32* countRead) 2365 { 2366 *countRead = 0; 2367 2368 // check capability 2369 if (!fFileSystem->HasCapability(FS_CAPABILITY_READ_INDEX_DIR)) 2370 return B_BAD_VALUE; 2371 2372 // get a free port 2373 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 2374 if (!port) 2375 return B_ERROR; 2376 PortReleaser _(fFileSystem->GetPortPool(), port); 2377 2378 // prepare the request 2379 RequestAllocator allocator(port->GetPort()); 2380 ReadIndexDirRequest* request; 2381 status_t error = AllocateRequest(allocator, &request); 2382 if (error != B_OK) 2383 return error; 2384 2385 request->volume = fUserlandVolume; 2386 request->indexDirCookie = cookie; 2387 request->bufferSize = bufferSize; 2388 request->count = count; 2389 2390 // send the request 2391 KernelRequestHandler handler(this, READ_INDEX_DIR_REPLY); 2392 ReadIndexDirReply* reply; 2393 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 2394 if (error != B_OK) 2395 return error; 2396 RequestReleaser requestReleaser(port, reply); 2397 2398 // process the reply 2399 if (reply->error != B_OK) 2400 return reply->error; 2401 if (reply->count < 0 || reply->count > count) 2402 return B_BAD_DATA; 2403 if ((int32)bufferSize < reply->buffer.GetSize()) 2404 return B_BAD_DATA; 2405 2406 *countRead = reply->count; 2407 if (*countRead > 0) { 2408 // copy the buffer -- limit the number of bytes to copy 2409 uint32 maxBytes = *countRead 2410 * (sizeof(struct dirent) + B_FILE_NAME_LENGTH); 2411 uint32 copyBytes = reply->buffer.GetSize(); 2412 if (copyBytes > maxBytes) 2413 copyBytes = maxBytes; 2414 memcpy(buffer, reply->buffer.GetData(), copyBytes); 2415 } 2416 _SendReceiptAck(port); 2417 return error; 2418 } 2419 2420 // RewindIndexDir 2421 status_t 2422 Volume::RewindIndexDir(fs_cookie cookie) 2423 { 2424 // check capability 2425 if (!fFileSystem->HasCapability(FS_CAPABILITY_REWIND_INDEX_DIR)) 2426 return B_BAD_VALUE; 2427 2428 // get a free port 2429 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 2430 if (!port) 2431 return B_ERROR; 2432 PortReleaser _(fFileSystem->GetPortPool(), port); 2433 2434 // prepare the request 2435 RequestAllocator allocator(port->GetPort()); 2436 RewindIndexDirRequest* request; 2437 status_t error = AllocateRequest(allocator, &request); 2438 if (error != B_OK) 2439 return error; 2440 2441 request->volume = fUserlandVolume; 2442 request->indexDirCookie = cookie; 2443 2444 // send the request 2445 KernelRequestHandler handler(this, REWIND_INDEX_DIR_REPLY); 2446 RewindIndexDirReply* reply; 2447 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 2448 if (error != B_OK) 2449 return error; 2450 RequestReleaser requestReleaser(port, reply); 2451 2452 // process the reply 2453 if (reply->error != B_OK) 2454 return reply->error; 2455 return error; 2456 } 2457 2458 // CreateIndex 2459 status_t 2460 Volume::CreateIndex(const char* name, uint32 type, uint32 flags) 2461 { 2462 // check capability 2463 if (!fFileSystem->HasCapability(FS_CAPABILITY_CREATE_INDEX)) 2464 return B_BAD_VALUE; 2465 2466 // get a free port 2467 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 2468 if (!port) 2469 return B_ERROR; 2470 PortReleaser _(fFileSystem->GetPortPool(), port); 2471 2472 // prepare the request 2473 RequestAllocator allocator(port->GetPort()); 2474 CreateIndexRequest* request; 2475 status_t error = AllocateRequest(allocator, &request); 2476 if (error != B_OK) 2477 return error; 2478 2479 request->volume = fUserlandVolume; 2480 error = allocator.AllocateString(request->name, name); 2481 request->type = type; 2482 request->flags = flags; 2483 if (error != B_OK) 2484 return error; 2485 2486 // send the request 2487 KernelRequestHandler handler(this, CREATE_INDEX_REPLY); 2488 CreateIndexReply* reply; 2489 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 2490 if (error != B_OK) 2491 return error; 2492 RequestReleaser requestReleaser(port, reply); 2493 2494 // process the reply 2495 if (reply->error != B_OK) 2496 return reply->error; 2497 return error; 2498 } 2499 2500 // RemoveIndex 2501 status_t 2502 Volume::RemoveIndex(const char* name) 2503 { 2504 // check capability 2505 if (!fFileSystem->HasCapability(FS_CAPABILITY_REMOVE_INDEX)) 2506 return B_BAD_VALUE; 2507 2508 // get a free port 2509 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 2510 if (!port) 2511 return B_ERROR; 2512 PortReleaser _(fFileSystem->GetPortPool(), port); 2513 2514 // prepare the request 2515 RequestAllocator allocator(port->GetPort()); 2516 RemoveIndexRequest* request; 2517 status_t error = AllocateRequest(allocator, &request); 2518 if (error != B_OK) 2519 return error; 2520 2521 request->volume = fUserlandVolume; 2522 error = allocator.AllocateString(request->name, name); 2523 if (error != B_OK) 2524 return error; 2525 2526 // send the request 2527 KernelRequestHandler handler(this, REMOVE_INDEX_REPLY); 2528 RemoveIndexReply* reply; 2529 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 2530 if (error != B_OK) 2531 return error; 2532 RequestReleaser requestReleaser(port, reply); 2533 2534 // process the reply 2535 if (reply->error != B_OK) 2536 return reply->error; 2537 return error; 2538 } 2539 2540 // ReadIndexStat 2541 status_t 2542 Volume::ReadIndexStat(const char* name, struct stat *st) 2543 { 2544 // check capability 2545 if (!fFileSystem->HasCapability(FS_CAPABILITY_READ_INDEX_STAT)) 2546 return B_BAD_VALUE; 2547 2548 // get a free port 2549 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 2550 if (!port) 2551 return B_ERROR; 2552 PortReleaser _(fFileSystem->GetPortPool(), port); 2553 2554 // prepare the request 2555 RequestAllocator allocator(port->GetPort()); 2556 ReadIndexStatRequest* request; 2557 status_t error = AllocateRequest(allocator, &request); 2558 if (error != B_OK) 2559 return error; 2560 2561 request->volume = fUserlandVolume; 2562 error = allocator.AllocateString(request->name, name); 2563 if (error != B_OK) 2564 return error; 2565 2566 // send the request 2567 KernelRequestHandler handler(this, READ_INDEX_STAT_REPLY); 2568 ReadIndexStatReply* reply; 2569 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 2570 if (error != B_OK) 2571 return error; 2572 RequestReleaser requestReleaser(port, reply); 2573 2574 // process the reply 2575 if (reply->error != B_OK) 2576 return reply->error; 2577 *st = reply->st; 2578 return error; 2579 } 2580 2581 2582 // #pragma mark - queries 2583 2584 2585 // OpenQuery 2586 status_t 2587 Volume::OpenQuery(const char* queryString, uint32 flags, port_id targetPort, 2588 uint32 token, fs_cookie *cookie) 2589 { 2590 // check capability 2591 if (!fFileSystem->HasCapability(FS_CAPABILITY_OPEN_QUERY)) 2592 return B_BAD_VALUE; 2593 2594 // get a free port 2595 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 2596 if (!port) 2597 return B_ERROR; 2598 PortReleaser _(fFileSystem->GetPortPool(), port); 2599 AutoIncrementer incrementer(&fOpenQueries); 2600 2601 // prepare the request 2602 RequestAllocator allocator(port->GetPort()); 2603 OpenQueryRequest* request; 2604 status_t error = AllocateRequest(allocator, &request); 2605 if (error != B_OK) 2606 return error; 2607 2608 request->volume = fUserlandVolume; 2609 error = allocator.AllocateString(request->queryString, queryString); 2610 if (error != B_OK) 2611 return error; 2612 request->flags = flags; 2613 request->port = targetPort; 2614 request->token = token; 2615 2616 // send the request 2617 KernelRequestHandler handler(this, OPEN_QUERY_REPLY); 2618 OpenQueryReply* reply; 2619 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 2620 if (error != B_OK) 2621 return error; 2622 RequestReleaser requestReleaser(port, reply); 2623 2624 // process the reply 2625 if (reply->error != B_OK) 2626 return reply->error; 2627 incrementer.Keep(); 2628 *cookie = reply->queryCookie; 2629 return error; 2630 } 2631 2632 // CloseQuery 2633 status_t 2634 Volume::CloseQuery(fs_cookie cookie) 2635 { 2636 status_t error = _CloseQuery(cookie); 2637 if (error != B_OK && fFileSystem->GetPortPool()->IsDisconnected()) { 2638 // This isn't really necessary, as the return value is irrelevant to 2639 // the VFS. OBOS ignores it completely. The fsshell returns it to the 2640 // userland, but considers the node closed anyway. 2641 WARN(("Volume::CloseQuery(): connection lost, forcing close query\n")); 2642 return B_OK; 2643 } 2644 return error; 2645 } 2646 2647 // FreeQueryCookie 2648 status_t 2649 Volume::FreeQueryCookie(fs_cookie cookie) 2650 { 2651 status_t error = _FreeQueryCookie(cookie); 2652 bool disconnected = false; 2653 if (error != B_OK && fFileSystem->GetPortPool()->IsDisconnected()) { 2654 // This isn't really necessary, as the return value is irrelevant to 2655 // the VFS. It's completely ignored by OBOS as well as by the fsshell. 2656 WARN(("Volume::FreeQueryCookie(): connection lost, forcing free " 2657 "query cookie\n")); 2658 error = B_OK; 2659 disconnected = true; 2660 } 2661 2662 int32 openQueries = atomic_add(&fOpenQueries, -1); 2663 if (openQueries <= 1 && disconnected) 2664 _PutAllPendingVNodes(); 2665 return error; 2666 } 2667 2668 // ReadQuery 2669 status_t 2670 Volume::ReadQuery(fs_cookie cookie, void* buffer, size_t bufferSize, 2671 uint32 count, uint32* countRead) 2672 { 2673 *countRead = 0; 2674 2675 // check capability 2676 if (!fFileSystem->HasCapability(FS_CAPABILITY_READ_QUERY)) 2677 return B_BAD_VALUE; 2678 2679 // get a free port 2680 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 2681 if (!port) 2682 return B_ERROR; 2683 PortReleaser _(fFileSystem->GetPortPool(), port); 2684 2685 // prepare the request 2686 RequestAllocator allocator(port->GetPort()); 2687 ReadQueryRequest* request; 2688 status_t error = AllocateRequest(allocator, &request); 2689 if (error != B_OK) 2690 return error; 2691 2692 request->volume = fUserlandVolume; 2693 request->queryCookie = cookie; 2694 request->bufferSize = bufferSize; 2695 request->count = count; 2696 2697 // send the request 2698 KernelRequestHandler handler(this, READ_QUERY_REPLY); 2699 ReadQueryReply* reply; 2700 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 2701 if (error != B_OK) 2702 return error; 2703 RequestReleaser requestReleaser(port, reply); 2704 2705 // process the reply 2706 if (reply->error != B_OK) 2707 return reply->error; 2708 if (reply->count < 0 || reply->count > count) 2709 return B_BAD_DATA; 2710 if ((int32)bufferSize < reply->buffer.GetSize()) 2711 return B_BAD_DATA; 2712 2713 *countRead = reply->count; 2714 if (*countRead > 0) { 2715 // copy the buffer -- limit the number of bytes to copy 2716 uint32 maxBytes = *countRead 2717 * (sizeof(struct dirent) + B_FILE_NAME_LENGTH); 2718 uint32 copyBytes = reply->buffer.GetSize(); 2719 if (copyBytes > maxBytes) 2720 copyBytes = maxBytes; 2721 memcpy(buffer, reply->buffer.GetData(), copyBytes); 2722 } 2723 _SendReceiptAck(port); 2724 return error; 2725 } 2726 2727 // RewindQuery 2728 status_t 2729 Volume::RewindQuery(fs_cookie cookie) 2730 { 2731 // check capability 2732 if (!fFileSystem->HasCapability(FS_CAPABILITY_REWIND_QUERY)) 2733 return B_BAD_VALUE; 2734 2735 // get a free port 2736 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 2737 if (!port) 2738 return B_ERROR; 2739 PortReleaser _(fFileSystem->GetPortPool(), port); 2740 2741 // prepare the request 2742 RequestAllocator allocator(port->GetPort()); 2743 RewindQueryRequest* request; 2744 status_t error = AllocateRequest(allocator, &request); 2745 if (error != B_OK) 2746 return error; 2747 2748 request->volume = fUserlandVolume; 2749 request->queryCookie = cookie; 2750 2751 // send the request 2752 KernelRequestHandler handler(this, REWIND_QUERY_REPLY); 2753 RewindQueryReply* reply; 2754 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 2755 if (error != B_OK) 2756 return error; 2757 RequestReleaser requestReleaser(port, reply); 2758 2759 // process the reply 2760 if (reply->error != B_OK) 2761 return reply->error; 2762 return error; 2763 } 2764 2765 // #pragma mark - 2766 // #pragma mark ----- private implementations ----- 2767 2768 // _Mount 2769 status_t 2770 Volume::_Mount(const char* device, uint32 flags, const char* parameters) 2771 { 2772 // get a free port 2773 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 2774 if (!port) 2775 return B_ERROR; 2776 PortReleaser _(fFileSystem->GetPortPool(), port); 2777 2778 // get the current working directory 2779 char cwd[B_PATH_NAME_LENGTH]; 2780 if (!getcwd(cwd, sizeof(cwd))) 2781 return errno; 2782 2783 // prepare the request 2784 RequestAllocator allocator(port->GetPort()); 2785 MountVolumeRequest* request; 2786 status_t error = AllocateRequest(allocator, &request); 2787 if (error != B_OK) 2788 return error; 2789 2790 request->nsid = fID; 2791 error = allocator.AllocateString(request->cwd, cwd); 2792 if (error == B_OK) 2793 error = allocator.AllocateString(request->device, device); 2794 request->flags = flags; 2795 if (error == B_OK) 2796 error = allocator.AllocateString(request->parameters, parameters); 2797 if (error != B_OK) 2798 return error; 2799 2800 // send the request 2801 KernelRequestHandler handler(this, MOUNT_VOLUME_REPLY); 2802 MountVolumeReply* reply; 2803 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 2804 if (error != B_OK) 2805 return error; 2806 RequestReleaser requestReleaser(port, reply); 2807 2808 // process the reply 2809 if (reply->error != B_OK) 2810 return reply->error; 2811 fRootID = reply->rootID; 2812 fUserlandVolume = reply->volume; 2813 2814 // enable vnode counting 2815 fVNodeCountMap = new(nothrow) VNodeCountMap; 2816 if (fVNodeCountMap) 2817 fVNodeCountingEnabled = true; 2818 else 2819 ERROR(("Failed to allocate vnode count map.")); 2820 return error; 2821 } 2822 2823 // _Unmount 2824 status_t 2825 Volume::_Unmount() 2826 { 2827 // get a free port 2828 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 2829 if (!port) 2830 return B_ERROR; 2831 PortReleaser _(fFileSystem->GetPortPool(), port); 2832 2833 // prepare the request 2834 RequestAllocator allocator(port->GetPort()); 2835 UnmountVolumeRequest* request; 2836 status_t error = AllocateRequest(allocator, &request); 2837 if (error != B_OK) 2838 return error; 2839 2840 request->volume = fUserlandVolume; 2841 2842 // send the request 2843 KernelRequestHandler handler(this, UNMOUNT_VOLUME_REPLY); 2844 UnmountVolumeReply* reply; 2845 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 2846 if (error != B_OK) 2847 return error; 2848 RequestReleaser requestReleaser(port, reply); 2849 2850 // process the reply 2851 if (reply->error != B_OK) 2852 return reply->error; 2853 return error; 2854 } 2855 2856 // _ReadFSInfo 2857 status_t 2858 Volume::_ReadFSInfo(fs_info* info) 2859 { 2860 // check capability 2861 if (!fFileSystem->HasCapability(FS_CAPABILITY_READ_FS_INFO)) 2862 return B_BAD_VALUE; 2863 2864 // get a free port 2865 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 2866 if (!port) 2867 return B_ERROR; 2868 PortReleaser _(fFileSystem->GetPortPool(), port); 2869 2870 // prepare the request 2871 RequestAllocator allocator(port->GetPort()); 2872 ReadFSInfoRequest* request; 2873 status_t error = AllocateRequest(allocator, &request); 2874 if (error != B_OK) 2875 return error; 2876 2877 request->volume = fUserlandVolume; 2878 2879 // send the request 2880 KernelRequestHandler handler(this, READ_FS_INFO_REPLY); 2881 ReadFSInfoReply* reply; 2882 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 2883 if (error != B_OK) 2884 return error; 2885 RequestReleaser requestReleaser(port, reply); 2886 2887 // process the reply 2888 if (reply->error != B_OK) 2889 return reply->error; 2890 *info = reply->info; 2891 return error; 2892 } 2893 2894 // _Lookup 2895 status_t 2896 Volume::_Lookup(fs_vnode dir, const char* entryName, ino_t* vnid, int* type) 2897 { 2898 // get a free port 2899 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 2900 if (!port) 2901 return B_ERROR; 2902 PortReleaser _(fFileSystem->GetPortPool(), port); 2903 2904 // prepare the request 2905 RequestAllocator allocator(port->GetPort()); 2906 LookupRequest* request; 2907 status_t error = AllocateRequest(allocator, &request); 2908 if (error != B_OK) 2909 return error; 2910 request->volume = fUserlandVolume; 2911 request->node = dir; 2912 error = allocator.AllocateString(request->entryName, entryName); 2913 if (error != B_OK) 2914 return error; 2915 2916 // send the request 2917 KernelRequestHandler handler(this, LOOKUP_REPLY); 2918 LookupReply* reply; 2919 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 2920 if (error != B_OK) 2921 return error; 2922 RequestReleaser requestReleaser(port, reply); 2923 2924 // process the reply 2925 if (reply->error != B_OK) 2926 return reply->error; 2927 *vnid = reply->vnid; 2928 *type = reply->type; 2929 2930 // The VFS will balance the get_vnode() call for the FS. 2931 _DecrementVNodeCount(*vnid); 2932 return error; 2933 } 2934 2935 // _WriteVNode 2936 status_t 2937 Volume::_WriteVNode(fs_vnode node, bool reenter) 2938 { 2939 // get a free port 2940 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 2941 if (!port) 2942 return B_ERROR; 2943 PortReleaser _(fFileSystem->GetPortPool(), port); 2944 2945 // prepare the request 2946 RequestAllocator allocator(port->GetPort()); 2947 WriteVNodeRequest* request; 2948 status_t error = AllocateRequest(allocator, &request); 2949 if (error != B_OK) 2950 return error; 2951 request->volume = fUserlandVolume; 2952 request->node = node; 2953 request->reenter = reenter; 2954 2955 // send the request 2956 KernelRequestHandler handler(this, WRITE_VNODE_REPLY); 2957 WriteVNodeReply* reply; 2958 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 2959 if (error != B_OK) 2960 return error; 2961 RequestReleaser requestReleaser(port, reply); 2962 2963 // process the reply 2964 if (reply->error != B_OK) 2965 return reply->error; 2966 return error; 2967 } 2968 2969 // _ReadStat 2970 status_t 2971 Volume::_ReadStat(fs_vnode node, struct stat* st) 2972 { 2973 // check capability 2974 if (!fFileSystem->HasCapability(FS_CAPABILITY_READ_STAT)) 2975 return B_BAD_VALUE; 2976 2977 // get a free port 2978 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 2979 if (!port) 2980 return B_ERROR; 2981 PortReleaser _(fFileSystem->GetPortPool(), port); 2982 2983 // prepare the request 2984 RequestAllocator allocator(port->GetPort()); 2985 ReadStatRequest* request; 2986 status_t error = AllocateRequest(allocator, &request); 2987 if (error != B_OK) 2988 return error; 2989 2990 request->volume = fUserlandVolume; 2991 request->node = node; 2992 2993 // send the request 2994 KernelRequestHandler handler(this, READ_STAT_REPLY); 2995 ReadStatReply* reply; 2996 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 2997 if (error != B_OK) 2998 return error; 2999 RequestReleaser requestReleaser(port, reply); 3000 3001 // process the reply 3002 if (reply->error != B_OK) 3003 return reply->error; 3004 *st = reply->st; 3005 return error; 3006 } 3007 3008 // _Close 3009 status_t 3010 Volume::_Close(fs_vnode node, fs_cookie cookie) 3011 { 3012 // check capability 3013 if (!fFileSystem->HasCapability(FS_CAPABILITY_CLOSE)) 3014 return B_OK; 3015 3016 // get a free port 3017 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 3018 if (!port) 3019 return B_ERROR; 3020 PortReleaser _(fFileSystem->GetPortPool(), port); 3021 3022 // prepare the request 3023 RequestAllocator allocator(port->GetPort()); 3024 CloseRequest* request; 3025 status_t error = AllocateRequest(allocator, &request); 3026 if (error != B_OK) 3027 return error; 3028 3029 request->volume = fUserlandVolume; 3030 request->node = node; 3031 request->fileCookie = cookie; 3032 3033 // send the request 3034 KernelRequestHandler handler(this, CLOSE_REPLY); 3035 CloseReply* reply; 3036 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 3037 if (error != B_OK) 3038 return error; 3039 RequestReleaser requestReleaser(port, reply); 3040 3041 // process the reply 3042 if (reply->error != B_OK) 3043 return reply->error; 3044 return error; 3045 } 3046 3047 // _FreeCookie 3048 status_t 3049 Volume::_FreeCookie(fs_vnode node, fs_cookie cookie) 3050 { 3051 // check capability 3052 if (!fFileSystem->HasCapability(FS_CAPABILITY_FREE_COOKIE)) 3053 return B_OK; 3054 3055 // get a free port 3056 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 3057 if (!port) 3058 return B_ERROR; 3059 PortReleaser _(fFileSystem->GetPortPool(), port); 3060 3061 // prepare the request 3062 RequestAllocator allocator(port->GetPort()); 3063 FreeCookieRequest* request; 3064 status_t error = AllocateRequest(allocator, &request); 3065 if (error != B_OK) 3066 return error; 3067 3068 request->volume = fUserlandVolume; 3069 request->node = node; 3070 request->fileCookie = cookie; 3071 3072 // send the request 3073 KernelRequestHandler handler(this, FREE_COOKIE_REPLY); 3074 FreeCookieReply* reply; 3075 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 3076 if (error != B_OK) 3077 return error; 3078 RequestReleaser requestReleaser(port, reply); 3079 3080 // process the reply 3081 if (reply->error != B_OK) 3082 return reply->error; 3083 return error; 3084 } 3085 3086 // _CloseDir 3087 status_t 3088 Volume::_CloseDir(fs_vnode node, fs_vnode cookie) 3089 { 3090 // check capability 3091 if (!fFileSystem->HasCapability(FS_CAPABILITY_CLOSE_DIR)) 3092 return B_OK; 3093 3094 // get a free port 3095 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 3096 if (!port) 3097 return B_ERROR; 3098 PortReleaser _(fFileSystem->GetPortPool(), port); 3099 3100 // prepare the request 3101 RequestAllocator allocator(port->GetPort()); 3102 CloseDirRequest* request; 3103 status_t error = AllocateRequest(allocator, &request); 3104 if (error != B_OK) 3105 return error; 3106 3107 request->volume = fUserlandVolume; 3108 request->node = node; 3109 request->dirCookie = cookie; 3110 3111 // send the request 3112 KernelRequestHandler handler(this, CLOSE_DIR_REPLY); 3113 CloseDirReply* reply; 3114 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 3115 if (error != B_OK) 3116 return error; 3117 RequestReleaser requestReleaser(port, reply); 3118 3119 // process the reply 3120 if (reply->error != B_OK) 3121 return reply->error; 3122 return error; 3123 } 3124 3125 // _FreeDirCookie 3126 status_t 3127 Volume::_FreeDirCookie(fs_vnode node, fs_vnode cookie) 3128 { 3129 // check capability 3130 if (!fFileSystem->HasCapability(FS_CAPABILITY_FREE_DIR_COOKIE)) 3131 return B_OK; 3132 3133 // get a free port 3134 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 3135 if (!port) 3136 return B_ERROR; 3137 PortReleaser _(fFileSystem->GetPortPool(), port); 3138 3139 // prepare the request 3140 RequestAllocator allocator(port->GetPort()); 3141 FreeDirCookieRequest* request; 3142 status_t error = AllocateRequest(allocator, &request); 3143 if (error != B_OK) 3144 return error; 3145 3146 request->volume = fUserlandVolume; 3147 request->node = node; 3148 request->dirCookie = cookie; 3149 3150 // send the request 3151 KernelRequestHandler handler(this, FREE_DIR_COOKIE_REPLY); 3152 FreeDirCookieReply* reply; 3153 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 3154 if (error != B_OK) 3155 return error; 3156 RequestReleaser requestReleaser(port, reply); 3157 3158 // process the reply 3159 if (reply->error != B_OK) 3160 return reply->error; 3161 return error; 3162 } 3163 3164 // _CloseAttrDir 3165 status_t 3166 Volume::_CloseAttrDir(fs_vnode node, fs_cookie cookie) 3167 { 3168 // check capability 3169 if (!fFileSystem->HasCapability(FS_CAPABILITY_CLOSE_ATTR_DIR)) 3170 return B_OK; 3171 3172 // get a free port 3173 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 3174 if (!port) 3175 return B_ERROR; 3176 PortReleaser _(fFileSystem->GetPortPool(), port); 3177 3178 // prepare the request 3179 RequestAllocator allocator(port->GetPort()); 3180 CloseAttrDirRequest* request; 3181 status_t error = AllocateRequest(allocator, &request); 3182 if (error != B_OK) 3183 return error; 3184 3185 request->volume = fUserlandVolume; 3186 request->node = node; 3187 request->attrDirCookie = cookie; 3188 3189 // send the request 3190 KernelRequestHandler handler(this, CLOSE_ATTR_DIR_REPLY); 3191 CloseAttrDirReply* reply; 3192 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 3193 if (error != B_OK) 3194 return error; 3195 RequestReleaser requestReleaser(port, reply); 3196 3197 // process the reply 3198 if (reply->error != B_OK) 3199 return reply->error; 3200 return error; 3201 } 3202 3203 // _FreeAttrDirCookie 3204 status_t 3205 Volume::_FreeAttrDirCookie(fs_vnode node, fs_cookie cookie) 3206 { 3207 // check capability 3208 if (!fFileSystem->HasCapability(FS_CAPABILITY_FREE_ATTR_DIR_COOKIE)) 3209 return B_OK; 3210 3211 // get a free port 3212 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 3213 if (!port) 3214 return B_ERROR; 3215 PortReleaser _(fFileSystem->GetPortPool(), port); 3216 3217 // prepare the request 3218 RequestAllocator allocator(port->GetPort()); 3219 FreeAttrDirCookieRequest* request; 3220 status_t error = AllocateRequest(allocator, &request); 3221 if (error != B_OK) 3222 return error; 3223 3224 request->volume = fUserlandVolume; 3225 request->node = node; 3226 request->attrDirCookie = cookie; 3227 3228 // send the request 3229 KernelRequestHandler handler(this, FREE_ATTR_DIR_COOKIE_REPLY); 3230 FreeAttrDirCookieReply* reply; 3231 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 3232 if (error != B_OK) 3233 return error; 3234 RequestReleaser requestReleaser(port, reply); 3235 3236 // process the reply 3237 if (reply->error != B_OK) 3238 return reply->error; 3239 return error; 3240 } 3241 3242 // _CloseAttr 3243 status_t 3244 Volume::_CloseAttr(fs_vnode node, fs_cookie cookie) 3245 { 3246 // check capability 3247 if (!fFileSystem->HasCapability(FS_CAPABILITY_CLOSE_ATTR)) 3248 return B_OK; 3249 3250 // get a free port 3251 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 3252 if (!port) 3253 return B_ERROR; 3254 PortReleaser _(fFileSystem->GetPortPool(), port); 3255 3256 // prepare the request 3257 RequestAllocator allocator(port->GetPort()); 3258 CloseAttrRequest* request; 3259 status_t error = AllocateRequest(allocator, &request); 3260 if (error != B_OK) 3261 return error; 3262 3263 request->volume = fUserlandVolume; 3264 request->node = node; 3265 request->attrCookie = cookie; 3266 3267 // send the request 3268 KernelRequestHandler handler(this, CLOSE_ATTR_REPLY); 3269 CloseAttrReply* reply; 3270 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 3271 if (error != B_OK) 3272 return error; 3273 RequestReleaser requestReleaser(port, reply); 3274 3275 // process the reply 3276 if (reply->error != B_OK) 3277 return reply->error; 3278 return error; 3279 } 3280 3281 // _FreeAttrCookie 3282 status_t 3283 Volume::_FreeAttrCookie(fs_vnode node, fs_cookie cookie) 3284 { 3285 // check capability 3286 if (!fFileSystem->HasCapability(FS_CAPABILITY_FREE_ATTR_COOKIE)) 3287 return B_OK; 3288 3289 // get a free port 3290 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 3291 if (!port) 3292 return B_ERROR; 3293 PortReleaser _(fFileSystem->GetPortPool(), port); 3294 3295 // prepare the request 3296 RequestAllocator allocator(port->GetPort()); 3297 FreeAttrCookieRequest* request; 3298 status_t error = AllocateRequest(allocator, &request); 3299 if (error != B_OK) 3300 return error; 3301 3302 request->volume = fUserlandVolume; 3303 request->node = node; 3304 request->attrCookie = cookie; 3305 3306 // send the request 3307 KernelRequestHandler handler(this, FREE_ATTR_COOKIE_REPLY); 3308 FreeAttrCookieReply* reply; 3309 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 3310 if (error != B_OK) 3311 return error; 3312 RequestReleaser requestReleaser(port, reply); 3313 3314 // process the reply 3315 if (reply->error != B_OK) 3316 return reply->error; 3317 return error; 3318 } 3319 3320 // _CloseIndexDir 3321 status_t 3322 Volume::_CloseIndexDir(fs_cookie cookie) 3323 { 3324 // check capability 3325 if (!fFileSystem->HasCapability(FS_CAPABILITY_CLOSE_INDEX_DIR)) 3326 return B_OK; 3327 3328 // get a free port 3329 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 3330 if (!port) 3331 return B_ERROR; 3332 PortReleaser _(fFileSystem->GetPortPool(), port); 3333 3334 // prepare the request 3335 RequestAllocator allocator(port->GetPort()); 3336 CloseIndexDirRequest* request; 3337 status_t error = AllocateRequest(allocator, &request); 3338 if (error != B_OK) 3339 return error; 3340 3341 request->volume = fUserlandVolume; 3342 request->indexDirCookie = cookie; 3343 3344 // send the request 3345 KernelRequestHandler handler(this, CLOSE_INDEX_DIR_REPLY); 3346 CloseIndexDirReply* reply; 3347 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 3348 if (error != B_OK) 3349 return error; 3350 RequestReleaser requestReleaser(port, reply); 3351 3352 // process the reply 3353 if (reply->error != B_OK) 3354 return reply->error; 3355 return error; 3356 } 3357 3358 // _FreeIndexDirCookie 3359 status_t 3360 Volume::_FreeIndexDirCookie(fs_cookie cookie) 3361 { 3362 // check capability 3363 if (!fFileSystem->HasCapability(FS_CAPABILITY_FREE_INDEX_DIR_COOKIE)) 3364 return B_OK; 3365 3366 // get a free port 3367 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 3368 if (!port) 3369 return B_ERROR; 3370 PortReleaser _(fFileSystem->GetPortPool(), port); 3371 3372 // prepare the request 3373 RequestAllocator allocator(port->GetPort()); 3374 FreeIndexDirCookieRequest* request; 3375 status_t error = AllocateRequest(allocator, &request); 3376 if (error != B_OK) 3377 return error; 3378 3379 request->volume = fUserlandVolume; 3380 request->indexDirCookie = cookie; 3381 3382 // send the request 3383 KernelRequestHandler handler(this, FREE_INDEX_DIR_COOKIE_REPLY); 3384 FreeIndexDirCookieReply* reply; 3385 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 3386 if (error != B_OK) 3387 return error; 3388 RequestReleaser requestReleaser(port, reply); 3389 3390 // process the reply 3391 if (reply->error != B_OK) 3392 return reply->error; 3393 return error; 3394 } 3395 3396 // _CloseQuery 3397 status_t 3398 Volume::_CloseQuery(fs_cookie cookie) 3399 { 3400 // check capability 3401 if (!fFileSystem->HasCapability(FS_CAPABILITY_CLOSE_QUERY)) 3402 return B_OK; 3403 3404 // get a free port 3405 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 3406 if (!port) 3407 return B_ERROR; 3408 PortReleaser _(fFileSystem->GetPortPool(), port); 3409 3410 // prepare the request 3411 RequestAllocator allocator(port->GetPort()); 3412 CloseQueryRequest* request; 3413 status_t error = AllocateRequest(allocator, &request); 3414 if (error != B_OK) 3415 return error; 3416 3417 request->volume = fUserlandVolume; 3418 request->queryCookie = cookie; 3419 3420 // send the request 3421 KernelRequestHandler handler(this, CLOSE_QUERY_REPLY); 3422 CloseQueryReply* reply; 3423 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 3424 if (error != B_OK) 3425 return error; 3426 RequestReleaser requestReleaser(port, reply); 3427 3428 // process the reply 3429 if (reply->error != B_OK) 3430 return reply->error; 3431 return error; 3432 } 3433 3434 // _FreeQueryCookie 3435 status_t 3436 Volume::_FreeQueryCookie(fs_cookie cookie) 3437 { 3438 // check capability 3439 if (!fFileSystem->HasCapability(FS_CAPABILITY_FREE_QUERY_COOKIE)) 3440 return B_OK; 3441 3442 // get a free port 3443 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 3444 if (!port) 3445 return B_ERROR; 3446 PortReleaser _(fFileSystem->GetPortPool(), port); 3447 3448 // prepare the request 3449 RequestAllocator allocator(port->GetPort()); 3450 FreeQueryCookieRequest* request; 3451 status_t error = AllocateRequest(allocator, &request); 3452 if (error != B_OK) 3453 return error; 3454 3455 request->volume = fUserlandVolume; 3456 request->queryCookie = cookie; 3457 3458 // send the request 3459 KernelRequestHandler handler(this, FREE_QUERY_COOKIE_REPLY); 3460 FreeQueryCookieReply* reply; 3461 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 3462 if (error != B_OK) 3463 return error; 3464 RequestReleaser requestReleaser(port, reply); 3465 3466 // process the reply 3467 if (reply->error != B_OK) 3468 return reply->error; 3469 return error; 3470 } 3471 3472 // _SendRequest 3473 status_t 3474 Volume::_SendRequest(RequestPort* port, RequestAllocator* allocator, 3475 RequestHandler* handler, Request** reply) 3476 { 3477 if (!fFileSystem->IsUserlandServerThread()) 3478 return port->SendRequest(allocator, handler, reply); 3479 // Here it gets dangerous: a thread of the userland server team being here 3480 // calls for trouble. We try receiving the request with a timeout, and 3481 // close the port -- which will disconnect the whole FS. 3482 status_t error = port->SendRequest(allocator, handler, reply, 3483 kUserlandServerlandPortTimeout); 3484 if (error == B_TIMED_OUT || error == B_WOULD_BLOCK) 3485 port->Close(); 3486 return error; 3487 } 3488 3489 // _SendReceiptAck 3490 status_t 3491 Volume::_SendReceiptAck(RequestPort* port) 3492 { 3493 RequestAllocator allocator(port->GetPort()); 3494 ReceiptAckReply* request; 3495 status_t error = AllocateRequest(allocator, &request); 3496 if (error != B_OK) 3497 return error; 3498 return port->SendRequest(&allocator); 3499 } 3500 3501 // _IncrementVNodeCount 3502 void 3503 Volume::_IncrementVNodeCount(ino_t vnid) 3504 { 3505 if (!fVNodeCountingEnabled) 3506 return; 3507 AutoLocker<VNodeCountMap> _(fVNodeCountMap); 3508 if (!fVNodeCountingEnabled) // someone may have changed it 3509 return; 3510 // get the counter 3511 int32* count = fVNodeCountMap->Get(vnid); 3512 if (!count) { 3513 // vnode not known yet: create and add a new counter 3514 count = new(nothrow) int32(0); 3515 if (!count) { 3516 ERROR(("Volume::_IncrementVNodeCount(): Failed to allocate " 3517 "counter. Disabling vnode counting.\n")); 3518 fVNodeCountingEnabled = false; 3519 return; 3520 } 3521 if (fVNodeCountMap->Put(vnid, count) != B_OK) { 3522 ERROR(("Volume::_IncrementVNodeCount(): Failed to add counter. " 3523 "Disabling vnode counting.\n")); 3524 delete count; 3525 fVNodeCountingEnabled = false; 3526 return; 3527 } 3528 } 3529 // increment the counter 3530 (*count)++; 3531 //PRINT(("_IncrementVNodeCount(%Ld): count: %ld, fVNodeCountMap size: %ld\n", vnid, *count, fVNodeCountMap->Size())); 3532 } 3533 3534 // _DecrementVNodeCount 3535 void 3536 Volume::_DecrementVNodeCount(ino_t vnid) 3537 { 3538 if (!fVNodeCountingEnabled) 3539 return; 3540 AutoLocker<VNodeCountMap> _(fVNodeCountMap); 3541 if (!fVNodeCountingEnabled) // someone may have changed it 3542 return; 3543 int32* count = fVNodeCountMap->Get(vnid); 3544 if (!count) { 3545 // that should never happen 3546 ERROR(("Volume::_DecrementVNodeCount(): Failed to get counter. " 3547 "Disabling vnode counting.\n")); 3548 fVNodeCountingEnabled = false; 3549 return; 3550 } 3551 (*count)--; 3552 //int32 tmpCount = *count; 3553 if (*count == 0) 3554 fVNodeCountMap->Remove(vnid); 3555 //PRINT(("_DecrementVNodeCount(%Ld): count: %ld, fVNodeCountMap size: %ld\n", vnid, tmpCount, fVNodeCountMap->Size())); 3556 } 3557 3558 // _InternalIOCtl 3559 status_t 3560 Volume::_InternalIOCtl(userlandfs_ioctl* buffer, int32 bufferSize) 3561 { 3562 if (buffer->version != USERLAND_IOCTL_CURRENT_VERSION) 3563 return B_BAD_VALUE; 3564 status_t result = B_OK; 3565 switch (buffer->command) { 3566 case USERLAND_IOCTL_PUT_ALL_PENDING_VNODES: 3567 result = _PutAllPendingVNodes(); 3568 break; 3569 default: 3570 return B_BAD_VALUE; 3571 } 3572 buffer->error = result; 3573 return B_OK; 3574 } 3575 3576 // _PutAllPendingVNodes 3577 status_t 3578 Volume::_PutAllPendingVNodes() 3579 { 3580 PRINT(("Volume::_PutAllPendingVNodes()\n")); 3581 if (!fFileSystem->GetPortPool()->IsDisconnected()) { 3582 PRINT(("Volume::_PutAllPendingVNodes() failed: still connected\n")); 3583 return USERLAND_IOCTL_STILL_CONNECTED; 3584 } 3585 if (!fVNodeCountingEnabled) { 3586 PRINT(("Volume::_PutAllPendingVNodes() failed: vnode counting " 3587 "disabled\n")); 3588 return USERLAND_IOCTL_VNODE_COUNTING_DISABLED; 3589 } 3590 { 3591 AutoLocker<VNodeCountMap> _(fVNodeCountMap); 3592 if (!fVNodeCountingEnabled) {// someone may have changed it 3593 PRINT(("Volume::_PutAllPendingVNodes() failed: vnode counting " 3594 "disabled\n")); 3595 return USERLAND_IOCTL_VNODE_COUNTING_DISABLED; 3596 } 3597 // Check whether there are open entities at the moment. 3598 if (fOpenFiles > 0) { 3599 PRINT(("Volume::_PutAllPendingVNodes() failed: open files\n")); 3600 return USERLAND_IOCTL_OPEN_FILES; 3601 } 3602 if (fOpenDirectories > 0) { 3603 PRINT(("Volume::_PutAllPendingVNodes() failed: open dirs\n")); 3604 return USERLAND_IOCTL_OPEN_DIRECTORIES; 3605 } 3606 if (fOpenAttributeDirectories > 0) { 3607 PRINT(("Volume::_PutAllPendingVNodes() failed: open attr dirs\n")); 3608 return USERLAND_IOCTL_OPEN_ATTRIBUTE_DIRECTORIES; 3609 } 3610 if (fOpenAttributes > 0) { 3611 PRINT(("Volume::_PutAllPendingVNodes() failed: open attributes\n")); 3612 return USERLAND_IOCTL_OPEN_ATTRIBUTES; 3613 } 3614 if (fOpenIndexDirectories > 0) { 3615 PRINT(("Volume::_PutAllPendingVNodes() failed: open index dirs\n")); 3616 return USERLAND_IOCTL_OPEN_INDEX_DIRECTORIES; 3617 } 3618 if (fOpenQueries > 0) { 3619 PRINT(("Volume::_PutAllPendingVNodes() failed: open queries\n")); 3620 return USERLAND_IOCTL_OPEN_QUERIES; 3621 } 3622 // No open entities. Since the port pool is disconnected, no new 3623 // entities can be opened. Disable node counting and put all pending 3624 // vnodes. 3625 fVNodeCountingEnabled = false; 3626 } 3627 int32 putVNodeCount = 0; 3628 for (VNodeCountMap::Iterator it = fVNodeCountMap->GetIterator(); 3629 it.HasNext();) { 3630 VNodeCountMap::Entry entry = it.Next(); 3631 int32 count = *entry.value; 3632 for (int32 i = 0; i < count; i++) { 3633 PutVNode(entry.key.value); 3634 putVNodeCount++; 3635 } 3636 } 3637 PRINT(("Volume::_PutAllPendingVNodes() successful: Put %ld vnodes\n", 3638 putVNodeCount)); 3639 return B_OK; 3640 } 3641 3642