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