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