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