2 * Copyright 2012 Haiku, Inc. All rights reserved.
3 * Distributed under the terms of the MIT License.
6 * Paweł Dziepak, pdziepak@quarnos.org
12 #include <AutoDeleter.h>
14 #include <fs_interface.h>
16 #include "Connection.h"
17 #include "FileSystem.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"
34 static mutex gTraceLock
= MUTEX_INITIALIZER(NULL
);
38 mutex_lock(&gTraceLock); \
39 dprintf("nfs4: %s(): ", __FUNCTION__); \
42 mutex_unlock(&gTraceLock); \
45 #define TRACE(x...) (void)0
48 extern fs_volume_ops gNFSv4VolumeOps
;
49 extern fs_vnode_ops gNFSv4VnodeOps
;
52 RPC::ServerManager
* gRPCServerManager
;
56 CreateNFS4Server(RPC::Server
* serv
)
58 return new NFS4Server(serv
);
62 // Format: ip{4,6}_address:path 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
77 ParseArguments(const char* _args
, AddressResolver
** address
, char** _server
,
78 char** _path
, MountConfiguration
* conf
)
83 char* args
= strdup(_args
);
86 MemoryDeleter
argsDeleter(args
);
88 char* options
= strchr(args
, ' ');
92 char* path
= strrchr(args
, ':');
94 return B_MISMATCHED_VALUES
;
97 *_server
= strdup(args
);
100 *address
= new AddressResolver(args
);
101 if (*address
== NULL
) {
106 *_path
= strdup(path
);
107 if (*_path
== NULL
) {
114 conf
->fRetryLimit
= 5;
115 conf
->fRequestTimeout
= sSecToBigTime(60);
116 conf
->fEmulateNamedAttrs
= false;
117 conf
->fCacheMetadata
= true;
118 conf
->fDirectoryCacheTime
= sSecToBigTime(5);
120 char* optionsEnd
= NULL
;
122 optionsEnd
= strchr(options
, ' ');
123 while (options
!= NULL
&& *options
!= '\0') {
124 if (optionsEnd
!= NULL
)
125 *optionsEnd
++ = '\0';
127 if (strcmp(options
, "hard") == 0)
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
));
150 options
= optionsEnd
;
152 optionsEnd
= strchr(options
, ' ');
160 nfs4_mount(fs_volume
* volume
, const char* device
, uint32 flags
,
161 const char* args
, ino_t
* _rootVnodeID
)
163 TRACE("volume = %p, device = %s, flags = %" B_PRIu32
", args = %s", volume
,
164 device
, flags
, args
);
168 /* prepare idmapper server */
169 MutexLocker
locker(gIdMapperLock
);
170 if (gIdMapper
== NULL
) {
171 gIdMapper
= new(std::nothrow
) IdMap
;
172 if (gIdMapper
== NULL
)
175 result
= gIdMapper
->InitStatus();
176 if (result
!= B_OK
) {
184 AddressResolver
* resolver
;
185 MountConfiguration config
;
188 result
= ParseArguments(args
, &resolver
, &serverName
, &path
, &config
);
191 MemoryDeleter
pathDeleter(path
);
192 MemoryDeleter
serverNameDeleter(serverName
);
195 result
= gRPCServerManager
->Acquire(&server
, resolver
, CreateNFS4Server
);
201 result
= FileSystem::Mount(&fs
, server
, serverName
, path
, volume
->id
,
203 if (result
!= B_OK
) {
204 gRPCServerManager
->Release(server
);
208 Inode
* inode
= fs
->Root();
211 gRPCServerManager
->Release(server
);
216 volume
->private_volume
= fs
;
217 volume
->ops
= &gNFSv4VolumeOps
;
219 VnodeToInode
* vti
= new VnodeToInode(inode
->ID(), fs
);
222 gRPCServerManager
->Release(server
);
227 result
= publish_vnode(volume
, inode
->ID(), vti
, &gNFSv4VnodeOps
,
232 *_rootVnodeID
= inode
->ID();
234 TRACE("*_rootVnodeID = %" B_PRIi64
, inode
->ID());
241 nfs4_get_vnode(fs_volume
* volume
, ino_t id
, fs_vnode
* vnode
, int* _type
,
242 uint32
* _flags
, bool reenter
)
244 FileSystem
* fs
= reinterpret_cast<FileSystem
*>(volume
->private_volume
);
245 TRACE("volume = %p, id = %" B_PRIi64
, volume
, id
);
247 VnodeToInode
* vnodeToInode
= new VnodeToInode(id
, fs
);
248 if (vnodeToInode
== NULL
)
252 status_t result
= fs
->GetInode(id
, &inode
);
253 if (result
!= B_OK
) {
258 vnodeToInode
->Replace(inode
);
259 vnode
->ops
= &gNFSv4VnodeOps
;
260 vnode
->private_node
= vnodeToInode
;
262 *_type
= inode
->Type();
270 nfs4_unmount(fs_volume
* volume
)
272 TRACE("volume = %p", volume
);
273 FileSystem
* fs
= reinterpret_cast<FileSystem
*>(volume
->private_volume
);
274 RPC::Server
* server
= fs
->Server();
277 gRPCServerManager
->Release(server
);
284 nfs4_read_fs_info(fs_volume
* volume
, struct fs_info
* info
)
286 TRACE("volume = %p", volume
);
288 FileSystem
* fs
= reinterpret_cast<FileSystem
*>(volume
->private_volume
);
289 RootInode
* inode
= reinterpret_cast<RootInode
*>(fs
->Root());
290 return inode
->ReadInfo(info
);
295 nfs4_lookup(fs_volume
* volume
, fs_vnode
* dir
, const char* name
, ino_t
* _id
)
297 VnodeToInode
* vti
= reinterpret_cast<VnodeToInode
*>(dir
->private_node
);
299 if (!strcmp(name
, ".")) {
302 return get_vnode(volume
, *_id
, &ptr
);
305 VnodeToInodeLocker
locker(vti
);
307 Inode
* inode
= vti
->Get();
309 return B_ENTRY_NOT_FOUND
;
311 TRACE("volume = %p, dir = %" B_PRIi64
", name = %s", volume
, vti
->ID(),
314 status_t result
= inode
->LookUp(name
, _id
);
319 TRACE("*_id = %" B_PRIi64
, *_id
);
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.
327 result
= get_vnode(volume
, *_id
, &ptr
);
329 unremove_vnode(volume
, *_id
);
336 nfs4_put_vnode(fs_volume
* volume
, fs_vnode
* vnode
, bool reenter
)
338 VnodeToInode
* vti
= reinterpret_cast<VnodeToInode
*>(vnode
->private_node
);
339 TRACE("volume = %p, vnode = %" B_PRIi64
, volume
, vti
->ID());
347 nfs4_remove_vnode(fs_volume
* volume
, fs_vnode
* vnode
, bool reenter
)
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());
353 if (fs
->Root() == vti
->GetPointer())
356 ASSERT(vti
->GetPointer() == NULL
);
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
)
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
,
372 VnodeToInodeLocker
_(vti
);
373 Inode
* inode
= vti
->Get();
375 return B_ENTRY_NOT_FOUND
;
377 OpenFileCookie
* cookie
= reinterpret_cast<OpenFileCookie
*>(_cookie
);
380 size_t totalRead
= 0;
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
);
387 size_t bytesRead
= bytesLeft
;
388 result
= inode
->ReadDirect(cookie
, pos
, buffer
, &bytesRead
, &eof
);
392 totalRead
+= bytesRead
;
395 bytesLeft
-= bytesRead
;
396 } while (bytesLeft
> 0 && !eof
);
399 *_numBytes
= totalRead
;
401 TRACE("*numBytes = %lu", totalRead
);
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
)
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
,
416 VnodeToInodeLocker
_(vti
);
417 Inode
* inode
= vti
->Get();
419 return B_ENTRY_NOT_FOUND
;
421 OpenFileCookie
* cookie
= reinterpret_cast<OpenFileCookie
*>(_cookie
);
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
;
429 char* buffer
= reinterpret_cast<char*>(vecs
[i
].iov_base
);
432 size_t bytesWritten
= bytesLeft
;
434 result
= inode
->WriteDirect(cookie
, pos
, buffer
, &bytesWritten
);
438 bytesLeft
-= bytesWritten
;
440 buffer
+= bytesWritten
;
441 } while (bytesLeft
> 0);
449 nfs4_io(fs_volume
* volume
, fs_vnode
* vnode
, void* cookie
, io_request
* request
)
451 VnodeToInode
* vti
= reinterpret_cast<VnodeToInode
*>(vnode
->private_node
);
452 TRACE("volume = %p, vnode = %" B_PRIi64
", cookie = %p", volume
, vti
->ID(),
455 VnodeToInodeLocker
_(vti
);
456 Inode
* inode
= vti
->Get();
458 return B_ENTRY_NOT_FOUND
;
460 IORequestArgs
* args
= new(std::nothrow
) IORequestArgs
;
462 notify_io_request(request
, B_NO_MEMORY
);
465 args
->fRequest
= request
;
466 args
->fInode
= inode
;
468 status_t result
= gWorkQueue
->EnqueueJob(IORequest
, args
);
470 notify_io_request(request
, result
);
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
)
485 nfs4_set_flags(fs_volume
* volume
, fs_vnode
* vnode
, void* _cookie
, int flags
)
487 TRACE("volume = %p, vnode = %" B_PRIi64
", cookie = %p, flags = %d", volume
,
488 reinterpret_cast<VnodeToInode
*>(vnode
->private_node
)->ID(), _cookie
,
491 OpenFileCookie
* cookie
= reinterpret_cast<OpenFileCookie
*>(_cookie
);
492 cookie
->fMode
= (cookie
->fMode
& ~(O_APPEND
| O_NONBLOCK
)) | flags
;
498 nfs4_fsync(fs_volume
* volume
, fs_vnode
* vnode
)
500 VnodeToInode
* vti
= reinterpret_cast<VnodeToInode
*>(vnode
->private_node
);
501 TRACE("volume = %p, vnode = %" B_PRIi64
, volume
, vti
->ID());
503 VnodeToInodeLocker
_(vti
);
504 Inode
* inode
= vti
->Get();
506 return B_ENTRY_NOT_FOUND
;
508 return inode
->SyncAndCommit();
513 nfs4_read_symlink(fs_volume
* volume
, fs_vnode
* link
, char* buffer
,
516 VnodeToInode
* vti
= reinterpret_cast<VnodeToInode
*>(link
->private_node
);
517 TRACE("volume = %p, link = %" B_PRIi64
, volume
, vti
->ID());
519 VnodeToInodeLocker
_(vti
);
520 Inode
* inode
= vti
->Get();
522 return B_ENTRY_NOT_FOUND
;
524 return inode
->ReadLink(buffer
, _bufferSize
);
529 nfs4_create_symlink(fs_volume
* volume
, fs_vnode
* dir
, const char* name
,
530 const char* path
, int mode
)
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
);
536 VnodeToInodeLocker
_(vti
);
537 Inode
* inode
= vti
->Get();
539 return B_ENTRY_NOT_FOUND
;
542 status_t result
= inode
->CreateLink(name
, path
, mode
, &id
);
546 result
= get_vnode(volume
, id
, reinterpret_cast<void**>(&vti
));
547 if (result
== B_OK
) {
548 unremove_vnode(volume
, id
);
550 put_vnode(volume
, id
);
558 nfs4_link(fs_volume
* volume
, fs_vnode
* dir
, const char* name
, fs_vnode
* vnode
)
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());
565 VnodeToInodeLocker
_dir(dirVti
);
566 Inode
* dirInode
= dirVti
->Get();
567 if (dirInode
== NULL
)
568 return B_ENTRY_NOT_FOUND
;
571 VnodeToInodeLocker
_(vti
);
572 Inode
* inode
= vti
->Get();
574 return B_ENTRY_NOT_FOUND
;
576 return inode
->Link(dirInode
, name
);
581 nfs4_unlink(fs_volume
* volume
, fs_vnode
* dir
, const char* name
)
583 VnodeToInode
* vti
= reinterpret_cast<VnodeToInode
*>(dir
->private_node
);
585 VnodeToInodeLocker
locker(vti
);
586 Inode
* inode
= vti
->Get();
588 return B_ENTRY_NOT_FOUND
;
590 TRACE("volume = %p, dir = %" B_PRIi64
", name = %s", volume
, vti
->ID(),
594 status_t result
= inode
->Remove(name
, NF4REG
, &id
);
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
);
604 if (vti
->Unlink(inode
->fInfo
.fNames
, name
))
605 remove_vnode(volume
, id
);
607 put_vnode(volume
, id
);
608 put_vnode(volume
, id
);
616 nfs4_rename(fs_volume
* volume
, fs_vnode
* fromDir
, const char* fromName
,
617 fs_vnode
* toDir
, const char* toName
)
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(), \
626 VnodeToInodeLocker
_from(fromVti
);
627 Inode
* fromInode
= fromVti
->Get();
628 if (fromInode
== NULL
)
629 return B_ENTRY_NOT_FOUND
;
632 VnodeToInodeLocker
_to(toVti
);
633 Inode
* toInode
= toVti
->Get();
635 return B_ENTRY_NOT_FOUND
;
639 status_t result
= Inode::Rename(fromInode
, toInode
, fromName
, toName
, false,
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
);
655 put_vnode(volume
, oldID
);
656 put_vnode(volume
, oldID
);
660 result
= get_vnode(volume
, id
, reinterpret_cast<void**>(&vti
));
661 if (result
== B_OK
) {
662 Inode
* child
= vti
->Get();
664 put_vnode(volume
, id
);
665 return B_ENTRY_NOT_FOUND
;
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
);
679 nfs4_access(fs_volume
* volume
, fs_vnode
* vnode
, int mode
)
681 VnodeToInode
* vti
= reinterpret_cast<VnodeToInode
*>(vnode
->private_node
);
682 TRACE("volume = %p, vnode = %" B_PRIi64
", mode = %d", volume
, vti
->ID(),
685 VnodeToInodeLocker
_(vti
);
686 Inode
* inode
= vti
->Get();
688 return B_ENTRY_NOT_FOUND
;
690 return inode
->Access(mode
);
695 nfs4_read_stat(fs_volume
* volume
, fs_vnode
* vnode
, struct stat
* stat
)
697 VnodeToInode
* vti
= reinterpret_cast<VnodeToInode
*>(vnode
->private_node
);
698 TRACE("volume = %p, vnode = %" B_PRIi64
, volume
, vti
->ID());
700 VnodeToInodeLocker
_(vti
);
701 Inode
* inode
= vti
->Get();
703 return B_ENTRY_NOT_FOUND
;
705 status_t result
= inode
->Stat(stat
);
706 if (inode
->GetOpenState() != NULL
)
707 stat
->st_size
= inode
->MaxFileSize();
713 nfs4_write_stat(fs_volume
* volume
, fs_vnode
* vnode
, const struct stat
* stat
,
716 VnodeToInode
* vti
= reinterpret_cast<VnodeToInode
*>(vnode
->private_node
);
717 TRACE("volume = %p, vnode = %" B_PRIi64
", statMask = %" B_PRIu32
, volume
,
718 vti
->ID(), statMask
);
720 VnodeToInodeLocker
_(vti
);
721 Inode
* inode
= vti
->Get();
723 return B_ENTRY_NOT_FOUND
;
725 return inode
->WriteStat(stat
, statMask
);
730 get_new_vnode(fs_volume
* volume
, ino_t id
, VnodeToInode
** _vti
)
732 FileSystem
* fs
= reinterpret_cast<FileSystem
*>(volume
->private_volume
);
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
);
741 // Release after acquire
742 put_vnode(volume
, id
);
746 if (vti
->Get() == NULL
) {
747 result
= fs
->GetInode(id
, &inode
);
748 if (result
!= B_OK
) {
749 put_vnode(volume
, id
);
758 return get_vnode(volume
, id
, reinterpret_cast<void**>(_vti
));
763 nfs4_create(fs_volume
* volume
, fs_vnode
* dir
, const char* name
, int openMode
,
764 int perms
, void** _cookie
, ino_t
* _newVnodeID
)
766 FileSystem
* fs
= reinterpret_cast<FileSystem
*>(volume
->private_volume
);
768 OpenFileCookie
* cookie
= new OpenFileCookie(fs
);
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
);
777 VnodeToInodeLocker
_(vti
);
778 Inode
* inode
= vti
->Get();
780 return B_ENTRY_NOT_FOUND
;
782 MutexLocker
createLocker(fs
->CreateFileLock());
784 OpenDelegationData data
;
785 status_t result
= inode
->Create(name
, openMode
, perms
, cookie
, &data
,
787 if (result
!= B_OK
) {
792 result
= get_new_vnode(volume
, *_newVnodeID
, &vti
);
793 if (result
!= B_OK
) {
798 VnodeToInodeLocker
_child(vti
);
799 Inode
* child
= vti
->Get();
802 put_vnode(volume
, *_newVnodeID
);
803 return B_ENTRY_NOT_FOUND
;
806 child
->SetOpenState(cookie
->fOpenState
);
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
);
819 TRACE("*cookie = %p, *newVnodeID = %" B_PRIi64
, *_cookie
, *_newVnodeID
);
825 nfs4_open(fs_volume
* volume
, fs_vnode
* vnode
, int openMode
, void** _cookie
)
827 VnodeToInode
* vti
= reinterpret_cast<VnodeToInode
*>(vnode
->private_node
);
828 TRACE("volume = %p, vnode = %" B_PRIi64
", openMode = %d", volume
,
829 vti
->ID(), openMode
);
831 VnodeToInodeLocker
_(vti
);
832 Inode
* inode
= vti
->Get();
834 return B_ENTRY_NOT_FOUND
;
836 if (inode
->Type() == S_IFDIR
|| inode
->Type() == S_IFLNK
) {
841 FileSystem
* fs
= reinterpret_cast<FileSystem
*>(volume
->private_volume
);
842 OpenFileCookie
* cookie
= new OpenFileCookie(fs
);
847 status_t result
= inode
->Open(openMode
, cookie
);
851 TRACE("*cookie = %p", *_cookie
);
858 nfs4_close(fs_volume
* volume
, fs_vnode
* vnode
, void* _cookie
)
860 VnodeToInode
* vti
= reinterpret_cast<VnodeToInode
*>(vnode
->private_node
);
862 TRACE("volume = %p, vnode = %" B_PRIi64
", cookie = %p", volume
, vti
->ID(),
865 VnodeToInodeLocker
_(vti
);
866 Inode
* inode
= vti
->Get();
868 return B_ENTRY_NOT_FOUND
;
871 if (inode
->Type() == S_IFDIR
|| inode
->Type() == S_IFLNK
)
874 Cookie
* cookie
= reinterpret_cast<Cookie
*>(_cookie
);
875 return cookie
->CancelAll();
880 nfs4_free_cookie(fs_volume
* volume
, fs_vnode
* vnode
, void* _cookie
)
882 VnodeToInode
* vti
= reinterpret_cast<VnodeToInode
*>(vnode
->private_node
);
884 TRACE("volume = %p, vnode = %" B_PRIi64
", cookie = %p", volume
, vti
->ID(),
887 VnodeToInodeLocker
_(vti
);
888 Inode
* inode
= vti
->Get();
890 return B_ENTRY_NOT_FOUND
;
892 if (inode
->Type() == S_IFDIR
|| inode
->Type() == S_IFLNK
)
895 OpenFileCookie
* cookie
= reinterpret_cast<OpenFileCookie
*>(_cookie
);
897 inode
->Close(cookie
);
905 nfs4_read(fs_volume
* volume
, fs_vnode
* vnode
, void* _cookie
, off_t pos
,
906 void* buffer
, size_t* length
)
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
);
912 VnodeToInodeLocker
_(vti
);
913 Inode
* inode
= vti
->Get();
915 return B_ENTRY_NOT_FOUND
;
917 if (inode
->Type() == S_IFDIR
)
918 return B_IS_A_DIRECTORY
;
920 if (inode
->Type() == S_IFLNK
)
923 OpenFileCookie
* cookie
= reinterpret_cast<OpenFileCookie
*>(_cookie
);
925 return inode
->Read(cookie
, pos
, buffer
, length
);;
930 nfs4_write(fs_volume
* volume
, fs_vnode
* vnode
, void* _cookie
, off_t pos
,
931 const void* _buffer
, size_t* length
)
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
);
937 VnodeToInodeLocker
_(vti
);
938 Inode
* inode
= vti
->Get();
940 return B_ENTRY_NOT_FOUND
;
942 if (inode
->Type() == S_IFDIR
)
943 return B_IS_A_DIRECTORY
;
945 if (inode
->Type() == S_IFLNK
)
948 OpenFileCookie
* cookie
= reinterpret_cast<OpenFileCookie
*>(_cookie
);
950 return inode
->Write(cookie
, pos
, _buffer
, length
);
955 nfs4_create_dir(fs_volume
* volume
, fs_vnode
* parent
, const char* name
,
958 VnodeToInode
* vti
= reinterpret_cast<VnodeToInode
*>(parent
->private_node
);
959 TRACE("volume = %p, parent = %" B_PRIi64
", mode = %d", volume
, vti
->ID(),
962 VnodeToInodeLocker
_(vti
);
963 Inode
* inode
= vti
->Get();
965 return B_ENTRY_NOT_FOUND
;
968 status_t result
= inode
->CreateDir(name
, mode
, &id
);
972 result
= get_vnode(volume
, id
, reinterpret_cast<void**>(&vti
));
973 if (result
== B_OK
) {
974 unremove_vnode(volume
, id
);
976 put_vnode(volume
, id
);
984 nfs4_remove_dir(fs_volume
* volume
, fs_vnode
* parent
, const char* name
)
986 VnodeToInode
* vti
= reinterpret_cast<VnodeToInode
*>(parent
->private_node
);
987 TRACE("volume = %p, parent = %" B_PRIi64
", name = %s", volume
, vti
->ID(),
990 VnodeToInodeLocker
_(vti
);
991 Inode
* inode
= vti
->Get();
993 return B_ENTRY_NOT_FOUND
;
996 status_t result
= inode
->Remove(name
, NF4DIR
, &id
);
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
);
1005 if (vti
->Unlink(inode
->fInfo
.fNames
, name
))
1006 remove_vnode(volume
, id
);
1008 put_vnode(volume
, id
);
1009 put_vnode(volume
, id
);
1017 nfs4_open_dir(fs_volume
* volume
, fs_vnode
* vnode
, void** _cookie
)
1019 FileSystem
* fs
= reinterpret_cast<FileSystem
*>(volume
->private_volume
);
1020 OpenDirCookie
* cookie
= new(std::nothrow
) OpenDirCookie(fs
);
1025 VnodeToInode
* vti
= reinterpret_cast<VnodeToInode
*>(vnode
->private_node
);
1026 TRACE("volume = %p, vnode = %" B_PRIi64
, volume
, vti
->ID());
1028 VnodeToInodeLocker
_(vti
);
1029 Inode
* inode
= vti
->Get();
1031 return B_ENTRY_NOT_FOUND
;
1033 status_t result
= inode
->OpenDir(cookie
);
1037 TRACE("*cookie = %p", *_cookie
);
1044 nfs4_close_dir(fs_volume
* volume
, fs_vnode
* vnode
, void* _cookie
)
1046 TRACE("volume = %p, vnode = %" B_PRIi64
", cookie = %p", volume
,
1047 reinterpret_cast<VnodeToInode
*>(vnode
->private_node
)->ID(), _cookie
);
1049 Cookie
* cookie
= reinterpret_cast<Cookie
*>(_cookie
);
1050 return cookie
->CancelAll();
1055 nfs4_free_dir_cookie(fs_volume
* volume
, fs_vnode
* vnode
, void* cookie
)
1057 TRACE("volume = %p, vnode = %" B_PRIi64
", cookie = %p", volume
,
1058 reinterpret_cast<VnodeToInode
*>(vnode
->private_node
)->ID(), cookie
);
1060 delete reinterpret_cast<OpenDirCookie
*>(cookie
);
1066 nfs4_read_dir(fs_volume
* volume
, fs_vnode
* vnode
, void* _cookie
,
1067 struct dirent
* buffer
, size_t bufferSize
, uint32
* _num
)
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(),
1074 VnodeToInodeLocker
_(vti
);
1075 Inode
* inode
= vti
->Get();
1077 return B_ENTRY_NOT_FOUND
;
1079 return inode
->ReadDir(buffer
, bufferSize
, _num
, cookie
);
1084 nfs4_rewind_dir(fs_volume
* volume
, fs_vnode
* vnode
, void* _cookie
)
1086 TRACE("volume = %p, vnode = %" B_PRIi64
", cookie = %p", volume
,
1087 reinterpret_cast<VnodeToInode
*>(vnode
->private_node
)->ID(), _cookie
);
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;
1102 nfs4_open_attr_dir(fs_volume
* volume
, fs_vnode
* vnode
, void** _cookie
)
1104 FileSystem
* fs
= reinterpret_cast<FileSystem
*>(volume
->private_volume
);
1105 OpenDirCookie
* cookie
= new(std::nothrow
) OpenDirCookie(fs
);
1110 VnodeToInode
* vti
= reinterpret_cast<VnodeToInode
*>(vnode
->private_node
);
1111 TRACE("volume = %p, vnode = %" B_PRIi64
, volume
, vti
->ID());
1113 VnodeToInodeLocker
_(vti
);
1114 Inode
* inode
= vti
->Get();
1116 return B_ENTRY_NOT_FOUND
;
1118 status_t result
= inode
->OpenAttrDir(cookie
);
1127 nfs4_close_attr_dir(fs_volume
* volume
, fs_vnode
* vnode
, void* cookie
)
1129 return nfs4_close_dir(volume
, vnode
, cookie
);
1134 nfs4_free_attr_dir_cookie(fs_volume
* volume
, fs_vnode
* vnode
, void* cookie
)
1136 return nfs4_free_dir_cookie(volume
, vnode
, cookie
);
1141 nfs4_read_attr_dir(fs_volume
* volume
, fs_vnode
* vnode
, void* cookie
,
1142 struct dirent
* buffer
, size_t bufferSize
, uint32
* _num
)
1144 return nfs4_read_dir(volume
, vnode
, cookie
, buffer
, bufferSize
, _num
);
1149 nfs4_rewind_attr_dir(fs_volume
* volume
, fs_vnode
* vnode
, void* cookie
)
1151 return nfs4_rewind_dir(volume
, vnode
, cookie
);
1156 nfs4_create_attr(fs_volume
* volume
, fs_vnode
* vnode
, const char* name
,
1157 uint32 type
, int openMode
, void** _cookie
)
1159 VnodeToInode
* vti
= reinterpret_cast<VnodeToInode
*>(vnode
->private_node
);
1161 VnodeToInodeLocker
_(vti
);
1162 Inode
* inode
= vti
->Get();
1164 return B_ENTRY_NOT_FOUND
;
1166 FileSystem
* fs
= reinterpret_cast<FileSystem
*>(volume
->private_volume
);
1167 OpenAttrCookie
* cookie
= new OpenAttrCookie(fs
);
1172 status_t result
= inode
->OpenAttr(name
, openMode
, cookie
, true, type
);
1181 nfs4_open_attr(fs_volume
* volume
, fs_vnode
* vnode
, const char* name
,
1182 int openMode
, void** _cookie
)
1184 VnodeToInode
* vti
= reinterpret_cast<VnodeToInode
*>(vnode
->private_node
);
1186 VnodeToInodeLocker
_(vti
);
1187 Inode
* inode
= vti
->Get();
1189 return B_ENTRY_NOT_FOUND
;
1191 FileSystem
* fs
= reinterpret_cast<FileSystem
*>(volume
->private_volume
);
1192 OpenAttrCookie
* cookie
= new OpenAttrCookie(fs
);
1197 status_t result
= inode
->OpenAttr(name
, openMode
, cookie
, false);
1206 nfs4_close_attr(fs_volume
* volume
, fs_vnode
* vnode
, void* _cookie
)
1208 Cookie
* cookie
= reinterpret_cast<Cookie
*>(_cookie
);
1209 return cookie
->CancelAll();
1214 nfs4_free_attr_cookie(fs_volume
* volume
, fs_vnode
* vnode
, void* _cookie
)
1216 VnodeToInode
* vti
= reinterpret_cast<VnodeToInode
*>(vnode
->private_node
);
1218 VnodeToInodeLocker
_(vti
);
1219 Inode
* inode
= vti
->Get();
1221 return B_ENTRY_NOT_FOUND
;
1223 OpenAttrCookie
* cookie
= reinterpret_cast<OpenAttrCookie
*>(_cookie
);
1224 inode
->CloseAttr(cookie
);
1232 nfs4_read_attr(fs_volume
* volume
, fs_vnode
* vnode
, void* _cookie
, off_t pos
,
1233 void* buffer
, size_t* length
)
1235 VnodeToInode
* vti
= reinterpret_cast<VnodeToInode
*>(vnode
->private_node
);
1236 OpenAttrCookie
* cookie
= reinterpret_cast<OpenAttrCookie
*>(_cookie
);
1239 VnodeToInodeLocker
_(vti
);
1240 Inode
* inode
= vti
->Get();
1242 return B_ENTRY_NOT_FOUND
;
1244 return inode
->ReadDirect(cookie
, pos
, buffer
, length
, &eof
);
1249 nfs4_write_attr(fs_volume
* volume
, fs_vnode
* vnode
, void* _cookie
, off_t pos
,
1250 const void* buffer
, size_t* length
)
1252 VnodeToInode
* vti
= reinterpret_cast<VnodeToInode
*>(vnode
->private_node
);
1253 OpenAttrCookie
* cookie
= reinterpret_cast<OpenAttrCookie
*>(_cookie
);
1255 VnodeToInodeLocker
_(vti
);
1256 Inode
* inode
= vti
->Get();
1258 return B_ENTRY_NOT_FOUND
;
1260 return inode
->WriteDirect(cookie
, pos
, buffer
, length
);
1265 nfs4_read_attr_stat(fs_volume
* volume
, fs_vnode
* vnode
, void* _cookie
,
1268 VnodeToInode
* vti
= reinterpret_cast<VnodeToInode
*>(vnode
->private_node
);
1269 OpenAttrCookie
* cookie
= reinterpret_cast<OpenAttrCookie
*>(_cookie
);
1271 VnodeToInodeLocker
_(vti
);
1272 Inode
* inode
= vti
->Get();
1274 return B_ENTRY_NOT_FOUND
;
1276 return inode
->Stat(stat
, cookie
);
1281 nfs4_write_attr_stat(fs_volume
* volume
, fs_vnode
* vnode
, void* _cookie
,
1282 const struct stat
* stat
, int statMask
)
1284 VnodeToInode
* vti
= reinterpret_cast<VnodeToInode
*>(vnode
->private_node
);
1285 OpenAttrCookie
* cookie
= reinterpret_cast<OpenAttrCookie
*>(_cookie
);
1287 VnodeToInodeLocker
_(vti
);
1288 Inode
* inode
= vti
->Get();
1290 return B_ENTRY_NOT_FOUND
;
1292 return inode
->WriteStat(stat
, statMask
, cookie
);
1297 nfs4_rename_attr(fs_volume
* volume
, fs_vnode
* fromVnode
, const char* fromName
,
1298 fs_vnode
* toVnode
, const char* toName
)
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
;
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
;
1312 return Inode::Rename(fromInode
, toInode
, fromName
, toName
, true);
1317 nfs4_remove_attr(fs_volume
* volume
, fs_vnode
* vnode
, const char* name
)
1319 VnodeToInode
* vti
= reinterpret_cast<VnodeToInode
*>(vnode
->private_node
);
1321 VnodeToInodeLocker
_(vti
);
1322 Inode
* inode
= vti
->Get();
1324 return B_ENTRY_NOT_FOUND
;
1326 return inode
->Remove(name
, NF4NAMEDATTR
, NULL
);
1331 nfs4_test_lock(fs_volume
* volume
, fs_vnode
* vnode
, void* _cookie
,
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
);
1339 VnodeToInodeLocker
_(vti
);
1340 Inode
* inode
= vti
->Get();
1342 return B_ENTRY_NOT_FOUND
;
1344 return inode
->TestLock(cookie
, lock
);
1349 nfs4_acquire_lock(fs_volume
* volume
, fs_vnode
* vnode
, void* _cookie
,
1350 const struct flock
* lock
, bool wait
)
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
);
1358 VnodeToInodeLocker
_(vti
);
1359 Inode
* inode
= vti
->Get();
1361 return B_ENTRY_NOT_FOUND
;
1363 inode
->RevalidateFileCache();
1364 return inode
->AcquireLock(cookie
, lock
, wait
);
1369 nfs4_release_lock(fs_volume
* volume
, fs_vnode
* vnode
, void* _cookie
,
1370 const struct flock
* lock
)
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
);
1376 VnodeToInodeLocker
_(vti
);
1377 Inode
* inode
= vti
->Get();
1379 return B_ENTRY_NOT_FOUND
;
1381 if (inode
->Type() == S_IFDIR
|| inode
->Type() == S_IFLNK
)
1384 OpenFileCookie
* cookie
= reinterpret_cast<OpenFileCookie
*>(_cookie
);
1387 return inode
->ReleaseLock(cookie
, lock
);
1389 return inode
->ReleaseAllLocks(cookie
);
1396 gRPCServerManager
= new(std::nothrow
) RPC::ServerManager
;
1397 if (gRPCServerManager
== NULL
)
1400 mutex_init(&gIdMapperLock
, "idmapper Init Lock");
1403 gWorkQueue
= new(std::nothrow
) WorkQueue
;
1404 if (gWorkQueue
== NULL
|| gWorkQueue
->InitStatus() != B_OK
) {
1406 mutex_destroy(&gIdMapperLock
);
1407 delete gRPCServerManager
;
1418 RPC::CallbackServer::ShutdownAll();
1422 delete gRPCServerManager
;
1424 mutex_destroy(&gIdMapperLock
);
1431 nfs4_std_ops(int32 op
, ...)
1436 case B_MODULE_UNINIT
:
1437 return nfs4_uninit();
1444 fs_volume_ops gNFSv4VolumeOps
= {
1452 fs_vnode_ops gNFSv4VnodeOps
= {
1454 NULL
, // get_vnode_name()
1458 /* VM file access */
1464 NULL
, // cancel_io()
1470 NULL
, // fs_select()
1471 NULL
, // fs_deselect()
1475 nfs4_create_symlink
,
1484 NULL
, // fs_preallocate()
1486 /* file operations */
1494 /* directory operations */
1499 nfs4_free_dir_cookie
,
1503 /* attribute directory operations */
1505 nfs4_close_attr_dir
,
1506 nfs4_free_attr_dir_cookie
,
1508 nfs4_rewind_attr_dir
,
1510 /* attribute operations */
1514 nfs4_free_attr_cookie
,
1518 nfs4_read_attr_stat
,
1519 nfs4_write_attr_stat
,
1523 /* support for node and FS layers */
1524 NULL
, // create_special_node
1525 NULL
, // get_super_vnode
1527 /* lock operations */
1533 static file_system_module_info sNFSv4ModuleInfo
= {
1535 "file_systems/nfs4" B_CURRENT_FS_API_VERSION
,
1540 "nfs4", // short_name
1541 "Network File System version 4", // pretty_name
1547 NULL
, // identify_partition()
1548 NULL
, // scan_partition()
1549 NULL
, // free_identify_partition_cookie()
1550 NULL
, // free_partition_content_cookie()
1555 module_info
* modules
[] = {
1556 (module_info
*)&sNFSv4ModuleInfo
,