1// Volume.cpp 2 3#include <errno.h> 4#include <unistd.h> 5 6#include "AutoLocker.h" 7#include "Compatibility.h" 8#include "Debug.h" 9#include "FileSystem.h" 10#include "HashMap.h" 11#include "IOCtlInfo.h" 12#include "KernelRequestHandler.h" 13#include "PortReleaser.h" 14#include "RequestAllocator.h" 15#include "RequestPort.h" 16#include "Requests.h" 17#include "userlandfs_ioctl.h" 18#include "Volume.h" 19 20// If a thread of the userland server enters userland FS kernel code and 21// is sending a request, this is the time after which it shall time out 22// waiting for a reply. 23static const bigtime_t kUserlandServerlandPortTimeout = 10000000; // 10s 24 25// MountVNodeMap 26struct Volume::MountVNodeMap : public HashMap<HashKey64<vnode_id>, void*> { 27}; 28 29// VNodeCountMap 30struct Volume::VNodeCountMap 31 : public SynchronizedHashMap<HashKey64<vnode_id>, int32*> { 32}; 33 34// AutoIncrementer 35class Volume::AutoIncrementer { 36public: 37 AutoIncrementer(vint32* variable) 38 : fVariable(variable) 39 { 40 if (fVariable) 41 atomic_add(fVariable, 1); 42 } 43 44 ~AutoIncrementer() 45 { 46 if (fVariable) 47 atomic_add(fVariable, -1); 48 } 49 50 void Keep() 51 { 52 fVariable = NULL; 53 } 54 55private: 56 vint32* fVariable; 57}; 58 59// constructor 60Volume::Volume(FileSystem* fileSystem, nspace_id id) 61 : Referencable(true), 62 fFileSystem(fileSystem), 63 fID(id), 64 fUserlandVolume(NULL), 65 fRootID(0), 66 fRootNode(NULL), 67 fMountVNodes(NULL), 68 fOpenFiles(0), 69 fOpenDirectories(0), 70 fOpenAttributeDirectories(0), 71 fOpenIndexDirectories(0), 72 fOpenQueries(0), 73 fVNodeCountMap(NULL), 74 fVNodeCountingEnabled(false) 75{ 76} 77 78// destructor 79Volume::~Volume() 80{ 81} 82 83// GetFileSystem 84FileSystem* 85Volume::GetFileSystem() const 86{ 87 return fFileSystem; 88} 89 90// GetID 91nspace_id 92Volume::GetID() const 93{ 94 return fID; 95} 96 97// GetUserlandVolume 98void* 99Volume::GetUserlandVolume() const 100{ 101 return fUserlandVolume; 102} 103 104// GetRootID 105vnode_id 106Volume::GetRootID() const 107{ 108 return fRootID; 109} 110 111// IsMounting 112bool 113Volume::IsMounting() const 114{ 115 return fMountVNodes; 116} 117 118 119// #pragma mark - 120// #pragma mark ----- client methods ----- 121 122// GetVNode 123status_t 124Volume::GetVNode(vnode_id vnid, void** node) 125{ 126PRINT(("get_vnode(%ld, %Ld)\n", fID, vnid)); 127 if (IsMounting() && !fMountVNodes->ContainsKey(vnid)) { 128 ERROR(("Volume::GetVNode(): get_vnode() invoked for unknown vnode " 129 "while mounting!\n")); 130 } 131 status_t error = get_vnode(fID, vnid, node); 132 if (error == B_OK) 133 _IncrementVNodeCount(vnid); 134 return error; 135} 136 137// PutVNode 138status_t 139Volume::PutVNode(vnode_id vnid) 140{ 141PRINT(("put_vnode(%ld, %Ld)\n", fID, vnid)); 142 status_t error = put_vnode(fID, vnid); 143 if (error == B_OK) 144 _DecrementVNodeCount(vnid); 145 return error; 146} 147 148// NewVNode 149status_t 150Volume::NewVNode(vnode_id vnid, void* node) 151{ 152PRINT(("new_vnode(%ld, %Ld)\n", fID, vnid)); 153 status_t error = new_vnode(fID, vnid, node); 154 if (error == B_OK) { 155 if (IsMounting()) { 156 error = fMountVNodes->Put(vnid, node); 157 if (error != B_OK) { 158 ERROR(("Volume::NewVNode(): Failed to add vnode to mount " 159 "vnode map!\n")); 160 put_vnode(fID, vnid); 161 return error; 162 } 163 } 164 _IncrementVNodeCount(vnid); 165 } 166 return error; 167} 168 169// RemoveVNode 170status_t 171Volume::RemoveVNode(vnode_id vnid) 172{ 173PRINT(("remove_vnode(%ld, %Ld)\n", fID, vnid)); 174 return remove_vnode(fID, vnid); 175} 176 177// UnremoveVNode 178status_t 179Volume::UnremoveVNode(vnode_id vnid) 180{ 181PRINT(("unremove_vnode(%ld, %Ld)\n", fID, vnid)); 182 return unremove_vnode(fID, vnid); 183} 184 185// IsVNodeRemoved 186status_t 187Volume::IsVNodeRemoved(vnode_id vnid) 188{ 189PRINT(("is_vnode_removed(%ld, %Ld)\n", fID, vnid)); 190 return is_vnode_removed(fID, vnid); 191} 192 193// #pragma mark - 194// #pragma mark ----- FS ----- 195 196// Mount 197status_t 198Volume::Mount(const char* device, ulong flags, const char* parameters, 199 int32 len) 200{ 201 // Create a map that holds vnode_id->void* mappings of all vnodes 202 // created while mounting. We need it to get the root node. 203 MountVNodeMap vnodeMap; 204 status_t error = vnodeMap.InitCheck(); 205 if (error != B_OK) 206 RETURN_ERROR(error); 207 fMountVNodes = &vnodeMap; 208 error = _Mount(device, flags, parameters, len); 209 fMountVNodes = NULL; 210 if (error == B_OK) { 211 // fetch the root node, so that we can serve Walk() requests on it, 212 // after the connection to the userland server is gone 213 if (!vnodeMap.ContainsKey(fRootID)) { 214 // The root node was not added while mounting. That's a serious 215 // problem -- not only because we don't have it, but also because 216 // the VFS requires new_vnode() to be invoked for the root node. 217 ERROR(("Volume::Mount(): new_vnode() was not called for root node! " 218 "Unmounting...\n")); 219 Unmount(); 220 return B_ERROR; 221 } 222 fRootNode = vnodeMap.Get(fRootID); 223 } 224 return error; 225} 226 227// Unmount 228status_t 229Volume::Unmount() 230{ 231 status_t error = _Unmount(); 232 // free the memory associated with the vnode count map 233 if (fVNodeCountMap) { 234 AutoLocker<VNodeCountMap> _(fVNodeCountMap); 235 fVNodeCountingEnabled = false; 236 for (VNodeCountMap::Iterator it = fVNodeCountMap->GetIterator(); 237 it.HasNext();) { 238 VNodeCountMap::Entry entry = it.Next(); 239 delete entry.value; 240 } 241 delete fVNodeCountMap; 242 fVNodeCountMap = NULL; 243 } 244 fFileSystem->VolumeUnmounted(this); 245 return error; 246} 247 248// Sync 249status_t 250Volume::Sync() 251{ 252 // get a free port 253 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 254 if (!port) 255 return B_ERROR; 256 PortReleaser _(fFileSystem->GetPortPool(), port); 257 // prepare the request 258 RequestAllocator allocator(port->GetPort()); 259 SyncVolumeRequest* request; 260 status_t error = AllocateRequest(allocator, &request); 261 if (error != B_OK) 262 return error; 263 request->volume = fUserlandVolume; 264 // send the request 265 KernelRequestHandler handler(this, SYNC_VOLUME_REPLY); 266 SyncVolumeReply* reply; 267 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 268 if (error != B_OK) 269 return error; 270 RequestReleaser requestReleaser(port, reply); 271 // process the reply 272 if (reply->error != B_OK) 273 return reply->error; 274 return error; 275} 276 277// ReadFSStat 278status_t 279Volume::ReadFSStat(fs_info* info) 280{ 281 // get a free port 282 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 283 if (!port) 284 return B_ERROR; 285 PortReleaser _(fFileSystem->GetPortPool(), port); 286 // prepare the request 287 RequestAllocator allocator(port->GetPort()); 288 ReadFSStatRequest* request; 289 status_t error = AllocateRequest(allocator, &request); 290 if (error != B_OK) 291 return error; 292 request->volume = fUserlandVolume; 293 // send the request 294 KernelRequestHandler handler(this, READ_FS_STAT_REPLY); 295 ReadFSStatReply* reply; 296 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 297 if (error != B_OK) 298 return error; 299 RequestReleaser requestReleaser(port, reply); 300 // process the reply 301 if (reply->error != B_OK) 302 return reply->error; 303 *info = reply->info; 304 return error; 305} 306 307// WriteFSStat 308status_t 309Volume::WriteFSStat(struct fs_info *info, long mask) 310{ 311 // get a free port 312 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 313 if (!port) 314 return B_ERROR; 315 PortReleaser _(fFileSystem->GetPortPool(), port); 316 // prepare the request 317 RequestAllocator allocator(port->GetPort()); 318 WriteFSStatRequest* request; 319 status_t error = AllocateRequest(allocator, &request); 320 if (error != B_OK) 321 return error; 322 request->volume = fUserlandVolume; 323 request->info = *info; 324 request->mask = mask; 325 // send the request 326 KernelRequestHandler handler(this, WRITE_FS_STAT_REPLY); 327 WriteFSStatReply* reply; 328 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 329 if (error != B_OK) 330 return error; 331 RequestReleaser requestReleaser(port, reply); 332 // process the reply 333 if (reply->error != B_OK) 334 return reply->error; 335 return error; 336} 337 338// #pragma mark - 339// #pragma mark ----- vnodes ----- 340 341// ReadVNode 342status_t 343Volume::ReadVNode(vnode_id vnid, char reenter, void** node) 344{ 345 // get a free port 346 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 347 if (!port) 348 return B_ERROR; 349 PortReleaser _(fFileSystem->GetPortPool(), port); 350 // prepare the request 351 RequestAllocator allocator(port->GetPort()); 352 ReadVNodeRequest* request; 353 status_t error = AllocateRequest(allocator, &request); 354 if (error != B_OK) 355 return error; 356 request->volume = fUserlandVolume; 357 request->vnid = vnid; 358 request->reenter = reenter; 359 // send the request 360 KernelRequestHandler handler(this, READ_VNODE_REPLY); 361 ReadVNodeReply* reply; 362 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 363 if (error != B_OK) 364 return error; 365 RequestReleaser requestReleaser(port, reply); 366 // process the reply 367 if (reply->error != B_OK) 368 return reply->error; 369 *node = reply->node; 370 return error; 371} 372 373// WriteVNode 374status_t 375Volume::WriteVNode(void* node, char reenter) 376{ 377 status_t error = _WriteVNode(node, reenter); 378 if (error != B_OK && fFileSystem->GetPortPool()->IsDisconnected()) { 379 // This isn't really necessary, since the VFS basically ignores the 380 // return value -- at least OBOS. The fshell panic()s; didn't check 381 // BeOS. It doesn't harm to appear to behave nicely. :-) 382 WARN(("Volume::WriteVNode(): connection lost, forcing write vnode\n")); 383 return B_OK; 384 } 385 return error; 386} 387 388// RemoveVNode 389status_t 390Volume::RemoveVNode(void* node, char reenter) 391{ 392 // get a free port 393 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 394 if (!port) 395 return B_ERROR; 396 PortReleaser _(fFileSystem->GetPortPool(), port); 397 // prepare the request 398 RequestAllocator allocator(port->GetPort()); 399 FSRemoveVNodeRequest* request; 400 status_t error = AllocateRequest(allocator, &request); 401 if (error != B_OK) 402 return error; 403 request->volume = fUserlandVolume; 404 request->node = node; 405 request->reenter = reenter; 406 // send the request 407 KernelRequestHandler handler(this, FS_REMOVE_VNODE_REPLY); 408 FSRemoveVNodeReply* reply; 409 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 410 if (error != B_OK) 411 return error; 412 RequestReleaser requestReleaser(port, reply); 413 // process the reply 414 if (reply->error != B_OK) 415 return reply->error; 416 return error; 417} 418 419// #pragma mark - 420// #pragma mark ----- nodes ----- 421 422// FSync 423status_t 424Volume::FSync(void* node) 425{ 426 // get a free port 427 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 428 if (!port) 429 return B_ERROR; 430 PortReleaser _(fFileSystem->GetPortPool(), port); 431 // prepare the request 432 RequestAllocator allocator(port->GetPort()); 433 FSyncRequest* request; 434 status_t error = AllocateRequest(allocator, &request); 435 if (error != B_OK) 436 return error; 437 request->volume = fUserlandVolume; 438 request->node = node; 439 // send the request 440 KernelRequestHandler handler(this, FSYNC_REPLY); 441 FSyncReply* reply; 442 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 443 if (error != B_OK) 444 return error; 445 RequestReleaser requestReleaser(port, reply); 446 // process the reply 447 if (reply->error != B_OK) 448 return reply->error; 449 return error; 450} 451 452// ReadStat 453status_t 454Volume::ReadStat(void* node, struct stat* st) 455{ 456 // get a free port 457 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 458 if (!port) 459 return B_ERROR; 460 PortReleaser _(fFileSystem->GetPortPool(), port); 461 // prepare the request 462 RequestAllocator allocator(port->GetPort()); 463 ReadStatRequest* request; 464 status_t error = AllocateRequest(allocator, &request); 465 if (error != B_OK) 466 return error; 467 request->volume = fUserlandVolume; 468 request->node = node; 469 // send the request 470 KernelRequestHandler handler(this, READ_STAT_REPLY); 471 ReadStatReply* reply; 472 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 473 if (error != B_OK) 474 return error; 475 RequestReleaser requestReleaser(port, reply); 476 // process the reply 477 if (reply->error != B_OK) 478 return reply->error; 479 *st = reply->st; 480 return error; 481} 482 483// WriteStat 484status_t 485Volume::WriteStat(void* node, struct stat* st, long mask) 486{ 487 // get a free port 488 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 489 if (!port) 490 return B_ERROR; 491 PortReleaser _(fFileSystem->GetPortPool(), port); 492 // prepare the request 493 RequestAllocator allocator(port->GetPort()); 494 WriteStatRequest* request; 495 status_t error = AllocateRequest(allocator, &request); 496 if (error != B_OK) 497 return error; 498 request->volume = fUserlandVolume; 499 request->node = node; 500 request->st = *st; 501 request->mask = mask; 502 // send the request 503 KernelRequestHandler handler(this, WRITE_STAT_REPLY); 504 WriteStatReply* reply; 505 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 506 if (error != B_OK) 507 return error; 508 RequestReleaser requestReleaser(port, reply); 509 // process the reply 510 if (reply->error != B_OK) 511 return reply->error; 512 return error; 513} 514 515// Access 516status_t 517Volume::Access(void* node, int mode) 518{ 519 // get a free port 520 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 521 if (!port) 522 return B_ERROR; 523 PortReleaser _(fFileSystem->GetPortPool(), port); 524 // prepare the request 525 RequestAllocator allocator(port->GetPort()); 526 AccessRequest* request; 527 status_t error = AllocateRequest(allocator, &request); 528 if (error != B_OK) 529 return error; 530 request->volume = fUserlandVolume; 531 request->node = node; 532 request->mode = mode; 533 // send the request 534 KernelRequestHandler handler(this, ACCESS_REPLY); 535 AccessReply* reply; 536 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 537 if (error != B_OK) 538 return error; 539 RequestReleaser requestReleaser(port, reply); 540 // process the reply 541 if (reply->error != B_OK) 542 return reply->error; 543 return error; 544} 545 546// #pragma mark - 547// #pragma mark ----- files ----- 548 549// Create 550status_t 551Volume::Create(void* dir, const char* name, int openMode, int mode, 552 vnode_id* vnid, void** cookie) 553{ 554 // get a free port 555 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 556 if (!port) 557 return B_ERROR; 558 PortReleaser _(fFileSystem->GetPortPool(), port); 559 // prepare the request 560 RequestAllocator allocator(port->GetPort()); 561 CreateRequest* request; 562 status_t error = AllocateRequest(allocator, &request); 563 if (error != B_OK) 564 return error; 565 request->volume = fUserlandVolume; 566 request->node = dir; 567 error = allocator.AllocateString(request->name, name); 568 request->openMode = openMode; 569 request->mode = mode; 570 if (error != B_OK) 571 return error; 572 // send the request 573 KernelRequestHandler handler(this, CREATE_REPLY); 574 CreateReply* reply; 575 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 576 if (error != B_OK) 577 return error; 578 RequestReleaser requestReleaser(port, reply); 579 // process the reply 580 if (reply->error != B_OK) 581 return reply->error; 582 *vnid = reply->vnid; 583 *cookie = reply->fileCookie; 584 if (error == B_OK) 585 _DecrementVNodeCount(*vnid); 586 // The VFS will balance the new_vnode() call for the FS. 587 return error; 588} 589 590// Open 591status_t 592Volume::Open(void* node, int openMode, void** cookie) 593{ 594 // get a free port 595 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 596 if (!port) 597 return B_ERROR; 598 PortReleaser _(fFileSystem->GetPortPool(), port); 599 AutoIncrementer incrementer(&fOpenFiles); 600 // prepare the request 601 RequestAllocator allocator(port->GetPort()); 602 OpenRequest* request; 603 status_t error = AllocateRequest(allocator, &request); 604 if (error != B_OK) 605 return error; 606 request->volume = fUserlandVolume; 607 request->node = node; 608 request->openMode = openMode; 609 // send the request 610 KernelRequestHandler handler(this, OPEN_REPLY); 611 OpenReply* reply; 612 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 613 if (error != B_OK) 614 return error; 615 RequestReleaser requestReleaser(port, reply); 616 // process the reply 617 if (reply->error != B_OK) 618 return reply->error; 619 incrementer.Keep(); 620 *cookie = reply->fileCookie; 621 return error; 622} 623 624// Close 625status_t 626Volume::Close(void* node, void* cookie) 627{ 628 status_t error = _Close(node, cookie); 629 if (error != B_OK && fFileSystem->GetPortPool()->IsDisconnected()) { 630 // This isn't really necessary, as the return value is irrelevant to 631 // the VFS. OBOS ignores it completely. The fsshell returns it to the 632 // userland, but considers the node closed anyway. 633 WARN(("Volume::Close(): connection lost, forcing close\n")); 634 return B_OK; 635 } 636 return error; 637} 638 639// FreeCookie 640status_t 641Volume::FreeCookie(void* node, void* cookie) 642{ 643 status_t error = _FreeCookie(node, cookie); 644 bool disconnected = false; 645 if (error != B_OK && fFileSystem->GetPortPool()->IsDisconnected()) { 646 // This isn't really necessary, as the return value is irrelevant to 647 // the VFS. It's completely ignored by OBOS as well as by the fsshell. 648 WARN(("Volume::FreeCookie(): connection lost, forcing free cookie\n")); 649 error = B_OK; 650 disconnected = true; 651 } 652 int32 openFiles = atomic_add(&fOpenFiles, -1); 653 if (openFiles <= 1 && disconnected) 654 _PutAllPendingVNodes(); 655 return error; 656} 657 658// Read 659status_t 660Volume::Read(void* node, void* cookie, off_t pos, void* buffer, 661 size_t bufferSize, size_t* bytesRead) 662{ 663 *bytesRead = 0; 664 // get a free port 665 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 666 if (!port) 667 return B_ERROR; 668 PortReleaser _(fFileSystem->GetPortPool(), port); 669 // prepare the request 670 RequestAllocator allocator(port->GetPort()); 671 ReadRequest* request; 672 status_t error = AllocateRequest(allocator, &request); 673 if (error != B_OK) 674 return error; 675 request->volume = fUserlandVolume; 676 request->node = node; 677 request->fileCookie = cookie; 678 request->pos = pos; 679 request->size = bufferSize; 680 // send the request 681 KernelRequestHandler handler(this, READ_REPLY); 682 ReadReply* reply; 683 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 684 if (error != B_OK) 685 return error; 686 RequestReleaser requestReleaser(port, reply); 687 // process the reply 688 if (reply->error != B_OK) 689 return reply->error; 690 void* readBuffer = reply->buffer.GetData(); 691 if (reply->bytesRead > (uint32)reply->buffer.GetSize() 692 || reply->bytesRead > bufferSize) { 693 return B_BAD_DATA; 694 } 695 if (reply->bytesRead > 0) 696 memcpy(buffer, readBuffer, reply->bytesRead); 697 *bytesRead = reply->bytesRead; 698 _SendReceiptAck(port); 699 return error; 700} 701 702// Write 703status_t 704Volume::Write(void* node, void* cookie, off_t pos, const void* buffer, 705 size_t size, size_t* bytesWritten) 706{ 707 *bytesWritten = 0; 708 // get a free port 709 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 710 if (!port) 711 return B_ERROR; 712 PortReleaser _(fFileSystem->GetPortPool(), port); 713 // prepare the request 714 RequestAllocator allocator(port->GetPort()); 715 WriteRequest* request; 716 status_t error = AllocateRequest(allocator, &request); 717 if (error != B_OK) 718 return error; 719 request->volume = fUserlandVolume; 720 request->node = node; 721 request->fileCookie = cookie; 722 request->pos = pos; 723 error = allocator.AllocateData(request->buffer, buffer, size, 1); 724 if (error != B_OK) 725 return error; 726 // send the request 727 KernelRequestHandler handler(this, WRITE_REPLY); 728 WriteReply* reply; 729 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 730 if (error != B_OK) 731 return error; 732 RequestReleaser requestReleaser(port, reply); 733 // process the reply 734 if (reply->error != B_OK) 735 return reply->error; 736 *bytesWritten = reply->bytesWritten; 737 return error; 738} 739 740// IOCtl 741status_t 742Volume::IOCtl(void* node, void* cookie, int command, void *buffer, 743 size_t len) 744{ 745 // check the command and its parameters 746 bool isBuffer = false; 747 int32 bufferSize = 0; 748 int32 writeSize = 0; 749 switch (command) { 750 case IOCTL_FILE_UNCACHED_IO: 751 buffer = NULL; 752 break; 753 case IOCTL_CREATE_TIME: 754 case IOCTL_MODIFIED_TIME: 755 isBuffer = 0; 756 bufferSize = 0; 757 writeSize = sizeof(bigtime_t); 758 break; 759 case USERLANDFS_IOCTL: 760 area_id area; 761 area_info info; 762 PRINT(("Volume::IOCtl(): USERLANDFS_IOCTL\n")); 763 if ((area = area_for(buffer)) >= 0) { 764 if (get_area_info(area, &info) == B_OK) { 765 if ((uint8*)buffer - (uint8*)info.address 766 + sizeof(userlandfs_ioctl) <= info.size) { 767 if (strncmp(((userlandfs_ioctl*)buffer)->magic, 768 kUserlandFSIOCtlMagic, 769 USERLAND_IOCTL_MAGIC_LENGTH) == 0) { 770 return _InternalIOCtl((userlandfs_ioctl*)buffer, 771 bufferSize); 772 } else 773 PRINT(("Volume::IOCtl(): bad magic\n")); 774 } else 775 PRINT(("Volume::IOCtl(): bad buffer size\n")); 776 } else 777 PRINT(("Volume::IOCtl(): failed to get area info\n")); 778 } else 779 PRINT(("Volume::IOCtl(): bad area\n")); 780 // fall through... 781 default: 782 { 783 // We don't know the command. Check whether the FileSystem knows 784 // about it. 785 const IOCtlInfo* info = fFileSystem->GetIOCtlInfo(command); 786 if (!info) { 787 PRINT(("Volume::IOCtl(): unknown command\n")); 788 return B_BAD_VALUE; 789 } 790 isBuffer = info->isBuffer; 791 bufferSize = info->bufferSize; 792 writeSize = info->writeBufferSize; 793 // If the buffer shall indeed specify a buffer, check it. 794 if (info->isBuffer) { 795 if (!buffer) { 796 PRINT(("Volume::IOCtl(): buffer is NULL\n")); 797 return B_BAD_VALUE; 798 } 799 area_id area = area_for(buffer); 800 if (area < 0) { 801 PRINT(("Volume::IOCtl(): bad area\n")); 802 return B_BAD_VALUE; 803 } 804 area_info info; 805 if (get_area_info(area, &info) != B_OK) { 806 PRINT(("Volume::IOCtl(): failed to get area info\n")); 807 return B_BAD_VALUE; 808 } 809 int32 areaSize = info.size - ((uint8*)buffer 810 - (uint8*)info.address); 811 if (bufferSize > areaSize || writeSize > areaSize) { 812 PRINT(("Volume::IOCtl(): bad buffer size\n")); 813 return B_BAD_VALUE; 814 } 815 if (writeSize > 0 && !(info.protection & B_WRITE_AREA)) { 816 PRINT(("Volume::IOCtl(): buffer not writable\n")); 817 return B_BAD_VALUE; 818 } 819 } 820 break; 821 } 822 } 823 // get a free port 824 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 825 if (!port) 826 return B_ERROR; 827 PortReleaser _(fFileSystem->GetPortPool(), port); 828 // prepare the request 829 RequestAllocator allocator(port->GetPort()); 830 IOCtlRequest* request; 831 status_t error = AllocateRequest(allocator, &request); 832 if (error != B_OK) 833 return error; 834 request->volume = fUserlandVolume; 835 request->node = node; 836 request->fileCookie = cookie; 837 request->command = command; 838 request->bufferParameter = buffer; 839 request->isBuffer = isBuffer; 840 request->lenParameter = len; 841 request->writeSize = writeSize; 842 if (isBuffer && bufferSize > 0) { 843 error = allocator.AllocateData(request->buffer, buffer, bufferSize, 8); 844 if (error != B_OK) 845 return error; 846 } 847 // send the request 848 KernelRequestHandler handler(this, IOCTL_REPLY); 849 IOCtlReply* reply; 850 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 851 if (error != B_OK) 852 return error; 853 RequestReleaser requestReleaser(port, reply); 854 // process the reply 855 if (reply->error != B_OK) 856 return reply->error; 857 // Copy back the buffer even if the result is not B_OK. The protocol 858 // is defined by the FS developer and may include writing data into 859 // the buffer in some error cases. 860 if (isBuffer && writeSize > 0 && reply->buffer.GetData()) { 861 if (writeSize > reply->buffer.GetSize()) 862 writeSize = reply->buffer.GetSize(); 863 memcpy(buffer, reply->buffer.GetData(), writeSize); 864 _SendReceiptAck(port); 865 } 866 return reply->ioctlError; 867} 868 869// SetFlags 870status_t 871Volume::SetFlags(void* node, void* cookie, int flags) 872{ 873 // get a free port 874 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 875 if (!port) 876 return B_ERROR; 877 PortReleaser _(fFileSystem->GetPortPool(), port); 878 // prepare the request 879 RequestAllocator allocator(port->GetPort()); 880 SetFlagsRequest* request; 881 status_t error = AllocateRequest(allocator, &request); 882 if (error != B_OK) 883 return error; 884 request->volume = fUserlandVolume; 885 request->node = node; 886 request->fileCookie = cookie; 887 request->flags = flags; 888 // send the request 889 KernelRequestHandler handler(this, SET_FLAGS_REPLY); 890 SetFlagsReply* reply; 891 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 892 if (error != B_OK) 893 return error; 894 RequestReleaser requestReleaser(port, reply); 895 // process the reply 896 if (reply->error != B_OK) 897 return reply->error; 898 return error; 899} 900 901// Select 902status_t 903Volume::Select(void* node, void* cookie, uint8 event, uint32 ref, 904 selectsync* sync) 905{ 906 // get a free port 907 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 908 if (!port) 909 return B_ERROR; 910 PortReleaser _(fFileSystem->GetPortPool(), port); 911 // prepare the request 912 RequestAllocator allocator(port->GetPort()); 913 SelectRequest* request; 914 status_t error = AllocateRequest(allocator, &request); 915 if (error != B_OK) 916 return error; 917 request->volume = fUserlandVolume; 918 request->node = node; 919 request->fileCookie = cookie; 920 request->event = event; 921 request->ref = ref; 922 request->sync = sync; 923 // add a selectsync entry 924 error = fFileSystem->AddSelectSyncEntry(sync); 925 if (error != B_OK) 926 return error; 927 // send the request 928 KernelRequestHandler handler(this, SELECT_REPLY); 929 SelectReply* reply; 930 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 931 if (error != B_OK) { 932 fFileSystem->RemoveSelectSyncEntry(sync); 933 return error; 934 } 935 RequestReleaser requestReleaser(port, reply); 936 // process the reply 937 if (reply->error != B_OK) { 938 fFileSystem->RemoveSelectSyncEntry(sync); 939 return reply->error; 940 } 941 return error; 942} 943 944// Deselect 945status_t 946Volume::Deselect(void* node, void* cookie, uint8 event, selectsync* sync) 947{ 948 struct SyncRemover { 949 SyncRemover(FileSystem* fs, selectsync* sync) 950 : fs(fs), sync(sync) {} 951 ~SyncRemover() { fs->RemoveSelectSyncEntry(sync); } 952 953 FileSystem* fs; 954 selectsync* sync; 955 } syncRemover(fFileSystem, sync); 956 // get a free port 957 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 958 if (!port) 959 return B_ERROR; 960 PortReleaser _(fFileSystem->GetPortPool(), port); 961 // prepare the request 962 RequestAllocator allocator(port->GetPort()); 963 DeselectRequest* request; 964 status_t error = AllocateRequest(allocator, &request); 965 if (error != B_OK) 966 return error; 967 request->volume = fUserlandVolume; 968 request->node = node; 969 request->fileCookie = cookie; 970 request->event = event; 971 request->sync = sync; 972 // send the request 973 KernelRequestHandler handler(this, DESELECT_REPLY); 974 DeselectReply* reply; 975 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 976 if (error != B_OK) 977 return error; 978 RequestReleaser requestReleaser(port, reply); 979 // process the reply 980 if (reply->error != B_OK) 981 return reply->error; 982 return error; 983} 984 985// #pragma mark - 986// #pragma mark ----- hard links / symlinks ----- 987 988// Link 989status_t 990Volume::Link(void* dir, const char* name, void* node) 991{ 992 // get a free port 993 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 994 if (!port) 995 return B_ERROR; 996 PortReleaser _(fFileSystem->GetPortPool(), port); 997 // prepare the request 998 RequestAllocator allocator(port->GetPort()); 999 LinkRequest* request; 1000 status_t error = AllocateRequest(allocator, &request); 1001 if (error != B_OK) 1002 return error; 1003 request->volume = fUserlandVolume; 1004 request->node = dir; 1005 error = allocator.AllocateString(request->name, name); 1006 request->target = node; 1007 if (error != B_OK) 1008 return error; 1009 // send the request 1010 KernelRequestHandler handler(this, LINK_REPLY); 1011 LinkReply* reply; 1012 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 1013 if (error != B_OK) 1014 return error; 1015 RequestReleaser requestReleaser(port, reply); 1016 // process the reply 1017 if (reply->error != B_OK) 1018 return reply->error; 1019 return error; 1020} 1021 1022// Unlink 1023status_t 1024Volume::Unlink(void* dir, const char* name) 1025{ 1026 // get a free port 1027 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 1028 if (!port) 1029 return B_ERROR; 1030 PortReleaser _(fFileSystem->GetPortPool(), port); 1031 // prepare the request 1032 RequestAllocator allocator(port->GetPort()); 1033 UnlinkRequest* request; 1034 status_t error = AllocateRequest(allocator, &request); 1035 if (error != B_OK) 1036 return error; 1037 request->volume = fUserlandVolume; 1038 request->node = dir; 1039 error = allocator.AllocateString(request->name, name); 1040 if (error != B_OK) 1041 return error; 1042 // send the request 1043 KernelRequestHandler handler(this, UNLINK_REPLY); 1044 UnlinkReply* reply; 1045 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 1046 if (error != B_OK) 1047 return error; 1048 RequestReleaser requestReleaser(port, reply); 1049 // process the reply 1050 if (reply->error != B_OK) 1051 return reply->error; 1052 return error; 1053} 1054 1055// Symlink 1056status_t 1057Volume::Symlink(void* dir, const char* name, const char* target) 1058{ 1059 // get a free port 1060 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 1061 if (!port) 1062 return B_ERROR; 1063 PortReleaser _(fFileSystem->GetPortPool(), port); 1064 // prepare the request 1065 RequestAllocator allocator(port->GetPort()); 1066 SymlinkRequest* request; 1067 status_t error = AllocateRequest(allocator, &request); 1068 if (error != B_OK) 1069 return error; 1070 request->volume = fUserlandVolume; 1071 request->node = dir; 1072 error = allocator.AllocateString(request->name, name); 1073 if (error == B_OK) 1074 error = allocator.AllocateString(request->target, target); 1075 if (error != B_OK) 1076 return error; 1077 // send the request 1078 KernelRequestHandler handler(this, SYMLINK_REPLY); 1079 SymlinkReply* reply; 1080 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 1081 if (error != B_OK) 1082 return error; 1083 RequestReleaser requestReleaser(port, reply); 1084 // process the reply 1085 if (reply->error != B_OK) 1086 return reply->error; 1087 return error; 1088} 1089 1090// ReadLink 1091status_t 1092Volume::ReadLink(void* node, char* buffer, size_t bufferSize, size_t* bytesRead) 1093{ 1094 *bytesRead = 0; 1095 // get a free port 1096 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 1097 if (!port) 1098 return B_ERROR; 1099 PortReleaser _(fFileSystem->GetPortPool(), port); 1100 // prepare the request 1101 RequestAllocator allocator(port->GetPort()); 1102 ReadLinkRequest* request; 1103 status_t error = AllocateRequest(allocator, &request); 1104 if (error != B_OK) 1105 return error; 1106 request->volume = fUserlandVolume; 1107 request->node = node; 1108 request->size = bufferSize; 1109 // send the request 1110 KernelRequestHandler handler(this, READ_LINK_REPLY); 1111 ReadLinkReply* reply; 1112 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 1113 if (error != B_OK) 1114 return error; 1115 RequestReleaser requestReleaser(port, reply); 1116 // process the reply 1117 if (reply->error != B_OK) 1118 return reply->error; 1119 void* readBuffer = reply->buffer.GetData(); 1120 if (reply->bytesRead > (uint32)reply->buffer.GetSize() 1121 || reply->bytesRead > bufferSize) { 1122 return B_BAD_DATA; 1123 } 1124 if (reply->bytesRead > 0) 1125 memcpy(buffer, readBuffer, reply->bytesRead); 1126 *bytesRead = reply->bytesRead; 1127 _SendReceiptAck(port); 1128 return error; 1129} 1130 1131// Rename 1132status_t 1133Volume::Rename(void* oldDir, const char* oldName, void* newDir, 1134 const char* newName) 1135{ 1136 // get a free port 1137 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 1138 if (!port) 1139 return B_ERROR; 1140 PortReleaser _(fFileSystem->GetPortPool(), port); 1141 // prepare the request 1142 RequestAllocator allocator(port->GetPort()); 1143 RenameRequest* request; 1144 status_t error = AllocateRequest(allocator, &request); 1145 if (error != B_OK) 1146 return error; 1147 request->volume = fUserlandVolume; 1148 request->oldDir = oldDir; 1149 request->newDir = newDir; 1150 error = allocator.AllocateString(request->oldName, oldName); 1151 if (error == B_OK) 1152 error = allocator.AllocateString(request->newName, newName); 1153 if (error != B_OK) 1154 return error; 1155 // send the request 1156 KernelRequestHandler handler(this, RENAME_REPLY); 1157 RenameReply* reply; 1158 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 1159 if (error != B_OK) 1160 return error; 1161 RequestReleaser requestReleaser(port, reply); 1162 // process the reply 1163 if (reply->error != B_OK) 1164 return reply->error; 1165 return error; 1166} 1167 1168// #pragma mark - 1169// #pragma mark ----- directories ----- 1170 1171// MkDir 1172status_t 1173Volume::MkDir(void* dir, const char* name, int mode) 1174{ 1175 // get a free port 1176 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 1177 if (!port) 1178 return B_ERROR; 1179 PortReleaser _(fFileSystem->GetPortPool(), port); 1180 // prepare the request 1181 RequestAllocator allocator(port->GetPort()); 1182 MkDirRequest* request; 1183 status_t error = AllocateRequest(allocator, &request); 1184 if (error != B_OK) 1185 return error; 1186 request->volume = fUserlandVolume; 1187 request->node = dir; 1188 error = allocator.AllocateString(request->name, name); 1189 request->mode = mode; 1190 if (error != B_OK) 1191 return error; 1192 // send the request 1193 KernelRequestHandler handler(this, MKDIR_REPLY); 1194 MkDirReply* reply; 1195 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 1196 if (error != B_OK) 1197 return error; 1198 RequestReleaser requestReleaser(port, reply); 1199 // process the reply 1200 if (reply->error != B_OK) 1201 return reply->error; 1202 return error; 1203} 1204 1205// RmDir 1206status_t 1207Volume::RmDir(void* dir, const char* name) 1208{ 1209 // get a free port 1210 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 1211 if (!port) 1212 return B_ERROR; 1213 PortReleaser _(fFileSystem->GetPortPool(), port); 1214 // prepare the request 1215 RequestAllocator allocator(port->GetPort()); 1216 RmDirRequest* request; 1217 status_t error = AllocateRequest(allocator, &request); 1218 if (error != B_OK) 1219 return error; 1220 request->volume = fUserlandVolume; 1221 request->node = dir; 1222 error = allocator.AllocateString(request->name, name); 1223 if (error != B_OK) 1224 return error; 1225 // send the request 1226 KernelRequestHandler handler(this, RMDIR_REPLY); 1227 RmDirReply* reply; 1228 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 1229 if (error != B_OK) 1230 return error; 1231 RequestReleaser requestReleaser(port, reply); 1232 // process the reply 1233 if (reply->error != B_OK) 1234 return reply->error; 1235 return error; 1236} 1237 1238// OpenDir 1239status_t 1240Volume::OpenDir(void* node, void** cookie) 1241{ 1242 // get a free port 1243 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 1244 if (!port) 1245 return B_ERROR; 1246 PortReleaser _(fFileSystem->GetPortPool(), port); 1247 AutoIncrementer incrementer(&fOpenDirectories); 1248 // prepare the request 1249 RequestAllocator allocator(port->GetPort()); 1250 OpenDirRequest* request; 1251 status_t error = AllocateRequest(allocator, &request); 1252 if (error != B_OK) 1253 return error; 1254 request->volume = fUserlandVolume; 1255 request->node = node; 1256 // send the request 1257 KernelRequestHandler handler(this, OPEN_DIR_REPLY); 1258 OpenDirReply* reply; 1259 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 1260 if (error != B_OK) 1261 return error; 1262 RequestReleaser requestReleaser(port, reply); 1263 // process the reply 1264 if (reply->error != B_OK) 1265 return reply->error; 1266 incrementer.Keep(); 1267 *cookie = reply->dirCookie; 1268 return error; 1269} 1270 1271// CloseDir 1272status_t 1273Volume::CloseDir(void* node, void* cookie) 1274{ 1275 status_t error = _CloseDir(node, cookie); 1276 if (error != B_OK && fFileSystem->GetPortPool()->IsDisconnected()) { 1277 // This isn't really necessary, as the return value is irrelevant to 1278 // the VFS. OBOS ignores it completely. The fsshell returns it to the 1279 // userland, but considers the node closed anyway. 1280 WARN(("Volume::CloseDir(): connection lost, forcing close dir\n")); 1281 return B_OK; 1282 } 1283 return error; 1284} 1285 1286// FreeDirCookie 1287status_t 1288Volume::FreeDirCookie(void* node, void* cookie) 1289{ 1290 status_t error = _FreeDirCookie(node, cookie); 1291 bool disconnected = false; 1292 if (error != B_OK && fFileSystem->GetPortPool()->IsDisconnected()) { 1293 // This isn't really necessary, as the return value is irrelevant to 1294 // the VFS. It's completely ignored by OBOS as well as by the fsshell. 1295 WARN(("Volume::FreeDirCookie(): connection lost, forcing free dir " 1296 "cookie\n")); 1297 error = B_OK; 1298 disconnected = true; 1299 } 1300 int32 openDirs = atomic_add(&fOpenDirectories, -1); 1301 if (openDirs <= 1 && disconnected) 1302 _PutAllPendingVNodes(); 1303 return error; 1304} 1305 1306// ReadDir 1307status_t 1308Volume::ReadDir(void* node, void* cookie, void* buffer, size_t bufferSize, 1309 int32 count, int32* countRead) 1310{ 1311 *countRead = 0; 1312 // get a free port 1313 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 1314 if (!port) 1315 return B_ERROR; 1316 PortReleaser _(fFileSystem->GetPortPool(), port); 1317 // prepare the request 1318 RequestAllocator allocator(port->GetPort()); 1319 ReadDirRequest* request; 1320 status_t error = AllocateRequest(allocator, &request); 1321 if (error != B_OK) 1322 return error; 1323 request->volume = fUserlandVolume; 1324 request->node = node; 1325 request->dirCookie = cookie; 1326 request->bufferSize = bufferSize; 1327 request->count = count; 1328 // send the request 1329 KernelRequestHandler handler(this, READ_DIR_REPLY); 1330 ReadDirReply* reply; 1331 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 1332 if (error != B_OK) 1333 return error; 1334 RequestReleaser requestReleaser(port, reply); 1335 // process the reply 1336 if (reply->error != B_OK) 1337 return reply->error; 1338 if (reply->count < 0 || reply->count > count) 1339 return B_BAD_DATA; 1340 if ((int32)bufferSize < reply->buffer.GetSize()) 1341 return B_BAD_DATA; 1342PRINT(("Volume::ReadDir(): buffer returned: %ld bytes\n", 1343reply->buffer.GetSize())); 1344 *countRead = reply->count; 1345 if (*countRead > 0) { 1346 // copy the buffer -- limit the number of bytes to copy 1347 int32 maxBytes = *countRead 1348 * (sizeof(struct dirent) + B_FILE_NAME_LENGTH); 1349 int32 copyBytes = reply->buffer.GetSize(); 1350 if (copyBytes > maxBytes) 1351 copyBytes = maxBytes; 1352 memcpy(buffer, reply->buffer.GetData(), copyBytes); 1353 } 1354 _SendReceiptAck(port); 1355 return error; 1356} 1357 1358// RewindDir 1359status_t 1360Volume::RewindDir(void* node, void* cookie) 1361{ 1362 // get a free port 1363 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 1364 if (!port) 1365 return B_ERROR; 1366 PortReleaser _(fFileSystem->GetPortPool(), port); 1367 // prepare the request 1368 RequestAllocator allocator(port->GetPort()); 1369 RewindDirRequest* request; 1370 status_t error = AllocateRequest(allocator, &request); 1371 if (error != B_OK) 1372 return error; 1373 request->volume = fUserlandVolume; 1374 request->node = node; 1375 request->dirCookie = cookie; 1376 // send the request 1377 KernelRequestHandler handler(this, REWIND_DIR_REPLY); 1378 RewindDirReply* reply; 1379 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 1380 if (error != B_OK) 1381 return error; 1382 RequestReleaser requestReleaser(port, reply); 1383 // process the reply 1384 if (reply->error != B_OK) 1385 return reply->error; 1386 return error; 1387} 1388 1389// Walk 1390status_t 1391Volume::Walk(void* dir, const char* entryName, char** resolvedPath, 1392 vnode_id* vnid) 1393{ 1394 // When the connection to the userland server is lost, we serve 1395 // walk(fRootNode, `.') requests manually to allow clean unmounting. 1396 status_t error = _Walk(dir, entryName, resolvedPath, vnid); 1397 if (error != B_OK && fFileSystem->GetPortPool()->IsDisconnected() 1398 && dir == fRootNode && strcmp(entryName, ".") == 0) { 1399 WARN(("Volume::Walk(): connection lost, emulating walk `.'\n")); 1400 void* entryNode; 1401 if (GetVNode(fRootID, &entryNode) != B_OK) 1402 RETURN_ERROR(B_BAD_VALUE); 1403 *vnid = fRootID; 1404 // The VFS will balance the get_vnode() call for the FS. 1405 _DecrementVNodeCount(*vnid); 1406 return B_OK; 1407 } 1408 return error; 1409} 1410 1411// #pragma mark - 1412// #pragma mark ----- attributes ----- 1413 1414// OpenAttrDir 1415status_t 1416Volume::OpenAttrDir(void* node, void** cookie) 1417{ 1418 // get a free port 1419 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 1420 if (!port) 1421 return B_ERROR; 1422 PortReleaser _(fFileSystem->GetPortPool(), port); 1423 AutoIncrementer incrementer(&fOpenAttributeDirectories); 1424 // prepare the request 1425 RequestAllocator allocator(port->GetPort()); 1426 OpenAttrDirRequest* request; 1427 status_t error = AllocateRequest(allocator, &request); 1428 if (error != B_OK) 1429 return error; 1430 request->volume = fUserlandVolume; 1431 request->node = node; 1432 // send the request 1433 KernelRequestHandler handler(this, OPEN_ATTR_DIR_REPLY); 1434 OpenAttrDirReply* reply; 1435 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 1436 if (error != B_OK) 1437 return error; 1438 RequestReleaser requestReleaser(port, reply); 1439 // process the reply 1440 if (reply->error != B_OK) 1441 return reply->error; 1442 incrementer.Keep(); 1443 *cookie = reply->attrDirCookie; 1444 return error; 1445} 1446 1447// CloseAttrDir 1448status_t 1449Volume::CloseAttrDir(void* node, void* cookie) 1450{ 1451 status_t error = _CloseAttrDir(node, cookie); 1452 if (error != B_OK && fFileSystem->GetPortPool()->IsDisconnected()) { 1453 // This isn't really necessary, as the return value is irrelevant to 1454 // the VFS. OBOS ignores it completely. The fsshell returns it to the 1455 // userland, but considers the node closed anyway. 1456 WARN(("Volume::CloseAttrDir(): connection lost, forcing close attr " 1457 "dir\n")); 1458 return B_OK; 1459 } 1460 return error; 1461} 1462 1463// FreeAttrDirCookie 1464status_t 1465Volume::FreeAttrDirCookie(void* node, void* cookie) 1466{ 1467 status_t error = _FreeAttrDirCookie(node, cookie); 1468 bool disconnected = false; 1469 if (error != B_OK && fFileSystem->GetPortPool()->IsDisconnected()) { 1470 // This isn't really necessary, as the return value is irrelevant to 1471 // the VFS. It's completely ignored by OBOS as well as by the fsshell. 1472 WARN(("Volume::FreeAttrDirCookie(): connection lost, forcing free attr " 1473 "dir cookie\n")); 1474 error = B_OK; 1475 disconnected = true; 1476 } 1477 int32 openAttrDirs = atomic_add(&fOpenAttributeDirectories, -1); 1478 if (openAttrDirs <= 1 && disconnected) 1479 _PutAllPendingVNodes(); 1480 return error; 1481} 1482 1483// ReadAttrDir 1484status_t 1485Volume::ReadAttrDir(void* node, void* cookie, void* buffer, size_t bufferSize, 1486 int32 count, int32* countRead) 1487{ 1488 *countRead = 0; 1489 // get a free port 1490 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 1491 if (!port) 1492 return B_ERROR; 1493 PortReleaser _(fFileSystem->GetPortPool(), port); 1494 // prepare the request 1495 RequestAllocator allocator(port->GetPort()); 1496 ReadAttrDirRequest* request; 1497 status_t error = AllocateRequest(allocator, &request); 1498 if (error != B_OK) 1499 return error; 1500 request->volume = fUserlandVolume; 1501 request->node = node; 1502 request->attrDirCookie = cookie; 1503 request->bufferSize = bufferSize; 1504 request->count = count; 1505 // send the request 1506 KernelRequestHandler handler(this, READ_ATTR_DIR_REPLY); 1507 ReadAttrDirReply* reply; 1508 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 1509 if (error != B_OK) 1510 return error; 1511 RequestReleaser requestReleaser(port, reply); 1512 // process the reply 1513 if (reply->error != B_OK) 1514 return reply->error; 1515 if (reply->count < 0 || reply->count > count) 1516 return B_BAD_DATA; 1517 if ((int32)bufferSize < reply->buffer.GetSize()) 1518 return B_BAD_DATA; 1519 *countRead = reply->count; 1520 if (*countRead > 0) { 1521 // copy the buffer -- limit the number of bytes to copy 1522 int32 maxBytes = *countRead 1523 * (sizeof(struct dirent) + B_ATTR_NAME_LENGTH); 1524 int32 copyBytes = reply->buffer.GetSize(); 1525 if (copyBytes > maxBytes) 1526 copyBytes = maxBytes; 1527 memcpy(buffer, reply->buffer.GetData(), copyBytes); 1528 } 1529 _SendReceiptAck(port); 1530 return error; 1531} 1532 1533// RewindAttrDir 1534status_t 1535Volume::RewindAttrDir(void* node, void* cookie) 1536{ 1537 // get a free port 1538 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 1539 if (!port) 1540 return B_ERROR; 1541 PortReleaser _(fFileSystem->GetPortPool(), port); 1542 // prepare the request 1543 RequestAllocator allocator(port->GetPort()); 1544 RewindAttrDirRequest* request; 1545 status_t error = AllocateRequest(allocator, &request); 1546 if (error != B_OK) 1547 return error; 1548 request->volume = fUserlandVolume; 1549 request->node = node; 1550 request->attrDirCookie = cookie; 1551 // send the request 1552 KernelRequestHandler handler(this, REWIND_ATTR_DIR_REPLY); 1553 RewindAttrDirReply* reply; 1554 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 1555 if (error != B_OK) 1556 return error; 1557 RequestReleaser requestReleaser(port, reply); 1558 // process the reply 1559 if (reply->error != B_OK) 1560 return reply->error; 1561 return error; 1562} 1563 1564// ReadAttr 1565status_t 1566Volume::ReadAttr(void* node, const char* name, int type, off_t pos, 1567 void* buffer, size_t bufferSize, size_t* bytesRead) 1568{ 1569 *bytesRead = 0; 1570 // get a free port 1571 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 1572 if (!port) 1573 return B_ERROR; 1574 PortReleaser _(fFileSystem->GetPortPool(), port); 1575 // prepare the request 1576 RequestAllocator allocator(port->GetPort()); 1577 ReadAttrRequest* request; 1578 status_t error = AllocateRequest(allocator, &request); 1579 if (error != B_OK) 1580 return error; 1581 request->volume = fUserlandVolume; 1582 request->node = node; 1583 error = allocator.AllocateString(request->name, name); 1584 request->type = type; 1585 request->pos = pos; 1586 request->size = bufferSize; 1587 if (error != B_OK) 1588 return error; 1589 // send the request 1590 KernelRequestHandler handler(this, READ_ATTR_REPLY); 1591 ReadAttrReply* reply; 1592 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 1593 if (error != B_OK) 1594 return error; 1595 RequestReleaser requestReleaser(port, reply); 1596 // process the reply 1597 if (reply->error != B_OK) 1598 return reply->error; 1599 void* readBuffer = reply->buffer.GetData(); 1600 if (reply->bytesRead > (uint32)reply->buffer.GetSize() 1601 || reply->bytesRead > bufferSize) { 1602 return B_BAD_DATA; 1603 } 1604 if (reply->bytesRead > 0) 1605 memcpy(buffer, readBuffer, reply->bytesRead); 1606 *bytesRead = reply->bytesRead; 1607 _SendReceiptAck(port); 1608 return error; 1609} 1610 1611// WriteAttr 1612status_t 1613Volume::WriteAttr(void* node, const char* name, int type, off_t pos, 1614 const void* buffer, size_t bufferSize, size_t* bytesWritten) 1615{ 1616 *bytesWritten = 0; 1617 // get a free port 1618 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 1619 if (!port) 1620 return B_ERROR; 1621 PortReleaser _(fFileSystem->GetPortPool(), port); 1622 // prepare the request 1623 RequestAllocator allocator(port->GetPort()); 1624 WriteAttrRequest* request; 1625 status_t error = AllocateRequest(allocator, &request); 1626 if (error != B_OK) 1627 return error; 1628 request->volume = fUserlandVolume; 1629 request->node = node; 1630 error = allocator.AllocateString(request->name, name); 1631 request->type = type; 1632 request->pos = pos; 1633 if (error == B_OK) 1634 error = allocator.AllocateData(request->buffer, buffer, bufferSize, 1); 1635 if (error != B_OK) 1636 return error; 1637 // send the request 1638 KernelRequestHandler handler(this, WRITE_ATTR_REPLY); 1639 WriteAttrReply* reply; 1640 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 1641 if (error != B_OK) 1642 return error; 1643 RequestReleaser requestReleaser(port, reply); 1644 // process the reply 1645 if (reply->error != B_OK) 1646 return reply->error; 1647 *bytesWritten = reply->bytesWritten; 1648 return error; 1649} 1650 1651// RemoveAttr 1652status_t 1653Volume::RemoveAttr(void* node, const char* name) 1654{ 1655 // get a free port 1656 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 1657 if (!port) 1658 return B_ERROR; 1659 PortReleaser _(fFileSystem->GetPortPool(), port); 1660 // prepare the request 1661 RequestAllocator allocator(port->GetPort()); 1662 RemoveAttrRequest* request; 1663 status_t error = AllocateRequest(allocator, &request); 1664 if (error != B_OK) 1665 return error; 1666 request->volume = fUserlandVolume; 1667 request->node = node; 1668 error = allocator.AllocateString(request->name, name); 1669 if (error != B_OK) 1670 return error; 1671 // send the request 1672 KernelRequestHandler handler(this, REMOVE_ATTR_REPLY); 1673 RemoveAttrReply* reply; 1674 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 1675 if (error != B_OK) 1676 return error; 1677 RequestReleaser requestReleaser(port, reply); 1678 // process the reply 1679 if (reply->error != B_OK) 1680 return reply->error; 1681 return error; 1682} 1683 1684// RenameAttr 1685status_t 1686Volume::RenameAttr(void* node, const char* oldName, const char* newName) 1687{ 1688 // get a free port 1689 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 1690 if (!port) 1691 return B_ERROR; 1692 PortReleaser _(fFileSystem->GetPortPool(), port); 1693 // prepare the request 1694 RequestAllocator allocator(port->GetPort()); 1695 RenameAttrRequest* request; 1696 status_t error = AllocateRequest(allocator, &request); 1697 if (error != B_OK) 1698 return error; 1699 request->volume = fUserlandVolume; 1700 request->node = node; 1701 error = allocator.AllocateString(request->oldName, oldName); 1702 if (error == B_OK) 1703 error = allocator.AllocateString(request->newName, newName); 1704 if (error != B_OK) 1705 return error; 1706 // send the request 1707 KernelRequestHandler handler(this, RENAME_ATTR_REPLY); 1708 RenameAttrReply* reply; 1709 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 1710 if (error != B_OK) 1711 return error; 1712 RequestReleaser requestReleaser(port, reply); 1713 // process the reply 1714 if (reply->error != B_OK) 1715 return reply->error; 1716 return error; 1717} 1718 1719// StatAttr 1720status_t 1721Volume::StatAttr(void* node, const char* name, struct attr_info* attrInfo) 1722{ 1723 // get a free port 1724 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 1725 if (!port) 1726 return B_ERROR; 1727 PortReleaser _(fFileSystem->GetPortPool(), port); 1728 // prepare the request 1729 RequestAllocator allocator(port->GetPort()); 1730 StatAttrRequest* request; 1731 status_t error = AllocateRequest(allocator, &request); 1732 if (error != B_OK) 1733 return error; 1734 request->volume = fUserlandVolume; 1735 request->node = node; 1736 error = allocator.AllocateString(request->name, name); 1737 if (error != B_OK) 1738 return error; 1739 // send the request 1740 KernelRequestHandler handler(this, STAT_ATTR_REPLY); 1741 StatAttrReply* reply; 1742 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 1743 if (error != B_OK) 1744 return error; 1745 RequestReleaser requestReleaser(port, reply); 1746 // process the reply 1747 if (reply->error != B_OK) 1748 return reply->error; 1749 *attrInfo = reply->info; 1750 return error; 1751} 1752 1753// #pragma mark - 1754// #pragma mark ----- indices ----- 1755 1756// OpenIndexDir 1757status_t 1758Volume::OpenIndexDir(void** cookie) 1759{ 1760 // get a free port 1761 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 1762 if (!port) 1763 return B_ERROR; 1764 PortReleaser _(fFileSystem->GetPortPool(), port); 1765 AutoIncrementer incrementer(&fOpenIndexDirectories); 1766 // prepare the request 1767 RequestAllocator allocator(port->GetPort()); 1768 OpenIndexDirRequest* request; 1769 status_t error = AllocateRequest(allocator, &request); 1770 if (error != B_OK) 1771 return error; 1772 request->volume = fUserlandVolume; 1773 // send the request 1774 KernelRequestHandler handler(this, OPEN_INDEX_DIR_REPLY); 1775 OpenIndexDirReply* reply; 1776 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 1777 if (error != B_OK) 1778 return error; 1779 RequestReleaser requestReleaser(port, reply); 1780 // process the reply 1781 if (reply->error != B_OK) 1782 return reply->error; 1783 incrementer.Keep(); 1784 *cookie = reply->indexDirCookie; 1785 return error; 1786} 1787 1788// CloseIndexDir 1789status_t 1790Volume::CloseIndexDir(void* cookie) 1791{ 1792 status_t error = _CloseIndexDir(cookie); 1793 if (error != B_OK && fFileSystem->GetPortPool()->IsDisconnected()) { 1794 // This isn't really necessary, as the return value is irrelevant to 1795 // the VFS. OBOS ignores it completely. The fsshell returns it to the 1796 // userland, but considers the node closed anyway. 1797 WARN(("Volume::CloseIndexDir(): connection lost, forcing close " 1798 "index dir\n")); 1799 return B_OK; 1800 } 1801 return error; 1802} 1803 1804// FreeIndexDirCookie 1805status_t 1806Volume::FreeIndexDirCookie(void* cookie) 1807{ 1808 status_t error = _FreeIndexDirCookie(cookie); 1809 bool disconnected = false; 1810 if (error != B_OK && fFileSystem->GetPortPool()->IsDisconnected()) { 1811 // This isn't really necessary, as the return value is irrelevant to 1812 // the VFS. It's completely ignored by OBOS as well as by the fsshell. 1813 WARN(("Volume::FreeIndexDirCookie(): connection lost, forcing free " 1814 "index dir cookie\n")); 1815 error = B_OK; 1816 disconnected = true; 1817 } 1818 int32 openIndexDirs = atomic_add(&fOpenIndexDirectories, -1); 1819 if (openIndexDirs <= 1 && disconnected) 1820 _PutAllPendingVNodes(); 1821 return error; 1822} 1823 1824// ReadIndexDir 1825status_t 1826Volume::ReadIndexDir(void* cookie, void* buffer, size_t bufferSize, int32 count, 1827 int32* countRead) 1828{ 1829 *countRead = 0; 1830 // get a free port 1831 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 1832 if (!port) 1833 return B_ERROR; 1834 PortReleaser _(fFileSystem->GetPortPool(), port); 1835 // prepare the request 1836 RequestAllocator allocator(port->GetPort()); 1837 ReadIndexDirRequest* request; 1838 status_t error = AllocateRequest(allocator, &request); 1839 if (error != B_OK) 1840 return error; 1841 request->volume = fUserlandVolume; 1842 request->indexDirCookie = cookie; 1843 request->bufferSize = bufferSize; 1844 request->count = count; 1845 // send the request 1846 KernelRequestHandler handler(this, READ_INDEX_DIR_REPLY); 1847 ReadIndexDirReply* reply; 1848 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 1849 if (error != B_OK) 1850 return error; 1851 RequestReleaser requestReleaser(port, reply); 1852 // process the reply 1853 if (reply->error != B_OK) 1854 return reply->error; 1855 if (reply->count < 0 || reply->count > count) 1856 return B_BAD_DATA; 1857 if ((int32)bufferSize < reply->buffer.GetSize()) 1858 return B_BAD_DATA; 1859 *countRead = reply->count; 1860 if (*countRead > 0) { 1861 // copy the buffer -- limit the number of bytes to copy 1862 int32 maxBytes = *countRead 1863 * (sizeof(struct dirent) + B_FILE_NAME_LENGTH); 1864 int32 copyBytes = reply->buffer.GetSize(); 1865 if (copyBytes > maxBytes) 1866 copyBytes = maxBytes; 1867 memcpy(buffer, reply->buffer.GetData(), copyBytes); 1868 } 1869 _SendReceiptAck(port); 1870 return error; 1871} 1872 1873// RewindIndexDir 1874status_t 1875Volume::RewindIndexDir(void* cookie) 1876{ 1877 // get a free port 1878 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 1879 if (!port) 1880 return B_ERROR; 1881 PortReleaser _(fFileSystem->GetPortPool(), port); 1882 // prepare the request 1883 RequestAllocator allocator(port->GetPort()); 1884 RewindIndexDirRequest* request; 1885 status_t error = AllocateRequest(allocator, &request); 1886 if (error != B_OK) 1887 return error; 1888 request->volume = fUserlandVolume; 1889 request->indexDirCookie = cookie; 1890 // send the request 1891 KernelRequestHandler handler(this, REWIND_INDEX_DIR_REPLY); 1892 RewindIndexDirReply* reply; 1893 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 1894 if (error != B_OK) 1895 return error; 1896 RequestReleaser requestReleaser(port, reply); 1897 // process the reply 1898 if (reply->error != B_OK) 1899 return reply->error; 1900 return error; 1901} 1902 1903// CreateIndex 1904status_t 1905Volume::CreateIndex(const char* name, int type, int flags) 1906{ 1907 // get a free port 1908 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 1909 if (!port) 1910 return B_ERROR; 1911 PortReleaser _(fFileSystem->GetPortPool(), port); 1912 // prepare the request 1913 RequestAllocator allocator(port->GetPort()); 1914 CreateIndexRequest* request; 1915 status_t error = AllocateRequest(allocator, &request); 1916 if (error != B_OK) 1917 return error; 1918 request->volume = fUserlandVolume; 1919 error = allocator.AllocateString(request->name, name); 1920 request->type = type; 1921 request->flags = flags; 1922 if (error != B_OK) 1923 return error; 1924 // send the request 1925 KernelRequestHandler handler(this, CREATE_INDEX_REPLY); 1926 CreateIndexReply* reply; 1927 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 1928 if (error != B_OK) 1929 return error; 1930 RequestReleaser requestReleaser(port, reply); 1931 // process the reply 1932 if (reply->error != B_OK) 1933 return reply->error; 1934 return error; 1935} 1936 1937// RemoveIndex 1938status_t 1939Volume::RemoveIndex(const char* name) 1940{ 1941 // get a free port 1942 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 1943 if (!port) 1944 return B_ERROR; 1945 PortReleaser _(fFileSystem->GetPortPool(), port); 1946 // prepare the request 1947 RequestAllocator allocator(port->GetPort()); 1948 RemoveIndexRequest* request; 1949 status_t error = AllocateRequest(allocator, &request); 1950 if (error != B_OK) 1951 return error; 1952 request->volume = fUserlandVolume; 1953 error = allocator.AllocateString(request->name, name); 1954 if (error != B_OK) 1955 return error; 1956 // send the request 1957 KernelRequestHandler handler(this, REMOVE_INDEX_REPLY); 1958 RemoveIndexReply* reply; 1959 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 1960 if (error != B_OK) 1961 return error; 1962 RequestReleaser requestReleaser(port, reply); 1963 // process the reply 1964 if (reply->error != B_OK) 1965 return reply->error; 1966 return error; 1967} 1968 1969// RenameIndex 1970status_t 1971Volume::RenameIndex(const char* oldName, const char* newName) 1972{ 1973 // get a free port 1974 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 1975 if (!port) 1976 return B_ERROR; 1977 PortReleaser _(fFileSystem->GetPortPool(), port); 1978 // prepare the request 1979 RequestAllocator allocator(port->GetPort()); 1980 RenameIndexRequest* request; 1981 status_t error = AllocateRequest(allocator, &request); 1982 if (error != B_OK) 1983 return error; 1984 request->volume = fUserlandVolume; 1985 error = allocator.AllocateString(request->oldName, oldName); 1986 if (error == B_OK) 1987 error = allocator.AllocateString(request->newName, newName); 1988 if (error != B_OK) 1989 return error; 1990 // send the request 1991 KernelRequestHandler handler(this, RENAME_INDEX_REPLY); 1992 RenameIndexReply* reply; 1993 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 1994 if (error != B_OK) 1995 return error; 1996 RequestReleaser requestReleaser(port, reply); 1997 // process the reply 1998 if (reply->error != B_OK) 1999 return reply->error; 2000 return error; 2001} 2002 2003// StatIndex 2004status_t 2005Volume::StatIndex(const char *name, struct index_info* indexInfo) 2006{ 2007 // get a free port 2008 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 2009 if (!port) 2010 return B_ERROR; 2011 PortReleaser _(fFileSystem->GetPortPool(), port); 2012 // prepare the request 2013 RequestAllocator allocator(port->GetPort()); 2014 StatIndexRequest* request; 2015 status_t error = AllocateRequest(allocator, &request); 2016 if (error != B_OK) 2017 return error; 2018 request->volume = fUserlandVolume; 2019 error = allocator.AllocateString(request->name, name); 2020 if (error != B_OK) 2021 return error; 2022 // send the request 2023 KernelRequestHandler handler(this, STAT_INDEX_REPLY); 2024 StatIndexReply* reply; 2025 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 2026 if (error != B_OK) 2027 return error; 2028 RequestReleaser requestReleaser(port, reply); 2029 // process the reply 2030 if (reply->error != B_OK) 2031 return reply->error; 2032 *indexInfo = reply->info; 2033 return error; 2034} 2035 2036// #pragma mark - 2037// #pragma mark ----- queries ----- 2038 2039// OpenQuery 2040status_t 2041Volume::OpenQuery(const char* queryString, ulong flags, port_id targetPort, 2042 long token, void** cookie) 2043{ 2044 // get a free port 2045 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 2046 if (!port) 2047 return B_ERROR; 2048 PortReleaser _(fFileSystem->GetPortPool(), port); 2049 AutoIncrementer incrementer(&fOpenQueries); 2050 // prepare the request 2051 RequestAllocator allocator(port->GetPort()); 2052 OpenQueryRequest* request; 2053 status_t error = AllocateRequest(allocator, &request); 2054 if (error != B_OK) 2055 return error; 2056 request->volume = fUserlandVolume; 2057 error = allocator.AllocateString(request->queryString, queryString); 2058 if (error != B_OK) 2059 return error; 2060 request->flags = flags; 2061 request->port = targetPort; 2062 request->token = token; 2063 // send the request 2064 KernelRequestHandler handler(this, OPEN_QUERY_REPLY); 2065 OpenQueryReply* reply; 2066 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 2067 if (error != B_OK) 2068 return error; 2069 RequestReleaser requestReleaser(port, reply); 2070 // process the reply 2071 if (reply->error != B_OK) 2072 return reply->error; 2073 incrementer.Keep(); 2074 *cookie = reply->queryCookie; 2075 return error; 2076} 2077 2078// CloseQuery 2079status_t 2080Volume::CloseQuery(void* cookie) 2081{ 2082 status_t error = _CloseQuery(cookie); 2083 if (error != B_OK && fFileSystem->GetPortPool()->IsDisconnected()) { 2084 // This isn't really necessary, as the return value is irrelevant to 2085 // the VFS. OBOS ignores it completely. The fsshell returns it to the 2086 // userland, but considers the node closed anyway. 2087 WARN(("Volume::CloseQuery(): connection lost, forcing close query\n")); 2088 return B_OK; 2089 } 2090 return error; 2091} 2092 2093// FreeQueryCookie 2094status_t 2095Volume::FreeQueryCookie(void* cookie) 2096{ 2097 status_t error = _FreeQueryCookie(cookie); 2098 bool disconnected = false; 2099 if (error != B_OK && fFileSystem->GetPortPool()->IsDisconnected()) { 2100 // This isn't really necessary, as the return value is irrelevant to 2101 // the VFS. It's completely ignored by OBOS as well as by the fsshell. 2102 WARN(("Volume::FreeQueryCookie(): connection lost, forcing free " 2103 "query cookie\n")); 2104 error = B_OK; 2105 disconnected = true; 2106 } 2107 int32 openQueries = atomic_add(&fOpenQueries, -1); 2108 if (openQueries <= 1 && disconnected) 2109 _PutAllPendingVNodes(); 2110 return error; 2111} 2112 2113// ReadQuery 2114status_t 2115Volume::ReadQuery(void* cookie, void* buffer, size_t bufferSize, int32 count, 2116 int32* countRead) 2117{ 2118 *countRead = 0; 2119 // get a free port 2120 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 2121 if (!port) 2122 return B_ERROR; 2123 PortReleaser _(fFileSystem->GetPortPool(), port); 2124 // prepare the request 2125 RequestAllocator allocator(port->GetPort()); 2126 ReadQueryRequest* request; 2127 status_t error = AllocateRequest(allocator, &request); 2128 if (error != B_OK) 2129 return error; 2130 request->volume = fUserlandVolume; 2131 request->queryCookie = cookie; 2132 request->bufferSize = bufferSize; 2133 request->count = count; 2134 // send the request 2135 KernelRequestHandler handler(this, READ_QUERY_REPLY); 2136 ReadQueryReply* reply; 2137 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 2138 if (error != B_OK) 2139 return error; 2140 RequestReleaser requestReleaser(port, reply); 2141 // process the reply 2142 if (reply->error != B_OK) 2143 return reply->error; 2144 if (reply->count < 0 || reply->count > count) 2145 return B_BAD_DATA; 2146 if ((int32)bufferSize < reply->buffer.GetSize()) 2147 return B_BAD_DATA; 2148 *countRead = reply->count; 2149 if (*countRead > 0) { 2150 // copy the buffer -- limit the number of bytes to copy 2151 int32 maxBytes = *countRead 2152 * (sizeof(struct dirent) + B_FILE_NAME_LENGTH); 2153 int32 copyBytes = reply->buffer.GetSize(); 2154 if (copyBytes > maxBytes) 2155 copyBytes = maxBytes; 2156 memcpy(buffer, reply->buffer.GetData(), copyBytes); 2157 } 2158 _SendReceiptAck(port); 2159 return error; 2160} 2161 2162// #pragma mark - 2163// #pragma mark ----- private implementations ----- 2164 2165// _Mount 2166status_t 2167Volume::_Mount(const char* device, ulong flags, const char* parameters, 2168 int32 len) 2169{ 2170 // get a free port 2171 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 2172 if (!port) 2173 return B_ERROR; 2174 PortReleaser _(fFileSystem->GetPortPool(), port); 2175 2176 // get the current working directory 2177 char cwd[B_PATH_NAME_LENGTH]; 2178 if (!getcwd(cwd, sizeof(cwd))) 2179 return errno; 2180 2181 // prepare the request 2182 RequestAllocator allocator(port->GetPort()); 2183 MountVolumeRequest* request; 2184 status_t error = AllocateRequest(allocator, &request); 2185 if (error != B_OK) 2186 return error; 2187 request->nsid = fID; 2188 error = allocator.AllocateString(request->cwd, cwd); 2189 if (error == B_OK) 2190 error = allocator.AllocateString(request->device, device); 2191 request->flags = flags; 2192 if (error == B_OK) 2193 error = allocator.AllocateData(request->parameters, parameters, len, 1); 2194 if (error != B_OK) 2195 return error; 2196 2197 // send the request 2198 KernelRequestHandler handler(this, MOUNT_VOLUME_REPLY); 2199 MountVolumeReply* reply; 2200 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 2201 if (error != B_OK) 2202 return error; 2203 RequestReleaser requestReleaser(port, reply); 2204 2205 // process the reply 2206 if (reply->error != B_OK) 2207 return reply->error; 2208 fRootID = reply->rootID; 2209 fUserlandVolume = reply->volume; 2210 2211 // enable vnode counting 2212 fVNodeCountMap = new(nothrow) VNodeCountMap; 2213 if (fVNodeCountMap) 2214 fVNodeCountingEnabled = true; 2215 else 2216 ERROR(("Failed to allocate vnode count map.")); 2217 return error; 2218} 2219 2220// _Unmount 2221status_t 2222Volume::_Unmount() 2223{ 2224 // get a free port 2225 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 2226 if (!port) 2227 return B_ERROR; 2228 PortReleaser _(fFileSystem->GetPortPool(), port); 2229 // prepare the request 2230 RequestAllocator allocator(port->GetPort()); 2231 UnmountVolumeRequest* request; 2232 status_t error = AllocateRequest(allocator, &request); 2233 if (error != B_OK) 2234 return error; 2235 request->volume = fUserlandVolume; 2236 // send the request 2237 KernelRequestHandler handler(this, UNMOUNT_VOLUME_REPLY); 2238 UnmountVolumeReply* reply; 2239 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 2240 if (error != B_OK) 2241 return error; 2242 RequestReleaser requestReleaser(port, reply); 2243 // process the reply 2244 if (reply->error != B_OK) 2245 return reply->error; 2246 return error; 2247} 2248 2249// _WriteVNode 2250status_t 2251Volume::_WriteVNode(void* node, char reenter) 2252{ 2253 // get a free port 2254 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 2255 if (!port) 2256 return B_ERROR; 2257 PortReleaser _(fFileSystem->GetPortPool(), port); 2258 // prepare the request 2259 RequestAllocator allocator(port->GetPort()); 2260 WriteVNodeRequest* request; 2261 status_t error = AllocateRequest(allocator, &request); 2262 if (error != B_OK) 2263 return error; 2264 request->volume = fUserlandVolume; 2265 request->node = node; 2266 request->reenter = reenter; 2267 // send the request 2268 KernelRequestHandler handler(this, WRITE_VNODE_REPLY); 2269 WriteVNodeReply* reply; 2270 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 2271 if (error != B_OK) 2272 return error; 2273 RequestReleaser requestReleaser(port, reply); 2274 // process the reply 2275 if (reply->error != B_OK) 2276 return reply->error; 2277 return error; 2278} 2279 2280// _Close 2281status_t 2282Volume::_Close(void* node, void* cookie) 2283{ 2284 // get a free port 2285 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 2286 if (!port) 2287 return B_ERROR; 2288 PortReleaser _(fFileSystem->GetPortPool(), port); 2289 // prepare the request 2290 RequestAllocator allocator(port->GetPort()); 2291 CloseRequest* request; 2292 status_t error = AllocateRequest(allocator, &request); 2293 if (error != B_OK) 2294 return error; 2295 request->volume = fUserlandVolume; 2296 request->node = node; 2297 request->fileCookie = cookie; 2298 // send the request 2299 KernelRequestHandler handler(this, CLOSE_REPLY); 2300 CloseReply* reply; 2301 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 2302 if (error != B_OK) 2303 return error; 2304 RequestReleaser requestReleaser(port, reply); 2305 // process the reply 2306 if (reply->error != B_OK) 2307 return reply->error; 2308 return error; 2309} 2310 2311// _FreeCookie 2312status_t 2313Volume::_FreeCookie(void* node, void* cookie) 2314{ 2315 // get a free port 2316 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 2317 if (!port) 2318 return B_ERROR; 2319 PortReleaser _(fFileSystem->GetPortPool(), port); 2320 // prepare the request 2321 RequestAllocator allocator(port->GetPort()); 2322 FreeCookieRequest* request; 2323 status_t error = AllocateRequest(allocator, &request); 2324 if (error != B_OK) 2325 return error; 2326 request->volume = fUserlandVolume; 2327 request->node = node; 2328 request->fileCookie = cookie; 2329 // send the request 2330 KernelRequestHandler handler(this, FREE_COOKIE_REPLY); 2331 FreeCookieReply* reply; 2332 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 2333 if (error != B_OK) 2334 return error; 2335 RequestReleaser requestReleaser(port, reply); 2336 // process the reply 2337 if (reply->error != B_OK) 2338 return reply->error; 2339 return error; 2340} 2341 2342// _CloseDir 2343status_t 2344Volume::_CloseDir(void* node, void* cookie) 2345{ 2346 // get a free port 2347 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 2348 if (!port) 2349 return B_ERROR; 2350 PortReleaser _(fFileSystem->GetPortPool(), port); 2351 // prepare the request 2352 RequestAllocator allocator(port->GetPort()); 2353 CloseDirRequest* request; 2354 status_t error = AllocateRequest(allocator, &request); 2355 if (error != B_OK) 2356 return error; 2357 request->volume = fUserlandVolume; 2358 request->node = node; 2359 request->dirCookie = cookie; 2360 // send the request 2361 KernelRequestHandler handler(this, CLOSE_DIR_REPLY); 2362 CloseDirReply* reply; 2363 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 2364 if (error != B_OK) 2365 return error; 2366 RequestReleaser requestReleaser(port, reply); 2367 // process the reply 2368 if (reply->error != B_OK) 2369 return reply->error; 2370 return error; 2371} 2372 2373// _FreeDirCookie 2374status_t 2375Volume::_FreeDirCookie(void* node, void* cookie) 2376{ 2377 // get a free port 2378 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 2379 if (!port) 2380 return B_ERROR; 2381 PortReleaser _(fFileSystem->GetPortPool(), port); 2382 // prepare the request 2383 RequestAllocator allocator(port->GetPort()); 2384 FreeDirCookieRequest* request; 2385 status_t error = AllocateRequest(allocator, &request); 2386 if (error != B_OK) 2387 return error; 2388 request->volume = fUserlandVolume; 2389 request->node = node; 2390 request->dirCookie = cookie; 2391 // send the request 2392 KernelRequestHandler handler(this, FREE_DIR_COOKIE_REPLY); 2393 FreeDirCookieReply* reply; 2394 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 2395 if (error != B_OK) 2396 return error; 2397 RequestReleaser requestReleaser(port, reply); 2398 // process the reply 2399 if (reply->error != B_OK) 2400 return reply->error; 2401 return error; 2402} 2403 2404// _Walk 2405status_t 2406Volume::_Walk(void* dir, const char* entryName, char** resolvedPath, 2407 vnode_id* vnid) 2408{ 2409 // get a free port 2410 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 2411 if (!port) 2412 return B_ERROR; 2413 PortReleaser _(fFileSystem->GetPortPool(), port); 2414 // prepare the request 2415 RequestAllocator allocator(port->GetPort()); 2416 WalkRequest* request; 2417 status_t error = AllocateRequest(allocator, &request); 2418 if (error != B_OK) 2419 return error; 2420 request->volume = fUserlandVolume; 2421 request->node = dir; 2422 error = allocator.AllocateString(request->entryName, entryName); 2423 request->traverseLink = resolvedPath; 2424 if (error != B_OK) 2425 return error; 2426 // send the request 2427 KernelRequestHandler handler(this, WALK_REPLY); 2428 WalkReply* reply; 2429 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 2430 if (error != B_OK) 2431 return error; 2432 RequestReleaser requestReleaser(port, reply); 2433 // process the reply 2434 if (reply->error != B_OK) 2435 return reply->error; 2436 *vnid = reply->vnid; 2437 if (resolvedPath) { 2438 const char* readPath = (const char*)reply->resolvedPath.GetData(); 2439 if (readPath) { 2440 int32 len = strnlen(readPath, reply->resolvedPath.GetSize()); 2441 *resolvedPath = (char*)malloc(len + 1); 2442 if (*resolvedPath) { 2443 memcpy(*resolvedPath, readPath, len); 2444 (*resolvedPath)[len] = '\0'; 2445 } else 2446 error = B_NO_MEMORY; 2447 _SendReceiptAck(port); 2448 } else 2449 _DecrementVNodeCount(*vnid); 2450 } else 2451 _DecrementVNodeCount(*vnid); 2452 // The VFS will balance the get_vnode() call for the FS. 2453 return error; 2454} 2455 2456// _CloseAttrDir 2457status_t 2458Volume::_CloseAttrDir(void* node, void* cookie) 2459{ 2460 // get a free port 2461 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 2462 if (!port) 2463 return B_ERROR; 2464 PortReleaser _(fFileSystem->GetPortPool(), port); 2465 // prepare the request 2466 RequestAllocator allocator(port->GetPort()); 2467 CloseAttrDirRequest* request; 2468 status_t error = AllocateRequest(allocator, &request); 2469 if (error != B_OK) 2470 return error; 2471 request->volume = fUserlandVolume; 2472 request->node = node; 2473 request->attrDirCookie = cookie; 2474 // send the request 2475 KernelRequestHandler handler(this, CLOSE_ATTR_DIR_REPLY); 2476 CloseAttrDirReply* reply; 2477 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 2478 if (error != B_OK) 2479 return error; 2480 RequestReleaser requestReleaser(port, reply); 2481 // process the reply 2482 if (reply->error != B_OK) 2483 return reply->error; 2484 return error; 2485} 2486 2487// _FreeAttrDirCookie 2488status_t 2489Volume::_FreeAttrDirCookie(void* node, void* cookie) 2490{ 2491 // get a free port 2492 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 2493 if (!port) 2494 return B_ERROR; 2495 PortReleaser _(fFileSystem->GetPortPool(), port); 2496 // prepare the request 2497 RequestAllocator allocator(port->GetPort()); 2498 FreeAttrDirCookieRequest* request; 2499 status_t error = AllocateRequest(allocator, &request); 2500 if (error != B_OK) 2501 return error; 2502 request->volume = fUserlandVolume; 2503 request->node = node; 2504 request->attrDirCookie = cookie; 2505 // send the request 2506 KernelRequestHandler handler(this, FREE_ATTR_DIR_COOKIE_REPLY); 2507 FreeAttrDirCookieReply* reply; 2508 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 2509 if (error != B_OK) 2510 return error; 2511 RequestReleaser requestReleaser(port, reply); 2512 // process the reply 2513 if (reply->error != B_OK) 2514 return reply->error; 2515 return error; 2516} 2517 2518// _CloseIndexDir 2519status_t 2520Volume::_CloseIndexDir(void* cookie) 2521{ 2522 // get a free port 2523 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 2524 if (!port) 2525 return B_ERROR; 2526 PortReleaser _(fFileSystem->GetPortPool(), port); 2527 // prepare the request 2528 RequestAllocator allocator(port->GetPort()); 2529 CloseIndexDirRequest* request; 2530 status_t error = AllocateRequest(allocator, &request); 2531 if (error != B_OK) 2532 return error; 2533 request->volume = fUserlandVolume; 2534 request->indexDirCookie = cookie; 2535 // send the request 2536 KernelRequestHandler handler(this, CLOSE_INDEX_DIR_REPLY); 2537 CloseIndexDirReply* reply; 2538 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 2539 if (error != B_OK) 2540 return error; 2541 RequestReleaser requestReleaser(port, reply); 2542 // process the reply 2543 if (reply->error != B_OK) 2544 return reply->error; 2545 return error; 2546} 2547 2548// _FreeIndexDirCookie 2549status_t 2550Volume::_FreeIndexDirCookie(void* cookie) 2551{ 2552 // get a free port 2553 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 2554 if (!port) 2555 return B_ERROR; 2556 PortReleaser _(fFileSystem->GetPortPool(), port); 2557 // prepare the request 2558 RequestAllocator allocator(port->GetPort()); 2559 FreeIndexDirCookieRequest* request; 2560 status_t error = AllocateRequest(allocator, &request); 2561 if (error != B_OK) 2562 return error; 2563 request->volume = fUserlandVolume; 2564 request->indexDirCookie = cookie; 2565 // send the request 2566 KernelRequestHandler handler(this, FREE_INDEX_DIR_COOKIE_REPLY); 2567 FreeIndexDirCookieReply* reply; 2568 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 2569 if (error != B_OK) 2570 return error; 2571 RequestReleaser requestReleaser(port, reply); 2572 // process the reply 2573 if (reply->error != B_OK) 2574 return reply->error; 2575 return error; 2576} 2577 2578// _CloseQuery 2579status_t 2580Volume::_CloseQuery(void* cookie) 2581{ 2582 // get a free port 2583 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 2584 if (!port) 2585 return B_ERROR; 2586 PortReleaser _(fFileSystem->GetPortPool(), port); 2587 // prepare the request 2588 RequestAllocator allocator(port->GetPort()); 2589 CloseQueryRequest* request; 2590 status_t error = AllocateRequest(allocator, &request); 2591 if (error != B_OK) 2592 return error; 2593 request->volume = fUserlandVolume; 2594 request->queryCookie = cookie; 2595 // send the request 2596 KernelRequestHandler handler(this, CLOSE_QUERY_REPLY); 2597 CloseQueryReply* reply; 2598 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 2599 if (error != B_OK) 2600 return error; 2601 RequestReleaser requestReleaser(port, reply); 2602 // process the reply 2603 if (reply->error != B_OK) 2604 return reply->error; 2605 return error; 2606} 2607 2608// _FreeQueryCookie 2609status_t 2610Volume::_FreeQueryCookie(void* cookie) 2611{ 2612 // get a free port 2613 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); 2614 if (!port) 2615 return B_ERROR; 2616 PortReleaser _(fFileSystem->GetPortPool(), port); 2617 // prepare the request 2618 RequestAllocator allocator(port->GetPort()); 2619 FreeQueryCookieRequest* request; 2620 status_t error = AllocateRequest(allocator, &request); 2621 if (error != B_OK) 2622 return error; 2623 request->volume = fUserlandVolume; 2624 request->queryCookie = cookie; 2625 // send the request 2626 KernelRequestHandler handler(this, FREE_QUERY_COOKIE_REPLY); 2627 FreeQueryCookieReply* reply; 2628 error = _SendRequest(port, &allocator, &handler, (Request**)&reply); 2629 if (error != B_OK) 2630 return error; 2631 RequestReleaser requestReleaser(port, reply); 2632 // process the reply 2633 if (reply->error != B_OK) 2634 return reply->error; 2635 return error; 2636} 2637 2638// _SendRequest 2639status_t 2640Volume::_SendRequest(RequestPort* port, RequestAllocator* allocator, 2641 RequestHandler* handler, Request** reply) 2642{ 2643 if (!fFileSystem->IsUserlandServerThread()) 2644 return port->SendRequest(allocator, handler, reply); 2645 // Here it gets dangerous: a thread of the userland server team being here 2646 // calls for trouble. We try receiving the request with a timeout, and 2647 // close the port -- which will disconnect the whole FS. 2648 status_t error = port->SendRequest(allocator, handler, reply, 2649 kUserlandServerlandPortTimeout); 2650 if (error == B_TIMED_OUT || error == B_WOULD_BLOCK) 2651 port->Close(); 2652 return error; 2653} 2654 2655// _SendReceiptAck 2656status_t 2657Volume::_SendReceiptAck(RequestPort* port) 2658{ 2659 RequestAllocator allocator(port->GetPort()); 2660 ReceiptAckReply* request; 2661 status_t error = AllocateRequest(allocator, &request); 2662 if (error != B_OK) 2663 return error; 2664 return port->SendRequest(&allocator); 2665} 2666 2667// _IncrementVNodeCount 2668void 2669Volume::_IncrementVNodeCount(vnode_id vnid) 2670{ 2671 if (!fVNodeCountingEnabled) 2672 return; 2673 AutoLocker<VNodeCountMap> _(fVNodeCountMap); 2674 if (!fVNodeCountingEnabled) // someone may have changed it 2675 return; 2676 // get the counter 2677 int32* count = fVNodeCountMap->Get(vnid); 2678 if (!count) { 2679 // vnode not known yet: create and add a new counter 2680 count = new(nothrow) int32(0); 2681 if (!count) { 2682 ERROR(("Volume::_IncrementVNodeCount(): Failed to allocate " 2683 "counter. Disabling vnode counting.\n")); 2684 fVNodeCountingEnabled = false; 2685 return; 2686 } 2687 if (fVNodeCountMap->Put(vnid, count) != B_OK) { 2688 ERROR(("Volume::_IncrementVNodeCount(): Failed to add counter. " 2689 "Disabling vnode counting.\n")); 2690 delete count; 2691 fVNodeCountingEnabled = false; 2692 return; 2693 } 2694 } 2695 // increment the counter 2696 (*count)++; 2697//PRINT(("_IncrementVNodeCount(%Ld): count: %ld, fVNodeCountMap size: %ld\n", vnid, *count, fVNodeCountMap->Size())); 2698} 2699 2700// _DecrementVNodeCount 2701void 2702Volume::_DecrementVNodeCount(vnode_id vnid) 2703{ 2704 if (!fVNodeCountingEnabled) 2705 return; 2706 AutoLocker<VNodeCountMap> _(fVNodeCountMap); 2707 if (!fVNodeCountingEnabled) // someone may have changed it 2708 return; 2709 int32* count = fVNodeCountMap->Get(vnid); 2710 if (!count) { 2711 // that should never happen 2712 ERROR(("Volume::_DecrementVNodeCount(): Failed to get counter. " 2713 "Disabling vnode counting.\n")); 2714 fVNodeCountingEnabled = false; 2715 return; 2716 } 2717 (*count)--; 2718//int32 tmpCount = *count; 2719 if (*count == 0) 2720 fVNodeCountMap->Remove(vnid); 2721//PRINT(("_DecrementVNodeCount(%Ld): count: %ld, fVNodeCountMap size: %ld\n", vnid, tmpCount, fVNodeCountMap->Size())); 2722} 2723 2724// _InternalIOCtl 2725status_t 2726Volume::_InternalIOCtl(userlandfs_ioctl* buffer, int32 bufferSize) 2727{ 2728 if (buffer->version != USERLAND_IOCTL_CURRENT_VERSION) 2729 return B_BAD_VALUE; 2730 status_t result = B_OK; 2731 switch (buffer->command) { 2732 case USERLAND_IOCTL_PUT_ALL_PENDING_VNODES: 2733 result = _PutAllPendingVNodes(); 2734 break; 2735 default: 2736 return B_BAD_VALUE; 2737 } 2738 buffer->error = result; 2739 return B_OK; 2740} 2741 2742// _PutAllPendingVNodes 2743status_t 2744Volume::_PutAllPendingVNodes() 2745{ 2746PRINT(("Volume::_PutAllPendingVNodes()\n")); 2747 if (!fFileSystem->GetPortPool()->IsDisconnected()) { 2748 PRINT(("Volume::_PutAllPendingVNodes() failed: still connected\n")); 2749 return USERLAND_IOCTL_STILL_CONNECTED; 2750 } 2751 if (!fVNodeCountingEnabled) { 2752 PRINT(("Volume::_PutAllPendingVNodes() failed: vnode counting " 2753 "disabled\n")); 2754 return USERLAND_IOCTL_VNODE_COUNTING_DISABLED; 2755 } 2756 { 2757 AutoLocker<VNodeCountMap> _(fVNodeCountMap); 2758 if (!fVNodeCountingEnabled) {// someone may have changed it 2759 PRINT(("Volume::_PutAllPendingVNodes() failed: vnode counting " 2760 "disabled\n")); 2761 return USERLAND_IOCTL_VNODE_COUNTING_DISABLED; 2762 } 2763 // Check whether there are open entities at the moment. 2764 if (fOpenFiles > 0) { 2765 PRINT(("Volume::_PutAllPendingVNodes() failed: open files\n")); 2766 return USERLAND_IOCTL_OPEN_FILES; 2767 } 2768 if (fOpenDirectories > 0) { 2769 PRINT(("Volume::_PutAllPendingVNodes() failed: open dirs\n")); 2770 return USERLAND_IOCTL_OPEN_DIRECTORIES; 2771 } 2772 if (fOpenAttributeDirectories > 0) { 2773 PRINT(("Volume::_PutAllPendingVNodes() failed: open attr dirs\n")); 2774 return USERLAND_IOCTL_OPEN_ATTRIBUTE_DIRECTORIES; 2775 } 2776 if (fOpenIndexDirectories > 0) { 2777 PRINT(("Volume::_PutAllPendingVNodes() failed: open index dirs\n")); 2778 return USERLAND_IOCTL_OPEN_INDEX_DIRECTORIES; 2779 } 2780 if (fOpenQueries > 0) { 2781 PRINT(("Volume::_PutAllPendingVNodes() failed: open queries\n")); 2782 return USERLAND_IOCTL_OPEN_QUERIES; 2783 } 2784 // No open entities. Since the port pool is disconnected, no new 2785 // entities can be opened. Disable node counting and put all pending 2786 // vnodes. 2787 fVNodeCountingEnabled = false; 2788 } 2789 int32 putVNodeCount = 0; 2790 for (VNodeCountMap::Iterator it = fVNodeCountMap->GetIterator(); 2791 it.HasNext();) { 2792 VNodeCountMap::Entry entry = it.Next(); 2793 int32 count = *entry.value; 2794 for (int32 i = 0; i < count; i++) { 2795 PutVNode(entry.key.value); 2796 putVNodeCount++; 2797 } 2798 } 2799 PRINT(("Volume::_PutAllPendingVNodes() successful: Put %ld vnodes\n", 2800 putVNodeCount)); 2801 return B_OK; 2802} 2803 2804