1 /*
2 * Copyright 2001-2011, Ingo Weinhold, ingo_weinhold@gmx.de.
3 * Distributed under the terms of the MIT License.
4 */
5
6 #include "Volume.h"
7
8 #include <errno.h>
9 #include <string.h>
10 #include <unistd.h>
11 #include <sys/stat.h>
12
13 #include <algorithm>
14
15 #include <fs_cache.h>
16
17 #include <util/AutoLock.h>
18 #include <util/OpenHashTable.h>
19
20 #include <fs/fd.h> // kernel private
21 #include <io_requests.h>
22 #include <thread.h>
23
24 #include "IORequest.h" // kernel internal
25
26 #include "Compatibility.h"
27 #include "Debug.h"
28 #include "FileSystem.h"
29 #include "IOCtlInfo.h"
30 #include "kernel_interface.h"
31 #include "KernelRequestHandler.h"
32 #include "PortReleaser.h"
33 #include "RequestAllocator.h"
34 #include "RequestPort.h"
35 #include "Requests.h"
36 #include "userlandfs_ioctl.h"
37
38 // missing ioctl()s
39 // TODO: Place somewhere else.
40 #define IOCTL_FILE_UNCACHED_IO 10000
41 #define IOCTL_CREATE_TIME 10002
42 #define IOCTL_MODIFIED_TIME 10003
43
44 // If a thread of the userland server enters userland FS kernel code and
45 // is sending a request, this is the time after which it shall time out
46 // waiting for a reply.
47 static const bigtime_t kUserlandServerlandPortTimeout = 10000000; // 10s
48
49
50 // VNode
51 struct Volume::VNode {
52 ino_t id;
53 void* clientNode;
54 void* fileCache;
55 VNodeOps* ops;
56 int32 useCount;
57 bool valid;
58 bool published;
59 VNode* hash_link;
60
VNodeVolume::VNode61 VNode(ino_t id, void* clientNode, VNodeOps* ops)
62 :
63 id(id),
64 clientNode(clientNode),
65 fileCache(NULL),
66 ops(ops),
67 useCount(0),
68 valid(true),
69 published(true)
70 {
71 }
72
DeleteVolume::VNode73 void Delete(Volume* volume)
74 {
75 if (ops != NULL)
76 volume->GetFileSystem()->PutVNodeOps(ops);
77 delete this;
78 }
79
80 protected: // should be private, but gcc 2.95.3 issues a warning
~VNodeVolume::VNode81 ~VNode()
82 {
83 if (fileCache != NULL) {
84 ERROR(("VNode %" B_PRId64 " still has a file cache!\n", id));
85 file_cache_delete(fileCache);
86 }
87 }
88 };
89
90
91 // VNodeHashDefinition
92 struct Volume::VNodeHashDefinition {
93 typedef ino_t KeyType;
94 typedef VNode ValueType;
95
HashKeyVolume::VNodeHashDefinition96 size_t HashKey(ino_t key) const
97 { return (uint32)key ^ (uint32)(key >> 32); }
HashVolume::VNodeHashDefinition98 size_t Hash(const VNode* value) const
99 { return HashKey(value->id); }
CompareVolume::VNodeHashDefinition100 bool Compare(ino_t key, const VNode* value) const
101 { return value->id == key; }
GetLinkVolume::VNodeHashDefinition102 VNode*& GetLink(VNode* value) const
103 { return value->hash_link; }
104 };
105
106
107 // VNodeMap
108 struct Volume::VNodeMap
109 : public BOpenHashTable<VNodeHashDefinition> {
110 };
111
112
113 // IORequestInfo
114 struct Volume::IORequestInfo {
115 io_request* request;
116 int32 id;
117
118 IORequestInfo* idLink;
119 IORequestInfo* structLink;
120
IORequestInfoVolume::IORequestInfo121 IORequestInfo(io_request* request, int32 id)
122 :
123 request(request),
124 id(id)
125 {
126 }
127 };
128
129
130 // IORequestIDHashDefinition
131 struct Volume::IORequestIDHashDefinition {
132 typedef int32 KeyType;
133 typedef IORequestInfo ValueType;
134
HashKeyVolume::IORequestIDHashDefinition135 size_t HashKey(int32 key) const
136 { return key; }
HashVolume::IORequestIDHashDefinition137 size_t Hash(const IORequestInfo* value) const
138 { return HashKey(value->id); }
CompareVolume::IORequestIDHashDefinition139 bool Compare(int32 key, const IORequestInfo* value) const
140 { return value->id == key; }
GetLinkVolume::IORequestIDHashDefinition141 IORequestInfo*& GetLink(IORequestInfo* value) const
142 { return value->idLink; }
143 };
144
145
146 // IORequestStructHashDefinition
147 struct Volume::IORequestStructHashDefinition {
148 typedef io_request* KeyType;
149 typedef IORequestInfo ValueType;
150
HashKeyVolume::IORequestStructHashDefinition151 size_t HashKey(io_request* key) const
152 { return (size_t)(addr_t)key; }
HashVolume::IORequestStructHashDefinition153 size_t Hash(const IORequestInfo* value) const
154 { return HashKey(value->request); }
CompareVolume::IORequestStructHashDefinition155 bool Compare(io_request* key, const IORequestInfo* value) const
156 { return value->request == key; }
GetLinkVolume::IORequestStructHashDefinition157 IORequestInfo*& GetLink(IORequestInfo* value) const
158 { return value->structLink; }
159 };
160
161
162 // IORequestIDMap
163 struct Volume::IORequestIDMap
164 : public BOpenHashTable<IORequestIDHashDefinition> {
165 };
166
167
168 // IORequestStructMap
169 struct Volume::IORequestStructMap
170 : public BOpenHashTable<IORequestStructHashDefinition> {
171 };
172
173
174 // IterativeFDIOCookie
175 struct Volume::IterativeFDIOCookie : public BReferenceable {
176 Volume* volume;
177 int fd;
178 int32 requestID;
179 void* clientCookie;
180 off_t offset;
181 const file_io_vec* vecs;
182 uint32 vecCount;
183
IterativeFDIOCookieVolume::IterativeFDIOCookie184 IterativeFDIOCookie(Volume* volume, int fd, int32 requestID,
185 void* clientCookie, off_t offset, const file_io_vec* vecs,
186 uint32 vecCount)
187 :
188 volume(volume),
189 fd(fd),
190 requestID(requestID),
191 clientCookie(clientCookie),
192 offset(offset),
193 vecs(vecs),
194 vecCount(vecCount)
195 {
196 }
197
~IterativeFDIOCookieVolume::IterativeFDIOCookie198 ~IterativeFDIOCookie()
199 {
200 if (fd >= 0)
201 close(fd);
202 }
203 };
204
205
206 // AutoIncrementer
207 class Volume::AutoIncrementer {
208 public:
AutoIncrementer(int32 * variable)209 AutoIncrementer(int32* variable)
210 : fVariable(variable)
211 {
212 if (fVariable)
213 atomic_add(fVariable, 1);
214 }
215
~AutoIncrementer()216 ~AutoIncrementer()
217 {
218 if (fVariable)
219 atomic_add(fVariable, -1);
220 }
221
Keep()222 void Keep()
223 {
224 fVariable = NULL;
225 }
226
227 private:
228 int32* fVariable;
229 };
230
231
232 // IORequestRemover
233 class Volume::IORequestRemover {
234 public:
IORequestRemover(Volume * volume,int32 requestID)235 IORequestRemover(Volume* volume, int32 requestID)
236 :
237 fVolume(volume),
238 fRequestID(requestID)
239 {
240 }
241
~IORequestRemover()242 ~IORequestRemover()
243 {
244 if (fVolume != NULL)
245 fVolume->_UnregisterIORequest(fRequestID);
246 }
247
Detach()248 void Detach()
249 {
250 fVolume = NULL;
251 }
252
253 private:
254 Volume* fVolume;
255 int32 fRequestID;
256 };
257
258
259 // VNodeRemover
260 class Volume::VNodeRemover {
261 public:
VNodeRemover(Volume * volume,VNode * node)262 VNodeRemover(Volume* volume, VNode* node)
263 :
264 fVolume(volume),
265 fNode(node)
266 {
267 }
268
~VNodeRemover()269 ~VNodeRemover()
270 {
271 if (fNode != NULL) {
272 MutexLocker locker(fVolume->fLock);
273 fVolume->fVNodes->Remove(fNode);
274 locker.Unlock();
275
276 fNode->Delete(fVolume);
277 }
278 }
279
280 private:
281 Volume* fVolume;
282 VNode* fNode;
283 };
284
285
286 // HasVNodeCapability
287 inline bool
HasVNodeCapability(VNode * vnode,int capability) const288 Volume::HasVNodeCapability(VNode* vnode, int capability) const
289 {
290 return vnode->ops->capabilities.Get(capability);
291 }
292
293
294 // constructor
Volume(FileSystem * fileSystem,fs_volume * fsVolume)295 Volume::Volume(FileSystem* fileSystem, fs_volume* fsVolume)
296 :
297 BReferenceable(),
298 fFileSystem(fileSystem),
299 fFSVolume(fsVolume),
300 fUserlandVolume(NULL),
301 fRootID(0),
302 fRootNode(NULL),
303 fOpenFiles(0),
304 fOpenDirectories(0),
305 fOpenAttributeDirectories(0),
306 fOpenAttributes(0),
307 fOpenIndexDirectories(0),
308 fOpenQueries(0),
309 fVNodes(NULL),
310 fIORequestInfosByID(NULL),
311 fIORequestInfosByStruct(NULL),
312 fLastIORequestID(0),
313 fVNodeCountingEnabled(false)
314 {
315 mutex_init(&fLock, "userlandfs volume");
316 }
317
318
319 // destructor
~Volume()320 Volume::~Volume()
321 {
322 mutex_destroy(&fLock);
323
324 delete fIORequestInfosByID;
325 delete fIORequestInfosByStruct;
326 delete fVNodes;
327 }
328
329
330 // #pragma mark - client methods
331
332 // GetVNode
333 status_t
GetVNode(ino_t vnid,void ** _node)334 Volume::GetVNode(ino_t vnid, void** _node)
335 {
336 PRINT(("get_vnode(%" B_PRId32 ", %" B_PRId64 ")\n", GetID(), vnid));
337 void* vnode;
338 status_t error = get_vnode(fFSVolume, vnid, &vnode);
339 if (error == B_OK) {
340 _IncrementVNodeCount(vnid);
341 *_node = ((VNode*)vnode)->clientNode;
342 }
343
344 return error;
345 }
346
347 // PutVNode
348 status_t
PutVNode(ino_t vnid)349 Volume::PutVNode(ino_t vnid)
350 {
351 PRINT(("put_vnode(%" B_PRId32 ", %" B_PRId64 ")\n", GetID(), vnid));
352 // Decrement the count first. We might not have another chance, since
353 // put_vnode() could put the last reference, thus causing the node to be
354 // removed from our map. This is all not very dramatic, but this way we
355 // avoid an erroneous error message from _DecrementVNodeCount().
356 _DecrementVNodeCount(vnid);
357
358 return put_vnode(fFSVolume, vnid);
359 }
360
361
362 // AcquireVNode
363 status_t
AcquireVNode(ino_t vnid)364 Volume::AcquireVNode(ino_t vnid)
365 {
366 PRINT(("acquire_vnode(%" B_PRId32 ", %" B_PRId64 ")\n", GetID(), vnid));
367 status_t error = acquire_vnode(fFSVolume, vnid);
368 if (error == B_OK)
369 _IncrementVNodeCount(vnid);
370 return error;
371 }
372
373
374 // NewVNode
375 status_t
NewVNode(ino_t vnid,void * clientNode,const FSVNodeCapabilities & capabilities)376 Volume::NewVNode(ino_t vnid, void* clientNode,
377 const FSVNodeCapabilities& capabilities)
378 {
379 PRINT(("new_vnode(%" B_PRId32 ", %" B_PRId64 ")\n", GetID(), vnid));
380 // lookup the node
381 MutexLocker locker(fLock);
382 VNode* node = fVNodes->Lookup(vnid);
383 if (node != NULL) {
384 // The node is already known -- this is an error.
385 RETURN_ERROR(B_BAD_VALUE);
386 }
387
388 // get the ops vector for the node
389 VNodeOps* ops = fFileSystem->GetVNodeOps(capabilities);
390 if (ops == NULL)
391 RETURN_ERROR(B_NO_MEMORY);
392
393 // create the node
394 node = new(std::nothrow) VNode(vnid, clientNode, ops);
395 if (node == NULL) {
396 fFileSystem->PutVNodeOps(ops);
397 RETURN_ERROR(B_NO_MEMORY);
398 }
399
400 node->published = false;
401
402 locker.Unlock();
403
404 // tell the VFS
405 status_t error = new_vnode(fFSVolume, vnid, node, node->ops->ops);
406 if (error != B_OK) {
407 node->Delete(this);
408 RETURN_ERROR(error);
409 }
410
411 // add the node to our map
412 locker.Lock();
413 fVNodes->Insert(node);
414
415 // Increment its use count. After new_vnode() the caller has a reference,
416 // but a subsequent publish_vnode() won't get another one. We handle that
417 // there.
418 if (fVNodeCountingEnabled)
419 node->useCount++;
420
421 return B_OK;
422 }
423
424 // PublishVNode
425 status_t
PublishVNode(ino_t vnid,void * clientNode,int type,uint32 flags,const FSVNodeCapabilities & capabilities)426 Volume::PublishVNode(ino_t vnid, void* clientNode, int type, uint32 flags,
427 const FSVNodeCapabilities& capabilities)
428 {
429 PRINT(("publish_vnode(%" B_PRId32 ", %" B_PRId64 ", %p)\n", GetID(), vnid,
430 clientNode));
431
432 // lookup the node
433 MutexLocker locker(fLock);
434 VNode* node = fVNodes->Lookup(vnid);
435 bool nodeKnown = node != NULL;
436
437 if (nodeKnown) {
438 if (node->published) {
439 WARN(("publish_vnode(): vnode (%" B_PRId32 ", %" B_PRId64
440 ") already published!\n", GetID(), vnid));
441 RETURN_ERROR(B_BAD_VALUE);
442 }
443 } else if (!nodeKnown) {
444 // The node is not yet known -- create it.
445
446 // get the ops vector for the node
447 VNodeOps* ops = fFileSystem->GetVNodeOps(capabilities);
448 if (ops == NULL)
449 RETURN_ERROR(B_NO_MEMORY);
450
451 // create the node
452 node = new(std::nothrow) VNode(vnid, clientNode, ops);
453 if (node == NULL) {
454 fFileSystem->PutVNodeOps(ops);
455 RETURN_ERROR(B_NO_MEMORY);
456 }
457 }
458
459 locker.Unlock();
460
461 // tell the VFS
462 status_t error = publish_vnode(fFSVolume, vnid, node, node->ops->ops,
463 type, flags);
464 if (error != B_OK) {
465 if (nodeKnown) {
466 // The node was known, i.e. it had been made known via new_vnode()
467 // and thus already had a use count of 1. Decrement that use count
468 // and remove the node completely.
469 _DecrementVNodeCount(vnid);
470 _RemoveInvalidVNode(vnid);
471 } else
472 node->Delete(this);
473 RETURN_ERROR(error);
474 }
475
476 // add the node to our map, if not known yet
477 locker.Lock();
478 if (nodeKnown) {
479 // The node is now published. Don't increment its use count. It already
480 // has 1 from new_vnode() and this publish_vnode() didn't increment it.
481 node->published = true;
482 } else {
483 // New node: increment its use count and add it to the map.
484 if (fVNodeCountingEnabled)
485 node->useCount++;
486 fVNodes->Insert(node);
487 }
488
489 return B_OK;
490 }
491
492 // RemoveVNode
493 status_t
RemoveVNode(ino_t vnid)494 Volume::RemoveVNode(ino_t vnid)
495 {
496 PRINT(("remove_vnode(%" B_PRId32 ", %" B_PRId64 ")\n", GetID(), vnid));
497 return remove_vnode(fFSVolume, vnid);
498 }
499
500 // UnremoveVNode
501 status_t
UnremoveVNode(ino_t vnid)502 Volume::UnremoveVNode(ino_t vnid)
503 {
504 PRINT(("unremove_vnode(%" B_PRId32 ", %" B_PRId64 ")\n", GetID(), vnid));
505 return unremove_vnode(fFSVolume, vnid);
506 }
507
508 // GetVNodeRemoved
509 status_t
GetVNodeRemoved(ino_t vnid,bool * removed)510 Volume::GetVNodeRemoved(ino_t vnid, bool* removed)
511 {
512 PRINT(("get_vnode_removed(%" B_PRId32 ", %" B_PRId64 ", %p)\n", GetID(),
513 vnid, removed));
514 return get_vnode_removed(fFSVolume, vnid, removed);
515 }
516
517
518 // CreateFileCache
519 status_t
CreateFileCache(ino_t vnodeID,off_t size)520 Volume::CreateFileCache(ino_t vnodeID, off_t size)
521 {
522 // lookup the node
523 MutexLocker locker(fLock);
524 VNode* vnode = fVNodes->Lookup(vnodeID);
525 if (vnode == NULL)
526 RETURN_ERROR(B_BAD_VALUE);
527
528 // does the node already have a file cache?
529 if (vnode->fileCache != NULL)
530 RETURN_ERROR(B_BAD_VALUE);
531
532 // create the file cache
533 locker.Unlock();
534 void* fileCache = file_cache_create(GetID(), vnodeID, size);
535 locker.Lock();
536
537 // re-check whether the node still lives
538 vnode = fVNodes->Lookup(vnodeID);
539 if (vnode == NULL) {
540 file_cache_delete(fileCache);
541 RETURN_ERROR(B_BAD_VALUE);
542 }
543
544 vnode->fileCache = fileCache;
545
546 return B_OK;
547 }
548
549
550 // DeleteFileCache
551 status_t
DeleteFileCache(ino_t vnodeID)552 Volume::DeleteFileCache(ino_t vnodeID)
553 {
554 // lookup the node
555 MutexLocker locker(fLock);
556 VNode* vnode = fVNodes->Lookup(vnodeID);
557 if (vnode == NULL)
558 RETURN_ERROR(B_BAD_VALUE);
559
560 // does the node have a file cache
561 if (vnode->fileCache == NULL)
562 RETURN_ERROR(B_BAD_VALUE);
563
564 void* fileCache = vnode->fileCache;
565 vnode->fileCache = NULL;
566
567 locker.Unlock();
568
569 file_cache_delete(fileCache);
570
571 return B_OK;
572 }
573
574
575 // SetFileCacheEnabled
576 status_t
SetFileCacheEnabled(ino_t vnodeID,bool enabled)577 Volume::SetFileCacheEnabled(ino_t vnodeID, bool enabled)
578 {
579 // lookup the node
580 MutexLocker locker(fLock);
581 VNode* vnode = fVNodes->Lookup(vnodeID);
582 if (vnode == NULL)
583 RETURN_ERROR(B_BAD_VALUE);
584
585 // does the node have a file cache
586 if (vnode->fileCache == NULL)
587 RETURN_ERROR(B_BAD_VALUE);
588
589 void* fileCache = vnode->fileCache;
590 locker.Unlock();
591 // TODO: We should use some kind of ref counting to avoid that another thread
592 // deletes the file cache now that we have dropped the lock. Applies to the
593 // other file cache operations as well.
594
595 // enable/disable the file cache
596 if (enabled) {
597 file_cache_enable(fileCache);
598 return B_OK;
599 }
600
601 return file_cache_disable(fileCache);
602 }
603
604
605 // SetFileCacheSize
606 status_t
SetFileCacheSize(ino_t vnodeID,off_t size)607 Volume::SetFileCacheSize(ino_t vnodeID, off_t size)
608 {
609 // lookup the node
610 MutexLocker locker(fLock);
611 VNode* vnode = fVNodes->Lookup(vnodeID);
612 if (vnode == NULL)
613 RETURN_ERROR(B_BAD_VALUE);
614
615 // does the node have a file cache
616 if (vnode->fileCache == NULL)
617 RETURN_ERROR(B_BAD_VALUE);
618
619 void* fileCache = vnode->fileCache;
620 locker.Unlock();
621
622 // set the size
623 return file_cache_set_size(fileCache, size);
624 }
625
626
627 // SyncFileCache
628 status_t
SyncFileCache(ino_t vnodeID)629 Volume::SyncFileCache(ino_t vnodeID)
630 {
631 // lookup the node
632 MutexLocker locker(fLock);
633 VNode* vnode = fVNodes->Lookup(vnodeID);
634 if (vnode == NULL)
635 RETURN_ERROR(B_BAD_VALUE);
636
637 // does the node have a file cache
638 if (vnode->fileCache == NULL)
639 RETURN_ERROR(B_BAD_VALUE);
640
641 void* fileCache = vnode->fileCache;
642 locker.Unlock();
643
644 // sync
645 return file_cache_sync(fileCache);
646 }
647
648
649 // ReadFileCache
650 status_t
ReadFileCache(ino_t vnodeID,void * cookie,off_t offset,void * buffer,size_t * _size)651 Volume::ReadFileCache(ino_t vnodeID, void* cookie,
652 off_t offset, void* buffer, size_t* _size)
653 {
654 // lookup the node
655 MutexLocker locker(fLock);
656 VNode* vnode = fVNodes->Lookup(vnodeID);
657 if (vnode == NULL)
658 RETURN_ERROR(B_BAD_VALUE);
659
660 // does the node have a file cache
661 if (vnode->fileCache == NULL)
662 RETURN_ERROR(B_BAD_VALUE);
663
664 void* fileCache = vnode->fileCache;
665 locker.Unlock();
666
667 // read
668 return file_cache_read(fileCache, cookie, offset, buffer, _size);
669 }
670
671
672 // WriteFileCache
673 status_t
WriteFileCache(ino_t vnodeID,void * cookie,off_t offset,const void * buffer,size_t * _size)674 Volume::WriteFileCache(ino_t vnodeID, void* cookie,
675 off_t offset, const void* buffer, size_t* _size)
676 {
677 // lookup the node
678 MutexLocker locker(fLock);
679 VNode* vnode = fVNodes->Lookup(vnodeID);
680 if (vnode == NULL)
681 RETURN_ERROR(B_BAD_VALUE);
682
683 // does the node have a file cache
684 if (vnode->fileCache == NULL)
685 RETURN_ERROR(B_BAD_VALUE);
686
687 void* fileCache = vnode->fileCache;
688 locker.Unlock();
689
690 // read
691 return file_cache_write(fileCache, cookie, offset, buffer, _size);
692 }
693
694
695 status_t
ReadFromIORequest(int32 requestID,void * buffer,size_t size)696 Volume::ReadFromIORequest(int32 requestID, void* buffer, size_t size)
697 {
698 // get the request
699 io_request* request;
700 status_t error = _FindIORequest(requestID, &request);
701 if (error != B_OK)
702 RETURN_ERROR(error);
703
704 return read_from_io_request(request, buffer, size);
705 }
706
707
708 status_t
WriteToIORequest(int32 requestID,const void * buffer,size_t size)709 Volume::WriteToIORequest(int32 requestID, const void* buffer, size_t size)
710 {
711 // get the request
712 io_request* request;
713 status_t error = _FindIORequest(requestID, &request);
714 if (error != B_OK)
715 RETURN_ERROR(error);
716
717 return write_to_io_request(request, buffer, size);
718 }
719
720
721 // DoIterativeFDIO
722 status_t
DoIterativeFDIO(int fd,int32 requestID,void * clientCookie,const file_io_vec * vecs,uint32 vecCount)723 Volume::DoIterativeFDIO(int fd, int32 requestID, void* clientCookie,
724 const file_io_vec* vecs, uint32 vecCount)
725 {
726 // get the request
727 io_request* request;
728 status_t error = _FindIORequest(requestID, &request);
729 if (error != B_OK)
730 RETURN_ERROR(error);
731
732 // copy the FD into the kernel
733 fd = dup_foreign_fd(fFileSystem->GetTeam(), fd, true);
734 if (fd < 0)
735 RETURN_ERROR(fd);
736
737 // create a cookie
738 IterativeFDIOCookie* cookie = new(std::nothrow) IterativeFDIOCookie(
739 this, fd, requestID, clientCookie, request->Offset(), vecs, vecCount);
740 if (cookie == NULL) {
741 close(fd);
742 RETURN_ERROR(B_NO_MEMORY);
743 }
744
745 // we need another reference, so we can still access the cookie below
746 cookie->AcquireReference();
747
748 // TODO: Up to this point we're responsible for calling the finished hook on
749 // error!
750 // call the kernel function
751 error = do_iterative_fd_io(fd, request, &_IterativeFDIOGetVecs,
752 &_IterativeFDIOFinished, cookie);
753
754 // unset the vecs -- they are on the stack an will become invalid when we
755 // return
756 MutexLocker _(fLock);
757 cookie->vecs = NULL;
758 cookie->vecCount = 0;
759 cookie->ReleaseReference();
760
761 return error;
762 }
763
764
765 status_t
NotifyIORequest(int32 requestID,status_t status)766 Volume::NotifyIORequest(int32 requestID, status_t status)
767 {
768 // get the request
769 io_request* request;
770 status_t error = _FindIORequest(requestID, &request);
771 if (error != B_OK)
772 RETURN_ERROR(error);
773
774 notify_io_request(request, status);
775 return B_OK;
776 }
777
778
779 // #pragma mark - FS
780
781
782 // Mount
783 status_t
Mount(const char * device,uint32 flags,const char * parameters)784 Volume::Mount(const char* device, uint32 flags, const char* parameters)
785 {
786 // create the maps
787 fVNodes = new(std::nothrow) VNodeMap;
788 fIORequestInfosByID = new(std::nothrow) IORequestIDMap;
789 fIORequestInfosByStruct = new(std::nothrow) IORequestStructMap;
790
791 if (fVNodes == NULL || fIORequestInfosByID == NULL
792 || fIORequestInfosByStruct == NULL
793 || fVNodes->Init() != B_OK
794 || fIORequestInfosByID->Init() != B_OK
795 || fIORequestInfosByStruct->Init() != B_OK) {
796 return B_NO_MEMORY;
797 }
798
799 // enable vnode counting
800 fVNodeCountingEnabled = true;
801
802 // init IORequest ID's
803 fLastIORequestID = 0;
804
805 // mount
806 status_t error = _Mount(device, flags, parameters);
807 if (error != B_OK)
808 RETURN_ERROR(error);
809
810 MutexLocker locker(fLock);
811 // fetch the root node, so that we can serve Walk() requests on it,
812 // after the connection to the userland server is gone
813 fRootNode = fVNodes->Lookup(fRootID);
814 if (fRootNode == NULL) {
815 // The root node was not added while mounting. That's a serious
816 // problem -- not only because we don't have it, but also because
817 // the VFS requires publish_vnode() to be invoked for the root node.
818 ERROR(("Volume::Mount(): new_vnode() was not called for root node! "
819 "Unmounting...\n"));
820 locker.Unlock();
821 Unmount();
822 return B_ERROR;
823 }
824
825 // Decrement the root node use count. The publish_vnode() the client FS
826 // did will be balanced by the VFS.
827 if (fVNodeCountingEnabled)
828 fRootNode->useCount--;
829
830 // init the volume ops vector we'll give the VFS
831 _InitVolumeOps();
832
833 return B_OK;
834 }
835
836 // Unmount
837 status_t
Unmount()838 Volume::Unmount()
839 {
840 status_t error = _Unmount();
841
842 // free the memory associated with the maps
843 {
844 // vnodes
845 MutexLocker _(fLock);
846 if (fVNodes != NULL) {
847 VNode* node = fVNodes->Clear(true);
848 while (node != NULL) {
849 VNode* nextNode = node->hash_link;
850 node->Delete(this);
851 node = nextNode;
852 }
853 delete fVNodes;
854 fVNodes = NULL;
855 }
856
857 // io request infos
858 if (fIORequestInfosByID != NULL) {
859 fIORequestInfosByID->Clear();
860 delete fIORequestInfosByID;
861 fIORequestInfosByID = NULL;
862 }
863
864 if (fIORequestInfosByStruct != NULL) {
865 IORequestInfo* info = fIORequestInfosByStruct->Clear(true);
866 while (info != NULL) {
867 IORequestInfo* nextInfo = info->structLink;
868 delete info;
869 // TODO: We should probably also notify the request, if that
870 // hasn't happened yet.
871 info = nextInfo;
872 }
873 delete fIORequestInfosByStruct;
874 fIORequestInfosByStruct = NULL;
875 }
876 }
877
878 fFileSystem->VolumeUnmounted(this);
879 return error;
880 }
881
882 // Sync
883 status_t
Sync()884 Volume::Sync()
885 {
886 // check capability
887 if (!HasCapability(FS_VOLUME_CAPABILITY_SYNC))
888 return B_BAD_VALUE;
889
890 // get a free port
891 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
892 if (!port)
893 return B_ERROR;
894 PortReleaser _(fFileSystem->GetPortPool(), port);
895
896 // prepare the request
897 RequestAllocator allocator(port->GetPort());
898 SyncVolumeRequest* request;
899 status_t error = AllocateRequest(allocator, &request);
900 if (error != B_OK)
901 return error;
902
903 request->volume = fUserlandVolume;
904
905 // send the request
906 KernelRequestHandler handler(this, SYNC_VOLUME_REPLY);
907 SyncVolumeReply* reply;
908 error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
909 if (error != B_OK)
910 return error;
911 RequestReleaser requestReleaser(port, reply);
912
913 // process the reply
914 if (reply->error != B_OK)
915 return reply->error;
916 return error;
917 }
918
919 // ReadFSInfo
920 status_t
ReadFSInfo(fs_info * info)921 Volume::ReadFSInfo(fs_info* info)
922 {
923 // When the connection to the userland server is lost, we serve
924 // read_fs_info() requests manually.
925 status_t error = _ReadFSInfo(info);
926 if (error != B_OK && fFileSystem->GetPortPool()->IsDisconnected()) {
927 WARN(("Volume::ReadFSInfo(): connection lost, emulating lookup `.'\n"));
928
929 info->flags = B_FS_IS_PERSISTENT | B_FS_IS_READONLY;
930 info->block_size = 512;
931 info->io_size = 512;
932 info->total_blocks = 0;
933 info->free_blocks = 0;
934 strlcpy(info->volume_name, fFileSystem->GetName(),
935 sizeof(info->volume_name));
936 strlcat(info->volume_name, ":disconnected", sizeof(info->volume_name));
937
938 error = B_OK;
939 }
940 return error;
941 }
942
943 // WriteFSInfo
944 status_t
WriteFSInfo(const struct fs_info * info,uint32 mask)945 Volume::WriteFSInfo(const struct fs_info *info, uint32 mask)
946 {
947 // check capability
948 if (!HasCapability(FS_VOLUME_CAPABILITY_WRITE_FS_INFO))
949 return B_BAD_VALUE;
950
951 // get a free port
952 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
953 if (!port)
954 return B_ERROR;
955 PortReleaser _(fFileSystem->GetPortPool(), port);
956
957 // prepare the request
958 RequestAllocator allocator(port->GetPort());
959 WriteFSInfoRequest* request;
960 status_t error = AllocateRequest(allocator, &request);
961 if (error != B_OK)
962 return error;
963
964 request->volume = fUserlandVolume;
965 request->info = *info;
966 request->mask = mask;
967
968 // send the request
969 KernelRequestHandler handler(this, WRITE_FS_INFO_REPLY);
970 WriteFSInfoReply* reply;
971 error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
972 if (error != B_OK)
973 return error;
974 RequestReleaser requestReleaser(port, reply);
975
976 // process the reply
977 if (reply->error != B_OK)
978 return reply->error;
979 return error;
980 }
981
982
983 // #pragma mark - vnodes
984
985
986 // Lookup
987 status_t
Lookup(void * dir,const char * entryName,ino_t * vnid)988 Volume::Lookup(void* dir, const char* entryName, ino_t* vnid)
989 {
990 // When the connection to the userland server is lost, we serve
991 // lookup(fRootNode, `.') requests manually to allow clean unmounting.
992 status_t error = _Lookup(dir, entryName, vnid);
993 if (error != B_OK && fFileSystem->GetPortPool()->IsDisconnected()
994 && dir == fRootNode && strcmp(entryName, ".") == 0) {
995 WARN(("Volume::Lookup(): connection lost, emulating lookup `.'\n"));
996 void* entryNode;
997 if (GetVNode(fRootID, &entryNode) != B_OK)
998 RETURN_ERROR(B_BAD_VALUE);
999 *vnid = fRootID;
1000 // The VFS will balance the get_vnode() call for the FS.
1001 _DecrementVNodeCount(*vnid);
1002 return B_OK;
1003 }
1004 return error;
1005 }
1006
1007 // GetVNodeName
1008 status_t
GetVNodeName(void * _node,char * buffer,size_t bufferSize)1009 Volume::GetVNodeName(void* _node, char* buffer, size_t bufferSize)
1010 {
1011 // We don't check the capability -- if not implemented by the client FS,
1012 // the functionality is emulated in userland.
1013
1014 VNode* vnode = (VNode*)_node;
1015
1016 // get a free port
1017 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
1018 if (!port)
1019 return B_ERROR;
1020 PortReleaser _(fFileSystem->GetPortPool(), port);
1021
1022 // prepare the request
1023 RequestAllocator allocator(port->GetPort());
1024 GetVNodeNameRequest* request;
1025 status_t error = AllocateRequest(allocator, &request);
1026 if (error != B_OK)
1027 return error;
1028
1029 request->volume = fUserlandVolume;
1030 request->node = vnode->clientNode;
1031 request->size = bufferSize;
1032
1033 // send the request
1034 KernelRequestHandler handler(this, GET_VNODE_NAME_REPLY);
1035 GetVNodeNameReply* reply;
1036 error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
1037 if (error != B_OK)
1038 return error;
1039 RequestReleaser requestReleaser(port, reply);
1040
1041 // process the reply
1042 if (reply->error != B_OK)
1043 return reply->error;
1044
1045 char* readBuffer = (char*)reply->buffer.GetData();
1046 size_t nameLen = reply->buffer.GetSize();
1047 nameLen = strnlen(readBuffer, nameLen);
1048 if (nameLen <= 0 || nameLen >= bufferSize)
1049 RETURN_ERROR(B_BAD_DATA);
1050
1051 memcpy(buffer, readBuffer, nameLen);
1052 buffer[nameLen] = '\0';
1053
1054 _SendReceiptAck(port);
1055 return error;
1056 }
1057
1058 // ReadVNode
1059 status_t
ReadVNode(ino_t vnid,bool reenter,void ** _node,fs_vnode_ops ** _ops,int * type,uint32 * flags)1060 Volume::ReadVNode(ino_t vnid, bool reenter, void** _node, fs_vnode_ops** _ops,
1061 int* type, uint32* flags)
1062 {
1063 // get a free port
1064 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
1065 if (!port)
1066 return B_ERROR;
1067 PortReleaser _(fFileSystem->GetPortPool(), port);
1068
1069 // prepare the request
1070 RequestAllocator allocator(port->GetPort());
1071 ReadVNodeRequest* request;
1072 status_t error = AllocateRequest(allocator, &request);
1073 if (error != B_OK)
1074 return error;
1075
1076 request->volume = fUserlandVolume;
1077 request->vnid = vnid;
1078 request->reenter = reenter;
1079
1080 // add the uninitialized node to our map
1081 VNode* vnode = new(std::nothrow) VNode(vnid, NULL, NULL);
1082 if (vnode == NULL)
1083 RETURN_ERROR(B_NO_MEMORY);
1084 vnode->valid = false;
1085
1086 MutexLocker locker(fLock);
1087 fVNodes->Insert(vnode);
1088 locker.Unlock();
1089
1090 // send the request
1091 KernelRequestHandler handler(this, READ_VNODE_REPLY);
1092 ReadVNodeReply* reply;
1093 error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
1094 if (error != B_OK) {
1095 _RemoveInvalidVNode(vnid);
1096 return error;
1097 }
1098 RequestReleaser requestReleaser(port, reply);
1099
1100 // process the reply
1101 if (reply->error != B_OK) {
1102 _RemoveInvalidVNode(vnid);
1103 return reply->error;
1104 }
1105
1106 // get the ops vector for the node
1107 VNodeOps* ops = fFileSystem->GetVNodeOps(reply->capabilities);
1108 if (ops == NULL) {
1109 _RemoveInvalidVNode(vnid);
1110 RETURN_ERROR(B_NO_MEMORY);
1111 }
1112
1113 // everything went fine -- mark the node valid
1114 locker.Lock();
1115 vnode->clientNode = reply->node;
1116 vnode->ops = ops;
1117 vnode->valid = true;
1118
1119 *_node = vnode;
1120 *type = reply->type;
1121 *flags = reply->flags;
1122 *_ops = ops->ops;
1123 return B_OK;
1124 }
1125
1126 // WriteVNode
1127 status_t
WriteVNode(void * node,bool reenter)1128 Volume::WriteVNode(void* node, bool reenter)
1129 {
1130 status_t error = _WriteVNode(node, reenter);
1131 if (error != B_OK && fFileSystem->GetPortPool()->IsDisconnected()) {
1132 // This isn't really necessary, since the VFS basically ignores the
1133 // return value -- at least Haiku. The fshell panic()s; didn't check
1134 // BeOS. It doesn't harm to appear to behave nicely. :-)
1135 WARN(("Volume::WriteVNode(): connection lost, forcing write vnode\n"));
1136 return B_OK;
1137 }
1138 return error;
1139 }
1140
1141 // RemoveVNode
1142 status_t
RemoveVNode(void * _node,bool reenter)1143 Volume::RemoveVNode(void* _node, bool reenter)
1144 {
1145 VNode* vnode = (VNode*)_node;
1146
1147 // At any rate remove the vnode from our map and delete it. We don't do that
1148 // right now, though, since we might still need to serve file cache requests
1149 // from the client FS.
1150 VNodeRemover nodeRemover(this, vnode);
1151
1152 void* clientNode = vnode->clientNode;
1153
1154 // get a free port
1155 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
1156 if (!port)
1157 return B_ERROR;
1158 PortReleaser _(fFileSystem->GetPortPool(), port);
1159
1160 // prepare the request
1161 RequestAllocator allocator(port->GetPort());
1162 FSRemoveVNodeRequest* request;
1163 status_t error = AllocateRequest(allocator, &request);
1164 if (error != B_OK)
1165 return error;
1166
1167 request->volume = fUserlandVolume;
1168 request->node = clientNode;
1169 request->reenter = reenter;
1170
1171 // send the request
1172 KernelRequestHandler handler(this, FS_REMOVE_VNODE_REPLY);
1173 FSRemoveVNodeReply* reply;
1174 error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
1175 if (error != B_OK)
1176 return error;
1177 RequestReleaser requestReleaser(port, reply);
1178
1179 // process the reply
1180 if (reply->error != B_OK)
1181 return reply->error;
1182 return error;
1183 }
1184
1185
1186 // #pragma mark - asynchronous I/O
1187
1188
1189 // DoIO
1190 status_t
DoIO(void * _node,void * cookie,io_request * ioRequest)1191 Volume::DoIO(void* _node, void* cookie, io_request* ioRequest)
1192 {
1193 VNode* vnode = (VNode*)_node;
1194
1195 // check capability
1196 if (!HasVNodeCapability(vnode, FS_VNODE_CAPABILITY_IO))
1197 return B_UNSUPPORTED;
1198
1199 // register the IO request
1200 int32 requestID;
1201 status_t error = _RegisterIORequest(ioRequest, &requestID);
1202 if (error != B_OK) {
1203 notify_io_request(ioRequest, error);
1204 return error;
1205 }
1206
1207 IORequestRemover requestRemover(this, requestID);
1208
1209 // get a free port
1210 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
1211 if (!port) {
1212 notify_io_request(ioRequest, B_ERROR);
1213 return B_ERROR;
1214 }
1215 PortReleaser _(fFileSystem->GetPortPool(), port);
1216
1217 // prepare the request
1218 RequestAllocator allocator(port->GetPort());
1219 DoIORequest* request;
1220 error = AllocateRequest(allocator, &request);
1221 if (error != B_OK) {
1222 notify_io_request(ioRequest, error);
1223 return error;
1224 }
1225
1226 request->volume = fUserlandVolume;
1227 request->node = vnode->clientNode;
1228 request->fileCookie = cookie;
1229 request->request = requestID;
1230 request->offset = ioRequest->Offset();
1231 request->length = ioRequest->Length();
1232 request->isWrite = ioRequest->IsWrite();
1233 request->isVIP = (ioRequest->Flags() & B_VIP_IO_REQUEST) != 0;
1234
1235 // send the request
1236 KernelRequestHandler handler(this, DO_IO_REPLY);
1237 DoIOReply* reply;
1238
1239 // TODO: when to notify the io_request?
1240 error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
1241 if (error != B_OK)
1242 return error;
1243 RequestReleaser requestReleaser(port, reply);
1244
1245 // process the reply
1246 if (reply->error != B_OK)
1247 return reply->error;
1248
1249 requestRemover.Detach();
1250
1251 return B_OK;
1252 }
1253
1254
1255 // CancelIO
1256 status_t
CancelIO(void * _node,void * cookie,io_request * ioRequest)1257 Volume::CancelIO(void* _node, void* cookie, io_request* ioRequest)
1258 {
1259 VNode* vnode = (VNode*)_node;
1260
1261 // check capability
1262 if (!HasVNodeCapability(vnode, FS_VNODE_CAPABILITY_CANCEL_IO))
1263 return B_BAD_VALUE;
1264
1265 // find the request
1266 int32 requestID;
1267 status_t error = _FindIORequest(ioRequest, &requestID);
1268 if (error != B_OK)
1269 return error;
1270
1271 IORequestRemover requestRemover(this, requestID);
1272
1273 // get a free port
1274 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
1275 if (!port)
1276 return B_ERROR;
1277 PortReleaser _(fFileSystem->GetPortPool(), port);
1278
1279 // prepare the request
1280 RequestAllocator allocator(port->GetPort());
1281 CancelIORequest* request;
1282 error = AllocateRequest(allocator, &request);
1283 if (error != B_OK)
1284 return error;
1285
1286 request->volume = fUserlandVolume;
1287 request->node = vnode->clientNode;
1288 request->fileCookie = cookie;
1289 request->request = requestID;
1290
1291 // send the request
1292 KernelRequestHandler handler(this, CANCEL_IO_REPLY);
1293 CancelIOReply* reply;
1294 error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
1295 if (error != B_OK) {
1296 _UnregisterIORequest(requestID);
1297 return error;
1298 }
1299 RequestReleaser requestReleaser(port, reply);
1300
1301 // process the reply
1302 if (reply->error != B_OK) {
1303 _UnregisterIORequest(requestID);
1304 return reply->error;
1305 }
1306
1307 return B_OK;
1308 }
1309
1310
1311 // #pragma mark - nodes
1312
1313
1314 // IOCtl
1315 status_t
IOCtl(void * _node,void * cookie,uint32 command,void * buffer,size_t len)1316 Volume::IOCtl(void* _node, void* cookie, uint32 command, void *buffer,
1317 size_t len)
1318 {
1319 VNode* vnode = (VNode*)_node;
1320
1321 // check the command and its parameters
1322 bool isBuffer = false;
1323 int32 bufferSize = 0;
1324 int32 writeSize = 0;
1325 switch (command) {
1326 case IOCTL_FILE_UNCACHED_IO:
1327 buffer = NULL;
1328 break;
1329 case IOCTL_CREATE_TIME:
1330 case IOCTL_MODIFIED_TIME:
1331 isBuffer = 0;
1332 bufferSize = 0;
1333 writeSize = sizeof(bigtime_t);
1334 break;
1335 case USERLANDFS_IOCTL:
1336 area_id area;
1337 area_info info;
1338 PRINT(("Volume::IOCtl(): USERLANDFS_IOCTL\n"));
1339 if ((area = area_for(buffer)) >= 0) {
1340 if (get_area_info(area, &info) == B_OK) {
1341 if ((uint8*)buffer - (uint8*)info.address
1342 + sizeof(userlandfs_ioctl) <= info.size) {
1343 if (strncmp(((userlandfs_ioctl*)buffer)->magic,
1344 kUserlandFSIOCtlMagic,
1345 USERLAND_IOCTL_MAGIC_LENGTH) == 0) {
1346 return _InternalIOCtl((userlandfs_ioctl*)buffer,
1347 bufferSize);
1348 } else
1349 PRINT(("Volume::IOCtl(): bad magic\n"));
1350 } else
1351 PRINT(("Volume::IOCtl(): bad buffer size\n"));
1352 } else
1353 PRINT(("Volume::IOCtl(): failed to get area info\n"));
1354 } else
1355 PRINT(("Volume::IOCtl(): bad area\n"));
1356 // fall through...
1357 default:
1358 {
1359 // We don't know the command. Check whether the FileSystem knows
1360 // about it.
1361 const IOCtlInfo* info = fFileSystem->GetIOCtlInfo(command);
1362 if (!info) {
1363 PRINT(("Volume::IOCtl(): unknown command\n"));
1364 return B_BAD_VALUE;
1365 }
1366
1367 isBuffer = info->isBuffer;
1368 bufferSize = info->bufferSize;
1369 writeSize = info->writeBufferSize;
1370
1371 // If the buffer shall indeed specify a buffer, check it.
1372 if (info->isBuffer) {
1373 if (!buffer) {
1374 PRINT(("Volume::IOCtl(): buffer is NULL\n"));
1375 return B_BAD_VALUE;
1376 }
1377
1378 area_id area = area_for(buffer);
1379 if (area < 0) {
1380 PRINT(("Volume::IOCtl(): bad area\n"));
1381 return B_BAD_VALUE;
1382 }
1383
1384 area_info info;
1385 if (get_area_info(area, &info) != B_OK) {
1386 PRINT(("Volume::IOCtl(): failed to get area info\n"));
1387 return B_BAD_VALUE;
1388 }
1389
1390 int32 areaSize = info.size - ((uint8*)buffer
1391 - (uint8*)info.address);
1392 if (bufferSize > areaSize || writeSize > areaSize) {
1393 PRINT(("Volume::IOCtl(): bad buffer size\n"));
1394 return B_BAD_VALUE;
1395 }
1396
1397 if (writeSize > 0 && !(info.protection & B_WRITE_AREA)) {
1398 PRINT(("Volume::IOCtl(): buffer not writable\n"));
1399 return B_BAD_VALUE;
1400 }
1401 }
1402 break;
1403 }
1404 }
1405
1406 // check capability
1407 if (!HasVNodeCapability(vnode, FS_VNODE_CAPABILITY_IOCTL))
1408 return B_BAD_VALUE;
1409
1410 // get a free port
1411 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
1412 if (!port)
1413 return B_ERROR;
1414 PortReleaser _(fFileSystem->GetPortPool(), port);
1415
1416 // prepare the request
1417 RequestAllocator allocator(port->GetPort());
1418 IOCtlRequest* request;
1419 status_t error = AllocateRequest(allocator, &request);
1420 if (error != B_OK)
1421 return error;
1422
1423 request->volume = fUserlandVolume;
1424 request->node = vnode->clientNode;
1425 request->fileCookie = cookie;
1426 request->command = command;
1427 request->bufferParameter = buffer;
1428 request->isBuffer = isBuffer;
1429 request->lenParameter = len;
1430 request->writeSize = writeSize;
1431
1432 if (isBuffer && bufferSize > 0) {
1433 error = allocator.AllocateData(request->buffer, buffer, bufferSize, 8);
1434 if (error != B_OK)
1435 return error;
1436 }
1437
1438 // send the request
1439 KernelRequestHandler handler(this, IOCTL_REPLY);
1440 IOCtlReply* reply;
1441 error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
1442 if (error != B_OK)
1443 return error;
1444 RequestReleaser requestReleaser(port, reply);
1445
1446 // process the reply
1447 if (reply->error != B_OK)
1448 return reply->error;
1449
1450 // Copy back the buffer even if the result is not B_OK. The protocol
1451 // is defined by the FS developer and may include writing data into
1452 // the buffer in some error cases.
1453 if (isBuffer && writeSize > 0 && reply->buffer.GetData()) {
1454 if (writeSize > reply->buffer.GetSize())
1455 writeSize = reply->buffer.GetSize();
1456 memcpy(buffer, reply->buffer.GetData(), writeSize);
1457 _SendReceiptAck(port);
1458 }
1459 return reply->ioctlError;
1460 }
1461
1462 // SetFlags
1463 status_t
SetFlags(void * _node,void * cookie,int flags)1464 Volume::SetFlags(void* _node, void* cookie, int flags)
1465 {
1466 VNode* vnode = (VNode*)_node;
1467
1468 // check capability
1469 if (!HasVNodeCapability(vnode, FS_VNODE_CAPABILITY_SET_FLAGS))
1470 return B_BAD_VALUE;
1471
1472 // get a free port
1473 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
1474 if (!port)
1475 return B_ERROR;
1476 PortReleaser _(fFileSystem->GetPortPool(), port);
1477
1478 // prepare the request
1479 RequestAllocator allocator(port->GetPort());
1480 SetFlagsRequest* request;
1481 status_t error = AllocateRequest(allocator, &request);
1482 if (error != B_OK)
1483 return error;
1484
1485 request->volume = fUserlandVolume;
1486 request->node = vnode->clientNode;
1487 request->fileCookie = cookie;
1488 request->flags = flags;
1489
1490 // send the request
1491 KernelRequestHandler handler(this, SET_FLAGS_REPLY);
1492 SetFlagsReply* reply;
1493 error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
1494 if (error != B_OK)
1495 return error;
1496 RequestReleaser requestReleaser(port, reply);
1497
1498 // process the reply
1499 if (reply->error != B_OK)
1500 return reply->error;
1501 return error;
1502 }
1503
1504 // Select
1505 status_t
Select(void * _node,void * cookie,uint8 event,selectsync * sync)1506 Volume::Select(void* _node, void* cookie, uint8 event, selectsync* sync)
1507 {
1508 VNode* vnode = (VNode*)_node;
1509
1510 // check capability
1511 if (!HasVNodeCapability(vnode, FS_VNODE_CAPABILITY_SELECT)) {
1512 notify_select_event(sync, event);
1513 return B_OK;
1514 }
1515
1516 // get a free port
1517 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
1518 if (!port)
1519 return B_ERROR;
1520 PortReleaser _(fFileSystem->GetPortPool(), port);
1521
1522 // prepare the request
1523 RequestAllocator allocator(port->GetPort());
1524 SelectRequest* request;
1525 status_t error = AllocateRequest(allocator, &request);
1526 if (error != B_OK)
1527 return error;
1528
1529 request->volume = fUserlandVolume;
1530 request->node = vnode->clientNode;
1531 request->fileCookie = cookie;
1532 request->event = event;
1533 request->sync = sync;
1534
1535 // add a selectsync entry
1536 error = fFileSystem->AddSelectSyncEntry(sync);
1537 if (error != B_OK)
1538 return error;
1539
1540 // send the request
1541 KernelRequestHandler handler(this, SELECT_REPLY);
1542 SelectReply* reply;
1543 error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
1544 if (error != B_OK) {
1545 fFileSystem->RemoveSelectSyncEntry(sync);
1546 return error;
1547 }
1548 RequestReleaser requestReleaser(port, reply);
1549
1550 // process the reply
1551 if (reply->error != B_OK) {
1552 fFileSystem->RemoveSelectSyncEntry(sync);
1553 return reply->error;
1554 }
1555 return error;
1556 }
1557
1558 // Deselect
1559 status_t
Deselect(void * _node,void * cookie,uint8 event,selectsync * sync)1560 Volume::Deselect(void* _node, void* cookie, uint8 event, selectsync* sync)
1561 {
1562 VNode* vnode = (VNode*)_node;
1563
1564 // check capability
1565 if (!HasVNodeCapability(vnode, FS_VNODE_CAPABILITY_DESELECT))
1566 return B_OK;
1567
1568 struct SyncRemover {
1569 SyncRemover(FileSystem* fs, selectsync* sync)
1570 : fs(fs), sync(sync) {}
1571 ~SyncRemover() { fs->RemoveSelectSyncEntry(sync); }
1572
1573 FileSystem* fs;
1574 selectsync* sync;
1575 } syncRemover(fFileSystem, sync);
1576
1577 // get a free port
1578 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
1579 if (!port)
1580 return B_ERROR;
1581 PortReleaser _(fFileSystem->GetPortPool(), port);
1582
1583 // prepare the request
1584 RequestAllocator allocator(port->GetPort());
1585 DeselectRequest* request;
1586 status_t error = AllocateRequest(allocator, &request);
1587 if (error != B_OK)
1588 return error;
1589
1590 request->volume = fUserlandVolume;
1591 request->node = vnode->clientNode;
1592 request->fileCookie = cookie;
1593 request->event = event;
1594 request->sync = sync;
1595
1596 // send the request
1597 KernelRequestHandler handler(this, DESELECT_REPLY);
1598 DeselectReply* reply;
1599 error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
1600 if (error != B_OK)
1601 return error;
1602 RequestReleaser requestReleaser(port, reply);
1603
1604 // process the reply
1605 if (reply->error != B_OK)
1606 return reply->error;
1607 return error;
1608 }
1609
1610 // FSync
1611 status_t
FSync(void * _node)1612 Volume::FSync(void* _node)
1613 {
1614 VNode* vnode = (VNode*)_node;
1615
1616 // check capability
1617 if (!HasVNodeCapability(vnode, FS_VNODE_CAPABILITY_FSYNC))
1618 return B_BAD_VALUE;
1619
1620 // get a free port
1621 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
1622 if (!port)
1623 return B_ERROR;
1624 PortReleaser _(fFileSystem->GetPortPool(), port);
1625
1626 // prepare the request
1627 RequestAllocator allocator(port->GetPort());
1628 FSyncRequest* request;
1629 status_t error = AllocateRequest(allocator, &request);
1630 if (error != B_OK)
1631 return error;
1632
1633 request->volume = fUserlandVolume;
1634 request->node = vnode->clientNode;
1635
1636 // send the request
1637 KernelRequestHandler handler(this, FSYNC_REPLY);
1638 FSyncReply* reply;
1639 error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
1640 if (error != B_OK)
1641 return error;
1642 RequestReleaser requestReleaser(port, reply);
1643
1644 // process the reply
1645 if (reply->error != B_OK)
1646 return reply->error;
1647 return error;
1648 }
1649
1650 // ReadSymlink
1651 status_t
ReadSymlink(void * _node,char * buffer,size_t bufferSize,size_t * bytesRead)1652 Volume::ReadSymlink(void* _node, char* buffer, size_t bufferSize,
1653 size_t* bytesRead)
1654 {
1655 VNode* vnode = (VNode*)_node;
1656
1657 *bytesRead = 0;
1658
1659 // check capability
1660 if (!HasVNodeCapability(vnode, FS_VNODE_CAPABILITY_READ_SYMLINK))
1661 return B_BAD_VALUE;
1662
1663 // get a free port
1664 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
1665 if (!port)
1666 return B_ERROR;
1667 PortReleaser _(fFileSystem->GetPortPool(), port);
1668
1669 // prepare the request
1670 RequestAllocator allocator(port->GetPort());
1671 ReadSymlinkRequest* request;
1672 status_t error = AllocateRequest(allocator, &request);
1673 if (error != B_OK)
1674 return error;
1675
1676 request->volume = fUserlandVolume;
1677 request->node = vnode->clientNode;
1678 request->size = bufferSize;
1679
1680 // send the request
1681 KernelRequestHandler handler(this, READ_SYMLINK_REPLY);
1682 ReadSymlinkReply* reply;
1683 error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
1684 if (error != B_OK)
1685 return error;
1686 RequestReleaser requestReleaser(port, reply);
1687
1688 // process the reply
1689 if (reply->error != B_OK)
1690 return reply->error;
1691 void* readBuffer = reply->buffer.GetData();
1692 if (reply->bytesRead > (uint32)reply->buffer.GetSize()
1693 || reply->bytesRead > bufferSize) {
1694 return B_BAD_DATA;
1695 }
1696 if (reply->bytesRead > 0)
1697 memcpy(buffer, readBuffer, reply->bytesRead);
1698 *bytesRead = reply->bytesRead;
1699 _SendReceiptAck(port);
1700 return error;
1701 }
1702
1703 // CreateSymlink
1704 status_t
CreateSymlink(void * _dir,const char * name,const char * target,int mode)1705 Volume::CreateSymlink(void* _dir, const char* name, const char* target,
1706 int mode)
1707 {
1708 VNode* vnode = (VNode*)_dir;
1709
1710 // check capability
1711 if (!HasVNodeCapability(vnode, FS_VNODE_CAPABILITY_CREATE_SYMLINK))
1712 return B_BAD_VALUE;
1713
1714 // get a free port
1715 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
1716 if (!port)
1717 return B_ERROR;
1718 PortReleaser _(fFileSystem->GetPortPool(), port);
1719
1720 // prepare the request
1721 RequestAllocator allocator(port->GetPort());
1722 CreateSymlinkRequest* request;
1723 status_t error = AllocateRequest(allocator, &request);
1724 if (error != B_OK)
1725 return error;
1726
1727 request->volume = fUserlandVolume;
1728 request->node = vnode->clientNode;
1729 error = allocator.AllocateString(request->name, name);
1730 if (error == B_OK)
1731 error = allocator.AllocateString(request->target, target);
1732 if (error != B_OK)
1733 return error;
1734 request->mode = mode;
1735
1736 // send the request
1737 KernelRequestHandler handler(this, CREATE_SYMLINK_REPLY);
1738 CreateSymlinkReply* reply;
1739 error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
1740 if (error != B_OK)
1741 return error;
1742 RequestReleaser requestReleaser(port, reply);
1743
1744 // process the reply
1745 if (reply->error != B_OK)
1746 return reply->error;
1747 return error;
1748 }
1749
1750 // Link
1751 status_t
Link(void * _dir,const char * name,void * node)1752 Volume::Link(void* _dir, const char* name, void* node)
1753 {
1754 VNode* vnode = (VNode*)_dir;
1755 VNode* targetVnode = (VNode*)node;
1756
1757 // check capability
1758 if (!HasVNodeCapability(vnode, FS_VNODE_CAPABILITY_LINK))
1759 return B_BAD_VALUE;
1760
1761 // get a free port
1762 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
1763 if (!port)
1764 return B_ERROR;
1765 PortReleaser _(fFileSystem->GetPortPool(), port);
1766
1767 // prepare the request
1768 RequestAllocator allocator(port->GetPort());
1769 LinkRequest* request;
1770 status_t error = AllocateRequest(allocator, &request);
1771 if (error != B_OK)
1772 return error;
1773
1774 request->volume = fUserlandVolume;
1775 request->node = vnode->clientNode;
1776 error = allocator.AllocateString(request->name, name);
1777 request->target = targetVnode->clientNode;
1778 if (error != B_OK)
1779 return error;
1780
1781 // send the request
1782 KernelRequestHandler handler(this, LINK_REPLY);
1783 LinkReply* reply;
1784 error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
1785 if (error != B_OK)
1786 return error;
1787 RequestReleaser requestReleaser(port, reply);
1788
1789 // process the reply
1790 if (reply->error != B_OK)
1791 return reply->error;
1792 return error;
1793 }
1794
1795 // Unlink
1796 status_t
Unlink(void * _dir,const char * name)1797 Volume::Unlink(void* _dir, const char* name)
1798 {
1799 VNode* vnode = (VNode*)_dir;
1800
1801 // check capability
1802 if (!HasVNodeCapability(vnode, FS_VNODE_CAPABILITY_UNLINK))
1803 return B_BAD_VALUE;
1804
1805 // get a free port
1806 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
1807 if (!port)
1808 return B_ERROR;
1809 PortReleaser _(fFileSystem->GetPortPool(), port);
1810
1811 // prepare the request
1812 RequestAllocator allocator(port->GetPort());
1813 UnlinkRequest* request;
1814 status_t error = AllocateRequest(allocator, &request);
1815 if (error != B_OK)
1816 return error;
1817
1818 request->volume = fUserlandVolume;
1819 request->node = vnode->clientNode;
1820 error = allocator.AllocateString(request->name, name);
1821 if (error != B_OK)
1822 return error;
1823
1824 // send the request
1825 KernelRequestHandler handler(this, UNLINK_REPLY);
1826 UnlinkReply* reply;
1827 error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
1828 if (error != B_OK)
1829 return error;
1830 RequestReleaser requestReleaser(port, reply);
1831
1832 // process the reply
1833 if (reply->error != B_OK)
1834 return reply->error;
1835 return error;
1836 }
1837
1838 // Rename
1839 status_t
Rename(void * _oldDir,const char * oldName,void * _newDir,const char * newName)1840 Volume::Rename(void* _oldDir, const char* oldName, void* _newDir,
1841 const char* newName)
1842 {
1843 VNode* oldVNode = (VNode*)_oldDir;
1844 VNode* newVNode = (VNode*)_newDir;
1845
1846 // check capability
1847 if (!HasVNodeCapability(oldVNode, FS_VNODE_CAPABILITY_RENAME))
1848 return B_BAD_VALUE;
1849
1850 // get a free port
1851 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
1852 if (!port)
1853 return B_ERROR;
1854 PortReleaser _(fFileSystem->GetPortPool(), port);
1855
1856 // prepare the request
1857 RequestAllocator allocator(port->GetPort());
1858 RenameRequest* request;
1859 status_t error = AllocateRequest(allocator, &request);
1860 if (error != B_OK)
1861 return error;
1862
1863 request->volume = fUserlandVolume;
1864 request->oldDir = oldVNode->clientNode;
1865 request->newDir = newVNode->clientNode;
1866 error = allocator.AllocateString(request->oldName, oldName);
1867 if (error == B_OK)
1868 error = allocator.AllocateString(request->newName, newName);
1869 if (error != B_OK)
1870 return error;
1871
1872 // send the request
1873 KernelRequestHandler handler(this, RENAME_REPLY);
1874 RenameReply* reply;
1875 error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
1876 if (error != B_OK)
1877 return error;
1878 RequestReleaser requestReleaser(port, reply);
1879
1880 // process the reply
1881 if (reply->error != B_OK)
1882 return reply->error;
1883 return error;
1884 }
1885
1886 // Access
1887 status_t
Access(void * _node,int mode)1888 Volume::Access(void* _node, int mode)
1889 {
1890 VNode* vnode = (VNode*)_node;
1891
1892 // check capability
1893 if (!HasVNodeCapability(vnode, FS_VNODE_CAPABILITY_ACCESS))
1894 return B_OK;
1895
1896 // get a free port
1897 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
1898 if (!port)
1899 return B_ERROR;
1900 PortReleaser _(fFileSystem->GetPortPool(), port);
1901
1902 // prepare the request
1903 RequestAllocator allocator(port->GetPort());
1904 AccessRequest* request;
1905 status_t error = AllocateRequest(allocator, &request);
1906 if (error != B_OK)
1907 return error;
1908
1909 request->volume = fUserlandVolume;
1910 request->node = vnode->clientNode;
1911 request->mode = mode;
1912
1913 // send the request
1914 KernelRequestHandler handler(this, ACCESS_REPLY);
1915 AccessReply* reply;
1916 error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
1917 if (error != B_OK)
1918 return error;
1919 RequestReleaser requestReleaser(port, reply);
1920
1921 // process the reply
1922 if (reply->error != B_OK)
1923 return reply->error;
1924 return error;
1925 }
1926
1927 // ReadStat
1928 status_t
ReadStat(void * node,struct stat * st)1929 Volume::ReadStat(void* node, struct stat* st)
1930 {
1931 // When the connection to the userland server is lost, we serve
1932 // read_stat(fRootNode) requests manually to allow clean unmounting.
1933 status_t error = _ReadStat(node, st);
1934 if (error != B_OK && fFileSystem->GetPortPool()->IsDisconnected()
1935 && node == fRootNode) {
1936 WARN(("Volume::ReadStat(): connection lost, emulating stat for the "
1937 "root node\n"));
1938
1939 st->st_dev = GetID();
1940 st->st_ino = fRootID;
1941 st->st_mode = ACCESSPERMS;
1942 st->st_nlink = 1;
1943 st->st_uid = 0;
1944 st->st_gid = 0;
1945 st->st_size = 512;
1946 st->st_blksize = 512;
1947 st->st_atime = 0;
1948 st->st_mtime = 0;
1949 st->st_ctime = 0;
1950 st->st_crtime = 0;
1951
1952 error = B_OK;
1953 }
1954 return error;
1955 }
1956
1957 // WriteStat
1958 status_t
WriteStat(void * _node,const struct stat * st,uint32 mask)1959 Volume::WriteStat(void* _node, const struct stat* st, uint32 mask)
1960 {
1961 VNode* vnode = (VNode*)_node;
1962
1963 // check capability
1964 if (!HasVNodeCapability(vnode, FS_VNODE_CAPABILITY_WRITE_STAT))
1965 return B_BAD_VALUE;
1966
1967 // get a free port
1968 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
1969 if (!port)
1970 return B_ERROR;
1971 PortReleaser _(fFileSystem->GetPortPool(), port);
1972
1973 // prepare the request
1974 RequestAllocator allocator(port->GetPort());
1975 WriteStatRequest* request;
1976 status_t error = AllocateRequest(allocator, &request);
1977 if (error != B_OK)
1978 return error;
1979
1980 request->volume = fUserlandVolume;
1981 request->node = vnode->clientNode;
1982 request->st = *st;
1983 request->mask = mask;
1984
1985 // send the request
1986 KernelRequestHandler handler(this, WRITE_STAT_REPLY);
1987 WriteStatReply* reply;
1988 error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
1989 if (error != B_OK)
1990 return error;
1991 RequestReleaser requestReleaser(port, reply);
1992
1993 // process the reply
1994 if (reply->error != B_OK)
1995 return reply->error;
1996 return error;
1997 }
1998
1999
2000 // #pragma mark - files
2001
2002 // Create
2003 status_t
Create(void * _dir,const char * name,int openMode,int mode,void ** cookie,ino_t * vnid)2004 Volume::Create(void* _dir, const char* name, int openMode, int mode,
2005 void** cookie, ino_t* vnid)
2006 {
2007 VNode* vnode = (VNode*)_dir;
2008
2009 // check capability
2010 if (!HasVNodeCapability(vnode, FS_VNODE_CAPABILITY_CREATE))
2011 return B_BAD_VALUE;
2012
2013 // get a free port
2014 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
2015 if (!port)
2016 return B_ERROR;
2017 PortReleaser _(fFileSystem->GetPortPool(), port);
2018 AutoIncrementer incrementer(&fOpenFiles);
2019
2020 // prepare the request
2021 RequestAllocator allocator(port->GetPort());
2022 CreateRequest* request;
2023 status_t error = AllocateRequest(allocator, &request);
2024 if (error != B_OK)
2025 return error;
2026
2027 request->volume = fUserlandVolume;
2028 request->node = vnode->clientNode;
2029 error = allocator.AllocateString(request->name, name);
2030 request->openMode = openMode;
2031 request->mode = mode;
2032 if (error != B_OK)
2033 return error;
2034
2035 // send the request
2036 KernelRequestHandler handler(this, CREATE_REPLY);
2037 CreateReply* reply;
2038 error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
2039 if (error != B_OK)
2040 return error;
2041 RequestReleaser requestReleaser(port, reply);
2042
2043 // process the reply
2044 if (reply->error != B_OK)
2045 return reply->error;
2046 incrementer.Keep();
2047 *vnid = reply->vnid;
2048 *cookie = reply->fileCookie;
2049
2050 // The VFS will balance the publish_vnode() call for the FS.
2051 if (error == B_OK)
2052 _DecrementVNodeCount(*vnid);
2053 return error;
2054 }
2055
2056 // Open
2057 status_t
Open(void * _node,int openMode,void ** cookie)2058 Volume::Open(void* _node, int openMode, void** cookie)
2059 {
2060 VNode* vnode = (VNode*)_node;
2061
2062 // check capability
2063 if (!HasVNodeCapability(vnode, FS_VNODE_CAPABILITY_OPEN))
2064 return B_BAD_VALUE;
2065
2066 // get a free port
2067 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
2068 if (!port)
2069 return B_ERROR;
2070 PortReleaser _(fFileSystem->GetPortPool(), port);
2071 AutoIncrementer incrementer(&fOpenFiles);
2072
2073 // prepare the request
2074 RequestAllocator allocator(port->GetPort());
2075 OpenRequest* request;
2076 status_t error = AllocateRequest(allocator, &request);
2077 if (error != B_OK)
2078 return error;
2079 request->volume = fUserlandVolume;
2080 request->node = vnode->clientNode;
2081 request->openMode = openMode;
2082
2083 // send the request
2084 KernelRequestHandler handler(this, OPEN_REPLY);
2085 OpenReply* reply;
2086 error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
2087 if (error != B_OK)
2088 return error;
2089 RequestReleaser requestReleaser(port, reply);
2090
2091 // process the reply
2092 if (reply->error != B_OK)
2093 return reply->error;
2094 incrementer.Keep();
2095 *cookie = reply->fileCookie;
2096 return error;
2097 }
2098
2099 // Close
2100 status_t
Close(void * node,void * cookie)2101 Volume::Close(void* node, void* cookie)
2102 {
2103 status_t error = _Close(node, cookie);
2104 if (error != B_OK && fFileSystem->GetPortPool()->IsDisconnected()) {
2105 // This isn't really necessary, as the return value is irrelevant to
2106 // the VFS. Haiku ignores it completely. The fsshell returns it to the
2107 // userland, but considers the node closed anyway.
2108 WARN(("Volume::Close(): connection lost, forcing close\n"));
2109 return B_OK;
2110 }
2111 return error;
2112 }
2113
2114 // FreeCookie
2115 status_t
FreeCookie(void * node,void * cookie)2116 Volume::FreeCookie(void* node, void* cookie)
2117 {
2118 status_t error = _FreeCookie(node, cookie);
2119 bool disconnected = false;
2120 if (error != B_OK && fFileSystem->GetPortPool()->IsDisconnected()) {
2121 // This isn't really necessary, as the return value is irrelevant to
2122 // the VFS. It's completely ignored by Haiku as well as by the fsshell.
2123 WARN(("Volume::FreeCookie(): connection lost, forcing free cookie\n"));
2124 error = B_OK;
2125 disconnected = true;
2126 }
2127
2128 int32 openFiles = atomic_add(&fOpenFiles, -1);
2129 if (openFiles <= 1 && disconnected)
2130 _PutAllPendingVNodes();
2131 return error;
2132 }
2133
2134 // Read
2135 status_t
Read(void * _node,void * cookie,off_t pos,void * buffer,size_t bufferSize,size_t * bytesRead)2136 Volume::Read(void* _node, void* cookie, off_t pos, void* buffer,
2137 size_t bufferSize, size_t* bytesRead)
2138 {
2139 VNode* vnode = (VNode*)_node;
2140
2141 *bytesRead = 0;
2142
2143 // check capability
2144 if (!HasVNodeCapability(vnode, FS_VNODE_CAPABILITY_READ))
2145 return B_BAD_VALUE;
2146
2147 // get a free port
2148 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
2149 if (!port)
2150 return B_ERROR;
2151 PortReleaser _(fFileSystem->GetPortPool(), port);
2152
2153 // prepare the request
2154 RequestAllocator allocator(port->GetPort());
2155 ReadRequest* request;
2156 status_t error = AllocateRequest(allocator, &request);
2157 if (error != B_OK)
2158 return error;
2159
2160 request->volume = fUserlandVolume;
2161 request->node = vnode->clientNode;
2162 request->fileCookie = cookie;
2163 request->pos = pos;
2164 request->size = bufferSize;
2165
2166 // send the request
2167 KernelRequestHandler handler(this, READ_REPLY);
2168 ReadReply* reply;
2169 error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
2170 if (error != B_OK)
2171 return error;
2172 RequestReleaser requestReleaser(port, reply);
2173
2174 // process the reply
2175 if (reply->error != B_OK)
2176 return reply->error;
2177 void* readBuffer = reply->buffer.GetData();
2178 if (reply->bytesRead > (uint32)reply->buffer.GetSize()
2179 || reply->bytesRead > bufferSize) {
2180 return B_BAD_DATA;
2181 }
2182 if (reply->bytesRead > 0
2183 && user_memcpy(buffer, readBuffer, reply->bytesRead) < B_OK) {
2184 return B_BAD_ADDRESS;
2185 }
2186
2187 *bytesRead = reply->bytesRead;
2188 _SendReceiptAck(port);
2189 return error;
2190 }
2191
2192 // Write
2193 status_t
Write(void * _node,void * cookie,off_t pos,const void * buffer,size_t size,size_t * bytesWritten)2194 Volume::Write(void* _node, void* cookie, off_t pos, const void* buffer,
2195 size_t size, size_t* bytesWritten)
2196 {
2197 VNode* vnode = (VNode*)_node;
2198
2199 *bytesWritten = 0;
2200
2201 // check capability
2202 if (!HasVNodeCapability(vnode, FS_VNODE_CAPABILITY_WRITE))
2203 return B_BAD_VALUE;
2204
2205 // get a free port
2206 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
2207 if (!port)
2208 return B_ERROR;
2209 PortReleaser _(fFileSystem->GetPortPool(), port);
2210
2211 // prepare the request
2212 RequestAllocator allocator(port->GetPort());
2213 WriteRequest* request;
2214 status_t error = AllocateRequest(allocator, &request);
2215 if (error != B_OK)
2216 return error;
2217
2218 request->volume = fUserlandVolume;
2219 request->node = vnode->clientNode;
2220 request->fileCookie = cookie;
2221 request->pos = pos;
2222 error = allocator.AllocateData(request->buffer, buffer, size, 1);
2223 if (error != B_OK)
2224 return error;
2225
2226 // send the request
2227 KernelRequestHandler handler(this, WRITE_REPLY);
2228 WriteReply* reply;
2229 error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
2230 if (error != B_OK)
2231 return error;
2232 RequestReleaser requestReleaser(port, reply);
2233
2234 // process the reply
2235 if (reply->error != B_OK)
2236 return reply->error;
2237 *bytesWritten = reply->bytesWritten;
2238 return error;
2239 }
2240
2241
2242 // #pragma mark - directories
2243
2244 // CreateDir
2245 status_t
CreateDir(void * _dir,const char * name,int mode)2246 Volume::CreateDir(void* _dir, const char* name, int mode)
2247 {
2248 VNode* vnode = (VNode*)_dir;
2249
2250 // check capability
2251 if (!HasVNodeCapability(vnode, FS_VNODE_CAPABILITY_CREATE_DIR))
2252 return B_BAD_VALUE;
2253
2254 // get a free port
2255 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
2256 if (!port)
2257 return B_ERROR;
2258 PortReleaser _(fFileSystem->GetPortPool(), port);
2259
2260 // prepare the request
2261 RequestAllocator allocator(port->GetPort());
2262 CreateDirRequest* request;
2263 status_t error = AllocateRequest(allocator, &request);
2264 if (error != B_OK)
2265 return error;
2266
2267 request->volume = fUserlandVolume;
2268 request->node = vnode->clientNode;
2269 error = allocator.AllocateString(request->name, name);
2270 request->mode = mode;
2271 if (error != B_OK)
2272 return error;
2273
2274 // send the request
2275 KernelRequestHandler handler(this, CREATE_DIR_REPLY);
2276 CreateDirReply* reply;
2277 error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
2278 if (error != B_OK)
2279 return error;
2280 RequestReleaser requestReleaser(port, reply);
2281
2282 // process the reply
2283 if (reply->error != B_OK)
2284 return reply->error;
2285 return error;
2286 }
2287
2288 // RemoveDir
2289 status_t
RemoveDir(void * _dir,const char * name)2290 Volume::RemoveDir(void* _dir, const char* name)
2291 {
2292 VNode* vnode = (VNode*)_dir;
2293
2294 // check capability
2295 if (!HasVNodeCapability(vnode, FS_VNODE_CAPABILITY_REMOVE_DIR))
2296 return B_BAD_VALUE;
2297
2298 // get a free port
2299 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
2300 if (!port)
2301 return B_ERROR;
2302 PortReleaser _(fFileSystem->GetPortPool(), port);
2303
2304 // prepare the request
2305 RequestAllocator allocator(port->GetPort());
2306 RemoveDirRequest* request;
2307 status_t error = AllocateRequest(allocator, &request);
2308 if (error != B_OK)
2309 return error;
2310
2311 request->volume = fUserlandVolume;
2312 request->node = vnode->clientNode;
2313 error = allocator.AllocateString(request->name, name);
2314 if (error != B_OK)
2315 return error;
2316
2317 // send the request
2318 KernelRequestHandler handler(this, REMOVE_DIR_REPLY);
2319 RemoveDirReply* reply;
2320 error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
2321 if (error != B_OK)
2322 return error;
2323 RequestReleaser requestReleaser(port, reply);
2324
2325 // process the reply
2326 if (reply->error != B_OK)
2327 return reply->error;
2328 return error;
2329 }
2330
2331 // OpenDir
2332 status_t
OpenDir(void * _node,void ** cookie)2333 Volume::OpenDir(void* _node, void** cookie)
2334 {
2335 VNode* vnode = (VNode*)_node;
2336
2337 // check capability
2338 if (!HasVNodeCapability(vnode, FS_VNODE_CAPABILITY_OPEN_DIR))
2339 return B_BAD_VALUE;
2340
2341 // get a free port
2342 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
2343 if (!port)
2344 return B_ERROR;
2345 PortReleaser _(fFileSystem->GetPortPool(), port);
2346 AutoIncrementer incrementer(&fOpenDirectories);
2347
2348 // prepare the request
2349 RequestAllocator allocator(port->GetPort());
2350 OpenDirRequest* request;
2351 status_t error = AllocateRequest(allocator, &request);
2352 if (error != B_OK)
2353 return error;
2354
2355 request->volume = fUserlandVolume;
2356 request->node = vnode->clientNode;
2357
2358 // send the request
2359 KernelRequestHandler handler(this, OPEN_DIR_REPLY);
2360 OpenDirReply* reply;
2361 error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
2362 if (error != B_OK)
2363 return error;
2364 RequestReleaser requestReleaser(port, reply);
2365
2366 // process the reply
2367 if (reply->error != B_OK)
2368 return reply->error;
2369 incrementer.Keep();
2370 *cookie = reply->dirCookie;
2371 return error;
2372 }
2373
2374 // CloseDir
2375 status_t
CloseDir(void * node,void * cookie)2376 Volume::CloseDir(void* node, void* cookie)
2377 {
2378 status_t error = _CloseDir(node, cookie);
2379 if (error != B_OK && fFileSystem->GetPortPool()->IsDisconnected()) {
2380 // This isn't really necessary, as the return value is irrelevant to
2381 // the VFS. Haiku ignores it completely. The fsshell returns it to the
2382 // userland, but considers the node closed anyway.
2383 WARN(("Volume::CloseDir(): connection lost, forcing close dir\n"));
2384 return B_OK;
2385 }
2386 return error;
2387 }
2388
2389 // FreeDirCookie
2390 status_t
FreeDirCookie(void * node,void * cookie)2391 Volume::FreeDirCookie(void* node, void* cookie)
2392 {
2393 status_t error = _FreeDirCookie(node, cookie);
2394 bool disconnected = false;
2395 if (error != B_OK && fFileSystem->GetPortPool()->IsDisconnected()) {
2396 // This isn't really necessary, as the return value is irrelevant to
2397 // the VFS. It's completely ignored by Haiku as well as by the fsshell.
2398 WARN(("Volume::FreeDirCookie(): connection lost, forcing free dir "
2399 "cookie\n"));
2400 error = B_OK;
2401 disconnected = true;
2402 }
2403 int32 openDirs = atomic_add(&fOpenDirectories, -1);
2404 if (openDirs <= 1 && disconnected)
2405 _PutAllPendingVNodes();
2406 return error;
2407 }
2408
2409 // ReadDir
2410 status_t
ReadDir(void * _node,void * cookie,void * buffer,size_t bufferSize,uint32 count,uint32 * countRead)2411 Volume::ReadDir(void* _node, void* cookie, void* buffer, size_t bufferSize,
2412 uint32 count, uint32* countRead)
2413 {
2414 VNode* vnode = (VNode*)_node;
2415
2416 *countRead = 0;
2417
2418 // check capability
2419 if (!HasVNodeCapability(vnode, FS_VNODE_CAPABILITY_READ_DIR))
2420 return B_BAD_VALUE;
2421
2422 // get a free port
2423 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
2424 if (!port)
2425 return B_ERROR;
2426 PortReleaser _(fFileSystem->GetPortPool(), port);
2427
2428 // prepare the request
2429 RequestAllocator allocator(port->GetPort());
2430 ReadDirRequest* request;
2431 status_t error = AllocateRequest(allocator, &request);
2432 if (error != B_OK)
2433 return error;
2434
2435 request->volume = fUserlandVolume;
2436 request->node = vnode->clientNode;
2437 request->dirCookie = cookie;
2438 request->bufferSize = bufferSize;
2439 request->count = count;
2440
2441 // send the request
2442 KernelRequestHandler handler(this, READ_DIR_REPLY);
2443 ReadDirReply* reply;
2444 error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
2445 if (error != B_OK)
2446 return error;
2447 RequestReleaser requestReleaser(port, reply);
2448
2449 // process the reply
2450 if (reply->error != B_OK)
2451 return reply->error;
2452 if (reply->count < 0 || reply->count > count)
2453 return B_BAD_DATA;
2454 if ((int32)bufferSize < reply->buffer.GetSize())
2455 return B_BAD_DATA;
2456
2457 PRINT(("Volume::ReadDir(): buffer returned: %" B_PRId32 " bytes\n",
2458 reply->buffer.GetSize()));
2459
2460 *countRead = reply->count;
2461 if (*countRead > 0) {
2462 // copy the buffer -- limit the number of bytes to copy
2463 uint32 maxBytes = *countRead
2464 * (sizeof(struct dirent) + B_FILE_NAME_LENGTH);
2465 uint32 copyBytes = reply->buffer.GetSize();
2466 if (copyBytes > maxBytes)
2467 copyBytes = maxBytes;
2468 memcpy(buffer, reply->buffer.GetData(), copyBytes);
2469 }
2470 _SendReceiptAck(port);
2471 return error;
2472 }
2473
2474 // RewindDir
2475 status_t
RewindDir(void * _node,void * cookie)2476 Volume::RewindDir(void* _node, void* cookie)
2477 {
2478 VNode* vnode = (VNode*)_node;
2479
2480 // check capability
2481 if (!HasVNodeCapability(vnode, FS_VNODE_CAPABILITY_REWIND_DIR))
2482 return B_BAD_VALUE;
2483
2484 // get a free port
2485 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
2486 if (!port)
2487 return B_ERROR;
2488 PortReleaser _(fFileSystem->GetPortPool(), port);
2489
2490 // prepare the request
2491 RequestAllocator allocator(port->GetPort());
2492 RewindDirRequest* request;
2493 status_t error = AllocateRequest(allocator, &request);
2494 if (error != B_OK)
2495 return error;
2496
2497 request->volume = fUserlandVolume;
2498 request->node = vnode->clientNode;
2499 request->dirCookie = cookie;
2500
2501 // send the request
2502 KernelRequestHandler handler(this, REWIND_DIR_REPLY);
2503 RewindDirReply* reply;
2504 error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
2505 if (error != B_OK)
2506 return error;
2507 RequestReleaser requestReleaser(port, reply);
2508
2509 // process the reply
2510 if (reply->error != B_OK)
2511 return reply->error;
2512 return error;
2513 }
2514
2515
2516 // #pragma mark - attribute directories
2517
2518
2519 // OpenAttrDir
2520 status_t
OpenAttrDir(void * _node,void ** cookie)2521 Volume::OpenAttrDir(void* _node, void** cookie)
2522 {
2523 VNode* vnode = (VNode*)_node;
2524
2525 // check capability
2526 if (!HasVNodeCapability(vnode, FS_VNODE_CAPABILITY_OPEN_ATTR_DIR))
2527 return B_BAD_VALUE;
2528
2529 // get a free port
2530 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
2531 if (!port)
2532 return B_ERROR;
2533 PortReleaser _(fFileSystem->GetPortPool(), port);
2534 AutoIncrementer incrementer(&fOpenAttributeDirectories);
2535
2536 // prepare the request
2537 RequestAllocator allocator(port->GetPort());
2538 OpenAttrDirRequest* request;
2539 status_t error = AllocateRequest(allocator, &request);
2540 if (error != B_OK)
2541 return error;
2542
2543 request->volume = fUserlandVolume;
2544 request->node = vnode->clientNode;
2545
2546 // send the request
2547 KernelRequestHandler handler(this, OPEN_ATTR_DIR_REPLY);
2548 OpenAttrDirReply* reply;
2549 error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
2550 if (error != B_OK)
2551 return error;
2552 RequestReleaser requestReleaser(port, reply);
2553
2554 // process the reply
2555 if (reply->error != B_OK)
2556 return reply->error;
2557 incrementer.Keep();
2558 *cookie = reply->attrDirCookie;
2559 return error;
2560 }
2561
2562 // CloseAttrDir
2563 status_t
CloseAttrDir(void * node,void * cookie)2564 Volume::CloseAttrDir(void* node, void* cookie)
2565 {
2566 status_t error = _CloseAttrDir(node, cookie);
2567 if (error != B_OK && fFileSystem->GetPortPool()->IsDisconnected()) {
2568 // This isn't really necessary, as the return value is irrelevant to
2569 // the VFS. Haiku ignores it completely. The fsshell returns it to the
2570 // userland, but considers the node closed anyway.
2571 WARN(("Volume::CloseAttrDir(): connection lost, forcing close attr "
2572 "dir\n"));
2573 return B_OK;
2574 }
2575 return error;
2576 }
2577
2578 // FreeAttrDirCookie
2579 status_t
FreeAttrDirCookie(void * node,void * cookie)2580 Volume::FreeAttrDirCookie(void* node, void* cookie)
2581 {
2582 status_t error = _FreeAttrDirCookie(node, cookie);
2583 bool disconnected = false;
2584 if (error != B_OK && fFileSystem->GetPortPool()->IsDisconnected()) {
2585 // This isn't really necessary, as the return value is irrelevant to
2586 // the VFS. It's completely ignored by Haiku as well as by the fsshell.
2587 WARN(("Volume::FreeAttrDirCookie(): connection lost, forcing free attr "
2588 "dir cookie\n"));
2589 error = B_OK;
2590 disconnected = true;
2591 }
2592
2593 int32 openAttrDirs = atomic_add(&fOpenAttributeDirectories, -1);
2594 if (openAttrDirs <= 1 && disconnected)
2595 _PutAllPendingVNodes();
2596 return error;
2597 }
2598
2599 // ReadAttrDir
2600 status_t
ReadAttrDir(void * _node,void * cookie,void * buffer,size_t bufferSize,uint32 count,uint32 * countRead)2601 Volume::ReadAttrDir(void* _node, void* cookie, void* buffer,
2602 size_t bufferSize, uint32 count, uint32* countRead)
2603 {
2604 VNode* vnode = (VNode*)_node;
2605
2606 // check capability
2607 if (!HasVNodeCapability(vnode, FS_VNODE_CAPABILITY_READ_ATTR_DIR))
2608 return B_BAD_VALUE;
2609
2610 *countRead = 0;
2611 // get a free port
2612 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
2613 if (!port)
2614 return B_ERROR;
2615 PortReleaser _(fFileSystem->GetPortPool(), port);
2616
2617 // prepare the request
2618 RequestAllocator allocator(port->GetPort());
2619 ReadAttrDirRequest* request;
2620 status_t error = AllocateRequest(allocator, &request);
2621 if (error != B_OK)
2622 return error;
2623
2624 request->volume = fUserlandVolume;
2625 request->node = vnode->clientNode;
2626 request->attrDirCookie = cookie;
2627 request->bufferSize = bufferSize;
2628 request->count = count;
2629
2630 // send the request
2631 KernelRequestHandler handler(this, READ_ATTR_DIR_REPLY);
2632 ReadAttrDirReply* reply;
2633 error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
2634 if (error != B_OK)
2635 return error;
2636 RequestReleaser requestReleaser(port, reply);
2637
2638 // process the reply
2639 if (reply->error != B_OK)
2640 return reply->error;
2641 if (reply->count < 0 || reply->count > count)
2642 return B_BAD_DATA;
2643 if ((int32)bufferSize < reply->buffer.GetSize())
2644 return B_BAD_DATA;
2645
2646 *countRead = reply->count;
2647 if (*countRead > 0) {
2648 // copy the buffer -- limit the number of bytes to copy
2649 uint32 maxBytes = *countRead
2650 * (sizeof(struct dirent) + B_ATTR_NAME_LENGTH);
2651 uint32 copyBytes = reply->buffer.GetSize();
2652 if (copyBytes > maxBytes)
2653 copyBytes = maxBytes;
2654 memcpy(buffer, reply->buffer.GetData(), copyBytes);
2655 }
2656 _SendReceiptAck(port);
2657 return error;
2658 }
2659
2660 // RewindAttrDir
2661 status_t
RewindAttrDir(void * _node,void * cookie)2662 Volume::RewindAttrDir(void* _node, void* cookie)
2663 {
2664 VNode* vnode = (VNode*)_node;
2665
2666 // check capability
2667 if (!HasVNodeCapability(vnode, FS_VNODE_CAPABILITY_REWIND_ATTR_DIR))
2668 return B_BAD_VALUE;
2669
2670 // get a free port
2671 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
2672 if (!port)
2673 return B_ERROR;
2674 PortReleaser _(fFileSystem->GetPortPool(), port);
2675
2676 // prepare the request
2677 RequestAllocator allocator(port->GetPort());
2678 RewindAttrDirRequest* request;
2679 status_t error = AllocateRequest(allocator, &request);
2680 if (error != B_OK)
2681 return error;
2682
2683 request->volume = fUserlandVolume;
2684 request->node = vnode->clientNode;
2685 request->attrDirCookie = cookie;
2686
2687 // send the request
2688 KernelRequestHandler handler(this, REWIND_ATTR_DIR_REPLY);
2689 RewindAttrDirReply* reply;
2690 error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
2691 if (error != B_OK)
2692 return error;
2693 RequestReleaser requestReleaser(port, reply);
2694
2695 // process the reply
2696 if (reply->error != B_OK)
2697 return reply->error;
2698 return error;
2699 }
2700
2701
2702 // #pragma mark - attributes
2703
2704 // CreateAttr
2705 status_t
CreateAttr(void * _node,const char * name,uint32 type,int openMode,void ** cookie)2706 Volume::CreateAttr(void* _node, const char* name, uint32 type, int openMode,
2707 void** cookie)
2708 {
2709 VNode* vnode = (VNode*)_node;
2710
2711 // check capability
2712 if (!HasVNodeCapability(vnode, FS_VNODE_CAPABILITY_CREATE_ATTR))
2713 return B_BAD_VALUE;
2714
2715 // get a free port
2716 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
2717 if (!port)
2718 return B_ERROR;
2719 PortReleaser _(fFileSystem->GetPortPool(), port);
2720 AutoIncrementer incrementer(&fOpenAttributes);
2721
2722 // prepare the request
2723 RequestAllocator allocator(port->GetPort());
2724 CreateAttrRequest* request;
2725 status_t error = AllocateRequest(allocator, &request);
2726 if (error != B_OK)
2727 return error;
2728
2729 request->volume = fUserlandVolume;
2730 request->node = vnode->clientNode;
2731 error = allocator.AllocateString(request->name, name);
2732 request->type = type;
2733 request->openMode = openMode;
2734 if (error != B_OK)
2735 return error;
2736
2737 // send the request
2738 KernelRequestHandler handler(this, CREATE_ATTR_REPLY);
2739 CreateAttrReply* reply;
2740 error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
2741 if (error != B_OK)
2742 return error;
2743 RequestReleaser requestReleaser(port, reply);
2744
2745 // process the reply
2746 if (reply->error != B_OK)
2747 return reply->error;
2748 incrementer.Keep();
2749 *cookie = reply->attrCookie;
2750 return error;
2751 }
2752
2753 // OpenAttr
2754 status_t
OpenAttr(void * _node,const char * name,int openMode,void ** cookie)2755 Volume::OpenAttr(void* _node, const char* name, int openMode,
2756 void** cookie)
2757 {
2758 VNode* vnode = (VNode*)_node;
2759
2760 // check capability
2761 if (!HasVNodeCapability(vnode, FS_VNODE_CAPABILITY_OPEN_ATTR))
2762 return B_BAD_VALUE;
2763
2764 // get a free port
2765 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
2766 if (!port)
2767 return B_ERROR;
2768 PortReleaser _(fFileSystem->GetPortPool(), port);
2769 AutoIncrementer incrementer(&fOpenAttributes);
2770
2771 // prepare the request
2772 RequestAllocator allocator(port->GetPort());
2773 OpenAttrRequest* request;
2774 status_t error = AllocateRequest(allocator, &request);
2775 if (error != B_OK)
2776 return error;
2777
2778 request->volume = fUserlandVolume;
2779 request->node = vnode->clientNode;
2780 error = allocator.AllocateString(request->name, name);
2781 request->openMode = openMode;
2782 if (error != B_OK)
2783 return error;
2784
2785 // send the request
2786 KernelRequestHandler handler(this, OPEN_ATTR_REPLY);
2787 OpenAttrReply* reply;
2788 error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
2789 if (error != B_OK)
2790 return error;
2791 RequestReleaser requestReleaser(port, reply);
2792
2793 // process the reply
2794 if (reply->error != B_OK)
2795 return reply->error;
2796 incrementer.Keep();
2797 *cookie = reply->attrCookie;
2798 return error;
2799 }
2800
2801 // CloseAttr
2802 status_t
CloseAttr(void * node,void * cookie)2803 Volume::CloseAttr(void* node, void* cookie)
2804 {
2805 status_t error = _CloseAttr(node, cookie);
2806 if (error != B_OK && fFileSystem->GetPortPool()->IsDisconnected()) {
2807 // This isn't really necessary, as the return value is irrelevant to
2808 // the VFS. Haiku ignores it completely. The fsshell returns it to the
2809 // userland, but considers the node closed anyway.
2810 WARN(("Volume::CloseAttr(): connection lost, forcing close attr\n"));
2811 return B_OK;
2812 }
2813 return error;
2814 }
2815
2816 // FreeAttrCookie
2817 status_t
FreeAttrCookie(void * node,void * cookie)2818 Volume::FreeAttrCookie(void* node, void* cookie)
2819 {
2820 status_t error = _FreeAttrCookie(node, cookie);
2821 bool disconnected = false;
2822 if (error != B_OK && fFileSystem->GetPortPool()->IsDisconnected()) {
2823 // This isn't really necessary, as the return value is irrelevant to
2824 // the VFS. It's completely ignored by Haiku as well as by the fsshell.
2825 WARN(("Volume::FreeAttrCookie(): connection lost, forcing free attr "
2826 "cookie\n"));
2827 error = B_OK;
2828 disconnected = true;
2829 }
2830
2831 int32 openAttributes = atomic_add(&fOpenAttributes, -1);
2832 if (openAttributes <= 1 && disconnected)
2833 _PutAllPendingVNodes();
2834 return error;
2835 }
2836
2837 // ReadAttr
2838 status_t
ReadAttr(void * _node,void * cookie,off_t pos,void * buffer,size_t bufferSize,size_t * bytesRead)2839 Volume::ReadAttr(void* _node, void* cookie, off_t pos,
2840 void* buffer, size_t bufferSize, size_t* bytesRead)
2841 {
2842 VNode* vnode = (VNode*)_node;
2843
2844 *bytesRead = 0;
2845
2846 // check capability
2847 if (!HasVNodeCapability(vnode, FS_VNODE_CAPABILITY_READ_ATTR))
2848 return B_BAD_VALUE;
2849
2850 // get a free port
2851 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
2852 if (!port)
2853 return B_ERROR;
2854 PortReleaser _(fFileSystem->GetPortPool(), port);
2855
2856 // prepare the request
2857 RequestAllocator allocator(port->GetPort());
2858 ReadAttrRequest* request;
2859 status_t error = AllocateRequest(allocator, &request);
2860 if (error != B_OK)
2861 return error;
2862
2863 request->volume = fUserlandVolume;
2864 request->node = vnode->clientNode;
2865 request->attrCookie = cookie;
2866 request->pos = pos;
2867 request->size = bufferSize;
2868
2869 // send the request
2870 KernelRequestHandler handler(this, READ_ATTR_REPLY);
2871 ReadAttrReply* reply;
2872 error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
2873 if (error != B_OK)
2874 return error;
2875 RequestReleaser requestReleaser(port, reply);
2876
2877 // process the reply
2878 if (reply->error != B_OK)
2879 return reply->error;
2880 void* readBuffer = reply->buffer.GetData();
2881 if (reply->bytesRead > (uint32)reply->buffer.GetSize()
2882 || reply->bytesRead > bufferSize) {
2883 return B_BAD_DATA;
2884 }
2885 if (reply->bytesRead > 0
2886 && user_memcpy(buffer, readBuffer, reply->bytesRead) < B_OK) {
2887 return B_BAD_ADDRESS;
2888 }
2889 *bytesRead = reply->bytesRead;
2890 _SendReceiptAck(port);
2891 return error;
2892 }
2893
2894 // WriteAttr
2895 status_t
WriteAttr(void * _node,void * cookie,off_t pos,const void * buffer,size_t bufferSize,size_t * bytesWritten)2896 Volume::WriteAttr(void* _node, void* cookie, off_t pos,
2897 const void* buffer, size_t bufferSize, size_t* bytesWritten)
2898 {
2899 VNode* vnode = (VNode*)_node;
2900
2901 *bytesWritten = 0;
2902
2903 // check capability
2904 if (!HasVNodeCapability(vnode, FS_VNODE_CAPABILITY_WRITE_ATTR))
2905 return B_BAD_VALUE;
2906
2907 // get a free port
2908 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
2909 if (!port)
2910 return B_ERROR;
2911 PortReleaser _(fFileSystem->GetPortPool(), port);
2912
2913 // prepare the request
2914 RequestAllocator allocator(port->GetPort());
2915 WriteAttrRequest* request;
2916 status_t error = AllocateRequest(allocator, &request);
2917 if (error != B_OK)
2918 return error;
2919
2920 request->volume = fUserlandVolume;
2921 request->node = vnode->clientNode;
2922 request->attrCookie = cookie;
2923 request->pos = pos;
2924 error = allocator.AllocateData(request->buffer, buffer, bufferSize, 1);
2925 if (error != B_OK)
2926 return error;
2927
2928 // send the request
2929 KernelRequestHandler handler(this, WRITE_ATTR_REPLY);
2930 WriteAttrReply* reply;
2931 error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
2932 if (error != B_OK)
2933 return error;
2934 RequestReleaser requestReleaser(port, reply);
2935
2936 // process the reply
2937 if (reply->error != B_OK)
2938 return reply->error;
2939 *bytesWritten = reply->bytesWritten;
2940 return error;
2941 }
2942
2943 // ReadAttrStat
2944 status_t
ReadAttrStat(void * _node,void * cookie,struct stat * st)2945 Volume::ReadAttrStat(void* _node, void* cookie, struct stat *st)
2946 {
2947 VNode* vnode = (VNode*)_node;
2948
2949 // check capability
2950 if (!HasVNodeCapability(vnode, FS_VNODE_CAPABILITY_READ_ATTR_STAT))
2951 return B_BAD_VALUE;
2952
2953 // get a free port
2954 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
2955 if (!port)
2956 return B_ERROR;
2957 PortReleaser _(fFileSystem->GetPortPool(), port);
2958
2959 // prepare the request
2960 RequestAllocator allocator(port->GetPort());
2961 ReadAttrStatRequest* request;
2962 status_t error = AllocateRequest(allocator, &request);
2963 if (error != B_OK)
2964 return error;
2965
2966 request->volume = fUserlandVolume;
2967 request->node = vnode->clientNode;
2968 request->attrCookie = cookie;
2969
2970 // send the request
2971 KernelRequestHandler handler(this, READ_ATTR_STAT_REPLY);
2972 ReadAttrStatReply* reply;
2973 error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
2974 if (error != B_OK)
2975 return error;
2976 RequestReleaser requestReleaser(port, reply);
2977
2978 // process the reply
2979 if (reply->error != B_OK)
2980 return reply->error;
2981 *st = reply->st;
2982 return error;
2983 }
2984
2985 // WriteAttrStat
2986 status_t
WriteAttrStat(void * _node,void * cookie,const struct stat * st,int statMask)2987 Volume::WriteAttrStat(void* _node, void* cookie, const struct stat *st,
2988 int statMask)
2989 {
2990 VNode* vnode = (VNode*)_node;
2991
2992 // check capability
2993 if (!HasVNodeCapability(vnode, FS_VNODE_CAPABILITY_WRITE_ATTR_STAT))
2994 return B_BAD_VALUE;
2995
2996 // get a free port
2997 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
2998 if (!port)
2999 return B_ERROR;
3000 PortReleaser _(fFileSystem->GetPortPool(), port);
3001
3002 // prepare the request
3003 RequestAllocator allocator(port->GetPort());
3004 WriteAttrStatRequest* request;
3005 status_t error = AllocateRequest(allocator, &request);
3006 if (error != B_OK)
3007 return error;
3008
3009 request->volume = fUserlandVolume;
3010 request->node = vnode->clientNode;
3011 request->attrCookie = cookie;
3012 request->st = *st;
3013 request->mask = statMask;
3014
3015 // send the request
3016 KernelRequestHandler handler(this, WRITE_ATTR_STAT_REPLY);
3017 WriteAttrStatReply* reply;
3018 error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
3019 if (error != B_OK)
3020 return error;
3021 RequestReleaser requestReleaser(port, reply);
3022
3023 // process the reply
3024 if (reply->error != B_OK)
3025 return reply->error;
3026 return error;
3027 }
3028
3029 // RenameAttr
3030 status_t
RenameAttr(void * _oldNode,const char * oldName,void * _newNode,const char * newName)3031 Volume::RenameAttr(void* _oldNode, const char* oldName, void* _newNode,
3032 const char* newName)
3033 {
3034 VNode* oldVNode = (VNode*)_oldNode;
3035 VNode* newVNode = (VNode*)_newNode;
3036
3037 // check capability
3038 if (!HasVNodeCapability(oldVNode, FS_VNODE_CAPABILITY_RENAME_ATTR))
3039 return B_BAD_VALUE;
3040
3041 // get a free port
3042 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
3043 if (!port)
3044 return B_ERROR;
3045 PortReleaser _(fFileSystem->GetPortPool(), port);
3046
3047 // prepare the request
3048 RequestAllocator allocator(port->GetPort());
3049 RenameAttrRequest* request;
3050 status_t error = AllocateRequest(allocator, &request);
3051 if (error != B_OK)
3052 return error;
3053
3054 request->volume = fUserlandVolume;
3055 request->oldNode = oldVNode->clientNode;
3056 request->newNode = newVNode->clientNode;
3057 error = allocator.AllocateString(request->oldName, oldName);
3058 if (error == B_OK)
3059 error = allocator.AllocateString(request->newName, newName);
3060 if (error != B_OK)
3061 return error;
3062
3063 // send the request
3064 KernelRequestHandler handler(this, RENAME_ATTR_REPLY);
3065 RenameAttrReply* reply;
3066 error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
3067 if (error != B_OK)
3068 return error;
3069 RequestReleaser requestReleaser(port, reply);
3070
3071 // process the reply
3072 if (reply->error != B_OK)
3073 return reply->error;
3074 return error;
3075 }
3076
3077 // RemoveAttr
3078 status_t
RemoveAttr(void * _node,const char * name)3079 Volume::RemoveAttr(void* _node, const char* name)
3080 {
3081 VNode* vnode = (VNode*)_node;
3082
3083 // check capability
3084 if (!HasVNodeCapability(vnode, FS_VNODE_CAPABILITY_REMOVE_ATTR))
3085 return B_BAD_VALUE;
3086
3087 // get a free port
3088 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
3089 if (!port)
3090 return B_ERROR;
3091 PortReleaser _(fFileSystem->GetPortPool(), port);
3092
3093 // prepare the request
3094 RequestAllocator allocator(port->GetPort());
3095 RemoveAttrRequest* request;
3096 status_t error = AllocateRequest(allocator, &request);
3097 if (error != B_OK)
3098 return error;
3099
3100 request->volume = fUserlandVolume;
3101 request->node = vnode->clientNode;
3102 error = allocator.AllocateString(request->name, name);
3103 if (error != B_OK)
3104 return error;
3105
3106 // send the request
3107 KernelRequestHandler handler(this, REMOVE_ATTR_REPLY);
3108 RemoveAttrReply* reply;
3109 error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
3110 if (error != B_OK)
3111 return error;
3112 RequestReleaser requestReleaser(port, reply);
3113
3114 // process the reply
3115 if (reply->error != B_OK)
3116 return reply->error;
3117 return error;
3118 }
3119
3120
3121 // #pragma mark - indices
3122
3123
3124 // OpenIndexDir
3125 status_t
OpenIndexDir(void ** cookie)3126 Volume::OpenIndexDir(void** cookie)
3127 {
3128 // check capability
3129 if (!HasCapability(FS_VOLUME_CAPABILITY_OPEN_INDEX_DIR))
3130 return B_BAD_VALUE;
3131
3132 // get a free port
3133 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
3134 if (!port)
3135 return B_ERROR;
3136 PortReleaser _(fFileSystem->GetPortPool(), port);
3137 AutoIncrementer incrementer(&fOpenIndexDirectories);
3138
3139 // prepare the request
3140 RequestAllocator allocator(port->GetPort());
3141 OpenIndexDirRequest* request;
3142 status_t error = AllocateRequest(allocator, &request);
3143 if (error != B_OK)
3144 return error;
3145
3146 request->volume = fUserlandVolume;
3147
3148 // send the request
3149 KernelRequestHandler handler(this, OPEN_INDEX_DIR_REPLY);
3150 OpenIndexDirReply* reply;
3151 error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
3152 if (error != B_OK)
3153 return error;
3154 RequestReleaser requestReleaser(port, reply);
3155
3156 // process the reply
3157 if (reply->error != B_OK)
3158 return reply->error;
3159 incrementer.Keep();
3160 *cookie = reply->indexDirCookie;
3161 return error;
3162 }
3163
3164 // CloseIndexDir
3165 status_t
CloseIndexDir(void * cookie)3166 Volume::CloseIndexDir(void* cookie)
3167 {
3168 status_t error = _CloseIndexDir(cookie);
3169 if (error != B_OK && fFileSystem->GetPortPool()->IsDisconnected()) {
3170 // This isn't really necessary, as the return value is irrelevant to
3171 // the VFS. Haiku ignores it completely. The fsshell returns it to the
3172 // userland, but considers the node closed anyway.
3173 WARN(("Volume::CloseIndexDir(): connection lost, forcing close "
3174 "index dir\n"));
3175 return B_OK;
3176 }
3177 return error;
3178 }
3179
3180 // FreeIndexDirCookie
3181 status_t
FreeIndexDirCookie(void * cookie)3182 Volume::FreeIndexDirCookie(void* cookie)
3183 {
3184 status_t error = _FreeIndexDirCookie(cookie);
3185 bool disconnected = false;
3186 if (error != B_OK && fFileSystem->GetPortPool()->IsDisconnected()) {
3187 // This isn't really necessary, as the return value is irrelevant to
3188 // the VFS. It's completely ignored by Haiku as well as by the fsshell.
3189 WARN(("Volume::FreeIndexDirCookie(): connection lost, forcing free "
3190 "index dir cookie\n"));
3191 error = B_OK;
3192 disconnected = true;
3193 }
3194
3195 int32 openIndexDirs = atomic_add(&fOpenIndexDirectories, -1);
3196 if (openIndexDirs <= 1 && disconnected)
3197 _PutAllPendingVNodes();
3198 return error;
3199 }
3200
3201 // ReadIndexDir
3202 status_t
ReadIndexDir(void * cookie,void * buffer,size_t bufferSize,uint32 count,uint32 * countRead)3203 Volume::ReadIndexDir(void* cookie, void* buffer, size_t bufferSize,
3204 uint32 count, uint32* countRead)
3205 {
3206 *countRead = 0;
3207
3208 // check capability
3209 if (!HasCapability(FS_VOLUME_CAPABILITY_READ_INDEX_DIR))
3210 return B_BAD_VALUE;
3211
3212 // get a free port
3213 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
3214 if (!port)
3215 return B_ERROR;
3216 PortReleaser _(fFileSystem->GetPortPool(), port);
3217
3218 // prepare the request
3219 RequestAllocator allocator(port->GetPort());
3220 ReadIndexDirRequest* request;
3221 status_t error = AllocateRequest(allocator, &request);
3222 if (error != B_OK)
3223 return error;
3224
3225 request->volume = fUserlandVolume;
3226 request->indexDirCookie = cookie;
3227 request->bufferSize = bufferSize;
3228 request->count = count;
3229
3230 // send the request
3231 KernelRequestHandler handler(this, READ_INDEX_DIR_REPLY);
3232 ReadIndexDirReply* reply;
3233 error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
3234 if (error != B_OK)
3235 return error;
3236 RequestReleaser requestReleaser(port, reply);
3237
3238 // process the reply
3239 if (reply->error != B_OK)
3240 return reply->error;
3241 if (reply->count < 0 || reply->count > count)
3242 return B_BAD_DATA;
3243 if ((int32)bufferSize < reply->buffer.GetSize())
3244 return B_BAD_DATA;
3245
3246 *countRead = reply->count;
3247 if (*countRead > 0) {
3248 // copy the buffer -- limit the number of bytes to copy
3249 uint32 maxBytes = *countRead
3250 * (sizeof(struct dirent) + B_FILE_NAME_LENGTH);
3251 uint32 copyBytes = reply->buffer.GetSize();
3252 if (copyBytes > maxBytes)
3253 copyBytes = maxBytes;
3254 memcpy(buffer, reply->buffer.GetData(), copyBytes);
3255 }
3256 _SendReceiptAck(port);
3257 return error;
3258 }
3259
3260 // RewindIndexDir
3261 status_t
RewindIndexDir(void * cookie)3262 Volume::RewindIndexDir(void* cookie)
3263 {
3264 // check capability
3265 if (!HasCapability(FS_VOLUME_CAPABILITY_REWIND_INDEX_DIR))
3266 return B_BAD_VALUE;
3267
3268 // get a free port
3269 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
3270 if (!port)
3271 return B_ERROR;
3272 PortReleaser _(fFileSystem->GetPortPool(), port);
3273
3274 // prepare the request
3275 RequestAllocator allocator(port->GetPort());
3276 RewindIndexDirRequest* request;
3277 status_t error = AllocateRequest(allocator, &request);
3278 if (error != B_OK)
3279 return error;
3280
3281 request->volume = fUserlandVolume;
3282 request->indexDirCookie = cookie;
3283
3284 // send the request
3285 KernelRequestHandler handler(this, REWIND_INDEX_DIR_REPLY);
3286 RewindIndexDirReply* reply;
3287 error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
3288 if (error != B_OK)
3289 return error;
3290 RequestReleaser requestReleaser(port, reply);
3291
3292 // process the reply
3293 if (reply->error != B_OK)
3294 return reply->error;
3295 return error;
3296 }
3297
3298 // CreateIndex
3299 status_t
CreateIndex(const char * name,uint32 type,uint32 flags)3300 Volume::CreateIndex(const char* name, uint32 type, uint32 flags)
3301 {
3302 // check capability
3303 if (!HasCapability(FS_VOLUME_CAPABILITY_CREATE_INDEX))
3304 return B_BAD_VALUE;
3305
3306 // get a free port
3307 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
3308 if (!port)
3309 return B_ERROR;
3310 PortReleaser _(fFileSystem->GetPortPool(), port);
3311
3312 // prepare the request
3313 RequestAllocator allocator(port->GetPort());
3314 CreateIndexRequest* request;
3315 status_t error = AllocateRequest(allocator, &request);
3316 if (error != B_OK)
3317 return error;
3318
3319 request->volume = fUserlandVolume;
3320 error = allocator.AllocateString(request->name, name);
3321 request->type = type;
3322 request->flags = flags;
3323 if (error != B_OK)
3324 return error;
3325
3326 // send the request
3327 KernelRequestHandler handler(this, CREATE_INDEX_REPLY);
3328 CreateIndexReply* reply;
3329 error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
3330 if (error != B_OK)
3331 return error;
3332 RequestReleaser requestReleaser(port, reply);
3333
3334 // process the reply
3335 if (reply->error != B_OK)
3336 return reply->error;
3337 return error;
3338 }
3339
3340 // RemoveIndex
3341 status_t
RemoveIndex(const char * name)3342 Volume::RemoveIndex(const char* name)
3343 {
3344 // check capability
3345 if (!HasCapability(FS_VOLUME_CAPABILITY_REMOVE_INDEX))
3346 return B_BAD_VALUE;
3347
3348 // get a free port
3349 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
3350 if (!port)
3351 return B_ERROR;
3352 PortReleaser _(fFileSystem->GetPortPool(), port);
3353
3354 // prepare the request
3355 RequestAllocator allocator(port->GetPort());
3356 RemoveIndexRequest* request;
3357 status_t error = AllocateRequest(allocator, &request);
3358 if (error != B_OK)
3359 return error;
3360
3361 request->volume = fUserlandVolume;
3362 error = allocator.AllocateString(request->name, name);
3363 if (error != B_OK)
3364 return error;
3365
3366 // send the request
3367 KernelRequestHandler handler(this, REMOVE_INDEX_REPLY);
3368 RemoveIndexReply* reply;
3369 error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
3370 if (error != B_OK)
3371 return error;
3372 RequestReleaser requestReleaser(port, reply);
3373
3374 // process the reply
3375 if (reply->error != B_OK)
3376 return reply->error;
3377 return error;
3378 }
3379
3380 // ReadIndexStat
3381 status_t
ReadIndexStat(const char * name,struct stat * st)3382 Volume::ReadIndexStat(const char* name, struct stat *st)
3383 {
3384 // check capability
3385 if (!HasCapability(FS_VOLUME_CAPABILITY_READ_INDEX_STAT))
3386 return B_BAD_VALUE;
3387
3388 // get a free port
3389 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
3390 if (!port)
3391 return B_ERROR;
3392 PortReleaser _(fFileSystem->GetPortPool(), port);
3393
3394 // prepare the request
3395 RequestAllocator allocator(port->GetPort());
3396 ReadIndexStatRequest* request;
3397 status_t error = AllocateRequest(allocator, &request);
3398 if (error != B_OK)
3399 return error;
3400
3401 request->volume = fUserlandVolume;
3402 error = allocator.AllocateString(request->name, name);
3403 if (error != B_OK)
3404 return error;
3405
3406 // send the request
3407 KernelRequestHandler handler(this, READ_INDEX_STAT_REPLY);
3408 ReadIndexStatReply* reply;
3409 error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
3410 if (error != B_OK)
3411 return error;
3412 RequestReleaser requestReleaser(port, reply);
3413
3414 // process the reply
3415 if (reply->error != B_OK)
3416 return reply->error;
3417 *st = reply->st;
3418 return error;
3419 }
3420
3421
3422 // #pragma mark - queries
3423
3424
3425 // OpenQuery
3426 status_t
OpenQuery(const char * queryString,uint32 flags,port_id targetPort,uint32 token,void ** cookie)3427 Volume::OpenQuery(const char* queryString, uint32 flags, port_id targetPort,
3428 uint32 token, void** cookie)
3429 {
3430 // check capability
3431 if (!HasCapability(FS_VOLUME_CAPABILITY_OPEN_QUERY))
3432 return B_BAD_VALUE;
3433
3434 // get a free port
3435 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
3436 if (!port)
3437 return B_ERROR;
3438 PortReleaser _(fFileSystem->GetPortPool(), port);
3439 AutoIncrementer incrementer(&fOpenQueries);
3440
3441 // prepare the request
3442 RequestAllocator allocator(port->GetPort());
3443 OpenQueryRequest* request;
3444 status_t error = AllocateRequest(allocator, &request);
3445 if (error != B_OK)
3446 return error;
3447
3448 request->volume = fUserlandVolume;
3449 error = allocator.AllocateString(request->queryString, queryString);
3450 if (error != B_OK)
3451 return error;
3452 request->flags = flags;
3453 request->port = targetPort;
3454 request->token = token;
3455
3456 // send the request
3457 KernelRequestHandler handler(this, OPEN_QUERY_REPLY);
3458 OpenQueryReply* reply;
3459 error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
3460 if (error != B_OK)
3461 return error;
3462 RequestReleaser requestReleaser(port, reply);
3463
3464 // process the reply
3465 if (reply->error != B_OK)
3466 return reply->error;
3467 incrementer.Keep();
3468 *cookie = reply->queryCookie;
3469 return error;
3470 }
3471
3472 // CloseQuery
3473 status_t
CloseQuery(void * cookie)3474 Volume::CloseQuery(void* cookie)
3475 {
3476 status_t error = _CloseQuery(cookie);
3477 if (error != B_OK && fFileSystem->GetPortPool()->IsDisconnected()) {
3478 // This isn't really necessary, as the return value is irrelevant to
3479 // the VFS. Haiku ignores it completely. The fsshell returns it to the
3480 // userland, but considers the node closed anyway.
3481 WARN(("Volume::CloseQuery(): connection lost, forcing close query\n"));
3482 return B_OK;
3483 }
3484 return error;
3485 }
3486
3487 // FreeQueryCookie
3488 status_t
FreeQueryCookie(void * cookie)3489 Volume::FreeQueryCookie(void* cookie)
3490 {
3491 status_t error = _FreeQueryCookie(cookie);
3492 bool disconnected = false;
3493 if (error != B_OK && fFileSystem->GetPortPool()->IsDisconnected()) {
3494 // This isn't really necessary, as the return value is irrelevant to
3495 // the VFS. It's completely ignored by Haiku as well as by the fsshell.
3496 WARN(("Volume::FreeQueryCookie(): connection lost, forcing free "
3497 "query cookie\n"));
3498 error = B_OK;
3499 disconnected = true;
3500 }
3501
3502 int32 openQueries = atomic_add(&fOpenQueries, -1);
3503 if (openQueries <= 1 && disconnected)
3504 _PutAllPendingVNodes();
3505 return error;
3506 }
3507
3508 // ReadQuery
3509 status_t
ReadQuery(void * cookie,void * buffer,size_t bufferSize,uint32 count,uint32 * countRead)3510 Volume::ReadQuery(void* cookie, void* buffer, size_t bufferSize,
3511 uint32 count, uint32* countRead)
3512 {
3513 *countRead = 0;
3514
3515 // check capability
3516 if (!HasCapability(FS_VOLUME_CAPABILITY_READ_QUERY))
3517 return B_BAD_VALUE;
3518
3519 // get a free port
3520 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
3521 if (!port)
3522 return B_ERROR;
3523 PortReleaser _(fFileSystem->GetPortPool(), port);
3524
3525 // prepare the request
3526 RequestAllocator allocator(port->GetPort());
3527 ReadQueryRequest* request;
3528 status_t error = AllocateRequest(allocator, &request);
3529 if (error != B_OK)
3530 return error;
3531
3532 request->volume = fUserlandVolume;
3533 request->queryCookie = cookie;
3534 request->bufferSize = bufferSize;
3535 request->count = count;
3536
3537 // send the request
3538 KernelRequestHandler handler(this, READ_QUERY_REPLY);
3539 ReadQueryReply* reply;
3540 error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
3541 if (error != B_OK)
3542 return error;
3543 RequestReleaser requestReleaser(port, reply);
3544
3545 // process the reply
3546 if (reply->error != B_OK)
3547 return reply->error;
3548 if (reply->count < 0 || reply->count > count)
3549 return B_BAD_DATA;
3550 if ((int32)bufferSize < reply->buffer.GetSize())
3551 return B_BAD_DATA;
3552
3553 *countRead = reply->count;
3554 if (*countRead > 0) {
3555 // copy the buffer -- limit the number of bytes to copy
3556 uint32 maxBytes = *countRead
3557 * (sizeof(struct dirent) + B_FILE_NAME_LENGTH);
3558 uint32 copyBytes = reply->buffer.GetSize();
3559 if (copyBytes > maxBytes)
3560 copyBytes = maxBytes;
3561 memcpy(buffer, reply->buffer.GetData(), copyBytes);
3562 }
3563 _SendReceiptAck(port);
3564 return error;
3565 }
3566
3567 // RewindQuery
3568 status_t
RewindQuery(void * cookie)3569 Volume::RewindQuery(void* cookie)
3570 {
3571 // check capability
3572 if (!HasCapability(FS_VOLUME_CAPABILITY_REWIND_QUERY))
3573 return B_BAD_VALUE;
3574
3575 // get a free port
3576 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
3577 if (!port)
3578 return B_ERROR;
3579 PortReleaser _(fFileSystem->GetPortPool(), port);
3580
3581 // prepare the request
3582 RequestAllocator allocator(port->GetPort());
3583 RewindQueryRequest* request;
3584 status_t error = AllocateRequest(allocator, &request);
3585 if (error != B_OK)
3586 return error;
3587
3588 request->volume = fUserlandVolume;
3589 request->queryCookie = cookie;
3590
3591 // send the request
3592 KernelRequestHandler handler(this, REWIND_QUERY_REPLY);
3593 RewindQueryReply* reply;
3594 error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
3595 if (error != B_OK)
3596 return error;
3597 RequestReleaser requestReleaser(port, reply);
3598
3599 // process the reply
3600 if (reply->error != B_OK)
3601 return reply->error;
3602 return error;
3603 }
3604
3605 // #pragma mark -
3606 // #pragma mark ----- private implementations -----
3607
3608
3609 // _InitVolumeOps
3610 void
_InitVolumeOps()3611 Volume::_InitVolumeOps()
3612 {
3613 memcpy(&fVolumeOps, &gUserlandFSVolumeOps, sizeof(fs_volume_ops));
3614
3615 #undef CLEAR_UNSUPPORTED
3616 #define CLEAR_UNSUPPORTED(capability, op) \
3617 if (!fCapabilities.Get(capability)) \
3618 fVolumeOps.op = NULL
3619
3620 // FS operations
3621 // FS_VOLUME_CAPABILITY_UNMOUNT: unmount
3622 // always needed
3623
3624 // FS_VOLUME_CAPABILITY_READ_FS_INFO: read_fs_info
3625 // always needed
3626 CLEAR_UNSUPPORTED(FS_VOLUME_CAPABILITY_WRITE_FS_INFO, write_fs_info);
3627 CLEAR_UNSUPPORTED(FS_VOLUME_CAPABILITY_SYNC, sync);
3628
3629 // vnode operations
3630 // FS_VOLUME_CAPABILITY_GET_VNODE: get_vnode
3631 // always needed
3632
3633 // index directory & index operations
3634 CLEAR_UNSUPPORTED(FS_VOLUME_CAPABILITY_OPEN_INDEX_DIR, open_index_dir);
3635 // FS_VOLUME_CAPABILITY_CLOSE_INDEX_DIR: close_index_dir
3636 // always needed
3637 // FS_VOLUME_CAPABILITY_FREE_INDEX_DIR_COOKIE: free_index_dir_cookie
3638 // always needed
3639 CLEAR_UNSUPPORTED(FS_VOLUME_CAPABILITY_READ_INDEX_DIR, read_index_dir);
3640 CLEAR_UNSUPPORTED(FS_VOLUME_CAPABILITY_REWIND_INDEX_DIR, rewind_index_dir);
3641
3642 CLEAR_UNSUPPORTED(FS_VOLUME_CAPABILITY_CREATE_INDEX, create_index);
3643 CLEAR_UNSUPPORTED(FS_VOLUME_CAPABILITY_REMOVE_INDEX, remove_index);
3644 CLEAR_UNSUPPORTED(FS_VOLUME_CAPABILITY_READ_INDEX_STAT, read_index_stat);
3645
3646 // query operations
3647 CLEAR_UNSUPPORTED(FS_VOLUME_CAPABILITY_OPEN_QUERY, open_query);
3648 // FS_VOLUME_CAPABILITY_CLOSE_QUERY: close_query
3649 // always needed
3650 // FS_VOLUME_CAPABILITY_FREE_QUERY_COOKIE: free_query_cookie
3651 // always needed
3652 CLEAR_UNSUPPORTED(FS_VOLUME_CAPABILITY_READ_QUERY, read_query);
3653 CLEAR_UNSUPPORTED(FS_VOLUME_CAPABILITY_REWIND_QUERY, rewind_query);
3654
3655 #undef CLEAR_UNSUPPORTED
3656 }
3657
3658
3659 // #pragma mark -
3660
3661
3662 // _Mount
3663 status_t
_Mount(const char * device,uint32 flags,const char * parameters)3664 Volume::_Mount(const char* device, uint32 flags, const char* parameters)
3665 {
3666 // get a free port
3667 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
3668 if (!port)
3669 return B_ERROR;
3670 PortReleaser _(fFileSystem->GetPortPool(), port);
3671
3672 // get the current working directory
3673 char cwd[B_PATH_NAME_LENGTH];
3674 if (!getcwd(cwd, sizeof(cwd)))
3675 return errno;
3676
3677 // prepare the request
3678 RequestAllocator allocator(port->GetPort());
3679 MountVolumeRequest* request;
3680 status_t error = AllocateRequest(allocator, &request);
3681 if (error != B_OK)
3682 return error;
3683
3684 request->nsid = GetID();
3685 error = allocator.AllocateString(request->cwd, cwd);
3686 if (error == B_OK)
3687 error = allocator.AllocateString(request->device, device);
3688 request->flags = flags;
3689 if (error == B_OK)
3690 error = allocator.AllocateString(request->parameters, parameters);
3691 if (error != B_OK)
3692 return error;
3693
3694 // send the request
3695 KernelRequestHandler handler(this, MOUNT_VOLUME_REPLY);
3696 MountVolumeReply* reply;
3697 error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
3698 if (error != B_OK)
3699 return error;
3700 RequestReleaser requestReleaser(port, reply);
3701
3702 // process the reply
3703 if (reply->error != B_OK)
3704 return reply->error;
3705 fRootID = reply->rootID;
3706 fUserlandVolume = reply->volume;
3707 fCapabilities = reply->capabilities;
3708
3709 return error;
3710 }
3711
3712 // _Unmount
3713 status_t
_Unmount()3714 Volume::_Unmount()
3715 {
3716 // get a free port
3717 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
3718 if (!port)
3719 return B_ERROR;
3720 PortReleaser _(fFileSystem->GetPortPool(), port);
3721
3722 // prepare the request
3723 RequestAllocator allocator(port->GetPort());
3724 UnmountVolumeRequest* request;
3725 status_t error = AllocateRequest(allocator, &request);
3726 if (error != B_OK)
3727 return error;
3728
3729 request->volume = fUserlandVolume;
3730
3731 // send the request
3732 KernelRequestHandler handler(this, UNMOUNT_VOLUME_REPLY);
3733 UnmountVolumeReply* reply;
3734 error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
3735 if (error != B_OK)
3736 return error;
3737 RequestReleaser requestReleaser(port, reply);
3738
3739 // process the reply
3740 if (reply->error != B_OK)
3741 return reply->error;
3742 return error;
3743 }
3744
3745 // _ReadFSInfo
3746 status_t
_ReadFSInfo(fs_info * info)3747 Volume::_ReadFSInfo(fs_info* info)
3748 {
3749 // check capability
3750 if (!HasCapability(FS_VOLUME_CAPABILITY_READ_FS_INFO))
3751 return B_BAD_VALUE;
3752
3753 // get a free port
3754 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
3755 if (!port)
3756 return B_ERROR;
3757 PortReleaser _(fFileSystem->GetPortPool(), port);
3758
3759 // prepare the request
3760 RequestAllocator allocator(port->GetPort());
3761 ReadFSInfoRequest* request;
3762 status_t error = AllocateRequest(allocator, &request);
3763 if (error != B_OK)
3764 return error;
3765
3766 request->volume = fUserlandVolume;
3767
3768 // send the request
3769 KernelRequestHandler handler(this, READ_FS_INFO_REPLY);
3770 ReadFSInfoReply* reply;
3771 error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
3772 if (error != B_OK)
3773 return error;
3774 RequestReleaser requestReleaser(port, reply);
3775
3776 // process the reply
3777 if (reply->error != B_OK)
3778 return reply->error;
3779 *info = reply->info;
3780 return error;
3781 }
3782
3783 // _Lookup
3784 status_t
_Lookup(void * _dir,const char * entryName,ino_t * vnid)3785 Volume::_Lookup(void* _dir, const char* entryName, ino_t* vnid)
3786 {
3787 VNode* vnode = (VNode*)_dir;
3788
3789 // get a free port
3790 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
3791 if (!port)
3792 return B_ERROR;
3793 PortReleaser _(fFileSystem->GetPortPool(), port);
3794
3795 // prepare the request
3796 RequestAllocator allocator(port->GetPort());
3797 LookupRequest* request;
3798 status_t error = AllocateRequest(allocator, &request);
3799 if (error != B_OK)
3800 return error;
3801 request->volume = fUserlandVolume;
3802 request->node = vnode->clientNode;
3803 error = allocator.AllocateString(request->entryName, entryName);
3804 if (error != B_OK)
3805 return error;
3806
3807 // send the request
3808 KernelRequestHandler handler(this, LOOKUP_REPLY);
3809 LookupReply* reply;
3810 error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
3811 if (error != B_OK)
3812 return error;
3813 RequestReleaser requestReleaser(port, reply);
3814
3815 // process the reply
3816 if (reply->error != B_OK)
3817 return reply->error;
3818 *vnid = reply->vnid;
3819
3820 // The VFS will balance the get_vnode() call for the FS.
3821 _DecrementVNodeCount(*vnid);
3822 return error;
3823 }
3824
3825 // _WriteVNode
3826 status_t
_WriteVNode(void * _node,bool reenter)3827 Volume::_WriteVNode(void* _node, bool reenter)
3828 {
3829 VNode* vnode = (VNode*)_node;
3830
3831 // At any rate remove the vnode from our map and delete it. We don't do that
3832 // right now, though, since we might still need to serve file cache requests
3833 // from the client FS.
3834 VNodeRemover nodeRemover(this, vnode);
3835
3836 void* clientNode = vnode->clientNode;
3837
3838 // get a free port
3839 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
3840 if (!port)
3841 return B_ERROR;
3842 PortReleaser _(fFileSystem->GetPortPool(), port);
3843
3844 // prepare the request
3845 RequestAllocator allocator(port->GetPort());
3846 WriteVNodeRequest* request;
3847 status_t error = AllocateRequest(allocator, &request);
3848 if (error != B_OK)
3849 return error;
3850 request->volume = fUserlandVolume;
3851 request->node = clientNode;
3852 request->reenter = reenter;
3853
3854 // send the request
3855 KernelRequestHandler handler(this, WRITE_VNODE_REPLY);
3856 WriteVNodeReply* reply;
3857 error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
3858 if (error != B_OK)
3859 return error;
3860 RequestReleaser requestReleaser(port, reply);
3861
3862 // process the reply
3863 if (reply->error != B_OK)
3864 return reply->error;
3865 return error;
3866 }
3867
3868 // _ReadStat
3869 status_t
_ReadStat(void * _node,struct stat * st)3870 Volume::_ReadStat(void* _node, struct stat* st)
3871 {
3872 VNode* vnode = (VNode*)_node;
3873
3874 // check capability
3875 if (!HasVNodeCapability(vnode, FS_VNODE_CAPABILITY_READ_STAT))
3876 return B_BAD_VALUE;
3877
3878 // get a free port
3879 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
3880 if (!port)
3881 return B_ERROR;
3882 PortReleaser _(fFileSystem->GetPortPool(), port);
3883
3884 // prepare the request
3885 RequestAllocator allocator(port->GetPort());
3886 ReadStatRequest* request;
3887 status_t error = AllocateRequest(allocator, &request);
3888 if (error != B_OK)
3889 return error;
3890
3891 request->volume = fUserlandVolume;
3892 request->node = vnode->clientNode;
3893
3894 // send the request
3895 KernelRequestHandler handler(this, READ_STAT_REPLY);
3896 ReadStatReply* reply;
3897 error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
3898 if (error != B_OK)
3899 return error;
3900 RequestReleaser requestReleaser(port, reply);
3901
3902 // process the reply
3903 if (reply->error != B_OK)
3904 return reply->error;
3905 *st = reply->st;
3906 return error;
3907 }
3908
3909 // _Close
3910 status_t
_Close(void * _node,void * cookie)3911 Volume::_Close(void* _node, void* cookie)
3912 {
3913 VNode* vnode = (VNode*)_node;
3914
3915 // check capability
3916 if (!HasVNodeCapability(vnode, FS_VNODE_CAPABILITY_CLOSE))
3917 return B_OK;
3918
3919 // get a free port
3920 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
3921 if (!port)
3922 return B_ERROR;
3923 PortReleaser _(fFileSystem->GetPortPool(), port);
3924
3925 // prepare the request
3926 RequestAllocator allocator(port->GetPort());
3927 CloseRequest* request;
3928 status_t error = AllocateRequest(allocator, &request);
3929 if (error != B_OK)
3930 return error;
3931
3932 request->volume = fUserlandVolume;
3933 request->node = vnode->clientNode;
3934 request->fileCookie = cookie;
3935
3936 // send the request
3937 KernelRequestHandler handler(this, CLOSE_REPLY);
3938 CloseReply* reply;
3939 error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
3940 if (error != B_OK)
3941 return error;
3942 RequestReleaser requestReleaser(port, reply);
3943
3944 // process the reply
3945 if (reply->error != B_OK)
3946 return reply->error;
3947 return error;
3948 }
3949
3950 // _FreeCookie
3951 status_t
_FreeCookie(void * _node,void * cookie)3952 Volume::_FreeCookie(void* _node, void* cookie)
3953 {
3954 VNode* vnode = (VNode*)_node;
3955
3956 // check capability
3957 if (!HasVNodeCapability(vnode, FS_VNODE_CAPABILITY_FREE_COOKIE))
3958 return B_OK;
3959
3960 // get a free port
3961 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
3962 if (!port)
3963 return B_ERROR;
3964 PortReleaser _(fFileSystem->GetPortPool(), port);
3965
3966 // prepare the request
3967 RequestAllocator allocator(port->GetPort());
3968 FreeCookieRequest* request;
3969 status_t error = AllocateRequest(allocator, &request);
3970 if (error != B_OK)
3971 return error;
3972
3973 request->volume = fUserlandVolume;
3974 request->node = vnode->clientNode;
3975 request->fileCookie = cookie;
3976
3977 // send the request
3978 KernelRequestHandler handler(this, FREE_COOKIE_REPLY);
3979 FreeCookieReply* reply;
3980 error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
3981 if (error != B_OK)
3982 return error;
3983 RequestReleaser requestReleaser(port, reply);
3984
3985 // process the reply
3986 if (reply->error != B_OK)
3987 return reply->error;
3988 return error;
3989 }
3990
3991 // _CloseDir
3992 status_t
_CloseDir(void * _node,void * cookie)3993 Volume::_CloseDir(void* _node, void* cookie)
3994 {
3995 VNode* vnode = (VNode*)_node;
3996
3997 // check capability
3998 if (!HasVNodeCapability(vnode, FS_VNODE_CAPABILITY_CLOSE_DIR))
3999 return B_OK;
4000
4001 // get a free port
4002 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
4003 if (!port)
4004 return B_ERROR;
4005 PortReleaser _(fFileSystem->GetPortPool(), port);
4006
4007 // prepare the request
4008 RequestAllocator allocator(port->GetPort());
4009 CloseDirRequest* request;
4010 status_t error = AllocateRequest(allocator, &request);
4011 if (error != B_OK)
4012 return error;
4013
4014 request->volume = fUserlandVolume;
4015 request->node = vnode->clientNode;
4016 request->dirCookie = cookie;
4017
4018 // send the request
4019 KernelRequestHandler handler(this, CLOSE_DIR_REPLY);
4020 CloseDirReply* reply;
4021 error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
4022 if (error != B_OK)
4023 return error;
4024 RequestReleaser requestReleaser(port, reply);
4025
4026 // process the reply
4027 if (reply->error != B_OK)
4028 return reply->error;
4029 return error;
4030 }
4031
4032 // _FreeDirCookie
4033 status_t
_FreeDirCookie(void * _node,void * cookie)4034 Volume::_FreeDirCookie(void* _node, void* cookie)
4035 {
4036 VNode* vnode = (VNode*)_node;
4037
4038 // check capability
4039 if (!HasVNodeCapability(vnode, FS_VNODE_CAPABILITY_FREE_DIR_COOKIE))
4040 return B_OK;
4041
4042 // get a free port
4043 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
4044 if (!port)
4045 return B_ERROR;
4046 PortReleaser _(fFileSystem->GetPortPool(), port);
4047
4048 // prepare the request
4049 RequestAllocator allocator(port->GetPort());
4050 FreeDirCookieRequest* request;
4051 status_t error = AllocateRequest(allocator, &request);
4052 if (error != B_OK)
4053 return error;
4054
4055 request->volume = fUserlandVolume;
4056 request->node = vnode->clientNode;
4057 request->dirCookie = cookie;
4058
4059 // send the request
4060 KernelRequestHandler handler(this, FREE_DIR_COOKIE_REPLY);
4061 FreeDirCookieReply* reply;
4062 error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
4063 if (error != B_OK)
4064 return error;
4065 RequestReleaser requestReleaser(port, reply);
4066
4067 // process the reply
4068 if (reply->error != B_OK)
4069 return reply->error;
4070 return error;
4071 }
4072
4073 // _CloseAttrDir
4074 status_t
_CloseAttrDir(void * _node,void * cookie)4075 Volume::_CloseAttrDir(void* _node, void* cookie)
4076 {
4077 VNode* vnode = (VNode*)_node;
4078
4079 // check capability
4080 if (!HasVNodeCapability(vnode, FS_VNODE_CAPABILITY_CLOSE_ATTR_DIR))
4081 return B_OK;
4082
4083 // get a free port
4084 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
4085 if (!port)
4086 return B_ERROR;
4087 PortReleaser _(fFileSystem->GetPortPool(), port);
4088
4089 // prepare the request
4090 RequestAllocator allocator(port->GetPort());
4091 CloseAttrDirRequest* request;
4092 status_t error = AllocateRequest(allocator, &request);
4093 if (error != B_OK)
4094 return error;
4095
4096 request->volume = fUserlandVolume;
4097 request->node = vnode->clientNode;
4098 request->attrDirCookie = cookie;
4099
4100 // send the request
4101 KernelRequestHandler handler(this, CLOSE_ATTR_DIR_REPLY);
4102 CloseAttrDirReply* reply;
4103 error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
4104 if (error != B_OK)
4105 return error;
4106 RequestReleaser requestReleaser(port, reply);
4107
4108 // process the reply
4109 if (reply->error != B_OK)
4110 return reply->error;
4111 return error;
4112 }
4113
4114 // _FreeAttrDirCookie
4115 status_t
_FreeAttrDirCookie(void * _node,void * cookie)4116 Volume::_FreeAttrDirCookie(void* _node, void* cookie)
4117 {
4118 VNode* vnode = (VNode*)_node;
4119
4120 // check capability
4121 if (!HasVNodeCapability(vnode, FS_VNODE_CAPABILITY_FREE_ATTR_DIR_COOKIE))
4122 return B_OK;
4123
4124 // get a free port
4125 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
4126 if (!port)
4127 return B_ERROR;
4128 PortReleaser _(fFileSystem->GetPortPool(), port);
4129
4130 // prepare the request
4131 RequestAllocator allocator(port->GetPort());
4132 FreeAttrDirCookieRequest* request;
4133 status_t error = AllocateRequest(allocator, &request);
4134 if (error != B_OK)
4135 return error;
4136
4137 request->volume = fUserlandVolume;
4138 request->node = vnode->clientNode;
4139 request->attrDirCookie = cookie;
4140
4141 // send the request
4142 KernelRequestHandler handler(this, FREE_ATTR_DIR_COOKIE_REPLY);
4143 FreeAttrDirCookieReply* reply;
4144 error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
4145 if (error != B_OK)
4146 return error;
4147 RequestReleaser requestReleaser(port, reply);
4148
4149 // process the reply
4150 if (reply->error != B_OK)
4151 return reply->error;
4152 return error;
4153 }
4154
4155 // _CloseAttr
4156 status_t
_CloseAttr(void * _node,void * cookie)4157 Volume::_CloseAttr(void* _node, void* cookie)
4158 {
4159 VNode* vnode = (VNode*)_node;
4160
4161 // check capability
4162 if (!HasVNodeCapability(vnode, FS_VNODE_CAPABILITY_CLOSE_ATTR))
4163 return B_OK;
4164
4165 // get a free port
4166 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
4167 if (!port)
4168 return B_ERROR;
4169 PortReleaser _(fFileSystem->GetPortPool(), port);
4170
4171 // prepare the request
4172 RequestAllocator allocator(port->GetPort());
4173 CloseAttrRequest* request;
4174 status_t error = AllocateRequest(allocator, &request);
4175 if (error != B_OK)
4176 return error;
4177
4178 request->volume = fUserlandVolume;
4179 request->node = vnode->clientNode;
4180 request->attrCookie = cookie;
4181
4182 // send the request
4183 KernelRequestHandler handler(this, CLOSE_ATTR_REPLY);
4184 CloseAttrReply* reply;
4185 error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
4186 if (error != B_OK)
4187 return error;
4188 RequestReleaser requestReleaser(port, reply);
4189
4190 // process the reply
4191 if (reply->error != B_OK)
4192 return reply->error;
4193 return error;
4194 }
4195
4196 // _FreeAttrCookie
4197 status_t
_FreeAttrCookie(void * _node,void * cookie)4198 Volume::_FreeAttrCookie(void* _node, void* cookie)
4199 {
4200 VNode* vnode = (VNode*)_node;
4201
4202 // check capability
4203 if (!HasVNodeCapability(vnode, FS_VNODE_CAPABILITY_FREE_ATTR_COOKIE))
4204 return B_OK;
4205
4206 // get a free port
4207 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
4208 if (!port)
4209 return B_ERROR;
4210 PortReleaser _(fFileSystem->GetPortPool(), port);
4211
4212 // prepare the request
4213 RequestAllocator allocator(port->GetPort());
4214 FreeAttrCookieRequest* request;
4215 status_t error = AllocateRequest(allocator, &request);
4216 if (error != B_OK)
4217 return error;
4218
4219 request->volume = fUserlandVolume;
4220 request->node = vnode->clientNode;
4221 request->attrCookie = cookie;
4222
4223 // send the request
4224 KernelRequestHandler handler(this, FREE_ATTR_COOKIE_REPLY);
4225 FreeAttrCookieReply* reply;
4226 error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
4227 if (error != B_OK)
4228 return error;
4229 RequestReleaser requestReleaser(port, reply);
4230
4231 // process the reply
4232 if (reply->error != B_OK)
4233 return reply->error;
4234 return error;
4235 }
4236
4237 // _CloseIndexDir
4238 status_t
_CloseIndexDir(void * cookie)4239 Volume::_CloseIndexDir(void* cookie)
4240 {
4241 // check capability
4242 if (!HasCapability(FS_VOLUME_CAPABILITY_CLOSE_INDEX_DIR))
4243 return B_OK;
4244
4245 // get a free port
4246 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
4247 if (!port)
4248 return B_ERROR;
4249 PortReleaser _(fFileSystem->GetPortPool(), port);
4250
4251 // prepare the request
4252 RequestAllocator allocator(port->GetPort());
4253 CloseIndexDirRequest* request;
4254 status_t error = AllocateRequest(allocator, &request);
4255 if (error != B_OK)
4256 return error;
4257
4258 request->volume = fUserlandVolume;
4259 request->indexDirCookie = cookie;
4260
4261 // send the request
4262 KernelRequestHandler handler(this, CLOSE_INDEX_DIR_REPLY);
4263 CloseIndexDirReply* reply;
4264 error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
4265 if (error != B_OK)
4266 return error;
4267 RequestReleaser requestReleaser(port, reply);
4268
4269 // process the reply
4270 if (reply->error != B_OK)
4271 return reply->error;
4272 return error;
4273 }
4274
4275 // _FreeIndexDirCookie
4276 status_t
_FreeIndexDirCookie(void * cookie)4277 Volume::_FreeIndexDirCookie(void* cookie)
4278 {
4279 // check capability
4280 if (!HasCapability(FS_VOLUME_CAPABILITY_FREE_INDEX_DIR_COOKIE))
4281 return B_OK;
4282
4283 // get a free port
4284 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
4285 if (!port)
4286 return B_ERROR;
4287 PortReleaser _(fFileSystem->GetPortPool(), port);
4288
4289 // prepare the request
4290 RequestAllocator allocator(port->GetPort());
4291 FreeIndexDirCookieRequest* request;
4292 status_t error = AllocateRequest(allocator, &request);
4293 if (error != B_OK)
4294 return error;
4295
4296 request->volume = fUserlandVolume;
4297 request->indexDirCookie = cookie;
4298
4299 // send the request
4300 KernelRequestHandler handler(this, FREE_INDEX_DIR_COOKIE_REPLY);
4301 FreeIndexDirCookieReply* reply;
4302 error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
4303 if (error != B_OK)
4304 return error;
4305 RequestReleaser requestReleaser(port, reply);
4306
4307 // process the reply
4308 if (reply->error != B_OK)
4309 return reply->error;
4310 return error;
4311 }
4312
4313 // _CloseQuery
4314 status_t
_CloseQuery(void * cookie)4315 Volume::_CloseQuery(void* cookie)
4316 {
4317 // check capability
4318 if (!HasCapability(FS_VOLUME_CAPABILITY_CLOSE_QUERY))
4319 return B_OK;
4320
4321 // get a free port
4322 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
4323 if (!port)
4324 return B_ERROR;
4325 PortReleaser _(fFileSystem->GetPortPool(), port);
4326
4327 // prepare the request
4328 RequestAllocator allocator(port->GetPort());
4329 CloseQueryRequest* request;
4330 status_t error = AllocateRequest(allocator, &request);
4331 if (error != B_OK)
4332 return error;
4333
4334 request->volume = fUserlandVolume;
4335 request->queryCookie = cookie;
4336
4337 // send the request
4338 KernelRequestHandler handler(this, CLOSE_QUERY_REPLY);
4339 CloseQueryReply* reply;
4340 error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
4341 if (error != B_OK)
4342 return error;
4343 RequestReleaser requestReleaser(port, reply);
4344
4345 // process the reply
4346 if (reply->error != B_OK)
4347 return reply->error;
4348 return error;
4349 }
4350
4351 // _FreeQueryCookie
4352 status_t
_FreeQueryCookie(void * cookie)4353 Volume::_FreeQueryCookie(void* cookie)
4354 {
4355 // check capability
4356 if (!HasCapability(FS_VOLUME_CAPABILITY_FREE_QUERY_COOKIE))
4357 return B_OK;
4358
4359 // get a free port
4360 RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
4361 if (!port)
4362 return B_ERROR;
4363 PortReleaser _(fFileSystem->GetPortPool(), port);
4364
4365 // prepare the request
4366 RequestAllocator allocator(port->GetPort());
4367 FreeQueryCookieRequest* request;
4368 status_t error = AllocateRequest(allocator, &request);
4369 if (error != B_OK)
4370 return error;
4371
4372 request->volume = fUserlandVolume;
4373 request->queryCookie = cookie;
4374
4375 // send the request
4376 KernelRequestHandler handler(this, FREE_QUERY_COOKIE_REPLY);
4377 FreeQueryCookieReply* reply;
4378 error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
4379 if (error != B_OK)
4380 return error;
4381 RequestReleaser requestReleaser(port, reply);
4382
4383 // process the reply
4384 if (reply->error != B_OK)
4385 return reply->error;
4386 return error;
4387 }
4388
4389 // _SendRequest
4390 status_t
_SendRequest(RequestPort * port,RequestAllocator * allocator,RequestHandler * handler,Request ** reply)4391 Volume::_SendRequest(RequestPort* port, RequestAllocator* allocator,
4392 RequestHandler* handler, Request** reply)
4393 {
4394 // fill in the caller info
4395 KernelRequest* request = static_cast<KernelRequest*>(
4396 allocator->GetRequest());
4397 Thread* thread = thread_get_current_thread();
4398 request->team = thread->team->id;
4399 request->thread = thread->id;
4400 request->user = geteuid();
4401 request->group = getegid();
4402
4403 if (!fFileSystem->IsUserlandServerThread())
4404 return port->SendRequest(allocator, handler, reply);
4405 // Here it gets dangerous: a thread of the userland server team being here
4406 // calls for trouble. We try receiving the request with a timeout, and
4407 // close the port -- which will disconnect the whole FS.
4408 status_t error = port->SendRequest(allocator, handler, reply,
4409 kUserlandServerlandPortTimeout);
4410 if (error == B_TIMED_OUT || error == B_WOULD_BLOCK)
4411 port->Close();
4412 return error;
4413 }
4414
4415 // _SendReceiptAck
4416 status_t
_SendReceiptAck(RequestPort * port)4417 Volume::_SendReceiptAck(RequestPort* port)
4418 {
4419 RequestAllocator allocator(port->GetPort());
4420 ReceiptAckReply* request;
4421 status_t error = AllocateRequest(allocator, &request);
4422 if (error != B_OK)
4423 return error;
4424 return port->SendRequest(&allocator);
4425 }
4426
4427 // _IncrementVNodeCount
4428 void
_IncrementVNodeCount(ino_t vnid)4429 Volume::_IncrementVNodeCount(ino_t vnid)
4430 {
4431 MutexLocker _(fLock);
4432
4433 if (!fVNodeCountingEnabled)
4434 return;
4435
4436 VNode* vnode = fVNodes->Lookup(vnid);
4437 if (vnode == NULL) {
4438 ERROR(("Volume::_IncrementVNodeCount(): Node with ID %" B_PRId64
4439 " not known!\n", vnid));
4440 return;
4441 }
4442
4443 vnode->useCount++;
4444 //PRINT(("_IncrementVNodeCount(%lld): count: %ld, fVNodeCountMap size: %ld\n", vnid, *count, fVNodeCountMap->Size()));
4445 }
4446
4447
4448 // _DecrementVNodeCount
4449 void
_DecrementVNodeCount(ino_t vnid)4450 Volume::_DecrementVNodeCount(ino_t vnid)
4451 {
4452 MutexLocker _(fLock);
4453
4454 if (!fVNodeCountingEnabled)
4455 return;
4456
4457 VNode* vnode = fVNodes->Lookup(vnid);
4458 if (vnode == NULL) {
4459 ERROR(("Volume::_DecrementVNodeCount(): Node with ID %" B_PRId64 " not "
4460 "known!\n", vnid));
4461 return;
4462 }
4463
4464 vnode->useCount--;
4465 //PRINT(("_DecrementVNodeCount(%lld): count: %ld, fVNodeCountMap size: %ld\n", vnid, tmpCount, fVNodeCountMap->Size()));
4466 }
4467
4468
4469 // _RemoveInvalidVNode
4470 void
_RemoveInvalidVNode(ino_t vnid)4471 Volume::_RemoveInvalidVNode(ino_t vnid)
4472 {
4473 MutexLocker locker(fLock);
4474
4475 VNode* vnode = fVNodes->Lookup(vnid);
4476 if (vnode == NULL) {
4477 ERROR(("Volume::_RemoveInvalidVNode(): Node with ID %" B_PRId64
4478 " not known!\n", vnid));
4479 return;
4480 }
4481
4482 fVNodes->Remove(vnode);
4483 locker.Unlock();
4484
4485 // release all references acquired so far
4486 if (fVNodeCountingEnabled) {
4487 for (; vnode->useCount > 0; vnode->useCount--)
4488 put_vnode(fFSVolume, vnid);
4489 }
4490
4491 vnode->Delete(this);
4492 }
4493
4494
4495 // _InternalIOCtl
4496 status_t
_InternalIOCtl(userlandfs_ioctl * buffer,int32 bufferSize)4497 Volume::_InternalIOCtl(userlandfs_ioctl* buffer, int32 bufferSize)
4498 {
4499 if (buffer->version != USERLAND_IOCTL_CURRENT_VERSION)
4500 return B_BAD_VALUE;
4501 status_t result = B_OK;
4502 switch (buffer->command) {
4503 case USERLAND_IOCTL_PUT_ALL_PENDING_VNODES:
4504 result = _PutAllPendingVNodes();
4505 break;
4506 default:
4507 return B_BAD_VALUE;
4508 }
4509 buffer->error = result;
4510 return B_OK;
4511 }
4512
4513 // _PutAllPendingVNodes
4514 status_t
_PutAllPendingVNodes()4515 Volume::_PutAllPendingVNodes()
4516 {
4517 PRINT(("Volume::_PutAllPendingVNodes()\n"));
4518 if (!fFileSystem->GetPortPool()->IsDisconnected()) {
4519 PRINT(("Volume::_PutAllPendingVNodes() failed: still connected\n"));
4520 return USERLAND_IOCTL_STILL_CONNECTED;
4521 }
4522
4523 MutexLocker locker(fLock);
4524
4525 if (!fVNodeCountingEnabled) {
4526 PRINT(("Volume::_PutAllPendingVNodes() failed: vnode counting "
4527 "disabled\n"));
4528 return USERLAND_IOCTL_VNODE_COUNTING_DISABLED;
4529 }
4530 // Check whether there are open entities at the moment.
4531 if (atomic_get(&fOpenFiles) > 0) {
4532 PRINT(("Volume::_PutAllPendingVNodes() failed: open files\n"));
4533 return USERLAND_IOCTL_OPEN_FILES;
4534 }
4535 if (atomic_get(&fOpenDirectories) > 0) {
4536 PRINT(("Volume::_PutAllPendingVNodes() failed: open dirs\n"));
4537 return USERLAND_IOCTL_OPEN_DIRECTORIES;
4538 }
4539 if (atomic_get(&fOpenAttributeDirectories) > 0) {
4540 PRINT(("Volume::_PutAllPendingVNodes() failed: open attr dirs\n"));
4541 return USERLAND_IOCTL_OPEN_ATTRIBUTE_DIRECTORIES;
4542 }
4543 if (atomic_get(&fOpenAttributes) > 0) {
4544 PRINT(("Volume::_PutAllPendingVNodes() failed: open attributes\n"));
4545 return USERLAND_IOCTL_OPEN_ATTRIBUTES;
4546 }
4547 if (atomic_get(&fOpenIndexDirectories) > 0) {
4548 PRINT(("Volume::_PutAllPendingVNodes() failed: open index dirs\n"));
4549 return USERLAND_IOCTL_OPEN_INDEX_DIRECTORIES;
4550 }
4551 if (atomic_get(&fOpenQueries) > 0) {
4552 PRINT(("Volume::_PutAllPendingVNodes() failed: open queries\n"));
4553 return USERLAND_IOCTL_OPEN_QUERIES;
4554 }
4555 // No open entities. Since the port pool is disconnected, no new
4556 // entities can be opened. Disable node counting and put all pending
4557 // vnodes.
4558 fVNodeCountingEnabled = false;
4559
4560 int32 putVNodeCount = 0;
4561
4562 // Since the vnode map can still change, we need to iterate to the first
4563 // node we need to put, drop the lock, put the node, and restart from the
4564 // beginning.
4565 // TODO: Optimize by extracting batches of relevant nodes to an on-stack
4566 // array.
4567 bool nodeFound;
4568 do {
4569 nodeFound = false;
4570
4571 // get the next node to put
4572 for (VNodeMap::Iterator it = fVNodes->GetIterator();
4573 VNode* vnode = it.Next();) {
4574 if (vnode->useCount > 0) {
4575 ino_t vnid = vnode->id;
4576 int32 count = vnode->useCount;
4577 vnode->useCount = 0;
4578 fs_vnode_ops* ops = vnode->ops->ops;
4579 bool published = vnode->published;
4580
4581 locker.Unlock();
4582
4583 // If the node has not yet been published, we have to do that
4584 // before putting otherwise the VFS will complain that the node
4585 // is busy when the last reference is gone.
4586 if (!published)
4587 publish_vnode(fFSVolume, vnid, vnode, ops, S_IFDIR, 0);
4588
4589 for (int32 i = 0; i < count; i++) {
4590 PutVNode(vnid);
4591 putVNodeCount++;
4592 }
4593
4594 locker.Lock();
4595
4596 nodeFound = true;
4597 break;
4598 }
4599 }
4600 } while (nodeFound);
4601
4602 PRINT(("Volume::_PutAllPendingVNodes() successful: Put %" B_PRId32
4603 " vnodes\n", putVNodeCount));
4604
4605 return B_OK;
4606 }
4607
4608
4609 // _RegisterIORequest
4610 status_t
_RegisterIORequest(io_request * request,int32 * requestID)4611 Volume::_RegisterIORequest(io_request* request, int32* requestID)
4612 {
4613 MutexLocker _(fLock);
4614
4615 // get the next free ID
4616 while (fIORequestInfosByID->Lookup(++fLastIORequestID) != NULL) {
4617 }
4618
4619 // allocate the info
4620 IORequestInfo* info = new(std::nothrow) IORequestInfo(request,
4621 ++fLastIORequestID);
4622 if (info == NULL)
4623 return B_NO_MEMORY;
4624
4625 // add the info to the maps
4626 fIORequestInfosByID->Insert(info);
4627 fIORequestInfosByStruct->Insert(info);
4628
4629 *requestID = info->id;
4630
4631 return B_OK;
4632 }
4633
4634
4635 // _UnregisterIORequest
4636 status_t
_UnregisterIORequest(int32 requestID)4637 Volume::_UnregisterIORequest(int32 requestID)
4638 {
4639 MutexLocker _(fLock);
4640
4641 if (IORequestInfo* info = fIORequestInfosByID->Lookup(requestID)) {
4642 fIORequestInfosByID->Remove(info);
4643 fIORequestInfosByStruct->Remove(info);
4644 return B_OK;
4645 }
4646
4647 return B_ENTRY_NOT_FOUND;
4648 }
4649
4650
4651 // _FindIORequest
4652 status_t
_FindIORequest(int32 requestID,io_request ** request)4653 Volume::_FindIORequest(int32 requestID, io_request** request)
4654 {
4655 MutexLocker _(fLock);
4656
4657 if (IORequestInfo* info = fIORequestInfosByID->Lookup(requestID)) {
4658 *request = info->request;
4659 return B_OK;
4660 }
4661
4662 return B_ENTRY_NOT_FOUND;
4663 }
4664
4665
4666 // _FindIORequest
4667 status_t
_FindIORequest(io_request * request,int32 * requestID)4668 Volume::_FindIORequest(io_request* request, int32* requestID)
4669 {
4670 MutexLocker _(fLock);
4671
4672 if (IORequestInfo* info = fIORequestInfosByStruct->Lookup(request)) {
4673 *requestID = info->id;
4674 return B_OK;
4675 }
4676
4677 return B_ENTRY_NOT_FOUND;
4678 }
4679
4680
4681 /*static*/ status_t
_IterativeFDIOGetVecs(void * _cookie,io_request * ioRequest,off_t offset,size_t size,struct file_io_vec * vecs,size_t * _count)4682 Volume::_IterativeFDIOGetVecs(void* _cookie, io_request* ioRequest,
4683 off_t offset, size_t size, struct file_io_vec* vecs, size_t* _count)
4684 {
4685 IterativeFDIOCookie* cookie = (IterativeFDIOCookie*)_cookie;
4686 Volume* volume = cookie->volume;
4687
4688 MutexLocker locker(volume->fLock);
4689
4690 // If there are vecs cached in the cookie and the offset matches, return
4691 // those.
4692 if (cookie->vecs != NULL) {
4693 size_t vecCount = 0;
4694 if (offset == cookie->offset) {
4695 // good, copy the vecs
4696 while (size > 0 && vecCount < cookie->vecCount
4697 && vecCount < *_count) {
4698 off_t maxSize = std::min((off_t)size,
4699 cookie->vecs[vecCount].length);
4700 vecs[vecCount].offset = cookie->vecs[vecCount].offset;
4701 vecs[vecCount].length = maxSize;
4702
4703 size -= maxSize;
4704 vecCount++;
4705 }
4706 }
4707
4708 cookie->vecs = NULL;
4709 cookie->vecCount = 0;
4710
4711 // got some vecs? -- then we're done
4712 if (vecCount > 0) {
4713 *_count = vecCount;
4714 return B_OK;
4715 }
4716 }
4717
4718 // we have to ask the client FS
4719 int32 requestID = cookie->requestID;
4720 void* clientCookie = cookie->clientCookie;
4721 locker.Unlock();
4722
4723 // get a free port
4724 RequestPort* port = volume->fFileSystem->GetPortPool()->AcquirePort();
4725 if (!port)
4726 return B_ERROR;
4727 PortReleaser _(volume->fFileSystem->GetPortPool(), port);
4728
4729 // prepare the request
4730 RequestAllocator allocator(port->GetPort());
4731 IterativeIOGetVecsRequest* request;
4732 status_t error = AllocateRequest(allocator, &request);
4733 if (error != B_OK)
4734 return error;
4735
4736 request->volume = volume->fUserlandVolume;
4737 request->cookie = clientCookie;
4738 request->offset = offset;
4739 request->request = requestID;
4740 request->size = size;
4741 size_t maxVecs = std::min(*_count,
4742 (size_t)IterativeIOGetVecsReply::MAX_VECS);
4743 request->vecCount = maxVecs;
4744
4745 // send the request
4746 KernelRequestHandler handler(volume, ITERATIVE_IO_GET_VECS_REPLY);
4747 IterativeIOGetVecsReply* reply;
4748 error = volume->_SendRequest(port, &allocator, &handler, (Request**)&reply);
4749 if (error != B_OK)
4750 return error;
4751 RequestReleaser requestReleaser(port, reply);
4752
4753 // process the reply
4754 if (reply->error != B_OK)
4755 return reply->error;
4756 uint32 vecCount = reply->vecCount;
4757 if (vecCount < 0 || vecCount > maxVecs)
4758 return B_BAD_DATA;
4759
4760 memcpy(vecs, reply->vecs, vecCount * sizeof(file_io_vec));
4761 *_count = vecCount;
4762
4763 return B_OK;
4764 }
4765
4766
4767 /*static*/ status_t
_IterativeFDIOFinished(void * _cookie,io_request * ioRequest,status_t status,bool partialTransfer,size_t bytesTransferred)4768 Volume::_IterativeFDIOFinished(void* _cookie, io_request* ioRequest,
4769 status_t status, bool partialTransfer, size_t bytesTransferred)
4770 {
4771 IterativeFDIOCookie* cookie = (IterativeFDIOCookie*)_cookie;
4772 Volume* volume = cookie->volume;
4773
4774 // At any rate, we're done with the cookie after this call -- it will not
4775 // be used anymore.
4776 BReference<IterativeFDIOCookie> _(cookie, true);
4777
4778 // We also want to dispose of the request.
4779 IORequestRemover _2(volume, cookie->requestID);
4780
4781 // get a free port
4782 RequestPort* port = volume->fFileSystem->GetPortPool()->AcquirePort();
4783 if (!port)
4784 return B_ERROR;
4785 PortReleaser _3(volume->fFileSystem->GetPortPool(), port);
4786
4787 // prepare the request
4788 RequestAllocator allocator(port->GetPort());
4789 IterativeIOFinishedRequest* request;
4790 status_t error = AllocateRequest(allocator, &request);
4791 if (error != B_OK)
4792 return error;
4793
4794 request->volume = volume->fUserlandVolume;
4795 request->cookie = cookie->clientCookie;
4796 request->request = cookie->requestID;
4797 request->status = status;
4798 request->partialTransfer = partialTransfer;
4799 request->bytesTransferred = bytesTransferred;
4800
4801 // send the request
4802 KernelRequestHandler handler(volume, ITERATIVE_IO_FINISHED_REPLY);
4803 IterativeIOFinishedReply* reply;
4804 error = volume->_SendRequest(port, &allocator, &handler, (Request**)&reply);
4805 if (error != B_OK)
4806 return error;
4807 RequestReleaser requestReleaser(port, reply);
4808
4809 // process the reply
4810 if (reply->error != B_OK)
4811 return reply->error;
4812 return B_OK;
4813 }
4814