xref: /haiku/src/add-ons/kernel/file_systems/userlandfs/kernel_add_on/Volume.cpp (revision 5629675a326ecf2ff3fd23f154beb525c171048d)
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 <= 1 || 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. OBOS 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 OBOS 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. OBOS 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 OBOS 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. OBOS 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 OBOS 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. OBOS 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 OBOS 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 		memcpy(buffer, readBuffer, reply->bytesRead);
2887 	*bytesRead = reply->bytesRead;
2888 	_SendReceiptAck(port);
2889 	return error;
2890 }
2891 
2892 // WriteAttr
2893 status_t
2894 Volume::WriteAttr(void* _node, void* cookie, off_t pos,
2895 	const void* buffer, size_t bufferSize, size_t* bytesWritten)
2896 {
2897 	VNode* vnode = (VNode*)_node;
2898 
2899 	*bytesWritten = 0;
2900 
2901 	// check capability
2902 	if (!HasVNodeCapability(vnode, FS_VNODE_CAPABILITY_WRITE_ATTR))
2903 		return B_BAD_VALUE;
2904 
2905 	// get a free port
2906 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
2907 	if (!port)
2908 		return B_ERROR;
2909 	PortReleaser _(fFileSystem->GetPortPool(), port);
2910 
2911 	// prepare the request
2912 	RequestAllocator allocator(port->GetPort());
2913 	WriteAttrRequest* request;
2914 	status_t error = AllocateRequest(allocator, &request);
2915 	if (error != B_OK)
2916 		return error;
2917 
2918 	request->volume = fUserlandVolume;
2919 	request->node = vnode->clientNode;
2920 	request->attrCookie = cookie;
2921 	request->pos = pos;
2922 	error = allocator.AllocateData(request->buffer, buffer, bufferSize, 1);
2923 	if (error != B_OK)
2924 		return error;
2925 
2926 	// send the request
2927 	KernelRequestHandler handler(this, WRITE_ATTR_REPLY);
2928 	WriteAttrReply* reply;
2929 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
2930 	if (error != B_OK)
2931 		return error;
2932 	RequestReleaser requestReleaser(port, reply);
2933 
2934 	// process the reply
2935 	if (reply->error != B_OK)
2936 		return reply->error;
2937 	*bytesWritten = reply->bytesWritten;
2938 	return error;
2939 }
2940 
2941 // ReadAttrStat
2942 status_t
2943 Volume::ReadAttrStat(void* _node, void* cookie, struct stat *st)
2944 {
2945 	VNode* vnode = (VNode*)_node;
2946 
2947 	// check capability
2948 	if (!HasVNodeCapability(vnode, FS_VNODE_CAPABILITY_READ_ATTR_STAT))
2949 		return B_BAD_VALUE;
2950 
2951 	// get a free port
2952 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
2953 	if (!port)
2954 		return B_ERROR;
2955 	PortReleaser _(fFileSystem->GetPortPool(), port);
2956 
2957 	// prepare the request
2958 	RequestAllocator allocator(port->GetPort());
2959 	ReadAttrStatRequest* request;
2960 	status_t error = AllocateRequest(allocator, &request);
2961 	if (error != B_OK)
2962 		return error;
2963 
2964 	request->volume = fUserlandVolume;
2965 	request->node = vnode->clientNode;
2966 	request->attrCookie = cookie;
2967 
2968 	// send the request
2969 	KernelRequestHandler handler(this, READ_ATTR_STAT_REPLY);
2970 	ReadAttrStatReply* reply;
2971 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
2972 	if (error != B_OK)
2973 		return error;
2974 	RequestReleaser requestReleaser(port, reply);
2975 
2976 	// process the reply
2977 	if (reply->error != B_OK)
2978 		return reply->error;
2979 	*st = reply->st;
2980 	return error;
2981 }
2982 
2983 // WriteAttrStat
2984 status_t
2985 Volume::WriteAttrStat(void* _node, void* cookie, const struct stat *st,
2986 	int statMask)
2987 {
2988 	VNode* vnode = (VNode*)_node;
2989 
2990 	// check capability
2991 	if (!HasVNodeCapability(vnode, FS_VNODE_CAPABILITY_WRITE_ATTR_STAT))
2992 		return B_BAD_VALUE;
2993 
2994 	// get a free port
2995 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
2996 	if (!port)
2997 		return B_ERROR;
2998 	PortReleaser _(fFileSystem->GetPortPool(), port);
2999 
3000 	// prepare the request
3001 	RequestAllocator allocator(port->GetPort());
3002 	WriteAttrStatRequest* request;
3003 	status_t error = AllocateRequest(allocator, &request);
3004 	if (error != B_OK)
3005 		return error;
3006 
3007 	request->volume = fUserlandVolume;
3008 	request->node = vnode->clientNode;
3009 	request->attrCookie = cookie;
3010 	request->st = *st;
3011 	request->mask = statMask;
3012 
3013 	// send the request
3014 	KernelRequestHandler handler(this, WRITE_ATTR_STAT_REPLY);
3015 	WriteAttrStatReply* reply;
3016 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
3017 	if (error != B_OK)
3018 		return error;
3019 	RequestReleaser requestReleaser(port, reply);
3020 
3021 	// process the reply
3022 	if (reply->error != B_OK)
3023 		return reply->error;
3024 	return error;
3025 }
3026 
3027 // RenameAttr
3028 status_t
3029 Volume::RenameAttr(void* _oldNode, const char* oldName, void* _newNode,
3030 	const char* newName)
3031 {
3032 	VNode* oldVNode = (VNode*)_oldNode;
3033 	VNode* newVNode = (VNode*)_newNode;
3034 
3035 	// check capability
3036 	if (!HasVNodeCapability(oldVNode, FS_VNODE_CAPABILITY_RENAME_ATTR))
3037 		return B_BAD_VALUE;
3038 
3039 	// get a free port
3040 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
3041 	if (!port)
3042 		return B_ERROR;
3043 	PortReleaser _(fFileSystem->GetPortPool(), port);
3044 
3045 	// prepare the request
3046 	RequestAllocator allocator(port->GetPort());
3047 	RenameAttrRequest* request;
3048 	status_t error = AllocateRequest(allocator, &request);
3049 	if (error != B_OK)
3050 		return error;
3051 
3052 	request->volume = fUserlandVolume;
3053 	request->oldNode = oldVNode->clientNode;
3054 	request->newNode = newVNode->clientNode;
3055 	error = allocator.AllocateString(request->oldName, oldName);
3056 	if (error == B_OK)
3057 		error = allocator.AllocateString(request->newName, newName);
3058 	if (error != B_OK)
3059 		return error;
3060 
3061 	// send the request
3062 	KernelRequestHandler handler(this, RENAME_ATTR_REPLY);
3063 	RenameAttrReply* reply;
3064 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
3065 	if (error != B_OK)
3066 		return error;
3067 	RequestReleaser requestReleaser(port, reply);
3068 
3069 	// process the reply
3070 	if (reply->error != B_OK)
3071 		return reply->error;
3072 	return error;
3073 }
3074 
3075 // RemoveAttr
3076 status_t
3077 Volume::RemoveAttr(void* _node, const char* name)
3078 {
3079 	VNode* vnode = (VNode*)_node;
3080 
3081 	// check capability
3082 	if (!HasVNodeCapability(vnode, FS_VNODE_CAPABILITY_REMOVE_ATTR))
3083 		return B_BAD_VALUE;
3084 
3085 	// get a free port
3086 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
3087 	if (!port)
3088 		return B_ERROR;
3089 	PortReleaser _(fFileSystem->GetPortPool(), port);
3090 
3091 	// prepare the request
3092 	RequestAllocator allocator(port->GetPort());
3093 	RemoveAttrRequest* request;
3094 	status_t error = AllocateRequest(allocator, &request);
3095 	if (error != B_OK)
3096 		return error;
3097 
3098 	request->volume = fUserlandVolume;
3099 	request->node = vnode->clientNode;
3100 	error = allocator.AllocateString(request->name, name);
3101 	if (error != B_OK)
3102 		return error;
3103 
3104 	// send the request
3105 	KernelRequestHandler handler(this, REMOVE_ATTR_REPLY);
3106 	RemoveAttrReply* reply;
3107 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
3108 	if (error != B_OK)
3109 		return error;
3110 	RequestReleaser requestReleaser(port, reply);
3111 
3112 	// process the reply
3113 	if (reply->error != B_OK)
3114 		return reply->error;
3115 	return error;
3116 }
3117 
3118 
3119 // #pragma mark - indices
3120 
3121 
3122 // OpenIndexDir
3123 status_t
3124 Volume::OpenIndexDir(void** cookie)
3125 {
3126 	// check capability
3127 	if (!HasCapability(FS_VOLUME_CAPABILITY_OPEN_INDEX_DIR))
3128 		return B_BAD_VALUE;
3129 
3130 	// get a free port
3131 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
3132 	if (!port)
3133 		return B_ERROR;
3134 	PortReleaser _(fFileSystem->GetPortPool(), port);
3135 	AutoIncrementer incrementer(&fOpenIndexDirectories);
3136 
3137 	// prepare the request
3138 	RequestAllocator allocator(port->GetPort());
3139 	OpenIndexDirRequest* request;
3140 	status_t error = AllocateRequest(allocator, &request);
3141 	if (error != B_OK)
3142 		return error;
3143 
3144 	request->volume = fUserlandVolume;
3145 
3146 	// send the request
3147 	KernelRequestHandler handler(this, OPEN_INDEX_DIR_REPLY);
3148 	OpenIndexDirReply* reply;
3149 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
3150 	if (error != B_OK)
3151 		return error;
3152 	RequestReleaser requestReleaser(port, reply);
3153 
3154 	// process the reply
3155 	if (reply->error != B_OK)
3156 		return reply->error;
3157 	incrementer.Keep();
3158 	*cookie = reply->indexDirCookie;
3159 	return error;
3160 }
3161 
3162 // CloseIndexDir
3163 status_t
3164 Volume::CloseIndexDir(void* cookie)
3165 {
3166 	status_t error = _CloseIndexDir(cookie);
3167 	if (error != B_OK && fFileSystem->GetPortPool()->IsDisconnected()) {
3168 		// This isn't really necessary, as the return value is irrelevant to
3169 		// the VFS. OBOS ignores it completely. The fsshell returns it to the
3170 		// userland, but considers the node closed anyway.
3171 		WARN(("Volume::CloseIndexDir(): connection lost, forcing close "
3172 			"index dir\n"));
3173 		return B_OK;
3174 	}
3175 	return error;
3176 }
3177 
3178 // FreeIndexDirCookie
3179 status_t
3180 Volume::FreeIndexDirCookie(void* cookie)
3181 {
3182 	status_t error = _FreeIndexDirCookie(cookie);
3183 	bool disconnected = false;
3184 	if (error != B_OK && fFileSystem->GetPortPool()->IsDisconnected()) {
3185 		// This isn't really necessary, as the return value is irrelevant to
3186 		// the VFS. It's completely ignored by OBOS as well as by the fsshell.
3187 		WARN(("Volume::FreeIndexDirCookie(): connection lost, forcing free "
3188 			"index dir cookie\n"));
3189 		error = B_OK;
3190 		disconnected = true;
3191 	}
3192 
3193 	int32 openIndexDirs = atomic_add(&fOpenIndexDirectories, -1);
3194 	if (openIndexDirs <= 1 && disconnected)
3195 		_PutAllPendingVNodes();
3196 	return error;
3197 }
3198 
3199 // ReadIndexDir
3200 status_t
3201 Volume::ReadIndexDir(void* cookie, void* buffer, size_t bufferSize,
3202 	uint32 count, uint32* countRead)
3203 {
3204 	*countRead = 0;
3205 
3206 	// check capability
3207 	if (!HasCapability(FS_VOLUME_CAPABILITY_READ_INDEX_DIR))
3208 		return B_BAD_VALUE;
3209 
3210 	// get a free port
3211 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
3212 	if (!port)
3213 		return B_ERROR;
3214 	PortReleaser _(fFileSystem->GetPortPool(), port);
3215 
3216 	// prepare the request
3217 	RequestAllocator allocator(port->GetPort());
3218 	ReadIndexDirRequest* request;
3219 	status_t error = AllocateRequest(allocator, &request);
3220 	if (error != B_OK)
3221 		return error;
3222 
3223 	request->volume = fUserlandVolume;
3224 	request->indexDirCookie = cookie;
3225 	request->bufferSize = bufferSize;
3226 	request->count = count;
3227 
3228 	// send the request
3229 	KernelRequestHandler handler(this, READ_INDEX_DIR_REPLY);
3230 	ReadIndexDirReply* reply;
3231 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
3232 	if (error != B_OK)
3233 		return error;
3234 	RequestReleaser requestReleaser(port, reply);
3235 
3236 	// process the reply
3237 	if (reply->error != B_OK)
3238 		return reply->error;
3239 	if (reply->count < 0 || reply->count > count)
3240 		return B_BAD_DATA;
3241 	if ((int32)bufferSize < reply->buffer.GetSize())
3242 		return B_BAD_DATA;
3243 
3244 	*countRead = reply->count;
3245 	if (*countRead > 0) {
3246 		// copy the buffer -- limit the number of bytes to copy
3247 		uint32 maxBytes = *countRead
3248 			* (sizeof(struct dirent) + B_FILE_NAME_LENGTH);
3249 		uint32 copyBytes = reply->buffer.GetSize();
3250 		if (copyBytes > maxBytes)
3251 			copyBytes = maxBytes;
3252 		memcpy(buffer, reply->buffer.GetData(), copyBytes);
3253 	}
3254 	_SendReceiptAck(port);
3255 	return error;
3256 }
3257 
3258 // RewindIndexDir
3259 status_t
3260 Volume::RewindIndexDir(void* cookie)
3261 {
3262 	// check capability
3263 	if (!HasCapability(FS_VOLUME_CAPABILITY_REWIND_INDEX_DIR))
3264 		return B_BAD_VALUE;
3265 
3266 	// get a free port
3267 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
3268 	if (!port)
3269 		return B_ERROR;
3270 	PortReleaser _(fFileSystem->GetPortPool(), port);
3271 
3272 	// prepare the request
3273 	RequestAllocator allocator(port->GetPort());
3274 	RewindIndexDirRequest* request;
3275 	status_t error = AllocateRequest(allocator, &request);
3276 	if (error != B_OK)
3277 		return error;
3278 
3279 	request->volume = fUserlandVolume;
3280 	request->indexDirCookie = cookie;
3281 
3282 	// send the request
3283 	KernelRequestHandler handler(this, REWIND_INDEX_DIR_REPLY);
3284 	RewindIndexDirReply* reply;
3285 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
3286 	if (error != B_OK)
3287 		return error;
3288 	RequestReleaser requestReleaser(port, reply);
3289 
3290 	// process the reply
3291 	if (reply->error != B_OK)
3292 		return reply->error;
3293 	return error;
3294 }
3295 
3296 // CreateIndex
3297 status_t
3298 Volume::CreateIndex(const char* name, uint32 type, uint32 flags)
3299 {
3300 	// check capability
3301 	if (!HasCapability(FS_VOLUME_CAPABILITY_CREATE_INDEX))
3302 		return B_BAD_VALUE;
3303 
3304 	// get a free port
3305 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
3306 	if (!port)
3307 		return B_ERROR;
3308 	PortReleaser _(fFileSystem->GetPortPool(), port);
3309 
3310 	// prepare the request
3311 	RequestAllocator allocator(port->GetPort());
3312 	CreateIndexRequest* request;
3313 	status_t error = AllocateRequest(allocator, &request);
3314 	if (error != B_OK)
3315 		return error;
3316 
3317 	request->volume = fUserlandVolume;
3318 	error = allocator.AllocateString(request->name, name);
3319 	request->type = type;
3320 	request->flags = flags;
3321 	if (error != B_OK)
3322 		return error;
3323 
3324 	// send the request
3325 	KernelRequestHandler handler(this, CREATE_INDEX_REPLY);
3326 	CreateIndexReply* reply;
3327 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
3328 	if (error != B_OK)
3329 		return error;
3330 	RequestReleaser requestReleaser(port, reply);
3331 
3332 	// process the reply
3333 	if (reply->error != B_OK)
3334 		return reply->error;
3335 	return error;
3336 }
3337 
3338 // RemoveIndex
3339 status_t
3340 Volume::RemoveIndex(const char* name)
3341 {
3342 	// check capability
3343 	if (!HasCapability(FS_VOLUME_CAPABILITY_REMOVE_INDEX))
3344 		return B_BAD_VALUE;
3345 
3346 	// get a free port
3347 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
3348 	if (!port)
3349 		return B_ERROR;
3350 	PortReleaser _(fFileSystem->GetPortPool(), port);
3351 
3352 	// prepare the request
3353 	RequestAllocator allocator(port->GetPort());
3354 	RemoveIndexRequest* request;
3355 	status_t error = AllocateRequest(allocator, &request);
3356 	if (error != B_OK)
3357 		return error;
3358 
3359 	request->volume = fUserlandVolume;
3360 	error = allocator.AllocateString(request->name, name);
3361 	if (error != B_OK)
3362 		return error;
3363 
3364 	// send the request
3365 	KernelRequestHandler handler(this, REMOVE_INDEX_REPLY);
3366 	RemoveIndexReply* reply;
3367 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
3368 	if (error != B_OK)
3369 		return error;
3370 	RequestReleaser requestReleaser(port, reply);
3371 
3372 	// process the reply
3373 	if (reply->error != B_OK)
3374 		return reply->error;
3375 	return error;
3376 }
3377 
3378 // ReadIndexStat
3379 status_t
3380 Volume::ReadIndexStat(const char* name, struct stat *st)
3381 {
3382 	// check capability
3383 	if (!HasCapability(FS_VOLUME_CAPABILITY_READ_INDEX_STAT))
3384 		return B_BAD_VALUE;
3385 
3386 	// get a free port
3387 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
3388 	if (!port)
3389 		return B_ERROR;
3390 	PortReleaser _(fFileSystem->GetPortPool(), port);
3391 
3392 	// prepare the request
3393 	RequestAllocator allocator(port->GetPort());
3394 	ReadIndexStatRequest* request;
3395 	status_t error = AllocateRequest(allocator, &request);
3396 	if (error != B_OK)
3397 		return error;
3398 
3399 	request->volume = fUserlandVolume;
3400 	error = allocator.AllocateString(request->name, name);
3401 	if (error != B_OK)
3402 		return error;
3403 
3404 	// send the request
3405 	KernelRequestHandler handler(this, READ_INDEX_STAT_REPLY);
3406 	ReadIndexStatReply* reply;
3407 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
3408 	if (error != B_OK)
3409 		return error;
3410 	RequestReleaser requestReleaser(port, reply);
3411 
3412 	// process the reply
3413 	if (reply->error != B_OK)
3414 		return reply->error;
3415 	*st = reply->st;
3416 	return error;
3417 }
3418 
3419 
3420 // #pragma mark - queries
3421 
3422 
3423 // OpenQuery
3424 status_t
3425 Volume::OpenQuery(const char* queryString, uint32 flags, port_id targetPort,
3426 	uint32 token, void** cookie)
3427 {
3428 	// check capability
3429 	if (!HasCapability(FS_VOLUME_CAPABILITY_OPEN_QUERY))
3430 		return B_BAD_VALUE;
3431 
3432 	// get a free port
3433 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
3434 	if (!port)
3435 		return B_ERROR;
3436 	PortReleaser _(fFileSystem->GetPortPool(), port);
3437 	AutoIncrementer incrementer(&fOpenQueries);
3438 
3439 	// prepare the request
3440 	RequestAllocator allocator(port->GetPort());
3441 	OpenQueryRequest* request;
3442 	status_t error = AllocateRequest(allocator, &request);
3443 	if (error != B_OK)
3444 		return error;
3445 
3446 	request->volume = fUserlandVolume;
3447 	error = allocator.AllocateString(request->queryString, queryString);
3448 	if (error != B_OK)
3449 		return error;
3450 	request->flags = flags;
3451 	request->port = targetPort;
3452 	request->token = token;
3453 
3454 	// send the request
3455 	KernelRequestHandler handler(this, OPEN_QUERY_REPLY);
3456 	OpenQueryReply* reply;
3457 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
3458 	if (error != B_OK)
3459 		return error;
3460 	RequestReleaser requestReleaser(port, reply);
3461 
3462 	// process the reply
3463 	if (reply->error != B_OK)
3464 		return reply->error;
3465 	incrementer.Keep();
3466 	*cookie = reply->queryCookie;
3467 	return error;
3468 }
3469 
3470 // CloseQuery
3471 status_t
3472 Volume::CloseQuery(void* cookie)
3473 {
3474 	status_t error = _CloseQuery(cookie);
3475 	if (error != B_OK && fFileSystem->GetPortPool()->IsDisconnected()) {
3476 		// This isn't really necessary, as the return value is irrelevant to
3477 		// the VFS. OBOS ignores it completely. The fsshell returns it to the
3478 		// userland, but considers the node closed anyway.
3479 		WARN(("Volume::CloseQuery(): connection lost, forcing close query\n"));
3480 		return B_OK;
3481 	}
3482 	return error;
3483 }
3484 
3485 // FreeQueryCookie
3486 status_t
3487 Volume::FreeQueryCookie(void* cookie)
3488 {
3489 	status_t error = _FreeQueryCookie(cookie);
3490 	bool disconnected = false;
3491 	if (error != B_OK && fFileSystem->GetPortPool()->IsDisconnected()) {
3492 		// This isn't really necessary, as the return value is irrelevant to
3493 		// the VFS. It's completely ignored by OBOS as well as by the fsshell.
3494 		WARN(("Volume::FreeQueryCookie(): connection lost, forcing free "
3495 			"query cookie\n"));
3496 		error = B_OK;
3497 		disconnected = true;
3498 	}
3499 
3500 	int32 openQueries = atomic_add(&fOpenQueries, -1);
3501 	if (openQueries <= 1 && disconnected)
3502 		_PutAllPendingVNodes();
3503 	return error;
3504 }
3505 
3506 // ReadQuery
3507 status_t
3508 Volume::ReadQuery(void* cookie, void* buffer, size_t bufferSize,
3509 	uint32 count, uint32* countRead)
3510 {
3511 	*countRead = 0;
3512 
3513 	// check capability
3514 	if (!HasCapability(FS_VOLUME_CAPABILITY_READ_QUERY))
3515 		return B_BAD_VALUE;
3516 
3517 	// get a free port
3518 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
3519 	if (!port)
3520 		return B_ERROR;
3521 	PortReleaser _(fFileSystem->GetPortPool(), port);
3522 
3523 	// prepare the request
3524 	RequestAllocator allocator(port->GetPort());
3525 	ReadQueryRequest* request;
3526 	status_t error = AllocateRequest(allocator, &request);
3527 	if (error != B_OK)
3528 		return error;
3529 
3530 	request->volume = fUserlandVolume;
3531 	request->queryCookie = cookie;
3532 	request->bufferSize = bufferSize;
3533 	request->count = count;
3534 
3535 	// send the request
3536 	KernelRequestHandler handler(this, READ_QUERY_REPLY);
3537 	ReadQueryReply* reply;
3538 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
3539 	if (error != B_OK)
3540 		return error;
3541 	RequestReleaser requestReleaser(port, reply);
3542 
3543 	// process the reply
3544 	if (reply->error != B_OK)
3545 		return reply->error;
3546 	if (reply->count < 0 || reply->count > count)
3547 		return B_BAD_DATA;
3548 	if ((int32)bufferSize < reply->buffer.GetSize())
3549 		return B_BAD_DATA;
3550 
3551 	*countRead = reply->count;
3552 	if (*countRead > 0) {
3553 		// copy the buffer -- limit the number of bytes to copy
3554 		uint32 maxBytes = *countRead
3555 			* (sizeof(struct dirent) + B_FILE_NAME_LENGTH);
3556 		uint32 copyBytes = reply->buffer.GetSize();
3557 		if (copyBytes > maxBytes)
3558 			copyBytes = maxBytes;
3559 		memcpy(buffer, reply->buffer.GetData(), copyBytes);
3560 	}
3561 	_SendReceiptAck(port);
3562 	return error;
3563 }
3564 
3565 // RewindQuery
3566 status_t
3567 Volume::RewindQuery(void* cookie)
3568 {
3569 	// check capability
3570 	if (!HasCapability(FS_VOLUME_CAPABILITY_REWIND_QUERY))
3571 		return B_BAD_VALUE;
3572 
3573 	// get a free port
3574 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
3575 	if (!port)
3576 		return B_ERROR;
3577 	PortReleaser _(fFileSystem->GetPortPool(), port);
3578 
3579 	// prepare the request
3580 	RequestAllocator allocator(port->GetPort());
3581 	RewindQueryRequest* request;
3582 	status_t error = AllocateRequest(allocator, &request);
3583 	if (error != B_OK)
3584 		return error;
3585 
3586 	request->volume = fUserlandVolume;
3587 	request->queryCookie = cookie;
3588 
3589 	// send the request
3590 	KernelRequestHandler handler(this, REWIND_QUERY_REPLY);
3591 	RewindQueryReply* reply;
3592 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
3593 	if (error != B_OK)
3594 		return error;
3595 	RequestReleaser requestReleaser(port, reply);
3596 
3597 	// process the reply
3598 	if (reply->error != B_OK)
3599 		return reply->error;
3600 	return error;
3601 }
3602 
3603 // #pragma mark -
3604 // #pragma mark ----- private implementations -----
3605 
3606 
3607 // _InitVolumeOps
3608 void
3609 Volume::_InitVolumeOps()
3610 {
3611 	memcpy(&fVolumeOps, &gUserlandFSVolumeOps, sizeof(fs_volume_ops));
3612 
3613 	#undef CLEAR_UNSUPPORTED
3614 	#define CLEAR_UNSUPPORTED(capability, op) 	\
3615 		if (!fCapabilities.Get(capability))				\
3616 			fVolumeOps.op = NULL
3617 
3618 	// FS operations
3619 	// FS_VOLUME_CAPABILITY_UNMOUNT: unmount
3620 		// always needed
3621 
3622 	// FS_VOLUME_CAPABILITY_READ_FS_INFO: read_fs_info
3623 		// always needed
3624 	CLEAR_UNSUPPORTED(FS_VOLUME_CAPABILITY_WRITE_FS_INFO, write_fs_info);
3625 	CLEAR_UNSUPPORTED(FS_VOLUME_CAPABILITY_SYNC, sync);
3626 
3627 	// vnode operations
3628 	// FS_VOLUME_CAPABILITY_GET_VNODE: get_vnode
3629 		// always needed
3630 
3631 	// index directory & index operations
3632 	CLEAR_UNSUPPORTED(FS_VOLUME_CAPABILITY_OPEN_INDEX_DIR, open_index_dir);
3633 	// FS_VOLUME_CAPABILITY_CLOSE_INDEX_DIR: close_index_dir
3634 		// always needed
3635 	// FS_VOLUME_CAPABILITY_FREE_INDEX_DIR_COOKIE: free_index_dir_cookie
3636 		// always needed
3637 	CLEAR_UNSUPPORTED(FS_VOLUME_CAPABILITY_READ_INDEX_DIR, read_index_dir);
3638 	CLEAR_UNSUPPORTED(FS_VOLUME_CAPABILITY_REWIND_INDEX_DIR, rewind_index_dir);
3639 
3640 	CLEAR_UNSUPPORTED(FS_VOLUME_CAPABILITY_CREATE_INDEX, create_index);
3641 	CLEAR_UNSUPPORTED(FS_VOLUME_CAPABILITY_REMOVE_INDEX, remove_index);
3642 	CLEAR_UNSUPPORTED(FS_VOLUME_CAPABILITY_READ_INDEX_STAT, read_index_stat);
3643 
3644 	// query operations
3645 	CLEAR_UNSUPPORTED(FS_VOLUME_CAPABILITY_OPEN_QUERY, open_query);
3646 	// FS_VOLUME_CAPABILITY_CLOSE_QUERY: close_query
3647 		// always needed
3648 	// FS_VOLUME_CAPABILITY_FREE_QUERY_COOKIE: free_query_cookie
3649 		// always needed
3650 	CLEAR_UNSUPPORTED(FS_VOLUME_CAPABILITY_READ_QUERY, read_query);
3651 	CLEAR_UNSUPPORTED(FS_VOLUME_CAPABILITY_REWIND_QUERY, rewind_query);
3652 
3653 	#undef CLEAR_UNSUPPORTED
3654 }
3655 
3656 
3657 // #pragma mark -
3658 
3659 
3660 // _Mount
3661 status_t
3662 Volume::_Mount(const char* device, uint32 flags, const char* parameters)
3663 {
3664 	// get a free port
3665 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
3666 	if (!port)
3667 		return B_ERROR;
3668 	PortReleaser _(fFileSystem->GetPortPool(), port);
3669 
3670 	// get the current working directory
3671 	char cwd[B_PATH_NAME_LENGTH];
3672 	if (!getcwd(cwd, sizeof(cwd)))
3673 		return errno;
3674 
3675 	// prepare the request
3676 	RequestAllocator allocator(port->GetPort());
3677 	MountVolumeRequest* request;
3678 	status_t error = AllocateRequest(allocator, &request);
3679 	if (error != B_OK)
3680 		return error;
3681 
3682 	request->nsid = GetID();
3683 	error = allocator.AllocateString(request->cwd, cwd);
3684 	if (error == B_OK)
3685 		error = allocator.AllocateString(request->device, device);
3686 	request->flags = flags;
3687 	if (error == B_OK)
3688 		error = allocator.AllocateString(request->parameters, parameters);
3689 	if (error != B_OK)
3690 		return error;
3691 
3692 	// send the request
3693 	KernelRequestHandler handler(this, MOUNT_VOLUME_REPLY);
3694 	MountVolumeReply* reply;
3695 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
3696 	if (error != B_OK)
3697 		return error;
3698 	RequestReleaser requestReleaser(port, reply);
3699 
3700 	// process the reply
3701 	if (reply->error != B_OK)
3702 		return reply->error;
3703 	fRootID = reply->rootID;
3704 	fUserlandVolume = reply->volume;
3705 	fCapabilities = reply->capabilities;
3706 
3707 	return error;
3708 }
3709 
3710 // _Unmount
3711 status_t
3712 Volume::_Unmount()
3713 {
3714 	// get a free port
3715 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
3716 	if (!port)
3717 		return B_ERROR;
3718 	PortReleaser _(fFileSystem->GetPortPool(), port);
3719 
3720 	// prepare the request
3721 	RequestAllocator allocator(port->GetPort());
3722 	UnmountVolumeRequest* request;
3723 	status_t error = AllocateRequest(allocator, &request);
3724 	if (error != B_OK)
3725 		return error;
3726 
3727 	request->volume = fUserlandVolume;
3728 
3729 	// send the request
3730 	KernelRequestHandler handler(this, UNMOUNT_VOLUME_REPLY);
3731 	UnmountVolumeReply* reply;
3732 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
3733 	if (error != B_OK)
3734 		return error;
3735 	RequestReleaser requestReleaser(port, reply);
3736 
3737 	// process the reply
3738 	if (reply->error != B_OK)
3739 		return reply->error;
3740 	return error;
3741 }
3742 
3743 // _ReadFSInfo
3744 status_t
3745 Volume::_ReadFSInfo(fs_info* info)
3746 {
3747 	// check capability
3748 	if (!HasCapability(FS_VOLUME_CAPABILITY_READ_FS_INFO))
3749 		return B_BAD_VALUE;
3750 
3751 	// get a free port
3752 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
3753 	if (!port)
3754 		return B_ERROR;
3755 	PortReleaser _(fFileSystem->GetPortPool(), port);
3756 
3757 	// prepare the request
3758 	RequestAllocator allocator(port->GetPort());
3759 	ReadFSInfoRequest* request;
3760 	status_t error = AllocateRequest(allocator, &request);
3761 	if (error != B_OK)
3762 		return error;
3763 
3764 	request->volume = fUserlandVolume;
3765 
3766 	// send the request
3767 	KernelRequestHandler handler(this, READ_FS_INFO_REPLY);
3768 	ReadFSInfoReply* reply;
3769 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
3770 	if (error != B_OK)
3771 		return error;
3772 	RequestReleaser requestReleaser(port, reply);
3773 
3774 	// process the reply
3775 	if (reply->error != B_OK)
3776 		return reply->error;
3777 	*info = reply->info;
3778 	return error;
3779 }
3780 
3781 // _Lookup
3782 status_t
3783 Volume::_Lookup(void* _dir, const char* entryName, ino_t* vnid)
3784 {
3785 	VNode* vnode = (VNode*)_dir;
3786 
3787 	// get a free port
3788 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
3789 	if (!port)
3790 		return B_ERROR;
3791 	PortReleaser _(fFileSystem->GetPortPool(), port);
3792 
3793 	// prepare the request
3794 	RequestAllocator allocator(port->GetPort());
3795 	LookupRequest* request;
3796 	status_t error = AllocateRequest(allocator, &request);
3797 	if (error != B_OK)
3798 		return error;
3799 	request->volume = fUserlandVolume;
3800 	request->node = vnode->clientNode;
3801 	error = allocator.AllocateString(request->entryName, entryName);
3802 	if (error != B_OK)
3803 		return error;
3804 
3805 	// send the request
3806 	KernelRequestHandler handler(this, LOOKUP_REPLY);
3807 	LookupReply* reply;
3808 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
3809 	if (error != B_OK)
3810 		return error;
3811 	RequestReleaser requestReleaser(port, reply);
3812 
3813 	// process the reply
3814 	if (reply->error != B_OK)
3815 		return reply->error;
3816 	*vnid = reply->vnid;
3817 
3818 	// The VFS will balance the get_vnode() call for the FS.
3819 	_DecrementVNodeCount(*vnid);
3820 	return error;
3821 }
3822 
3823 // _WriteVNode
3824 status_t
3825 Volume::_WriteVNode(void* _node, bool reenter)
3826 {
3827 	VNode* vnode = (VNode*)_node;
3828 
3829 	// At any rate remove the vnode from our map and delete it. We don't do that
3830 	// right now, though, since we might still need to serve file cache requests
3831 	// from the client FS.
3832 	VNodeRemover nodeRemover(this, vnode);
3833 
3834 	void* clientNode = vnode->clientNode;
3835 
3836 	// get a free port
3837 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
3838 	if (!port)
3839 		return B_ERROR;
3840 	PortReleaser _(fFileSystem->GetPortPool(), port);
3841 
3842 	// prepare the request
3843 	RequestAllocator allocator(port->GetPort());
3844 	WriteVNodeRequest* request;
3845 	status_t error = AllocateRequest(allocator, &request);
3846 	if (error != B_OK)
3847 		return error;
3848 	request->volume = fUserlandVolume;
3849 	request->node = clientNode;
3850 	request->reenter = reenter;
3851 
3852 	// send the request
3853 	KernelRequestHandler handler(this, WRITE_VNODE_REPLY);
3854 	WriteVNodeReply* reply;
3855 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
3856 	if (error != B_OK)
3857 		return error;
3858 	RequestReleaser requestReleaser(port, reply);
3859 
3860 	// process the reply
3861 	if (reply->error != B_OK)
3862 		return reply->error;
3863 	return error;
3864 }
3865 
3866 // _ReadStat
3867 status_t
3868 Volume::_ReadStat(void* _node, struct stat* st)
3869 {
3870 	VNode* vnode = (VNode*)_node;
3871 
3872 	// check capability
3873 	if (!HasVNodeCapability(vnode, FS_VNODE_CAPABILITY_READ_STAT))
3874 		return B_BAD_VALUE;
3875 
3876 	// get a free port
3877 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
3878 	if (!port)
3879 		return B_ERROR;
3880 	PortReleaser _(fFileSystem->GetPortPool(), port);
3881 
3882 	// prepare the request
3883 	RequestAllocator allocator(port->GetPort());
3884 	ReadStatRequest* request;
3885 	status_t error = AllocateRequest(allocator, &request);
3886 	if (error != B_OK)
3887 		return error;
3888 
3889 	request->volume = fUserlandVolume;
3890 	request->node = vnode->clientNode;
3891 
3892 	// send the request
3893 	KernelRequestHandler handler(this, READ_STAT_REPLY);
3894 	ReadStatReply* reply;
3895 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
3896 	if (error != B_OK)
3897 		return error;
3898 	RequestReleaser requestReleaser(port, reply);
3899 
3900 	// process the reply
3901 	if (reply->error != B_OK)
3902 		return reply->error;
3903 	*st = reply->st;
3904 	return error;
3905 }
3906 
3907 // _Close
3908 status_t
3909 Volume::_Close(void* _node, void* cookie)
3910 {
3911 	VNode* vnode = (VNode*)_node;
3912 
3913 	// check capability
3914 	if (!HasVNodeCapability(vnode, FS_VNODE_CAPABILITY_CLOSE))
3915 		return B_OK;
3916 
3917 	// get a free port
3918 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
3919 	if (!port)
3920 		return B_ERROR;
3921 	PortReleaser _(fFileSystem->GetPortPool(), port);
3922 
3923 	// prepare the request
3924 	RequestAllocator allocator(port->GetPort());
3925 	CloseRequest* request;
3926 	status_t error = AllocateRequest(allocator, &request);
3927 	if (error != B_OK)
3928 		return error;
3929 
3930 	request->volume = fUserlandVolume;
3931 	request->node = vnode->clientNode;
3932 	request->fileCookie = cookie;
3933 
3934 	// send the request
3935 	KernelRequestHandler handler(this, CLOSE_REPLY);
3936 	CloseReply* reply;
3937 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
3938 	if (error != B_OK)
3939 		return error;
3940 	RequestReleaser requestReleaser(port, reply);
3941 
3942 	// process the reply
3943 	if (reply->error != B_OK)
3944 		return reply->error;
3945 	return error;
3946 }
3947 
3948 // _FreeCookie
3949 status_t
3950 Volume::_FreeCookie(void* _node, void* cookie)
3951 {
3952 	VNode* vnode = (VNode*)_node;
3953 
3954 	// check capability
3955 	if (!HasVNodeCapability(vnode, FS_VNODE_CAPABILITY_FREE_COOKIE))
3956 		return B_OK;
3957 
3958 	// get a free port
3959 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
3960 	if (!port)
3961 		return B_ERROR;
3962 	PortReleaser _(fFileSystem->GetPortPool(), port);
3963 
3964 	// prepare the request
3965 	RequestAllocator allocator(port->GetPort());
3966 	FreeCookieRequest* request;
3967 	status_t error = AllocateRequest(allocator, &request);
3968 	if (error != B_OK)
3969 		return error;
3970 
3971 	request->volume = fUserlandVolume;
3972 	request->node = vnode->clientNode;
3973 	request->fileCookie = cookie;
3974 
3975 	// send the request
3976 	KernelRequestHandler handler(this, FREE_COOKIE_REPLY);
3977 	FreeCookieReply* reply;
3978 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
3979 	if (error != B_OK)
3980 		return error;
3981 	RequestReleaser requestReleaser(port, reply);
3982 
3983 	// process the reply
3984 	if (reply->error != B_OK)
3985 		return reply->error;
3986 	return error;
3987 }
3988 
3989 // _CloseDir
3990 status_t
3991 Volume::_CloseDir(void* _node, void* cookie)
3992 {
3993 	VNode* vnode = (VNode*)_node;
3994 
3995 	// check capability
3996 	if (!HasVNodeCapability(vnode, FS_VNODE_CAPABILITY_CLOSE_DIR))
3997 		return B_OK;
3998 
3999 	// get a free port
4000 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
4001 	if (!port)
4002 		return B_ERROR;
4003 	PortReleaser _(fFileSystem->GetPortPool(), port);
4004 
4005 	// prepare the request
4006 	RequestAllocator allocator(port->GetPort());
4007 	CloseDirRequest* request;
4008 	status_t error = AllocateRequest(allocator, &request);
4009 	if (error != B_OK)
4010 		return error;
4011 
4012 	request->volume = fUserlandVolume;
4013 	request->node = vnode->clientNode;
4014 	request->dirCookie = cookie;
4015 
4016 	// send the request
4017 	KernelRequestHandler handler(this, CLOSE_DIR_REPLY);
4018 	CloseDirReply* reply;
4019 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
4020 	if (error != B_OK)
4021 		return error;
4022 	RequestReleaser requestReleaser(port, reply);
4023 
4024 	// process the reply
4025 	if (reply->error != B_OK)
4026 		return reply->error;
4027 	return error;
4028 }
4029 
4030 // _FreeDirCookie
4031 status_t
4032 Volume::_FreeDirCookie(void* _node, void* cookie)
4033 {
4034 	VNode* vnode = (VNode*)_node;
4035 
4036 	// check capability
4037 	if (!HasVNodeCapability(vnode, FS_VNODE_CAPABILITY_FREE_DIR_COOKIE))
4038 		return B_OK;
4039 
4040 	// get a free port
4041 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
4042 	if (!port)
4043 		return B_ERROR;
4044 	PortReleaser _(fFileSystem->GetPortPool(), port);
4045 
4046 	// prepare the request
4047 	RequestAllocator allocator(port->GetPort());
4048 	FreeDirCookieRequest* request;
4049 	status_t error = AllocateRequest(allocator, &request);
4050 	if (error != B_OK)
4051 		return error;
4052 
4053 	request->volume = fUserlandVolume;
4054 	request->node = vnode->clientNode;
4055 	request->dirCookie = cookie;
4056 
4057 	// send the request
4058 	KernelRequestHandler handler(this, FREE_DIR_COOKIE_REPLY);
4059 	FreeDirCookieReply* reply;
4060 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
4061 	if (error != B_OK)
4062 		return error;
4063 	RequestReleaser requestReleaser(port, reply);
4064 
4065 	// process the reply
4066 	if (reply->error != B_OK)
4067 		return reply->error;
4068 	return error;
4069 }
4070 
4071 // _CloseAttrDir
4072 status_t
4073 Volume::_CloseAttrDir(void* _node, void* cookie)
4074 {
4075 	VNode* vnode = (VNode*)_node;
4076 
4077 	// check capability
4078 	if (!HasVNodeCapability(vnode, FS_VNODE_CAPABILITY_CLOSE_ATTR_DIR))
4079 		return B_OK;
4080 
4081 	// get a free port
4082 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
4083 	if (!port)
4084 		return B_ERROR;
4085 	PortReleaser _(fFileSystem->GetPortPool(), port);
4086 
4087 	// prepare the request
4088 	RequestAllocator allocator(port->GetPort());
4089 	CloseAttrDirRequest* request;
4090 	status_t error = AllocateRequest(allocator, &request);
4091 	if (error != B_OK)
4092 		return error;
4093 
4094 	request->volume = fUserlandVolume;
4095 	request->node = vnode->clientNode;
4096 	request->attrDirCookie = cookie;
4097 
4098 	// send the request
4099 	KernelRequestHandler handler(this, CLOSE_ATTR_DIR_REPLY);
4100 	CloseAttrDirReply* reply;
4101 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
4102 	if (error != B_OK)
4103 		return error;
4104 	RequestReleaser requestReleaser(port, reply);
4105 
4106 	// process the reply
4107 	if (reply->error != B_OK)
4108 		return reply->error;
4109 	return error;
4110 }
4111 
4112 // _FreeAttrDirCookie
4113 status_t
4114 Volume::_FreeAttrDirCookie(void* _node, void* cookie)
4115 {
4116 	VNode* vnode = (VNode*)_node;
4117 
4118 	// check capability
4119 	if (!HasVNodeCapability(vnode, FS_VNODE_CAPABILITY_FREE_ATTR_DIR_COOKIE))
4120 		return B_OK;
4121 
4122 	// get a free port
4123 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
4124 	if (!port)
4125 		return B_ERROR;
4126 	PortReleaser _(fFileSystem->GetPortPool(), port);
4127 
4128 	// prepare the request
4129 	RequestAllocator allocator(port->GetPort());
4130 	FreeAttrDirCookieRequest* request;
4131 	status_t error = AllocateRequest(allocator, &request);
4132 	if (error != B_OK)
4133 		return error;
4134 
4135 	request->volume = fUserlandVolume;
4136 	request->node = vnode->clientNode;
4137 	request->attrDirCookie = cookie;
4138 
4139 	// send the request
4140 	KernelRequestHandler handler(this, FREE_ATTR_DIR_COOKIE_REPLY);
4141 	FreeAttrDirCookieReply* reply;
4142 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
4143 	if (error != B_OK)
4144 		return error;
4145 	RequestReleaser requestReleaser(port, reply);
4146 
4147 	// process the reply
4148 	if (reply->error != B_OK)
4149 		return reply->error;
4150 	return error;
4151 }
4152 
4153 // _CloseAttr
4154 status_t
4155 Volume::_CloseAttr(void* _node, void* cookie)
4156 {
4157 	VNode* vnode = (VNode*)_node;
4158 
4159 	// check capability
4160 	if (!HasVNodeCapability(vnode, FS_VNODE_CAPABILITY_CLOSE_ATTR))
4161 		return B_OK;
4162 
4163 	// get a free port
4164 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
4165 	if (!port)
4166 		return B_ERROR;
4167 	PortReleaser _(fFileSystem->GetPortPool(), port);
4168 
4169 	// prepare the request
4170 	RequestAllocator allocator(port->GetPort());
4171 	CloseAttrRequest* request;
4172 	status_t error = AllocateRequest(allocator, &request);
4173 	if (error != B_OK)
4174 		return error;
4175 
4176 	request->volume = fUserlandVolume;
4177 	request->node = vnode->clientNode;
4178 	request->attrCookie = cookie;
4179 
4180 	// send the request
4181 	KernelRequestHandler handler(this, CLOSE_ATTR_REPLY);
4182 	CloseAttrReply* reply;
4183 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
4184 	if (error != B_OK)
4185 		return error;
4186 	RequestReleaser requestReleaser(port, reply);
4187 
4188 	// process the reply
4189 	if (reply->error != B_OK)
4190 		return reply->error;
4191 	return error;
4192 }
4193 
4194 // _FreeAttrCookie
4195 status_t
4196 Volume::_FreeAttrCookie(void* _node, void* cookie)
4197 {
4198 	VNode* vnode = (VNode*)_node;
4199 
4200 	// check capability
4201 	if (!HasVNodeCapability(vnode, FS_VNODE_CAPABILITY_FREE_ATTR_COOKIE))
4202 		return B_OK;
4203 
4204 	// get a free port
4205 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
4206 	if (!port)
4207 		return B_ERROR;
4208 	PortReleaser _(fFileSystem->GetPortPool(), port);
4209 
4210 	// prepare the request
4211 	RequestAllocator allocator(port->GetPort());
4212 	FreeAttrCookieRequest* request;
4213 	status_t error = AllocateRequest(allocator, &request);
4214 	if (error != B_OK)
4215 		return error;
4216 
4217 	request->volume = fUserlandVolume;
4218 	request->node = vnode->clientNode;
4219 	request->attrCookie = cookie;
4220 
4221 	// send the request
4222 	KernelRequestHandler handler(this, FREE_ATTR_COOKIE_REPLY);
4223 	FreeAttrCookieReply* reply;
4224 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
4225 	if (error != B_OK)
4226 		return error;
4227 	RequestReleaser requestReleaser(port, reply);
4228 
4229 	// process the reply
4230 	if (reply->error != B_OK)
4231 		return reply->error;
4232 	return error;
4233 }
4234 
4235 // _CloseIndexDir
4236 status_t
4237 Volume::_CloseIndexDir(void* cookie)
4238 {
4239 	// check capability
4240 	if (!HasCapability(FS_VOLUME_CAPABILITY_CLOSE_INDEX_DIR))
4241 		return B_OK;
4242 
4243 	// get a free port
4244 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
4245 	if (!port)
4246 		return B_ERROR;
4247 	PortReleaser _(fFileSystem->GetPortPool(), port);
4248 
4249 	// prepare the request
4250 	RequestAllocator allocator(port->GetPort());
4251 	CloseIndexDirRequest* request;
4252 	status_t error = AllocateRequest(allocator, &request);
4253 	if (error != B_OK)
4254 		return error;
4255 
4256 	request->volume = fUserlandVolume;
4257 	request->indexDirCookie = cookie;
4258 
4259 	// send the request
4260 	KernelRequestHandler handler(this, CLOSE_INDEX_DIR_REPLY);
4261 	CloseIndexDirReply* reply;
4262 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
4263 	if (error != B_OK)
4264 		return error;
4265 	RequestReleaser requestReleaser(port, reply);
4266 
4267 	// process the reply
4268 	if (reply->error != B_OK)
4269 		return reply->error;
4270 	return error;
4271 }
4272 
4273 // _FreeIndexDirCookie
4274 status_t
4275 Volume::_FreeIndexDirCookie(void* cookie)
4276 {
4277 	// check capability
4278 	if (!HasCapability(FS_VOLUME_CAPABILITY_FREE_INDEX_DIR_COOKIE))
4279 		return B_OK;
4280 
4281 	// get a free port
4282 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
4283 	if (!port)
4284 		return B_ERROR;
4285 	PortReleaser _(fFileSystem->GetPortPool(), port);
4286 
4287 	// prepare the request
4288 	RequestAllocator allocator(port->GetPort());
4289 	FreeIndexDirCookieRequest* request;
4290 	status_t error = AllocateRequest(allocator, &request);
4291 	if (error != B_OK)
4292 		return error;
4293 
4294 	request->volume = fUserlandVolume;
4295 	request->indexDirCookie = cookie;
4296 
4297 	// send the request
4298 	KernelRequestHandler handler(this, FREE_INDEX_DIR_COOKIE_REPLY);
4299 	FreeIndexDirCookieReply* reply;
4300 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
4301 	if (error != B_OK)
4302 		return error;
4303 	RequestReleaser requestReleaser(port, reply);
4304 
4305 	// process the reply
4306 	if (reply->error != B_OK)
4307 		return reply->error;
4308 	return error;
4309 }
4310 
4311 // _CloseQuery
4312 status_t
4313 Volume::_CloseQuery(void* cookie)
4314 {
4315 	// check capability
4316 	if (!HasCapability(FS_VOLUME_CAPABILITY_CLOSE_QUERY))
4317 		return B_OK;
4318 
4319 	// get a free port
4320 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
4321 	if (!port)
4322 		return B_ERROR;
4323 	PortReleaser _(fFileSystem->GetPortPool(), port);
4324 
4325 	// prepare the request
4326 	RequestAllocator allocator(port->GetPort());
4327 	CloseQueryRequest* request;
4328 	status_t error = AllocateRequest(allocator, &request);
4329 	if (error != B_OK)
4330 		return error;
4331 
4332 	request->volume = fUserlandVolume;
4333 	request->queryCookie = cookie;
4334 
4335 	// send the request
4336 	KernelRequestHandler handler(this, CLOSE_QUERY_REPLY);
4337 	CloseQueryReply* reply;
4338 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
4339 	if (error != B_OK)
4340 		return error;
4341 	RequestReleaser requestReleaser(port, reply);
4342 
4343 	// process the reply
4344 	if (reply->error != B_OK)
4345 		return reply->error;
4346 	return error;
4347 }
4348 
4349 // _FreeQueryCookie
4350 status_t
4351 Volume::_FreeQueryCookie(void* cookie)
4352 {
4353 	// check capability
4354 	if (!HasCapability(FS_VOLUME_CAPABILITY_FREE_QUERY_COOKIE))
4355 		return B_OK;
4356 
4357 	// get a free port
4358 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
4359 	if (!port)
4360 		return B_ERROR;
4361 	PortReleaser _(fFileSystem->GetPortPool(), port);
4362 
4363 	// prepare the request
4364 	RequestAllocator allocator(port->GetPort());
4365 	FreeQueryCookieRequest* request;
4366 	status_t error = AllocateRequest(allocator, &request);
4367 	if (error != B_OK)
4368 		return error;
4369 
4370 	request->volume = fUserlandVolume;
4371 	request->queryCookie = cookie;
4372 
4373 	// send the request
4374 	KernelRequestHandler handler(this, FREE_QUERY_COOKIE_REPLY);
4375 	FreeQueryCookieReply* reply;
4376 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
4377 	if (error != B_OK)
4378 		return error;
4379 	RequestReleaser requestReleaser(port, reply);
4380 
4381 	// process the reply
4382 	if (reply->error != B_OK)
4383 		return reply->error;
4384 	return error;
4385 }
4386 
4387 // _SendRequest
4388 status_t
4389 Volume::_SendRequest(RequestPort* port, RequestAllocator* allocator,
4390 	RequestHandler* handler, Request** reply)
4391 {
4392 	// fill in the caller info
4393 	KernelRequest* request = static_cast<KernelRequest*>(
4394 		allocator->GetRequest());
4395 	Thread* thread = thread_get_current_thread();
4396 	request->team = thread->team->id;
4397 	request->thread = thread->id;
4398 	request->user = geteuid();
4399 	request->group = getegid();
4400 
4401 	if (!fFileSystem->IsUserlandServerThread())
4402 		return port->SendRequest(allocator, handler, reply);
4403 	// Here it gets dangerous: a thread of the userland server team being here
4404 	// calls for trouble. We try receiving the request with a timeout, and
4405 	// close the port -- which will disconnect the whole FS.
4406 	status_t error = port->SendRequest(allocator, handler, reply,
4407 		kUserlandServerlandPortTimeout);
4408 	if (error == B_TIMED_OUT || error == B_WOULD_BLOCK)
4409 		port->Close();
4410 	return error;
4411 }
4412 
4413 // _SendReceiptAck
4414 status_t
4415 Volume::_SendReceiptAck(RequestPort* port)
4416 {
4417 	RequestAllocator allocator(port->GetPort());
4418 	ReceiptAckReply* request;
4419 	status_t error = AllocateRequest(allocator, &request);
4420 	if (error != B_OK)
4421 		return error;
4422 	return port->SendRequest(&allocator);
4423 }
4424 
4425 // _IncrementVNodeCount
4426 void
4427 Volume::_IncrementVNodeCount(ino_t vnid)
4428 {
4429 	MutexLocker _(fLock);
4430 
4431 	if (!fVNodeCountingEnabled)
4432 		return;
4433 
4434 	VNode* vnode = fVNodes->Lookup(vnid);
4435 	if (vnode == NULL) {
4436 		ERROR(("Volume::_IncrementVNodeCount(): Node with ID %" B_PRId64
4437 			" not known!\n", vnid));
4438 		return;
4439 	}
4440 
4441 	vnode->useCount++;
4442 //PRINT(("_IncrementVNodeCount(%Ld): count: %ld, fVNodeCountMap size: %ld\n", vnid, *count, fVNodeCountMap->Size()));
4443 }
4444 
4445 
4446 // _DecrementVNodeCount
4447 void
4448 Volume::_DecrementVNodeCount(ino_t vnid)
4449 {
4450 	MutexLocker _(fLock);
4451 
4452 	if (!fVNodeCountingEnabled)
4453 		return;
4454 
4455 	VNode* vnode = fVNodes->Lookup(vnid);
4456 	if (vnode == NULL) {
4457 		ERROR(("Volume::_DecrementVNodeCount(): Node with ID %" B_PRId64 " not "
4458 			"known!\n", vnid));
4459 		return;
4460 	}
4461 
4462 	vnode->useCount--;
4463 //PRINT(("_DecrementVNodeCount(%Ld): count: %ld, fVNodeCountMap size: %ld\n", vnid, tmpCount, fVNodeCountMap->Size()));
4464 }
4465 
4466 
4467 // _RemoveInvalidVNode
4468 void
4469 Volume::_RemoveInvalidVNode(ino_t vnid)
4470 {
4471 	MutexLocker locker(fLock);
4472 
4473 	VNode* vnode = fVNodes->Lookup(vnid);
4474 	if (vnode == NULL) {
4475 		ERROR(("Volume::_RemoveInvalidVNode(): Node with ID %" B_PRId64
4476 			" not known!\n", vnid));
4477 		return;
4478 	}
4479 
4480 	fVNodes->Remove(vnode);
4481 	locker.Unlock();
4482 
4483 	// release all references acquired so far
4484 	if (fVNodeCountingEnabled) {
4485 		for (; vnode->useCount > 0; vnode->useCount--)
4486 			put_vnode(fFSVolume, vnid);
4487 	}
4488 
4489 	vnode->Delete(this);
4490 }
4491 
4492 
4493 // _InternalIOCtl
4494 status_t
4495 Volume::_InternalIOCtl(userlandfs_ioctl* buffer, int32 bufferSize)
4496 {
4497 	if (buffer->version != USERLAND_IOCTL_CURRENT_VERSION)
4498 		return B_BAD_VALUE;
4499 	status_t result = B_OK;
4500 	switch (buffer->command) {
4501 		case USERLAND_IOCTL_PUT_ALL_PENDING_VNODES:
4502 			result = _PutAllPendingVNodes();
4503 			break;
4504 		default:
4505 			return B_BAD_VALUE;
4506 	}
4507 	buffer->error = result;
4508 	return B_OK;
4509 }
4510 
4511 // _PutAllPendingVNodes
4512 status_t
4513 Volume::_PutAllPendingVNodes()
4514 {
4515 PRINT(("Volume::_PutAllPendingVNodes()\n"));
4516 	if (!fFileSystem->GetPortPool()->IsDisconnected()) {
4517 		PRINT(("Volume::_PutAllPendingVNodes() failed: still connected\n"));
4518 		return USERLAND_IOCTL_STILL_CONNECTED;
4519 	}
4520 
4521 	MutexLocker locker(fLock);
4522 
4523 	if (!fVNodeCountingEnabled) {
4524 		PRINT(("Volume::_PutAllPendingVNodes() failed: vnode counting "
4525 			"disabled\n"));
4526 		return USERLAND_IOCTL_VNODE_COUNTING_DISABLED;
4527 	}
4528 	// Check whether there are open entities at the moment.
4529 	if (atomic_get(&fOpenFiles) > 0) {
4530 		PRINT(("Volume::_PutAllPendingVNodes() failed: open files\n"));
4531 		return USERLAND_IOCTL_OPEN_FILES;
4532 	}
4533 	if (atomic_get(&fOpenDirectories) > 0) {
4534 		PRINT(("Volume::_PutAllPendingVNodes() failed: open dirs\n"));
4535 		return USERLAND_IOCTL_OPEN_DIRECTORIES;
4536 	}
4537 	if (atomic_get(&fOpenAttributeDirectories) > 0) {
4538 		PRINT(("Volume::_PutAllPendingVNodes() failed: open attr dirs\n"));
4539 		return USERLAND_IOCTL_OPEN_ATTRIBUTE_DIRECTORIES;
4540 	}
4541 	if (atomic_get(&fOpenAttributes) > 0) {
4542 		PRINT(("Volume::_PutAllPendingVNodes() failed: open attributes\n"));
4543 		return USERLAND_IOCTL_OPEN_ATTRIBUTES;
4544 	}
4545 	if (atomic_get(&fOpenIndexDirectories) > 0) {
4546 		PRINT(("Volume::_PutAllPendingVNodes() failed: open index dirs\n"));
4547 		return USERLAND_IOCTL_OPEN_INDEX_DIRECTORIES;
4548 	}
4549 	if (atomic_get(&fOpenQueries) > 0) {
4550 		PRINT(("Volume::_PutAllPendingVNodes() failed: open queries\n"));
4551 		return USERLAND_IOCTL_OPEN_QUERIES;
4552 	}
4553 	// No open entities. Since the port pool is disconnected, no new
4554 	// entities can be opened. Disable node counting and put all pending
4555 	// vnodes.
4556 	fVNodeCountingEnabled = false;
4557 
4558 	int32 putVNodeCount = 0;
4559 
4560 	// Since the vnode map can still change, we need to iterate to the first
4561 	// node we need to put, drop the lock, put the node, and restart from the
4562 	// beginning.
4563 	// TODO: Optimize by extracting batches of relevant nodes to an on-stack
4564 	// array.
4565 	bool nodeFound;
4566 	do {
4567 		nodeFound = false;
4568 
4569 		// get the next node to put
4570 		for (VNodeMap::Iterator it = fVNodes->GetIterator();
4571 				VNode* vnode = it.Next();) {
4572 			if (vnode->useCount > 0) {
4573 				ino_t vnid = vnode->id;
4574 				int32 count = vnode->useCount;
4575 				vnode->useCount = 0;
4576 				fs_vnode_ops* ops = vnode->ops->ops;
4577 				bool published = vnode->published;
4578 
4579 				locker.Unlock();
4580 
4581 				// If the node has not yet been published, we have to do that
4582 				// before putting otherwise the VFS will complain that the node
4583 				// is busy when the last reference is gone.
4584 				if (!published)
4585 					publish_vnode(fFSVolume, vnid, vnode, ops, S_IFDIR, 0);
4586 
4587 				for (int32 i = 0; i < count; i++) {
4588 					PutVNode(vnid);
4589 					putVNodeCount++;
4590 				}
4591 
4592 				locker.Lock();
4593 
4594 				nodeFound = true;
4595 				break;
4596 			}
4597 		}
4598 	} while (nodeFound);
4599 
4600 	PRINT(("Volume::_PutAllPendingVNodes() successful: Put %" B_PRId32
4601 		" vnodes\n", putVNodeCount));
4602 
4603 	return B_OK;
4604 }
4605 
4606 
4607 // _RegisterIORequest
4608 status_t
4609 Volume::_RegisterIORequest(io_request* request, int32* requestID)
4610 {
4611 	MutexLocker _(fLock);
4612 
4613 	// get the next free ID
4614 	while (fIORequestInfosByID->Lookup(++fLastIORequestID) != NULL) {
4615 	}
4616 
4617 	// allocate the info
4618 	IORequestInfo* info = new(std::nothrow) IORequestInfo(request,
4619 		++fLastIORequestID);
4620 	if (info == NULL)
4621 		return B_NO_MEMORY;
4622 
4623 	// add the info to the maps
4624 	fIORequestInfosByID->Insert(info);
4625 	fIORequestInfosByStruct->Insert(info);
4626 
4627 	*requestID = info->id;
4628 
4629 	return B_OK;
4630 }
4631 
4632 
4633 // _UnregisterIORequest
4634 status_t
4635 Volume::_UnregisterIORequest(int32 requestID)
4636 {
4637 	MutexLocker _(fLock);
4638 
4639 	if (IORequestInfo* info = fIORequestInfosByID->Lookup(requestID)) {
4640 		fIORequestInfosByID->Remove(info);
4641 		fIORequestInfosByStruct->Remove(info);
4642 		return B_OK;
4643 	}
4644 
4645 	return B_ENTRY_NOT_FOUND;
4646 }
4647 
4648 
4649 // _FindIORequest
4650 status_t
4651 Volume::_FindIORequest(int32 requestID, io_request** request)
4652 {
4653 	MutexLocker _(fLock);
4654 
4655 	if (IORequestInfo* info = fIORequestInfosByID->Lookup(requestID)) {
4656 		*request = info->request;
4657 		return B_OK;
4658 	}
4659 
4660 	return B_ENTRY_NOT_FOUND;
4661 }
4662 
4663 
4664 // _FindIORequest
4665 status_t
4666 Volume::_FindIORequest(io_request* request, int32* requestID)
4667 {
4668 	MutexLocker _(fLock);
4669 
4670 	if (IORequestInfo* info = fIORequestInfosByStruct->Lookup(request)) {
4671 		*requestID = info->id;
4672 		return B_OK;
4673 	}
4674 
4675 	return B_ENTRY_NOT_FOUND;
4676 }
4677 
4678 
4679 /*static*/ status_t
4680 Volume::_IterativeFDIOGetVecs(void* _cookie, io_request* ioRequest,
4681 	off_t offset, size_t size, struct file_io_vec* vecs, size_t* _count)
4682 {
4683 	IterativeFDIOCookie* cookie = (IterativeFDIOCookie*)_cookie;
4684 	Volume* volume = cookie->volume;
4685 
4686 	MutexLocker locker(volume->fLock);
4687 
4688 	// If there are vecs cached in the cookie and the offset matches, return
4689 	// those.
4690 	if (cookie->vecs != NULL) {
4691 		size_t vecCount = 0;
4692 		if (offset == cookie->offset) {
4693 			// good, copy the vecs
4694 			while (size > 0 && vecCount < cookie->vecCount
4695 					&& vecCount < *_count) {
4696 				off_t maxSize = std::min((off_t)size,
4697 					cookie->vecs[vecCount].length);
4698 				vecs[vecCount].offset = cookie->vecs[vecCount].offset;
4699 				vecs[vecCount].length = maxSize;
4700 
4701 				size -= maxSize;
4702 				vecCount++;
4703 			}
4704 		}
4705 
4706 		cookie->vecs = NULL;
4707 		cookie->vecCount = 0;
4708 
4709 		// got some vecs? -- then we're done
4710 		if (vecCount > 0) {
4711 			*_count = vecCount;
4712 			return B_OK;
4713 		}
4714 	}
4715 
4716 	// we have to ask the client FS
4717 	int32 requestID = cookie->requestID;
4718 	void* clientCookie = cookie->clientCookie;
4719 	locker.Unlock();
4720 
4721 	// get a free port
4722 	RequestPort* port = volume->fFileSystem->GetPortPool()->AcquirePort();
4723 	if (!port)
4724 		return B_ERROR;
4725 	PortReleaser _(volume->fFileSystem->GetPortPool(), port);
4726 
4727 	// prepare the request
4728 	RequestAllocator allocator(port->GetPort());
4729 	IterativeIOGetVecsRequest* request;
4730 	status_t error = AllocateRequest(allocator, &request);
4731 	if (error != B_OK)
4732 		return error;
4733 
4734 	request->volume = volume->fUserlandVolume;
4735 	request->cookie = clientCookie;
4736 	request->offset = offset;
4737 	request->request = requestID;
4738 	request->size = size;
4739 	size_t maxVecs = std::min(*_count,
4740 		(size_t)IterativeIOGetVecsReply::MAX_VECS);
4741 	request->vecCount = maxVecs;
4742 
4743 	// send the request
4744 	KernelRequestHandler handler(volume, ITERATIVE_IO_GET_VECS_REPLY);
4745 	IterativeIOGetVecsReply* reply;
4746 	error = volume->_SendRequest(port, &allocator, &handler, (Request**)&reply);
4747 	if (error != B_OK)
4748 		return error;
4749 	RequestReleaser requestReleaser(port, reply);
4750 
4751 	// process the reply
4752 	if (reply->error != B_OK)
4753 		return reply->error;
4754 	uint32 vecCount = reply->vecCount;
4755 	if (vecCount < 0 || vecCount > maxVecs)
4756 		return B_BAD_DATA;
4757 
4758 	memcpy(vecs, reply->vecs, vecCount * sizeof(file_io_vec));
4759 	*_count = vecCount;
4760 
4761 	return B_OK;
4762 }
4763 
4764 
4765 /*static*/ status_t
4766 Volume::_IterativeFDIOFinished(void* _cookie, io_request* ioRequest,
4767 	status_t status, bool partialTransfer, size_t bytesTransferred)
4768 {
4769 	IterativeFDIOCookie* cookie = (IterativeFDIOCookie*)_cookie;
4770 	Volume* volume = cookie->volume;
4771 
4772 	// At any rate, we're done with the cookie after this call -- it will not
4773 	// be used anymore.
4774 	BReference<IterativeFDIOCookie> _(cookie, true);
4775 
4776 	// We also want to dispose of the request.
4777 	IORequestRemover _2(volume, cookie->requestID);
4778 
4779 	// get a free port
4780 	RequestPort* port = volume->fFileSystem->GetPortPool()->AcquirePort();
4781 	if (!port)
4782 		return B_ERROR;
4783 	PortReleaser _3(volume->fFileSystem->GetPortPool(), port);
4784 
4785 	// prepare the request
4786 	RequestAllocator allocator(port->GetPort());
4787 	IterativeIOFinishedRequest* request;
4788 	status_t error = AllocateRequest(allocator, &request);
4789 	if (error != B_OK)
4790 		return error;
4791 
4792 	request->volume = volume->fUserlandVolume;
4793 	request->cookie = cookie->clientCookie;
4794 	request->request = cookie->requestID;
4795 	request->status = status;
4796 	request->partialTransfer = partialTransfer;
4797 	request->bytesTransferred = bytesTransferred;
4798 
4799 	// send the request
4800 	KernelRequestHandler handler(volume, ITERATIVE_IO_FINISHED_REPLY);
4801 	IterativeIOFinishedReply* reply;
4802 	error = volume->_SendRequest(port, &allocator, &handler, (Request**)&reply);
4803 	if (error != B_OK)
4804 		return error;
4805 	RequestReleaser requestReleaser(port, reply);
4806 
4807 	// process the reply
4808 	if (reply->error != B_OK)
4809 		return reply->error;
4810 	return B_OK;
4811 }
4812