1 /* 2 * Copyright 2012-2020 Haiku, Inc. All rights reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Paweł Dziepak, pdziepak@quarnos.org 7 */ 8 9 10 #include <stdio.h> 11 12 #include <AutoDeleter.h> 13 #include <fs_cache.h> 14 #include <fs_interface.h> 15 16 #include "Connection.h" 17 #include "FileSystem.h" 18 #include "IdMap.h" 19 #include "Inode.h" 20 #include "NFS4Defs.h" 21 #include "RequestBuilder.h" 22 #include "ReplyInterpreter.h" 23 #include "RootInode.h" 24 #include "RPCCallbackServer.h" 25 #include "RPCServer.h" 26 #include "VnodeToInode.h" 27 #include "WorkQueue.h" 28 29 30 #define ERROR(format, args...) \ 31 dprintf("nfs4: %s()" format "\n", __func__ , ##args) 32 33 #ifdef DEBUG 34 #define TRACE(format, args...) \ 35 dprintf("nfs4: %s()" format "\n", __func__ , ##args) 36 #else 37 #define TRACE(x...) (void)0 38 #endif 39 40 extern fs_volume_ops gNFSv4VolumeOps; 41 extern fs_vnode_ops gNFSv4VnodeOps; 42 43 44 RPC::ServerManager* gRPCServerManager; 45 46 47 RPC::ProgramData* 48 CreateNFS4Server(RPC::Server* serv) 49 { 50 return new NFS4Server(serv); 51 } 52 53 54 // Format: ip{4,6}_address:path options 55 // Available options: 56 // hard - retry requests until success 57 // soft - retry requests no more than retrans times (default) 58 // timeo=X - request time limit before next retransmission (default: 60s) 59 // retrans=X - retry requests X times (default: 5) 60 // ac - use metadata cache (default) 61 // noac - do not use metadata cache 62 // xattr-emu - emulate named attributes 63 // noxattr-emu - do not emulate named attributes (default) 64 // port=X - connect to port X (default: 2049) 65 // proto=X - user transport protocol X (default: tcp) 66 // dirtime=X - attempt revalidate directory cache not more often than each X 67 // seconds 68 static status_t 69 ParseArguments(const char* _args, AddressResolver** address, char** _server, 70 char** _path, MountConfiguration* conf) 71 { 72 if (_args == NULL) 73 return B_BAD_VALUE; 74 75 char* args = strdup(_args); 76 if (args == NULL) 77 return B_NO_MEMORY; 78 MemoryDeleter argsDeleter(args); 79 80 char* options = strchr(args, ' '); 81 if (options != NULL) 82 *options++ = '\0'; 83 84 char* path = strrchr(args, ':'); 85 if (path == NULL) 86 return B_MISMATCHED_VALUES; 87 *path++ = '\0'; 88 89 *_server = strdup(args); 90 if (*_server == NULL) 91 return B_NO_MEMORY; 92 *address = new AddressResolver(args); 93 if (*address == NULL) { 94 free(*_server); 95 return B_NO_MEMORY; 96 } 97 98 *_path = strdup(path); 99 if (*_path == NULL) { 100 free(*_server); 101 delete *address; 102 return B_NO_MEMORY; 103 } 104 105 conf->fHard = false; 106 conf->fRetryLimit = 5; 107 conf->fRequestTimeout = sSecToBigTime(60); 108 conf->fEmulateNamedAttrs = false; 109 conf->fCacheMetadata = true; 110 conf->fDirectoryCacheTime = sSecToBigTime(5); 111 112 char* optionsEnd = NULL; 113 if (options != NULL) 114 optionsEnd = strchr(options, ' '); 115 while (options != NULL && *options != '\0') { 116 if (optionsEnd != NULL) 117 *optionsEnd++ = '\0'; 118 119 if (strcmp(options, "hard") == 0) 120 conf->fHard = true; 121 else if (strncmp(options, "retrans=", 8) == 0) { 122 options += strlen("retrans="); 123 conf->fRetryLimit = atoi(options); 124 } else if (strncmp(options, "timeo=", 6) == 0) { 125 options += strlen("timeo="); 126 conf->fRequestTimeout = atoi(options); 127 } else if (strcmp(options, "noac") == 0) 128 conf->fCacheMetadata = false; 129 else if (strcmp(options, "xattr-emu") == 0) 130 conf->fEmulateNamedAttrs = true; 131 else if (strncmp(options, "port=", 5) == 0) { 132 options += strlen("port="); 133 (*address)->ForcePort(atoi(options)); 134 } else if (strncmp(options, "proto=", 6) == 0) { 135 options += strlen("proto="); 136 (*address)->ForceProtocol(options); 137 } else if (strncmp(options, "dirtime=", 8) == 0) { 138 options += strlen("dirtime="); 139 conf->fDirectoryCacheTime = sSecToBigTime(atoi(options)); 140 } 141 142 options = optionsEnd; 143 if (options != NULL) 144 optionsEnd = strchr(options, ' '); 145 } 146 147 return B_OK; 148 } 149 150 151 static status_t 152 nfs4_mount(fs_volume* volume, const char* device, uint32 flags, 153 const char* args, ino_t* _rootVnodeID) 154 { 155 TRACE("volume = %p, device = %s, flags = %" B_PRIu32 ", args = %s\n", 156 volume, device, flags, args); 157 158 status_t result; 159 160 /* prepare idmapper server */ 161 MutexLocker locker(gIdMapperLock); 162 if (gIdMapper == NULL) { 163 gIdMapper = new(std::nothrow) IdMap; 164 if (gIdMapper == NULL) 165 return B_NO_MEMORY; 166 167 result = gIdMapper->InitStatus(); 168 if (result != B_OK) { 169 delete gIdMapper; 170 gIdMapper = NULL; 171 return result; 172 } 173 } 174 locker.Unlock(); 175 176 AddressResolver* resolver; 177 MountConfiguration config; 178 char* path; 179 char* serverName; 180 result = ParseArguments(args, &resolver, &serverName, &path, &config); 181 if (result != B_OK) { 182 ERROR("Unable to parse mount arguments!\n"); 183 return result; 184 } 185 186 MemoryDeleter pathDeleter(path); 187 MemoryDeleter serverNameDeleter(serverName); 188 189 RPC::Server* server; 190 result = gRPCServerManager->Acquire(&server, resolver, CreateNFS4Server); 191 delete resolver; 192 if (result != B_OK) { 193 ERROR("Unable to Acquire RPCServerManager!\n"); 194 return result; 195 } 196 197 FileSystem* fs; 198 result = FileSystem::Mount(&fs, server, serverName, path, volume->id, 199 config); 200 if (result != B_OK) { 201 ERROR("Error mounting filesystem: %s\n", strerror(result)); 202 gRPCServerManager->Release(server); 203 return result; 204 } 205 206 Inode* inode = fs->Root(); 207 if (inode == NULL) { 208 delete fs; 209 gRPCServerManager->Release(server); 210 ERROR("Unable to locate root inode!\n"); 211 return B_IO_ERROR; 212 } 213 214 volume->private_volume = fs; 215 volume->ops = &gNFSv4VolumeOps; 216 217 VnodeToInode* vti = new VnodeToInode(inode->ID(), fs); 218 if (vti == NULL) { 219 delete fs; 220 gRPCServerManager->Release(server); 221 ERROR("Unable to translate vnode to inode!\n"); 222 return B_NO_MEMORY; 223 } 224 225 vti->Replace(inode); 226 result = publish_vnode(volume, inode->ID(), vti, &gNFSv4VnodeOps, 227 inode->Type(), 0); 228 if (result != B_OK) 229 return result; 230 231 *_rootVnodeID = inode->ID(); 232 233 TRACE("*_rootVnodeID = %" B_PRIi64 "\n", inode->ID()); 234 235 return B_OK; 236 } 237 238 239 static status_t 240 nfs4_get_vnode(fs_volume* volume, ino_t id, fs_vnode* vnode, int* _type, 241 uint32* _flags, bool reenter) 242 { 243 FileSystem* fs = reinterpret_cast<FileSystem*>(volume->private_volume); 244 TRACE("volume = %p, id = %" B_PRIi64 "\n", volume, id); 245 246 VnodeToInode* vnodeToInode = new VnodeToInode(id, fs); 247 if (vnodeToInode == NULL) 248 return B_NO_MEMORY; 249 250 Inode* inode; 251 status_t result = fs->GetInode(id, &inode); 252 if (result != B_OK) { 253 delete vnodeToInode; 254 return result; 255 } 256 257 vnodeToInode->Replace(inode); 258 vnode->ops = &gNFSv4VnodeOps; 259 vnode->private_node = vnodeToInode; 260 261 *_type = inode->Type(); 262 *_flags = 0; 263 264 return B_OK; 265 } 266 267 268 static status_t 269 nfs4_unmount(fs_volume* volume) 270 { 271 TRACE("volume = %p\n", volume); 272 FileSystem* fs = reinterpret_cast<FileSystem*>(volume->private_volume); 273 RPC::Server* server = fs->Server(); 274 275 delete fs; 276 gRPCServerManager->Release(server); 277 278 return B_OK; 279 } 280 281 282 static status_t 283 nfs4_read_fs_info(fs_volume* volume, struct fs_info* info) 284 { 285 TRACE("volume = %p\n", volume); 286 287 FileSystem* fs = reinterpret_cast<FileSystem*>(volume->private_volume); 288 RootInode* inode = reinterpret_cast<RootInode*>(fs->Root()); 289 return inode->ReadInfo(info); 290 } 291 292 293 static status_t 294 nfs4_lookup(fs_volume* volume, fs_vnode* dir, const char* name, ino_t* _id) 295 { 296 VnodeToInode* vti = reinterpret_cast<VnodeToInode*>(dir->private_node); 297 298 if (!strcmp(name, ".")) { 299 *_id = vti->ID(); 300 void* ptr; 301 return get_vnode(volume, *_id, &ptr); 302 } 303 304 VnodeToInodeLocker locker(vti); 305 306 Inode* inode = vti->Get(); 307 if (inode == NULL) 308 return B_ENTRY_NOT_FOUND; 309 310 TRACE("volume = %p, dir = %" B_PRIi64 ", name = %s\n", volume, vti->ID(), 311 name); 312 313 status_t result = inode->LookUp(name, _id); 314 if (result != B_OK) 315 return result; 316 locker.Unlock(); 317 318 TRACE("*_id = %" B_PRIi64 "\n", *_id); 319 320 // If VTI holds an outdated Inode next operation performed on it will 321 // return either ERR_STALE or ERR_FHEXPIRED. Both of these error codes 322 // will cause FileInfo data to be updated (the former will also cause Inode 323 // object to be recreated). We are taking an optimistic (an lazy) approach 324 // here. The following code just ensures VTI won't be removed too soon. 325 void* ptr; 326 result = get_vnode(volume, *_id, &ptr); 327 if (result == B_OK) 328 unremove_vnode(volume, *_id); 329 330 return result; 331 } 332 333 334 static status_t 335 nfs4_put_vnode(fs_volume* volume, fs_vnode* vnode, bool reenter) 336 { 337 VnodeToInode* vti = reinterpret_cast<VnodeToInode*>(vnode->private_node); 338 TRACE("volume = %p, vnode = %" B_PRIi64 "\n", volume, vti->ID()); 339 340 delete vti; 341 return B_OK; 342 } 343 344 345 static status_t 346 nfs4_remove_vnode(fs_volume* volume, fs_vnode* vnode, bool reenter) 347 { 348 FileSystem* fs = reinterpret_cast<FileSystem*>(volume->private_volume); 349 VnodeToInode* vti = reinterpret_cast<VnodeToInode*>(vnode->private_node); 350 TRACE("volume = %p, vnode = %" B_PRIi64 "\n", volume, vti->ID()); 351 352 if (fs->Root() == vti->GetPointer()) 353 return B_OK; 354 355 ASSERT(vti->GetPointer() == NULL); 356 delete vti; 357 358 return B_OK; 359 } 360 361 362 static status_t 363 nfs4_read_pages(fs_volume* _volume, fs_vnode* vnode, void* _cookie, off_t pos, 364 const iovec* vecs, size_t count, size_t* _numBytes) 365 { 366 VnodeToInode* vti = reinterpret_cast<VnodeToInode*>(vnode->private_node); 367 TRACE("volume = %p, vnode = %" B_PRIi64 ", cookie = %p, pos = %" B_PRIi64 \ 368 ", count = %lu, numBytes = %lu\n", _volume, vti->ID(), _cookie, pos, 369 count, *_numBytes); 370 371 VnodeToInodeLocker _(vti); 372 Inode* inode = vti->Get(); 373 if (inode == NULL) 374 return B_ENTRY_NOT_FOUND; 375 376 OpenFileCookie* cookie = reinterpret_cast<OpenFileCookie*>(_cookie); 377 378 status_t result; 379 size_t totalRead = 0; 380 bool eof = false; 381 for (size_t i = 0; i < count && !eof; i++) { 382 size_t bytesLeft = vecs[i].iov_len; 383 char* buffer = reinterpret_cast<char*>(vecs[i].iov_base); 384 385 do { 386 size_t bytesRead = bytesLeft; 387 result = inode->ReadDirect(cookie, pos, buffer, &bytesRead, &eof); 388 if (result != B_OK) 389 return result; 390 391 totalRead += bytesRead; 392 pos += bytesRead; 393 buffer += bytesRead; 394 bytesLeft -= bytesRead; 395 } while (bytesLeft > 0 && !eof); 396 } 397 398 *_numBytes = totalRead; 399 400 TRACE("*numBytes = %lu\n", totalRead); 401 402 return B_OK; 403 } 404 405 406 static status_t 407 nfs4_write_pages(fs_volume* _volume, fs_vnode* vnode, void* _cookie, off_t pos, 408 const iovec* vecs, size_t count, size_t* _numBytes) 409 { 410 VnodeToInode* vti = reinterpret_cast<VnodeToInode*>(vnode->private_node); 411 TRACE("volume = %p, vnode = %" B_PRIi64 ", cookie = %p, pos = %" B_PRIi64 \ 412 ", count = %lu, numBytes = %lu\n", _volume, vti->ID(), _cookie, pos, 413 count, *_numBytes); 414 415 VnodeToInodeLocker _(vti); 416 Inode* inode = vti->Get(); 417 if (inode == NULL) 418 return B_ENTRY_NOT_FOUND; 419 420 OpenFileCookie* cookie = reinterpret_cast<OpenFileCookie*>(_cookie); 421 422 status_t result; 423 for (size_t i = 0; i < count; i++) { 424 uint64 bytesLeft = vecs[i].iov_len; 425 if (pos + bytesLeft > inode->MaxFileSize()) 426 bytesLeft = inode->MaxFileSize() - pos; 427 428 char* buffer = reinterpret_cast<char*>(vecs[i].iov_base); 429 430 do { 431 size_t bytesWritten = bytesLeft; 432 433 result = inode->WriteDirect(cookie, pos, buffer, &bytesWritten); 434 if (result != B_OK) 435 return result; 436 437 bytesLeft -= bytesWritten; 438 pos += bytesWritten; 439 buffer += bytesWritten; 440 } while (bytesLeft > 0); 441 } 442 443 return B_OK; 444 } 445 446 447 static status_t 448 nfs4_io(fs_volume* volume, fs_vnode* vnode, void* cookie, io_request* request) 449 { 450 VnodeToInode* vti = reinterpret_cast<VnodeToInode*>(vnode->private_node); 451 TRACE("volume = %p, vnode = %" B_PRIi64 ", cookie = %p\n", volume, 452 vti->ID(), cookie); 453 454 VnodeToInodeLocker _(vti); 455 Inode* inode = vti->Get(); 456 if (inode == NULL) 457 return B_ENTRY_NOT_FOUND; 458 459 IORequestArgs* args = new(std::nothrow) IORequestArgs; 460 if (args == NULL) { 461 notify_io_request(request, B_NO_MEMORY); 462 return B_NO_MEMORY; 463 } 464 args->fRequest = request; 465 args->fInode = inode; 466 467 status_t result = gWorkQueue->EnqueueJob(IORequest, args); 468 if (result != B_OK) 469 notify_io_request(request, result); 470 471 return result; 472 } 473 474 475 static status_t 476 nfs4_get_file_map(fs_volume* volume, fs_vnode* vnode, off_t _offset, 477 size_t size, struct file_io_vec* vecs, size_t* _count) 478 { 479 return B_ERROR; 480 } 481 482 483 static status_t 484 nfs4_set_flags(fs_volume* volume, fs_vnode* vnode, void* _cookie, int flags) 485 { 486 TRACE("volume = %p, vnode = %" B_PRIi64 ", cookie = %p, flags = %d\n", 487 volume, reinterpret_cast<VnodeToInode*>(vnode->private_node)->ID(), 488 _cookie, flags); 489 490 OpenFileCookie* cookie = reinterpret_cast<OpenFileCookie*>(_cookie); 491 cookie->fMode = (cookie->fMode & ~(O_APPEND | O_NONBLOCK)) | flags; 492 return B_OK; 493 } 494 495 496 static status_t 497 nfs4_fsync(fs_volume* volume, fs_vnode* vnode) 498 { 499 VnodeToInode* vti = reinterpret_cast<VnodeToInode*>(vnode->private_node); 500 TRACE("volume = %p, vnode = %" B_PRIi64 "\n", volume, vti->ID()); 501 502 VnodeToInodeLocker _(vti); 503 Inode* inode = vti->Get(); 504 if (inode == NULL) 505 return B_ENTRY_NOT_FOUND; 506 507 return inode->SyncAndCommit(); 508 } 509 510 511 static status_t 512 nfs4_read_symlink(fs_volume* volume, fs_vnode* link, char* buffer, 513 size_t* _bufferSize) 514 { 515 VnodeToInode* vti = reinterpret_cast<VnodeToInode*>(link->private_node); 516 TRACE("volume = %p, link = %" B_PRIi64 "\n", volume, vti->ID()); 517 518 VnodeToInodeLocker _(vti); 519 Inode* inode = vti->Get(); 520 if (inode == NULL) 521 return B_ENTRY_NOT_FOUND; 522 523 return inode->ReadLink(buffer, _bufferSize); 524 } 525 526 527 static status_t 528 nfs4_create_symlink(fs_volume* volume, fs_vnode* dir, const char* name, 529 const char* path, int mode) 530 { 531 VnodeToInode* vti = reinterpret_cast<VnodeToInode*>(dir->private_node); 532 TRACE("volume = %p, dir = %" B_PRIi64 ", name = %s, path = %s, mode = %d\n", 533 volume, vti->ID(), name, path, mode); 534 535 VnodeToInodeLocker _(vti); 536 Inode* inode = vti->Get(); 537 if (inode == NULL) 538 return B_ENTRY_NOT_FOUND; 539 540 ino_t id; 541 status_t result = inode->CreateLink(name, path, mode, &id); 542 if (result != B_OK) 543 return result; 544 545 result = get_vnode(volume, id, reinterpret_cast<void**>(&vti)); 546 if (result == B_OK) { 547 unremove_vnode(volume, id); 548 vti->Clear(); 549 put_vnode(volume, id); 550 } 551 552 return B_OK; 553 } 554 555 556 static status_t 557 nfs4_link(fs_volume* volume, fs_vnode* dir, const char* name, fs_vnode* vnode) 558 { 559 VnodeToInode* vti = reinterpret_cast<VnodeToInode*>(vnode->private_node); 560 VnodeToInode* dirVti = reinterpret_cast<VnodeToInode*>(dir->private_node); 561 TRACE("volume = %p, dir = %" B_PRIi64 ", name = %s, vnode = %" B_PRIi64 562 "\n", volume, dirVti->ID(), name, vti->ID()); 563 564 VnodeToInodeLocker _dir(dirVti); 565 Inode* dirInode = dirVti->Get(); 566 if (dirInode == NULL) 567 return B_ENTRY_NOT_FOUND; 568 569 570 VnodeToInodeLocker _(vti); 571 Inode* inode = vti->Get(); 572 if (inode == NULL) 573 return B_ENTRY_NOT_FOUND; 574 575 return inode->Link(dirInode, name); 576 } 577 578 579 static status_t 580 nfs4_unlink(fs_volume* volume, fs_vnode* dir, const char* name) 581 { 582 VnodeToInode* vti = reinterpret_cast<VnodeToInode*>(dir->private_node); 583 584 VnodeToInodeLocker locker(vti); 585 Inode* inode = vti->Get(); 586 if (inode == NULL) 587 return B_ENTRY_NOT_FOUND; 588 589 TRACE("volume = %p, dir = %" B_PRIi64 ", name = %s\n", volume, vti->ID(), 590 name); 591 592 ino_t id; 593 status_t result = inode->Remove(name, NF4REG, &id); 594 if (result != B_OK) 595 return result; 596 locker.Unlock(); 597 598 result = acquire_vnode(volume, id); 599 if (result == B_OK) { 600 result = get_vnode(volume, id, reinterpret_cast<void**>(&vti)); 601 ASSERT(result == B_OK); 602 603 if (vti->Unlink(inode->fInfo.fNames, name)) 604 remove_vnode(volume, id); 605 606 put_vnode(volume, id); 607 put_vnode(volume, id); 608 } 609 610 return B_OK; 611 } 612 613 614 static status_t 615 nfs4_rename(fs_volume* volume, fs_vnode* fromDir, const char* fromName, 616 fs_vnode* toDir, const char* toName) 617 { 618 VnodeToInode* fromVti 619 = reinterpret_cast<VnodeToInode*>(fromDir->private_node); 620 VnodeToInode* toVti = reinterpret_cast<VnodeToInode*>(toDir->private_node); 621 TRACE("volume = %p, fromDir = %" B_PRIi64 ", toDir = %" B_PRIi64 "," 622 " fromName = %s, toName = %s\n", volume, fromVti->ID(), toVti->ID(), 623 fromName, toName); 624 625 VnodeToInodeLocker _from(fromVti); 626 Inode* fromInode = fromVti->Get(); 627 if (fromInode == NULL) 628 return B_ENTRY_NOT_FOUND; 629 630 631 VnodeToInodeLocker _to(toVti); 632 Inode* toInode = toVti->Get(); 633 if (toInode == NULL) 634 return B_ENTRY_NOT_FOUND; 635 636 ino_t id; 637 ino_t oldID; 638 status_t result = Inode::Rename(fromInode, toInode, fromName, toName, false, 639 &id, &oldID); 640 if (result != B_OK) 641 return result; 642 643 VnodeToInode* vti; 644 645 if (oldID != 0) { 646 // we have overriden an inode 647 result = acquire_vnode(volume, oldID); 648 if (result == B_OK) { 649 result = get_vnode(volume, oldID, reinterpret_cast<void**>(&vti)); 650 ASSERT(result == B_OK); 651 if (vti->Unlink(toInode->fInfo.fNames, toName)) 652 remove_vnode(volume, oldID); 653 654 put_vnode(volume, oldID); 655 put_vnode(volume, oldID); 656 } 657 } 658 659 result = get_vnode(volume, id, reinterpret_cast<void**>(&vti)); 660 if (result == B_OK) { 661 Inode* child = vti->Get(); 662 if (child == NULL) { 663 put_vnode(volume, id); 664 return B_ENTRY_NOT_FOUND; 665 } 666 667 unremove_vnode(volume, id); 668 child->fInfo.fNames->RemoveName(fromInode->fInfo.fNames, fromName); 669 child->fInfo.fNames->AddName(toInode->fInfo.fNames, toName); 670 put_vnode(volume, id); 671 } 672 673 return B_OK; 674 } 675 676 677 static status_t 678 nfs4_access(fs_volume* volume, fs_vnode* vnode, int mode) 679 { 680 VnodeToInode* vti = reinterpret_cast<VnodeToInode*>(vnode->private_node); 681 TRACE("volume = %p, vnode = %" B_PRIi64 ", mode = %d\n", volume, vti->ID(), 682 mode); 683 684 VnodeToInodeLocker _(vti); 685 Inode* inode = vti->Get(); 686 if (inode == NULL) 687 return B_ENTRY_NOT_FOUND; 688 689 return inode->Access(mode); 690 } 691 692 693 static status_t 694 nfs4_read_stat(fs_volume* volume, fs_vnode* vnode, struct stat* stat) 695 { 696 VnodeToInode* vti = reinterpret_cast<VnodeToInode*>(vnode->private_node); 697 TRACE("volume = %p, vnode = %" B_PRIi64 "\n", volume, vti->ID()); 698 699 VnodeToInodeLocker _(vti); 700 Inode* inode = vti->Get(); 701 if (inode == NULL) 702 return B_ENTRY_NOT_FOUND; 703 704 status_t result = inode->Stat(stat); 705 if (inode->GetOpenState() != NULL) 706 stat->st_size = inode->MaxFileSize(); 707 return result; 708 } 709 710 711 static status_t 712 nfs4_write_stat(fs_volume* volume, fs_vnode* vnode, const struct stat* stat, 713 uint32 statMask) 714 { 715 VnodeToInode* vti = reinterpret_cast<VnodeToInode*>(vnode->private_node); 716 TRACE("volume = %p, vnode = %" B_PRIi64 ", statMask = %" B_PRIu32 "\n", 717 volume, vti->ID(), statMask); 718 719 VnodeToInodeLocker _(vti); 720 Inode* inode = vti->Get(); 721 if (inode == NULL) 722 return B_ENTRY_NOT_FOUND; 723 724 return inode->WriteStat(stat, statMask); 725 } 726 727 728 static status_t 729 get_new_vnode(fs_volume* volume, ino_t id, VnodeToInode** _vti) 730 { 731 FileSystem* fs = reinterpret_cast<FileSystem*>(volume->private_volume); 732 Inode* inode; 733 VnodeToInode* vti; 734 735 status_t result = acquire_vnode(volume, id); 736 if (result == B_OK) { 737 ASSERT(get_vnode(volume, id, reinterpret_cast<void**>(_vti)) == B_OK); 738 unremove_vnode(volume, id); 739 740 // Release after acquire 741 put_vnode(volume, id); 742 743 vti = *_vti; 744 745 if (vti->Get() == NULL) { 746 result = fs->GetInode(id, &inode); 747 if (result != B_OK) { 748 put_vnode(volume, id); 749 return result; 750 } 751 752 vti->Replace(inode); 753 } 754 return B_OK; 755 } 756 757 return get_vnode(volume, id, reinterpret_cast<void**>(_vti)); 758 } 759 760 761 static status_t 762 nfs4_create(fs_volume* volume, fs_vnode* dir, const char* name, int openMode, 763 int perms, void** _cookie, ino_t* _newVnodeID) 764 { 765 FileSystem* fs = reinterpret_cast<FileSystem*>(volume->private_volume); 766 767 OpenFileCookie* cookie = new OpenFileCookie(fs); 768 if (cookie == NULL) 769 return B_NO_MEMORY; 770 *_cookie = cookie; 771 772 VnodeToInode* vti = reinterpret_cast<VnodeToInode*>(dir->private_node); 773 TRACE("volume = %p, dir = %" B_PRIi64 ", name = %s, openMode = %d," \ 774 " perms = %d\n", volume, vti->ID(), name, openMode, perms); 775 776 VnodeToInodeLocker _(vti); 777 Inode* inode = vti->Get(); 778 if (inode == NULL) 779 return B_ENTRY_NOT_FOUND; 780 781 MutexLocker createLocker(fs->CreateFileLock()); 782 783 OpenDelegationData data; 784 status_t result = inode->Create(name, openMode, perms, cookie, &data, 785 _newVnodeID); 786 if (result != B_OK) { 787 delete cookie; 788 return result; 789 } 790 791 result = get_new_vnode(volume, *_newVnodeID, &vti); 792 if (result != B_OK) { 793 delete cookie; 794 return result; 795 } 796 797 VnodeToInodeLocker _child(vti); 798 Inode* child = vti->Get(); 799 if (child == NULL) { 800 delete cookie; 801 put_vnode(volume, *_newVnodeID); 802 return B_ENTRY_NOT_FOUND; 803 } 804 805 child->SetOpenState(cookie->fOpenState); 806 807 if (data.fType != OPEN_DELEGATE_NONE) { 808 Delegation* delegation 809 = new(std::nothrow) Delegation(data, child, 810 cookie->fOpenState->fClientID); 811 if (delegation != NULL) { 812 delegation->fInfo = cookie->fOpenState->fInfo; 813 delegation->fFileSystem = child->GetFileSystem(); 814 child->SetDelegation(delegation); 815 } 816 } 817 818 TRACE("*cookie = %p, *newVnodeID = %" B_PRIi64 "\n", *_cookie, 819 *_newVnodeID); 820 return result; 821 } 822 823 824 static status_t 825 nfs4_open(fs_volume* volume, fs_vnode* vnode, int openMode, void** _cookie) 826 { 827 VnodeToInode* vti = reinterpret_cast<VnodeToInode*>(vnode->private_node); 828 TRACE("volume = %p, vnode = %" B_PRIi64 ", openMode = %d\n", volume, 829 vti->ID(), openMode); 830 831 VnodeToInodeLocker _(vti); 832 Inode* inode = vti->Get(); 833 if (inode == NULL) 834 return B_ENTRY_NOT_FOUND; 835 836 if (inode->Type() == S_IFDIR || inode->Type() == S_IFLNK) { 837 *_cookie = NULL; 838 return B_OK; 839 } 840 841 FileSystem* fs = reinterpret_cast<FileSystem*>(volume->private_volume); 842 OpenFileCookie* cookie = new OpenFileCookie(fs); 843 if (cookie == NULL) 844 return B_NO_MEMORY; 845 *_cookie = cookie; 846 847 status_t result = inode->Open(openMode, cookie); 848 if (result != B_OK) 849 delete cookie; 850 851 TRACE("*cookie = %p\n", *_cookie); 852 853 return result; 854 } 855 856 857 static status_t 858 nfs4_close(fs_volume* volume, fs_vnode* vnode, void* _cookie) 859 { 860 VnodeToInode* vti = reinterpret_cast<VnodeToInode*>(vnode->private_node); 861 862 TRACE("volume = %p, vnode = %" B_PRIi64 ", cookie = %p\n", volume, 863 vti->ID(), _cookie); 864 865 VnodeToInodeLocker _(vti); 866 Inode* inode = vti->Get(); 867 if (inode == NULL) 868 return B_ENTRY_NOT_FOUND; 869 870 871 if (inode->Type() == S_IFDIR || inode->Type() == S_IFLNK) 872 return B_OK; 873 874 Cookie* cookie = reinterpret_cast<Cookie*>(_cookie); 875 return cookie->CancelAll(); 876 } 877 878 879 static status_t 880 nfs4_free_cookie(fs_volume* volume, fs_vnode* vnode, void* _cookie) 881 { 882 VnodeToInode* vti = reinterpret_cast<VnodeToInode*>(vnode->private_node); 883 884 TRACE("volume = %p, vnode = %" B_PRIi64 ", cookie = %p\n", volume, 885 vti->ID(), _cookie); 886 887 VnodeToInodeLocker _(vti); 888 Inode* inode = vti->Get(); 889 if (inode == NULL) 890 return B_ENTRY_NOT_FOUND; 891 892 if (inode->Type() == S_IFDIR || inode->Type() == S_IFLNK) 893 return B_OK; 894 895 OpenFileCookie* cookie = reinterpret_cast<OpenFileCookie*>(_cookie); 896 897 inode->Close(cookie); 898 delete cookie; 899 900 return B_OK; 901 } 902 903 904 static status_t 905 nfs4_read(fs_volume* volume, fs_vnode* vnode, void* _cookie, off_t pos, 906 void* buffer, size_t* length) 907 { 908 VnodeToInode* vti = reinterpret_cast<VnodeToInode*>(vnode->private_node); 909 TRACE("volume = %p, vnode = %" B_PRIi64 ", cookie = %p, pos = %" B_PRIi64 \ 910 ", length = %lu\n", volume, vti->ID(), _cookie, pos, *length); 911 912 VnodeToInodeLocker _(vti); 913 Inode* inode = vti->Get(); 914 if (inode == NULL) 915 return B_ENTRY_NOT_FOUND; 916 917 if (inode->Type() == S_IFDIR) 918 return B_IS_A_DIRECTORY; 919 920 if (inode->Type() == S_IFLNK) 921 return B_BAD_VALUE; 922 923 OpenFileCookie* cookie = reinterpret_cast<OpenFileCookie*>(_cookie); 924 925 return inode->Read(cookie, pos, buffer, length);; 926 } 927 928 929 static status_t 930 nfs4_write(fs_volume* volume, fs_vnode* vnode, void* _cookie, off_t pos, 931 const void* _buffer, size_t* length) 932 { 933 VnodeToInode* vti = reinterpret_cast<VnodeToInode*>(vnode->private_node); 934 TRACE("volume = %p, vnode = %" B_PRIi64 ", cookie = %p, pos = %" B_PRIi64 \ 935 ", length = %lu\n", volume, vti->ID(), _cookie, pos, *length); 936 937 VnodeToInodeLocker _(vti); 938 Inode* inode = vti->Get(); 939 if (inode == NULL) 940 return B_ENTRY_NOT_FOUND; 941 942 if (inode->Type() == S_IFDIR) 943 return B_IS_A_DIRECTORY; 944 945 if (inode->Type() == S_IFLNK) 946 return B_BAD_VALUE; 947 948 OpenFileCookie* cookie = reinterpret_cast<OpenFileCookie*>(_cookie); 949 950 return inode->Write(cookie, pos, _buffer, length); 951 } 952 953 954 static status_t 955 nfs4_create_dir(fs_volume* volume, fs_vnode* parent, const char* name, 956 int mode) 957 { 958 VnodeToInode* vti = reinterpret_cast<VnodeToInode*>(parent->private_node); 959 TRACE("volume = %p, parent = %" B_PRIi64 ", mode = %d\n", volume, vti->ID(), 960 mode); 961 962 VnodeToInodeLocker _(vti); 963 Inode* inode = vti->Get(); 964 if (inode == NULL) 965 return B_ENTRY_NOT_FOUND; 966 967 ino_t id; 968 status_t result = inode->CreateDir(name, mode, &id); 969 if (result != B_OK) 970 return result; 971 972 result = get_vnode(volume, id, reinterpret_cast<void**>(&vti)); 973 if (result == B_OK) { 974 unremove_vnode(volume, id); 975 vti->Clear(); 976 put_vnode(volume, id); 977 } 978 979 return B_OK; 980 } 981 982 983 static status_t 984 nfs4_remove_dir(fs_volume* volume, fs_vnode* parent, const char* name) 985 { 986 VnodeToInode* vti = reinterpret_cast<VnodeToInode*>(parent->private_node); 987 TRACE("volume = %p, parent = %" B_PRIi64 ", name = %s\n", volume, vti->ID(), 988 name); 989 990 VnodeToInodeLocker _(vti); 991 Inode* inode = vti->Get(); 992 if (inode == NULL) 993 return B_ENTRY_NOT_FOUND; 994 995 ino_t id; 996 status_t result = inode->Remove(name, NF4DIR, &id); 997 if (result != B_OK) 998 return result; 999 1000 result = acquire_vnode(volume, id); 1001 if (result == B_OK) { 1002 result = get_vnode(volume, id, reinterpret_cast<void**>(&vti)); 1003 ASSERT(result == B_OK); 1004 1005 if (vti->Unlink(inode->fInfo.fNames, name)) 1006 remove_vnode(volume, id); 1007 1008 put_vnode(volume, id); 1009 put_vnode(volume, id); 1010 } 1011 1012 return B_OK; 1013 } 1014 1015 1016 static status_t 1017 nfs4_open_dir(fs_volume* volume, fs_vnode* vnode, void** _cookie) 1018 { 1019 FileSystem* fs = reinterpret_cast<FileSystem*>(volume->private_volume); 1020 OpenDirCookie* cookie = new(std::nothrow) OpenDirCookie(fs); 1021 if (cookie == NULL) 1022 return B_NO_MEMORY; 1023 *_cookie = cookie; 1024 1025 VnodeToInode* vti = reinterpret_cast<VnodeToInode*>(vnode->private_node); 1026 TRACE("volume = %p, vnode = %" B_PRIi64 "\n", volume, vti->ID()); 1027 1028 VnodeToInodeLocker _(vti); 1029 Inode* inode = vti->Get(); 1030 if (inode == NULL) 1031 return B_ENTRY_NOT_FOUND; 1032 1033 status_t result = inode->OpenDir(cookie); 1034 if (result != B_OK) 1035 delete cookie; 1036 1037 TRACE("*cookie = %p\n", *_cookie); 1038 1039 return result; 1040 } 1041 1042 1043 static status_t 1044 nfs4_close_dir(fs_volume* volume, fs_vnode* vnode, void* _cookie) 1045 { 1046 TRACE("volume = %p, vnode = %" B_PRIi64 ", cookie = %p\n", volume, 1047 reinterpret_cast<VnodeToInode*>(vnode->private_node)->ID(), _cookie); 1048 1049 Cookie* cookie = reinterpret_cast<Cookie*>(_cookie); 1050 return cookie->CancelAll(); 1051 } 1052 1053 1054 static status_t 1055 nfs4_free_dir_cookie(fs_volume* volume, fs_vnode* vnode, void* cookie) 1056 { 1057 TRACE("volume = %p, vnode = %" B_PRIi64 ", cookie = %p\n", volume, 1058 reinterpret_cast<VnodeToInode*>(vnode->private_node)->ID(), cookie); 1059 1060 delete reinterpret_cast<OpenDirCookie*>(cookie); 1061 return B_OK; 1062 } 1063 1064 1065 static status_t 1066 nfs4_read_dir(fs_volume* volume, fs_vnode* vnode, void* _cookie, 1067 struct dirent* buffer, size_t bufferSize, uint32* _num) 1068 { 1069 OpenDirCookie* cookie = reinterpret_cast<OpenDirCookie*>(_cookie); 1070 VnodeToInode* vti = reinterpret_cast<VnodeToInode*>(vnode->private_node); 1071 TRACE("volume = %p, vnode = %" B_PRIi64 ", cookie = %p\n", volume, vti->ID(), 1072 _cookie); 1073 1074 VnodeToInodeLocker _(vti); 1075 Inode* inode = vti->Get(); 1076 if (inode == NULL) 1077 return B_ENTRY_NOT_FOUND; 1078 1079 return inode->ReadDir(buffer, bufferSize, _num, cookie); 1080 } 1081 1082 1083 static status_t 1084 nfs4_rewind_dir(fs_volume* volume, fs_vnode* vnode, void* _cookie) 1085 { 1086 TRACE("volume = %p, vnode = %" B_PRIi64 ", cookie = %p\n", volume, 1087 reinterpret_cast<VnodeToInode*>(vnode->private_node)->ID(), _cookie); 1088 1089 OpenDirCookie* cookie = reinterpret_cast<OpenDirCookie*>(_cookie); 1090 cookie->fSpecial = 0; 1091 if (cookie->fSnapshot != NULL) 1092 cookie->fSnapshot->ReleaseReference(); 1093 cookie->fSnapshot = NULL; 1094 cookie->fCurrent = NULL; 1095 cookie->fEOF = false; 1096 1097 return B_OK; 1098 } 1099 1100 1101 static status_t 1102 nfs4_open_attr_dir(fs_volume* volume, fs_vnode* vnode, void** _cookie) 1103 { 1104 FileSystem* fs = reinterpret_cast<FileSystem*>(volume->private_volume); 1105 OpenDirCookie* cookie = new(std::nothrow) OpenDirCookie(fs); 1106 if (cookie == NULL) 1107 return B_NO_MEMORY; 1108 *_cookie = cookie; 1109 1110 VnodeToInode* vti = reinterpret_cast<VnodeToInode*>(vnode->private_node); 1111 TRACE("volume = %p, vnode = %" B_PRIi64 "\n", volume, vti->ID()); 1112 1113 VnodeToInodeLocker _(vti); 1114 Inode* inode = vti->Get(); 1115 if (inode == NULL) 1116 return B_ENTRY_NOT_FOUND; 1117 1118 status_t result = inode->OpenAttrDir(cookie); 1119 if (result != B_OK) 1120 delete cookie; 1121 1122 return result; 1123 } 1124 1125 1126 static status_t 1127 nfs4_close_attr_dir(fs_volume* volume, fs_vnode* vnode, void* cookie) 1128 { 1129 return nfs4_close_dir(volume, vnode, cookie); 1130 } 1131 1132 1133 static status_t 1134 nfs4_free_attr_dir_cookie(fs_volume* volume, fs_vnode* vnode, void* cookie) 1135 { 1136 return nfs4_free_dir_cookie(volume, vnode, cookie); 1137 } 1138 1139 1140 static status_t 1141 nfs4_read_attr_dir(fs_volume* volume, fs_vnode* vnode, void* cookie, 1142 struct dirent* buffer, size_t bufferSize, uint32* _num) 1143 { 1144 return nfs4_read_dir(volume, vnode, cookie, buffer, bufferSize, _num); 1145 } 1146 1147 1148 static status_t 1149 nfs4_rewind_attr_dir(fs_volume* volume, fs_vnode* vnode, void* cookie) 1150 { 1151 return nfs4_rewind_dir(volume, vnode, cookie); 1152 } 1153 1154 1155 static status_t 1156 nfs4_create_attr(fs_volume* volume, fs_vnode* vnode, const char* name, 1157 uint32 type, int openMode, void** _cookie) 1158 { 1159 VnodeToInode* vti = reinterpret_cast<VnodeToInode*>(vnode->private_node); 1160 1161 VnodeToInodeLocker _(vti); 1162 Inode* inode = vti->Get(); 1163 if (inode == NULL) 1164 return B_ENTRY_NOT_FOUND; 1165 1166 FileSystem* fs = reinterpret_cast<FileSystem*>(volume->private_volume); 1167 OpenAttrCookie* cookie = new OpenAttrCookie(fs); 1168 if (cookie == NULL) 1169 return B_NO_MEMORY; 1170 *_cookie = cookie; 1171 1172 status_t result = inode->OpenAttr(name, openMode, cookie, true, type); 1173 if (result != B_OK) 1174 delete cookie; 1175 1176 return result; 1177 } 1178 1179 1180 static status_t 1181 nfs4_open_attr(fs_volume* volume, fs_vnode* vnode, const char* name, 1182 int openMode, void** _cookie) 1183 { 1184 VnodeToInode* vti = reinterpret_cast<VnodeToInode*>(vnode->private_node); 1185 1186 VnodeToInodeLocker _(vti); 1187 Inode* inode = vti->Get(); 1188 if (inode == NULL) 1189 return B_ENTRY_NOT_FOUND; 1190 1191 FileSystem* fs = reinterpret_cast<FileSystem*>(volume->private_volume); 1192 OpenAttrCookie* cookie = new OpenAttrCookie(fs); 1193 if (cookie == NULL) 1194 return B_NO_MEMORY; 1195 *_cookie = cookie; 1196 1197 status_t result = inode->OpenAttr(name, openMode, cookie, false); 1198 if (result != B_OK) 1199 delete cookie; 1200 1201 return result; 1202 } 1203 1204 1205 static status_t 1206 nfs4_close_attr(fs_volume* volume, fs_vnode* vnode, void* _cookie) 1207 { 1208 Cookie* cookie = reinterpret_cast<Cookie*>(_cookie); 1209 return cookie->CancelAll(); 1210 } 1211 1212 1213 static status_t 1214 nfs4_free_attr_cookie(fs_volume* volume, fs_vnode* vnode, void* _cookie) 1215 { 1216 VnodeToInode* vti = reinterpret_cast<VnodeToInode*>(vnode->private_node); 1217 1218 VnodeToInodeLocker _(vti); 1219 Inode* inode = vti->Get(); 1220 if (inode == NULL) 1221 return B_ENTRY_NOT_FOUND; 1222 1223 OpenAttrCookie* cookie = reinterpret_cast<OpenAttrCookie*>(_cookie); 1224 inode->CloseAttr(cookie); 1225 delete cookie; 1226 1227 return B_OK; 1228 } 1229 1230 1231 static status_t 1232 nfs4_read_attr(fs_volume* volume, fs_vnode* vnode, void* _cookie, off_t pos, 1233 void* buffer, size_t* length) 1234 { 1235 VnodeToInode* vti = reinterpret_cast<VnodeToInode*>(vnode->private_node); 1236 OpenAttrCookie* cookie = reinterpret_cast<OpenAttrCookie*>(_cookie); 1237 bool eof; 1238 1239 VnodeToInodeLocker _(vti); 1240 Inode* inode = vti->Get(); 1241 if (inode == NULL) 1242 return B_ENTRY_NOT_FOUND; 1243 1244 return inode->ReadDirect(cookie, pos, buffer, length, &eof); 1245 } 1246 1247 1248 static status_t 1249 nfs4_write_attr(fs_volume* volume, fs_vnode* vnode, void* _cookie, off_t pos, 1250 const void* buffer, size_t* length) 1251 { 1252 VnodeToInode* vti = reinterpret_cast<VnodeToInode*>(vnode->private_node); 1253 OpenAttrCookie* cookie = reinterpret_cast<OpenAttrCookie*>(_cookie); 1254 1255 VnodeToInodeLocker _(vti); 1256 Inode* inode = vti->Get(); 1257 if (inode == NULL) 1258 return B_ENTRY_NOT_FOUND; 1259 1260 return inode->WriteDirect(cookie, pos, buffer, length); 1261 } 1262 1263 1264 static status_t 1265 nfs4_read_attr_stat(fs_volume* volume, fs_vnode* vnode, void* _cookie, 1266 struct stat* stat) 1267 { 1268 VnodeToInode* vti = reinterpret_cast<VnodeToInode*>(vnode->private_node); 1269 OpenAttrCookie* cookie = reinterpret_cast<OpenAttrCookie*>(_cookie); 1270 1271 VnodeToInodeLocker _(vti); 1272 Inode* inode = vti->Get(); 1273 if (inode == NULL) 1274 return B_ENTRY_NOT_FOUND; 1275 1276 return inode->Stat(stat, cookie); 1277 } 1278 1279 1280 static status_t 1281 nfs4_write_attr_stat(fs_volume* volume, fs_vnode* vnode, void* _cookie, 1282 const struct stat* stat, int statMask) 1283 { 1284 VnodeToInode* vti = reinterpret_cast<VnodeToInode*>(vnode->private_node); 1285 OpenAttrCookie* cookie = reinterpret_cast<OpenAttrCookie*>(_cookie); 1286 1287 VnodeToInodeLocker _(vti); 1288 Inode* inode = vti->Get(); 1289 if (inode == NULL) 1290 return B_ENTRY_NOT_FOUND; 1291 1292 return inode->WriteStat(stat, statMask, cookie); 1293 } 1294 1295 1296 static status_t 1297 nfs4_rename_attr(fs_volume* volume, fs_vnode* fromVnode, const char* fromName, 1298 fs_vnode* toVnode, const char* toName) 1299 { 1300 VnodeToInode* vti = reinterpret_cast<VnodeToInode*>(toVnode->private_node); 1301 VnodeToInodeLocker to(vti); 1302 Inode* toInode = vti->Get(); 1303 if (toInode == NULL) 1304 return B_ENTRY_NOT_FOUND; 1305 1306 vti = reinterpret_cast<VnodeToInode*>(fromVnode->private_node); 1307 VnodeToInodeLocker from(vti); 1308 Inode* fromInode = vti->Get(); 1309 if (fromInode == NULL) 1310 return B_ENTRY_NOT_FOUND; 1311 1312 return Inode::Rename(fromInode, toInode, fromName, toName, true); 1313 } 1314 1315 1316 static status_t 1317 nfs4_remove_attr(fs_volume* volume, fs_vnode* vnode, const char* name) 1318 { 1319 VnodeToInode* vti = reinterpret_cast<VnodeToInode*>(vnode->private_node); 1320 1321 VnodeToInodeLocker _(vti); 1322 Inode* inode = vti->Get(); 1323 if (inode == NULL) 1324 return B_ENTRY_NOT_FOUND; 1325 1326 return inode->Remove(name, NF4NAMEDATTR, NULL); 1327 } 1328 1329 1330 static status_t 1331 nfs4_test_lock(fs_volume* volume, fs_vnode* vnode, void* _cookie, 1332 struct flock* lock) 1333 { 1334 VnodeToInode* vti = reinterpret_cast<VnodeToInode*>(vnode->private_node); 1335 OpenFileCookie* cookie = reinterpret_cast<OpenFileCookie*>(_cookie); 1336 TRACE("volume = %p, vnode = %" B_PRIi64 ", cookie = %p, lock = %p\n", 1337 volume, vti->ID(), _cookie, lock); 1338 1339 VnodeToInodeLocker _(vti); 1340 Inode* inode = vti->Get(); 1341 if (inode == NULL) 1342 return B_ENTRY_NOT_FOUND; 1343 1344 return inode->TestLock(cookie, lock); 1345 } 1346 1347 1348 static status_t 1349 nfs4_acquire_lock(fs_volume* volume, fs_vnode* vnode, void* _cookie, 1350 const struct flock* lock, bool wait) 1351 { 1352 VnodeToInode* vti = reinterpret_cast<VnodeToInode*>(vnode->private_node); 1353 OpenFileCookie* cookie = reinterpret_cast<OpenFileCookie*>(_cookie); 1354 TRACE("volume = %p, vnode = %" B_PRIi64 ", cookie = %p, lock = %p\n", 1355 volume, vti->ID(), _cookie, lock); 1356 1357 1358 VnodeToInodeLocker _(vti); 1359 Inode* inode = vti->Get(); 1360 if (inode == NULL) 1361 return B_ENTRY_NOT_FOUND; 1362 1363 inode->RevalidateFileCache(); 1364 return inode->AcquireLock(cookie, lock, wait); 1365 } 1366 1367 1368 static status_t 1369 nfs4_release_lock(fs_volume* volume, fs_vnode* vnode, void* _cookie, 1370 const struct flock* lock) 1371 { 1372 VnodeToInode* vti = reinterpret_cast<VnodeToInode*>(vnode->private_node); 1373 TRACE("volume = %p, vnode = %" B_PRIi64 ", cookie = %p, lock = %p\n", 1374 volume, vti->ID(), _cookie, lock); 1375 1376 VnodeToInodeLocker _(vti); 1377 Inode* inode = vti->Get(); 1378 if (inode == NULL) 1379 return B_ENTRY_NOT_FOUND; 1380 1381 if (inode->Type() == S_IFDIR || inode->Type() == S_IFLNK) 1382 return B_OK; 1383 1384 OpenFileCookie* cookie = reinterpret_cast<OpenFileCookie*>(_cookie); 1385 1386 if (lock != NULL) 1387 return inode->ReleaseLock(cookie, lock); 1388 else 1389 return inode->ReleaseAllLocks(cookie); 1390 } 1391 1392 1393 status_t 1394 nfs4_init() 1395 { 1396 gRPCServerManager = new(std::nothrow) RPC::ServerManager; 1397 if (gRPCServerManager == NULL) 1398 return B_NO_MEMORY; 1399 1400 mutex_init(&gIdMapperLock, "idmapper Init Lock"); 1401 gIdMapper = NULL; 1402 1403 gWorkQueue = new(std::nothrow) WorkQueue; 1404 if (gWorkQueue == NULL || gWorkQueue->InitStatus() != B_OK) { 1405 delete gWorkQueue; 1406 mutex_destroy(&gIdMapperLock); 1407 delete gRPCServerManager; 1408 return B_NO_MEMORY; 1409 } 1410 1411 return B_OK; 1412 } 1413 1414 1415 status_t 1416 nfs4_uninit() 1417 { 1418 RPC::CallbackServer::ShutdownAll(); 1419 1420 delete gIdMapper; 1421 delete gWorkQueue; 1422 delete gRPCServerManager; 1423 1424 mutex_destroy(&gIdMapperLock); 1425 1426 return B_OK; 1427 } 1428 1429 1430 static status_t 1431 nfs4_std_ops(int32 op, ...) 1432 { 1433 switch (op) { 1434 case B_MODULE_INIT: 1435 return nfs4_init(); 1436 case B_MODULE_UNINIT: 1437 return nfs4_uninit(); 1438 default: 1439 return B_ERROR; 1440 } 1441 } 1442 1443 1444 fs_volume_ops gNFSv4VolumeOps = { 1445 nfs4_unmount, 1446 nfs4_read_fs_info, 1447 NULL, 1448 NULL, 1449 nfs4_get_vnode, 1450 }; 1451 1452 fs_vnode_ops gNFSv4VnodeOps = { 1453 nfs4_lookup, 1454 NULL, // get_vnode_name() 1455 nfs4_put_vnode, 1456 nfs4_remove_vnode, 1457 1458 /* VM file access */ 1459 NULL, // can_page() 1460 nfs4_read_pages, 1461 nfs4_write_pages, 1462 1463 nfs4_io, 1464 NULL, // cancel_io() 1465 1466 nfs4_get_file_map, 1467 1468 NULL, // ioctl() 1469 nfs4_set_flags, 1470 NULL, // fs_select() 1471 NULL, // fs_deselect() 1472 nfs4_fsync, 1473 1474 nfs4_read_symlink, 1475 nfs4_create_symlink, 1476 1477 nfs4_link, 1478 nfs4_unlink, 1479 nfs4_rename, 1480 1481 nfs4_access, 1482 nfs4_read_stat, 1483 nfs4_write_stat, 1484 NULL, // fs_preallocate() 1485 1486 /* file operations */ 1487 nfs4_create, 1488 nfs4_open, 1489 nfs4_close, 1490 nfs4_free_cookie, 1491 nfs4_read, 1492 nfs4_write, 1493 1494 /* directory operations */ 1495 nfs4_create_dir, 1496 nfs4_remove_dir, 1497 nfs4_open_dir, 1498 nfs4_close_dir, 1499 nfs4_free_dir_cookie, 1500 nfs4_read_dir, 1501 nfs4_rewind_dir, 1502 1503 /* attribute directory operations */ 1504 nfs4_open_attr_dir, 1505 nfs4_close_attr_dir, 1506 nfs4_free_attr_dir_cookie, 1507 nfs4_read_attr_dir, 1508 nfs4_rewind_attr_dir, 1509 1510 /* attribute operations */ 1511 nfs4_create_attr, 1512 nfs4_open_attr, 1513 nfs4_close_attr, 1514 nfs4_free_attr_cookie, 1515 nfs4_read_attr, 1516 nfs4_write_attr, 1517 1518 nfs4_read_attr_stat, 1519 nfs4_write_attr_stat, 1520 nfs4_rename_attr, 1521 nfs4_remove_attr, 1522 1523 /* support for node and FS layers */ 1524 NULL, // create_special_node 1525 NULL, // get_super_vnode 1526 1527 /* lock operations */ 1528 nfs4_test_lock, 1529 nfs4_acquire_lock, 1530 nfs4_release_lock, 1531 }; 1532 1533 static file_system_module_info sNFSv4ModuleInfo = { 1534 { 1535 "file_systems/nfs4" B_CURRENT_FS_API_VERSION, 1536 0, 1537 nfs4_std_ops, 1538 }, 1539 1540 "nfs4", // short_name 1541 "Network File System version 4", // pretty_name 1542 1543 // DDM flags 1544 0, 1545 1546 // scanning 1547 NULL, // identify_partition() 1548 NULL, // scan_partition() 1549 NULL, // free_identify_partition_cookie() 1550 NULL, // free_partition_content_cookie() 1551 1552 nfs4_mount, 1553 }; 1554 1555 module_info* modules[] = { 1556 (module_info*)&sNFSv4ModuleInfo, 1557 NULL, 1558 }; 1559 1560