1 /* 2 * Copyright 2012 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 #ifdef DEBUG 30 #define TRACE_NFS4 31 #endif 32 33 #ifdef TRACE_NFS4 34 static mutex gTraceLock = MUTEX_INITIALIZER(NULL); 35 36 #define TRACE(x...) \ 37 { \ 38 mutex_lock(&gTraceLock); \ 39 dprintf("nfs4: %s(): ", __FUNCTION__); \ 40 dprintf(x); \ 41 dprintf("\n"); \ 42 mutex_unlock(&gTraceLock); \ 43 } 44 #else 45 #define TRACE(x...) (void)0 46 #endif 47 48 extern fs_volume_ops gNFSv4VolumeOps; 49 extern fs_vnode_ops gNFSv4VnodeOps; 50 51 52 RPC::ServerManager* gRPCServerManager; 53 54 55 RPC::ProgramData* 56 CreateNFS4Server(RPC::Server* serv) 57 { 58 return new NFS4Server(serv); 59 } 60 61 62 // Format: ip{4,6}_address:path options 63 // Available options: 64 // hard - retry requests until success 65 // soft - retry requests no more than retrans times (default) 66 // timeo=X - request time limit before next retransmission (default: 60s) 67 // retrans=X - retry requests X times (default: 5) 68 // ac - use metadata cache (default) 69 // noac - do not use metadata cache 70 // xattr-emu - emulate named attributes 71 // noxattr-emu - do not emulate named attributes (default) 72 // port=X - connect to port X (default: 2049) 73 // proto=X - user transport protocol X (default: tcp) 74 // dirtime=X - attempt revalidate directory cache not more often than each X 75 // seconds 76 static status_t 77 ParseArguments(const char* _args, AddressResolver** address, char** _server, 78 char** _path, MountConfiguration* conf) 79 { 80 if (_args == NULL) 81 return B_BAD_VALUE; 82 83 char* args = strdup(_args); 84 if (args == NULL) 85 return B_NO_MEMORY; 86 MemoryDeleter argsDeleter(args); 87 88 char* options = strchr(args, ' '); 89 if (options != NULL) 90 *options++ = '\0'; 91 92 char* path = strrchr(args, ':'); 93 if (path == NULL) 94 return B_MISMATCHED_VALUES; 95 *path++ = '\0'; 96 97 *_server = strdup(args); 98 if (*_server == NULL) 99 return B_NO_MEMORY; 100 *address = new AddressResolver(args); 101 if (*address == NULL) { 102 free(*_server); 103 return B_NO_MEMORY; 104 } 105 106 *_path = strdup(path); 107 if (*_path == NULL) { 108 free(*_server); 109 delete *address; 110 return B_NO_MEMORY; 111 } 112 113 conf->fHard = false; 114 conf->fRetryLimit = 5; 115 conf->fRequestTimeout = sSecToBigTime(60); 116 conf->fEmulateNamedAttrs = false; 117 conf->fCacheMetadata = true; 118 conf->fDirectoryCacheTime = sSecToBigTime(5); 119 120 char* optionsEnd = NULL; 121 if (options != NULL) 122 optionsEnd = strchr(options, ' '); 123 while (options != NULL && *options != '\0') { 124 if (optionsEnd != NULL) 125 *optionsEnd++ = '\0'; 126 127 if (strcmp(options, "hard") == 0) 128 conf->fHard = true; 129 else if (strncmp(options, "retrans=", 8) == 0) { 130 options += strlen("retrans="); 131 conf->fRetryLimit = atoi(options); 132 } else if (strncmp(options, "timeo=", 6) == 0) { 133 options += strlen("timeo="); 134 conf->fRequestTimeout = atoi(options); 135 } else if (strcmp(options, "noac") == 0) 136 conf->fCacheMetadata = false; 137 else if (strcmp(options, "xattr-emu") == 0) 138 conf->fEmulateNamedAttrs = true; 139 else if (strncmp(options, "port=", 5) == 0) { 140 options += strlen("port="); 141 (*address)->ForcePort(atoi(options)); 142 } else if (strncmp(options, "proto=", 6) == 0) { 143 options += strlen("proto="); 144 (*address)->ForceProtocol(options); 145 } else if (strncmp(options, "dirtime=", 8) == 0) { 146 options += strlen("dirtime="); 147 conf->fDirectoryCacheTime = sSecToBigTime(atoi(options)); 148 } 149 150 options = optionsEnd; 151 if (options != NULL) 152 optionsEnd = strchr(options, ' '); 153 } 154 155 return B_OK; 156 } 157 158 159 static status_t 160 nfs4_mount(fs_volume* volume, const char* device, uint32 flags, 161 const char* args, ino_t* _rootVnodeID) 162 { 163 TRACE("volume = %p, device = %s, flags = %" B_PRIu32 ", args = %s", volume, 164 device, flags, args); 165 166 status_t result; 167 168 /* prepare idmapper server */ 169 MutexLocker locker(gIdMapperLock); 170 if (gIdMapper == NULL) { 171 gIdMapper = new(std::nothrow) IdMap; 172 if (gIdMapper == NULL) 173 return B_NO_MEMORY; 174 175 result = gIdMapper->InitStatus(); 176 if (result != B_OK) { 177 delete gIdMapper; 178 gIdMapper = NULL; 179 return result; 180 } 181 } 182 locker.Unlock(); 183 184 AddressResolver* resolver; 185 MountConfiguration config; 186 char* path; 187 char* serverName; 188 result = ParseArguments(args, &resolver, &serverName, &path, &config); 189 if (result != B_OK) 190 return result; 191 MemoryDeleter pathDeleter(path); 192 MemoryDeleter serverNameDeleter(serverName); 193 194 RPC::Server* server; 195 result = gRPCServerManager->Acquire(&server, resolver, CreateNFS4Server); 196 delete resolver; 197 if (result != B_OK) 198 return result; 199 200 FileSystem* fs; 201 result = FileSystem::Mount(&fs, server, serverName, path, volume->id, 202 config); 203 if (result != B_OK) { 204 gRPCServerManager->Release(server); 205 return result; 206 } 207 208 Inode* inode = fs->Root(); 209 if (inode == NULL) { 210 delete fs; 211 gRPCServerManager->Release(server); 212 213 return B_IO_ERROR; 214 } 215 216 volume->private_volume = fs; 217 volume->ops = &gNFSv4VolumeOps; 218 219 VnodeToInode* vti = new VnodeToInode(inode->ID(), fs); 220 if (vti == NULL) { 221 delete fs; 222 gRPCServerManager->Release(server); 223 return B_NO_MEMORY; 224 } 225 226 vti->Replace(inode); 227 result = publish_vnode(volume, inode->ID(), vti, &gNFSv4VnodeOps, 228 inode->Type(), 0); 229 if (result != B_OK) 230 return result; 231 232 *_rootVnodeID = inode->ID(); 233 234 TRACE("*_rootVnodeID = %" B_PRIi64, inode->ID()); 235 236 return B_OK; 237 } 238 239 240 static status_t 241 nfs4_get_vnode(fs_volume* volume, ino_t id, fs_vnode* vnode, int* _type, 242 uint32* _flags, bool reenter) 243 { 244 FileSystem* fs = reinterpret_cast<FileSystem*>(volume->private_volume); 245 TRACE("volume = %p, id = %" B_PRIi64, volume, id); 246 247 VnodeToInode* vnodeToInode = new VnodeToInode(id, fs); 248 if (vnodeToInode == NULL) 249 return B_NO_MEMORY; 250 251 Inode* inode; 252 status_t result = fs->GetInode(id, &inode); 253 if (result != B_OK) { 254 delete vnodeToInode; 255 return result; 256 } 257 258 vnodeToInode->Replace(inode); 259 vnode->ops = &gNFSv4VnodeOps; 260 vnode->private_node = vnodeToInode; 261 262 *_type = inode->Type(); 263 *_flags = 0; 264 265 return B_OK; 266 } 267 268 269 static status_t 270 nfs4_unmount(fs_volume* volume) 271 { 272 TRACE("volume = %p", volume); 273 FileSystem* fs = reinterpret_cast<FileSystem*>(volume->private_volume); 274 RPC::Server* server = fs->Server(); 275 276 delete fs; 277 gRPCServerManager->Release(server); 278 279 return B_OK; 280 } 281 282 283 static status_t 284 nfs4_read_fs_info(fs_volume* volume, struct fs_info* info) 285 { 286 TRACE("volume = %p", volume); 287 288 FileSystem* fs = reinterpret_cast<FileSystem*>(volume->private_volume); 289 RootInode* inode = reinterpret_cast<RootInode*>(fs->Root()); 290 return inode->ReadInfo(info); 291 } 292 293 294 static status_t 295 nfs4_lookup(fs_volume* volume, fs_vnode* dir, const char* name, ino_t* _id) 296 { 297 VnodeToInode* vti = reinterpret_cast<VnodeToInode*>(dir->private_node); 298 299 if (!strcmp(name, ".")) { 300 *_id = vti->ID(); 301 void* ptr; 302 return get_vnode(volume, *_id, &ptr); 303 } 304 305 VnodeToInodeLocker locker(vti); 306 307 Inode* inode = vti->Get(); 308 if (inode == NULL) 309 return B_ENTRY_NOT_FOUND; 310 311 TRACE("volume = %p, dir = %" B_PRIi64 ", name = %s", volume, vti->ID(), 312 name); 313 314 status_t result = inode->LookUp(name, _id); 315 if (result != B_OK) 316 return result; 317 locker.Unlock(); 318 319 TRACE("*_id = %" B_PRIi64, *_id); 320 321 // If VTI holds an outdated Inode next operation performed on it will 322 // return either ERR_STALE or ERR_FHEXPIRED. Both of these error codes 323 // will cause FileInfo data to be updated (the former will also cause Inode 324 // object to be recreated). We are taking an optimistic (an lazy) approach 325 // here. The following code just ensures VTI won't be removed too soon. 326 void* ptr; 327 result = get_vnode(volume, *_id, &ptr); 328 if (result == B_OK) 329 unremove_vnode(volume, *_id); 330 331 return result; 332 } 333 334 335 static status_t 336 nfs4_put_vnode(fs_volume* volume, fs_vnode* vnode, bool reenter) 337 { 338 VnodeToInode* vti = reinterpret_cast<VnodeToInode*>(vnode->private_node); 339 TRACE("volume = %p, vnode = %" B_PRIi64, volume, vti->ID()); 340 341 delete vti; 342 return B_OK; 343 } 344 345 346 static status_t 347 nfs4_remove_vnode(fs_volume* volume, fs_vnode* vnode, bool reenter) 348 { 349 FileSystem* fs = reinterpret_cast<FileSystem*>(volume->private_volume); 350 VnodeToInode* vti = reinterpret_cast<VnodeToInode*>(vnode->private_node); 351 TRACE("volume = %p, vnode = %" B_PRIi64, volume, vti->ID()); 352 353 if (fs->Root() == vti->GetPointer()) 354 return B_OK; 355 356 ASSERT(vti->GetPointer() == NULL); 357 delete vti; 358 359 return B_OK; 360 } 361 362 363 static status_t 364 nfs4_read_pages(fs_volume* _volume, fs_vnode* vnode, void* _cookie, off_t pos, 365 const iovec* vecs, size_t count, size_t* _numBytes) 366 { 367 VnodeToInode* vti = reinterpret_cast<VnodeToInode*>(vnode->private_node); 368 TRACE("volume = %p, vnode = %" B_PRIi64 ", cookie = %p, pos = %" B_PRIi64 \ 369 ", count = %lu, numBytes = %lu", _volume, vti->ID(), _cookie, pos, 370 count, *_numBytes); 371 372 VnodeToInodeLocker _(vti); 373 Inode* inode = vti->Get(); 374 if (inode == NULL) 375 return B_ENTRY_NOT_FOUND; 376 377 OpenFileCookie* cookie = reinterpret_cast<OpenFileCookie*>(_cookie); 378 379 status_t result; 380 size_t totalRead = 0; 381 bool eof = false; 382 for (size_t i = 0; i < count && !eof; i++) { 383 size_t bytesLeft = vecs[i].iov_len; 384 char* buffer = reinterpret_cast<char*>(vecs[i].iov_base); 385 386 do { 387 size_t bytesRead = bytesLeft; 388 result = inode->ReadDirect(cookie, pos, buffer, &bytesRead, &eof); 389 if (result != B_OK) 390 return result; 391 392 totalRead += bytesRead; 393 pos += bytesRead; 394 buffer += bytesRead; 395 bytesLeft -= bytesRead; 396 } while (bytesLeft > 0 && !eof); 397 } 398 399 *_numBytes = totalRead; 400 401 TRACE("*numBytes = %lu", totalRead); 402 403 return B_OK; 404 } 405 406 407 static status_t 408 nfs4_write_pages(fs_volume* _volume, fs_vnode* vnode, void* _cookie, off_t pos, 409 const iovec* vecs, size_t count, size_t* _numBytes) 410 { 411 VnodeToInode* vti = reinterpret_cast<VnodeToInode*>(vnode->private_node); 412 TRACE("volume = %p, vnode = %" B_PRIi64 ", cookie = %p, pos = %" B_PRIi64 \ 413 ", count = %lu, numBytes = %lu", _volume, vti->ID(), _cookie, pos, 414 count, *_numBytes); 415 416 VnodeToInodeLocker _(vti); 417 Inode* inode = vti->Get(); 418 if (inode == NULL) 419 return B_ENTRY_NOT_FOUND; 420 421 OpenFileCookie* cookie = reinterpret_cast<OpenFileCookie*>(_cookie); 422 423 status_t result; 424 for (size_t i = 0; i < count; i++) { 425 uint64 bytesLeft = vecs[i].iov_len; 426 if (pos + bytesLeft > inode->MaxFileSize()) 427 bytesLeft = inode->MaxFileSize() - pos; 428 429 char* buffer = reinterpret_cast<char*>(vecs[i].iov_base); 430 431 do { 432 size_t bytesWritten = bytesLeft; 433 434 result = inode->WriteDirect(cookie, pos, buffer, &bytesWritten); 435 if (result != B_OK) 436 return result; 437 438 bytesLeft -= bytesWritten; 439 pos += bytesWritten; 440 buffer += bytesWritten; 441 } while (bytesLeft > 0); 442 } 443 444 return B_OK; 445 } 446 447 448 static status_t 449 nfs4_io(fs_volume* volume, fs_vnode* vnode, void* cookie, io_request* request) 450 { 451 VnodeToInode* vti = reinterpret_cast<VnodeToInode*>(vnode->private_node); 452 TRACE("volume = %p, vnode = %" B_PRIi64 ", cookie = %p", volume, vti->ID(), 453 cookie); 454 455 VnodeToInodeLocker _(vti); 456 Inode* inode = vti->Get(); 457 if (inode == NULL) 458 return B_ENTRY_NOT_FOUND; 459 460 IORequestArgs* args = new(std::nothrow) IORequestArgs; 461 if (args == NULL) { 462 notify_io_request(request, B_NO_MEMORY); 463 return B_NO_MEMORY; 464 } 465 args->fRequest = request; 466 args->fInode = inode; 467 468 status_t result = gWorkQueue->EnqueueJob(IORequest, args); 469 if (result != B_OK) 470 notify_io_request(request, result); 471 472 return result; 473 } 474 475 476 static status_t 477 nfs4_get_file_map(fs_volume* volume, fs_vnode* vnode, off_t _offset, 478 size_t size, struct file_io_vec* vecs, size_t* _count) 479 { 480 return B_ERROR; 481 } 482 483 484 static status_t 485 nfs4_set_flags(fs_volume* volume, fs_vnode* vnode, void* _cookie, int flags) 486 { 487 TRACE("volume = %p, vnode = %" B_PRIi64 ", cookie = %p, flags = %d", volume, 488 reinterpret_cast<VnodeToInode*>(vnode->private_node)->ID(), _cookie, 489 flags); 490 491 OpenFileCookie* cookie = reinterpret_cast<OpenFileCookie*>(_cookie); 492 cookie->fMode = (cookie->fMode & ~(O_APPEND | O_NONBLOCK)) | flags; 493 return B_OK; 494 } 495 496 497 static status_t 498 nfs4_fsync(fs_volume* volume, fs_vnode* vnode) 499 { 500 VnodeToInode* vti = reinterpret_cast<VnodeToInode*>(vnode->private_node); 501 TRACE("volume = %p, vnode = %" B_PRIi64, volume, vti->ID()); 502 503 VnodeToInodeLocker _(vti); 504 Inode* inode = vti->Get(); 505 if (inode == NULL) 506 return B_ENTRY_NOT_FOUND; 507 508 return inode->SyncAndCommit(); 509 } 510 511 512 static status_t 513 nfs4_read_symlink(fs_volume* volume, fs_vnode* link, char* buffer, 514 size_t* _bufferSize) 515 { 516 VnodeToInode* vti = reinterpret_cast<VnodeToInode*>(link->private_node); 517 TRACE("volume = %p, link = %" B_PRIi64, volume, vti->ID()); 518 519 VnodeToInodeLocker _(vti); 520 Inode* inode = vti->Get(); 521 if (inode == NULL) 522 return B_ENTRY_NOT_FOUND; 523 524 return inode->ReadLink(buffer, _bufferSize); 525 } 526 527 528 static status_t 529 nfs4_create_symlink(fs_volume* volume, fs_vnode* dir, const char* name, 530 const char* path, int mode) 531 { 532 VnodeToInode* vti = reinterpret_cast<VnodeToInode*>(dir->private_node); 533 TRACE("volume = %p, dir = %" B_PRIi64 ", name = %s, path = %s, mode = %d", 534 volume, vti->ID(), name, path, mode); 535 536 VnodeToInodeLocker _(vti); 537 Inode* inode = vti->Get(); 538 if (inode == NULL) 539 return B_ENTRY_NOT_FOUND; 540 541 ino_t id; 542 status_t result = inode->CreateLink(name, path, mode, &id); 543 if (result != B_OK) 544 return result; 545 546 result = get_vnode(volume, id, reinterpret_cast<void**>(&vti)); 547 if (result == B_OK) { 548 unremove_vnode(volume, id); 549 vti->Clear(); 550 put_vnode(volume, id); 551 } 552 553 return B_OK; 554 } 555 556 557 static status_t 558 nfs4_link(fs_volume* volume, fs_vnode* dir, const char* name, fs_vnode* vnode) 559 { 560 VnodeToInode* vti = reinterpret_cast<VnodeToInode*>(vnode->private_node); 561 VnodeToInode* dirVti = reinterpret_cast<VnodeToInode*>(dir->private_node); 562 TRACE("volume = %p, dir = %" B_PRIi64 ", name = %s, vnode = %" B_PRIi64, 563 volume, dirVti->ID(), name, vti->ID()); 564 565 VnodeToInodeLocker _dir(dirVti); 566 Inode* dirInode = dirVti->Get(); 567 if (dirInode == NULL) 568 return B_ENTRY_NOT_FOUND; 569 570 571 VnodeToInodeLocker _(vti); 572 Inode* inode = vti->Get(); 573 if (inode == NULL) 574 return B_ENTRY_NOT_FOUND; 575 576 return inode->Link(dirInode, name); 577 } 578 579 580 static status_t 581 nfs4_unlink(fs_volume* volume, fs_vnode* dir, const char* name) 582 { 583 VnodeToInode* vti = reinterpret_cast<VnodeToInode*>(dir->private_node); 584 585 VnodeToInodeLocker locker(vti); 586 Inode* inode = vti->Get(); 587 if (inode == NULL) 588 return B_ENTRY_NOT_FOUND; 589 590 TRACE("volume = %p, dir = %" B_PRIi64 ", name = %s", volume, vti->ID(), 591 name); 592 593 ino_t id; 594 status_t result = inode->Remove(name, NF4REG, &id); 595 if (result != B_OK) 596 return result; 597 locker.Unlock(); 598 599 result = acquire_vnode(volume, id); 600 if (result == B_OK) { 601 result = get_vnode(volume, id, reinterpret_cast<void**>(&vti)); 602 ASSERT(result == B_OK); 603 604 if (vti->Unlink(inode->fInfo.fNames, name)) 605 remove_vnode(volume, id); 606 607 put_vnode(volume, id); 608 put_vnode(volume, id); 609 } 610 611 return B_OK; 612 } 613 614 615 static status_t 616 nfs4_rename(fs_volume* volume, fs_vnode* fromDir, const char* fromName, 617 fs_vnode* toDir, const char* toName) 618 { 619 VnodeToInode* fromVti 620 = reinterpret_cast<VnodeToInode*>(fromDir->private_node); 621 VnodeToInode* toVti = reinterpret_cast<VnodeToInode*>(toDir->private_node); 622 TRACE("volume = %p, fromDir = %" B_PRIi64 ", toDir = %" B_PRIi64 "," \ 623 " fromName = %s, toName = %s", volume, fromVti->ID(), toVti->ID(), \ 624 fromName, toName); 625 626 VnodeToInodeLocker _from(fromVti); 627 Inode* fromInode = fromVti->Get(); 628 if (fromInode == NULL) 629 return B_ENTRY_NOT_FOUND; 630 631 632 VnodeToInodeLocker _to(toVti); 633 Inode* toInode = toVti->Get(); 634 if (toInode == NULL) 635 return B_ENTRY_NOT_FOUND; 636 637 ino_t id; 638 ino_t oldID; 639 status_t result = Inode::Rename(fromInode, toInode, fromName, toName, false, 640 &id, &oldID); 641 if (result != B_OK) 642 return result; 643 644 VnodeToInode* vti; 645 646 if (oldID != 0) { 647 // we have overriden an inode 648 result = acquire_vnode(volume, oldID); 649 if (result == B_OK) { 650 result = get_vnode(volume, oldID, reinterpret_cast<void**>(&vti)); 651 ASSERT(result == B_OK); 652 if (vti->Unlink(toInode->fInfo.fNames, toName)) 653 remove_vnode(volume, oldID); 654 655 put_vnode(volume, oldID); 656 put_vnode(volume, oldID); 657 } 658 } 659 660 result = get_vnode(volume, id, reinterpret_cast<void**>(&vti)); 661 if (result == B_OK) { 662 Inode* child = vti->Get(); 663 if (child == NULL) { 664 put_vnode(volume, id); 665 return B_ENTRY_NOT_FOUND; 666 } 667 668 unremove_vnode(volume, id); 669 child->fInfo.fNames->RemoveName(fromInode->fInfo.fNames, fromName); 670 child->fInfo.fNames->AddName(toInode->fInfo.fNames, toName); 671 put_vnode(volume, id); 672 } 673 674 return B_OK; 675 } 676 677 678 static status_t 679 nfs4_access(fs_volume* volume, fs_vnode* vnode, int mode) 680 { 681 VnodeToInode* vti = reinterpret_cast<VnodeToInode*>(vnode->private_node); 682 TRACE("volume = %p, vnode = %" B_PRIi64 ", mode = %d", volume, vti->ID(), 683 mode); 684 685 VnodeToInodeLocker _(vti); 686 Inode* inode = vti->Get(); 687 if (inode == NULL) 688 return B_ENTRY_NOT_FOUND; 689 690 return inode->Access(mode); 691 } 692 693 694 static status_t 695 nfs4_read_stat(fs_volume* volume, fs_vnode* vnode, struct stat* stat) 696 { 697 VnodeToInode* vti = reinterpret_cast<VnodeToInode*>(vnode->private_node); 698 TRACE("volume = %p, vnode = %" B_PRIi64, volume, vti->ID()); 699 700 VnodeToInodeLocker _(vti); 701 Inode* inode = vti->Get(); 702 if (inode == NULL) 703 return B_ENTRY_NOT_FOUND; 704 705 status_t result = inode->Stat(stat); 706 if (inode->GetOpenState() != NULL) 707 stat->st_size = inode->MaxFileSize(); 708 return result; 709 } 710 711 712 static status_t 713 nfs4_write_stat(fs_volume* volume, fs_vnode* vnode, const struct stat* stat, 714 uint32 statMask) 715 { 716 VnodeToInode* vti = reinterpret_cast<VnodeToInode*>(vnode->private_node); 717 TRACE("volume = %p, vnode = %" B_PRIi64 ", statMask = %" B_PRIu32, volume, 718 vti->ID(), statMask); 719 720 VnodeToInodeLocker _(vti); 721 Inode* inode = vti->Get(); 722 if (inode == NULL) 723 return B_ENTRY_NOT_FOUND; 724 725 return inode->WriteStat(stat, statMask); 726 } 727 728 729 static status_t 730 get_new_vnode(fs_volume* volume, ino_t id, VnodeToInode** _vti) 731 { 732 FileSystem* fs = reinterpret_cast<FileSystem*>(volume->private_volume); 733 Inode* inode; 734 VnodeToInode* vti; 735 736 status_t result = acquire_vnode(volume, id); 737 if (result == B_OK) { 738 ASSERT(get_vnode(volume, id, reinterpret_cast<void**>(_vti)) == B_OK); 739 unremove_vnode(volume, id); 740 741 // Release after acquire 742 put_vnode(volume, id); 743 744 vti = *_vti; 745 746 if (vti->Get() == NULL) { 747 result = fs->GetInode(id, &inode); 748 if (result != B_OK) { 749 put_vnode(volume, id); 750 return result; 751 } 752 753 vti->Replace(inode); 754 } 755 return B_OK; 756 } 757 758 return get_vnode(volume, id, reinterpret_cast<void**>(_vti)); 759 } 760 761 762 static status_t 763 nfs4_create(fs_volume* volume, fs_vnode* dir, const char* name, int openMode, 764 int perms, void** _cookie, ino_t* _newVnodeID) 765 { 766 FileSystem* fs = reinterpret_cast<FileSystem*>(volume->private_volume); 767 768 OpenFileCookie* cookie = new OpenFileCookie(fs); 769 if (cookie == NULL) 770 return B_NO_MEMORY; 771 *_cookie = cookie; 772 773 VnodeToInode* vti = reinterpret_cast<VnodeToInode*>(dir->private_node); 774 TRACE("volume = %p, dir = %" B_PRIi64 ", name = %s, openMode = %d," \ 775 " perms = %d", volume, vti->ID(), name, openMode, perms); 776 777 VnodeToInodeLocker _(vti); 778 Inode* inode = vti->Get(); 779 if (inode == NULL) 780 return B_ENTRY_NOT_FOUND; 781 782 MutexLocker createLocker(fs->CreateFileLock()); 783 784 OpenDelegationData data; 785 status_t result = inode->Create(name, openMode, perms, cookie, &data, 786 _newVnodeID); 787 if (result != B_OK) { 788 delete cookie; 789 return result; 790 } 791 792 result = get_new_vnode(volume, *_newVnodeID, &vti); 793 if (result != B_OK) { 794 delete cookie; 795 return result; 796 } 797 798 VnodeToInodeLocker _child(vti); 799 Inode* child = vti->Get(); 800 if (child == NULL) { 801 delete cookie; 802 put_vnode(volume, *_newVnodeID); 803 return B_ENTRY_NOT_FOUND; 804 } 805 806 child->SetOpenState(cookie->fOpenState); 807 808 if (data.fType != OPEN_DELEGATE_NONE) { 809 Delegation* delegation 810 = new(std::nothrow) Delegation(data, child, 811 cookie->fOpenState->fClientID); 812 if (delegation != NULL) { 813 delegation->fInfo = cookie->fOpenState->fInfo; 814 delegation->fFileSystem = child->GetFileSystem(); 815 child->SetDelegation(delegation); 816 } 817 } 818 819 TRACE("*cookie = %p, *newVnodeID = %" B_PRIi64, *_cookie, *_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", 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", *_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", volume, vti->ID(), 863 _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", volume, vti->ID(), 885 _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", 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", 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", 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", 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, 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", *_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", 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", 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", 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", 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, 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", volume, 1337 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", volume, 1355 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", volume, 1374 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