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