xref: /haiku/src/add-ons/kernel/file_systems/userlandfs/kernel_add_on/Volume.cpp (revision 2897df967633aab846ff4917b53e2af7d1e54eeb)
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 		memcpy(buffer, readBuffer, reply->bytesRead);
2184 	*bytesRead = reply->bytesRead;
2185 	_SendReceiptAck(port);
2186 	return error;
2187 }
2188 
2189 // Write
2190 status_t
2191 Volume::Write(void* _node, void* cookie, off_t pos, const void* buffer,
2192 	size_t size, size_t* bytesWritten)
2193 {
2194 	VNode* vnode = (VNode*)_node;
2195 
2196 	*bytesWritten = 0;
2197 
2198 	// check capability
2199 	if (!HasVNodeCapability(vnode, FS_VNODE_CAPABILITY_WRITE))
2200 		return B_BAD_VALUE;
2201 
2202 	// get a free port
2203 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
2204 	if (!port)
2205 		return B_ERROR;
2206 	PortReleaser _(fFileSystem->GetPortPool(), port);
2207 
2208 	// prepare the request
2209 	RequestAllocator allocator(port->GetPort());
2210 	WriteRequest* request;
2211 	status_t error = AllocateRequest(allocator, &request);
2212 	if (error != B_OK)
2213 		return error;
2214 
2215 	request->volume = fUserlandVolume;
2216 	request->node = vnode->clientNode;
2217 	request->fileCookie = cookie;
2218 	request->pos = pos;
2219 	error = allocator.AllocateData(request->buffer, buffer, size, 1);
2220 	if (error != B_OK)
2221 		return error;
2222 
2223 	// send the request
2224 	KernelRequestHandler handler(this, WRITE_REPLY);
2225 	WriteReply* reply;
2226 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
2227 	if (error != B_OK)
2228 		return error;
2229 	RequestReleaser requestReleaser(port, reply);
2230 
2231 	// process the reply
2232 	if (reply->error != B_OK)
2233 		return reply->error;
2234 	*bytesWritten = reply->bytesWritten;
2235 	return error;
2236 }
2237 
2238 
2239 // #pragma mark - directories
2240 
2241 // CreateDir
2242 status_t
2243 Volume::CreateDir(void* _dir, const char* name, int mode)
2244 {
2245 	VNode* vnode = (VNode*)_dir;
2246 
2247 	// check capability
2248 	if (!HasVNodeCapability(vnode, FS_VNODE_CAPABILITY_CREATE_DIR))
2249 		return B_BAD_VALUE;
2250 
2251 	// get a free port
2252 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
2253 	if (!port)
2254 		return B_ERROR;
2255 	PortReleaser _(fFileSystem->GetPortPool(), port);
2256 
2257 	// prepare the request
2258 	RequestAllocator allocator(port->GetPort());
2259 	CreateDirRequest* request;
2260 	status_t error = AllocateRequest(allocator, &request);
2261 	if (error != B_OK)
2262 		return error;
2263 
2264 	request->volume = fUserlandVolume;
2265 	request->node = vnode->clientNode;
2266 	error = allocator.AllocateString(request->name, name);
2267 	request->mode = mode;
2268 	if (error != B_OK)
2269 		return error;
2270 
2271 	// send the request
2272 	KernelRequestHandler handler(this, CREATE_DIR_REPLY);
2273 	CreateDirReply* reply;
2274 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
2275 	if (error != B_OK)
2276 		return error;
2277 	RequestReleaser requestReleaser(port, reply);
2278 
2279 	// process the reply
2280 	if (reply->error != B_OK)
2281 		return reply->error;
2282 	return error;
2283 }
2284 
2285 // RemoveDir
2286 status_t
2287 Volume::RemoveDir(void* _dir, const char* name)
2288 {
2289 	VNode* vnode = (VNode*)_dir;
2290 
2291 	// check capability
2292 	if (!HasVNodeCapability(vnode, FS_VNODE_CAPABILITY_REMOVE_DIR))
2293 		return B_BAD_VALUE;
2294 
2295 	// get a free port
2296 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
2297 	if (!port)
2298 		return B_ERROR;
2299 	PortReleaser _(fFileSystem->GetPortPool(), port);
2300 
2301 	// prepare the request
2302 	RequestAllocator allocator(port->GetPort());
2303 	RemoveDirRequest* request;
2304 	status_t error = AllocateRequest(allocator, &request);
2305 	if (error != B_OK)
2306 		return error;
2307 
2308 	request->volume = fUserlandVolume;
2309 	request->node = vnode->clientNode;
2310 	error = allocator.AllocateString(request->name, name);
2311 	if (error != B_OK)
2312 		return error;
2313 
2314 	// send the request
2315 	KernelRequestHandler handler(this, REMOVE_DIR_REPLY);
2316 	RemoveDirReply* reply;
2317 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
2318 	if (error != B_OK)
2319 		return error;
2320 	RequestReleaser requestReleaser(port, reply);
2321 
2322 	// process the reply
2323 	if (reply->error != B_OK)
2324 		return reply->error;
2325 	return error;
2326 }
2327 
2328 // OpenDir
2329 status_t
2330 Volume::OpenDir(void* _node, void** cookie)
2331 {
2332 	VNode* vnode = (VNode*)_node;
2333 
2334 	// check capability
2335 	if (!HasVNodeCapability(vnode, FS_VNODE_CAPABILITY_OPEN_DIR))
2336 		return B_BAD_VALUE;
2337 
2338 	// get a free port
2339 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
2340 	if (!port)
2341 		return B_ERROR;
2342 	PortReleaser _(fFileSystem->GetPortPool(), port);
2343 	AutoIncrementer incrementer(&fOpenDirectories);
2344 
2345 	// prepare the request
2346 	RequestAllocator allocator(port->GetPort());
2347 	OpenDirRequest* request;
2348 	status_t error = AllocateRequest(allocator, &request);
2349 	if (error != B_OK)
2350 		return error;
2351 
2352 	request->volume = fUserlandVolume;
2353 	request->node = vnode->clientNode;
2354 
2355 	// send the request
2356 	KernelRequestHandler handler(this, OPEN_DIR_REPLY);
2357 	OpenDirReply* reply;
2358 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
2359 	if (error != B_OK)
2360 		return error;
2361 	RequestReleaser requestReleaser(port, reply);
2362 
2363 	// process the reply
2364 	if (reply->error != B_OK)
2365 		return reply->error;
2366 	incrementer.Keep();
2367 	*cookie = reply->dirCookie;
2368 	return error;
2369 }
2370 
2371 // CloseDir
2372 status_t
2373 Volume::CloseDir(void* node, void* cookie)
2374 {
2375 	status_t error = _CloseDir(node, cookie);
2376 	if (error != B_OK && fFileSystem->GetPortPool()->IsDisconnected()) {
2377 		// This isn't really necessary, as the return value is irrelevant to
2378 		// the VFS. OBOS ignores it completely. The fsshell returns it to the
2379 		// userland, but considers the node closed anyway.
2380 		WARN(("Volume::CloseDir(): connection lost, forcing close dir\n"));
2381 		return B_OK;
2382 	}
2383 	return error;
2384 }
2385 
2386 // FreeDirCookie
2387 status_t
2388 Volume::FreeDirCookie(void* node, void* cookie)
2389 {
2390 	status_t error = _FreeDirCookie(node, cookie);
2391 	bool disconnected = false;
2392 	if (error != B_OK && fFileSystem->GetPortPool()->IsDisconnected()) {
2393 		// This isn't really necessary, as the return value is irrelevant to
2394 		// the VFS. It's completely ignored by OBOS as well as by the fsshell.
2395 		WARN(("Volume::FreeDirCookie(): connection lost, forcing free dir "
2396 			"cookie\n"));
2397 		error = B_OK;
2398 		disconnected = true;
2399 	}
2400 	int32 openDirs = atomic_add(&fOpenDirectories, -1);
2401 	if (openDirs <= 1 && disconnected)
2402 		_PutAllPendingVNodes();
2403 	return error;
2404 }
2405 
2406 // ReadDir
2407 status_t
2408 Volume::ReadDir(void* _node, void* cookie, void* buffer, size_t bufferSize,
2409 	uint32 count, uint32* countRead)
2410 {
2411 	VNode* vnode = (VNode*)_node;
2412 
2413 	*countRead = 0;
2414 
2415 	// check capability
2416 	if (!HasVNodeCapability(vnode, FS_VNODE_CAPABILITY_READ_DIR))
2417 		return B_BAD_VALUE;
2418 
2419 	// get a free port
2420 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
2421 	if (!port)
2422 		return B_ERROR;
2423 	PortReleaser _(fFileSystem->GetPortPool(), port);
2424 
2425 	// prepare the request
2426 	RequestAllocator allocator(port->GetPort());
2427 	ReadDirRequest* request;
2428 	status_t error = AllocateRequest(allocator, &request);
2429 	if (error != B_OK)
2430 		return error;
2431 
2432 	request->volume = fUserlandVolume;
2433 	request->node = vnode->clientNode;
2434 	request->dirCookie = cookie;
2435 	request->bufferSize = bufferSize;
2436 	request->count = count;
2437 
2438 	// send the request
2439 	KernelRequestHandler handler(this, READ_DIR_REPLY);
2440 	ReadDirReply* reply;
2441 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
2442 	if (error != B_OK)
2443 		return error;
2444 	RequestReleaser requestReleaser(port, reply);
2445 
2446 	// process the reply
2447 	if (reply->error != B_OK)
2448 		return reply->error;
2449 	if (reply->count < 0 || reply->count > count)
2450 		return B_BAD_DATA;
2451 	if ((int32)bufferSize < reply->buffer.GetSize())
2452 		return B_BAD_DATA;
2453 
2454 	PRINT(("Volume::ReadDir(): buffer returned: %" B_PRId32 " bytes\n",
2455 		reply->buffer.GetSize()));
2456 
2457 	*countRead = reply->count;
2458 	if (*countRead > 0) {
2459 		// copy the buffer -- limit the number of bytes to copy
2460 		uint32 maxBytes = *countRead
2461 			* (sizeof(struct dirent) + B_FILE_NAME_LENGTH);
2462 		uint32 copyBytes = reply->buffer.GetSize();
2463 		if (copyBytes > maxBytes)
2464 			copyBytes = maxBytes;
2465 		memcpy(buffer, reply->buffer.GetData(), copyBytes);
2466 	}
2467 	_SendReceiptAck(port);
2468 	return error;
2469 }
2470 
2471 // RewindDir
2472 status_t
2473 Volume::RewindDir(void* _node, void* cookie)
2474 {
2475 	VNode* vnode = (VNode*)_node;
2476 
2477 	// check capability
2478 	if (!HasVNodeCapability(vnode, FS_VNODE_CAPABILITY_REWIND_DIR))
2479 		return B_BAD_VALUE;
2480 
2481 	// get a free port
2482 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
2483 	if (!port)
2484 		return B_ERROR;
2485 	PortReleaser _(fFileSystem->GetPortPool(), port);
2486 
2487 	// prepare the request
2488 	RequestAllocator allocator(port->GetPort());
2489 	RewindDirRequest* request;
2490 	status_t error = AllocateRequest(allocator, &request);
2491 	if (error != B_OK)
2492 		return error;
2493 
2494 	request->volume = fUserlandVolume;
2495 	request->node = vnode->clientNode;
2496 	request->dirCookie = cookie;
2497 
2498 	// send the request
2499 	KernelRequestHandler handler(this, REWIND_DIR_REPLY);
2500 	RewindDirReply* reply;
2501 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
2502 	if (error != B_OK)
2503 		return error;
2504 	RequestReleaser requestReleaser(port, reply);
2505 
2506 	// process the reply
2507 	if (reply->error != B_OK)
2508 		return reply->error;
2509 	return error;
2510 }
2511 
2512 
2513 // #pragma mark - attribute directories
2514 
2515 
2516 // OpenAttrDir
2517 status_t
2518 Volume::OpenAttrDir(void* _node, void** cookie)
2519 {
2520 	VNode* vnode = (VNode*)_node;
2521 
2522 	// check capability
2523 	if (!HasVNodeCapability(vnode, FS_VNODE_CAPABILITY_OPEN_ATTR_DIR))
2524 		return B_BAD_VALUE;
2525 
2526 	// get a free port
2527 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
2528 	if (!port)
2529 		return B_ERROR;
2530 	PortReleaser _(fFileSystem->GetPortPool(), port);
2531 	AutoIncrementer incrementer(&fOpenAttributeDirectories);
2532 
2533 	// prepare the request
2534 	RequestAllocator allocator(port->GetPort());
2535 	OpenAttrDirRequest* request;
2536 	status_t error = AllocateRequest(allocator, &request);
2537 	if (error != B_OK)
2538 		return error;
2539 
2540 	request->volume = fUserlandVolume;
2541 	request->node = vnode->clientNode;
2542 
2543 	// send the request
2544 	KernelRequestHandler handler(this, OPEN_ATTR_DIR_REPLY);
2545 	OpenAttrDirReply* reply;
2546 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
2547 	if (error != B_OK)
2548 		return error;
2549 	RequestReleaser requestReleaser(port, reply);
2550 
2551 	// process the reply
2552 	if (reply->error != B_OK)
2553 		return reply->error;
2554 	incrementer.Keep();
2555 	*cookie = reply->attrDirCookie;
2556 	return error;
2557 }
2558 
2559 // CloseAttrDir
2560 status_t
2561 Volume::CloseAttrDir(void* node, void* cookie)
2562 {
2563 	status_t error = _CloseAttrDir(node, cookie);
2564 	if (error != B_OK && fFileSystem->GetPortPool()->IsDisconnected()) {
2565 		// This isn't really necessary, as the return value is irrelevant to
2566 		// the VFS. OBOS ignores it completely. The fsshell returns it to the
2567 		// userland, but considers the node closed anyway.
2568 		WARN(("Volume::CloseAttrDir(): connection lost, forcing close attr "
2569 			"dir\n"));
2570 		return B_OK;
2571 	}
2572 	return error;
2573 }
2574 
2575 // FreeAttrDirCookie
2576 status_t
2577 Volume::FreeAttrDirCookie(void* node, void* cookie)
2578 {
2579 	status_t error = _FreeAttrDirCookie(node, cookie);
2580 	bool disconnected = false;
2581 	if (error != B_OK && fFileSystem->GetPortPool()->IsDisconnected()) {
2582 		// This isn't really necessary, as the return value is irrelevant to
2583 		// the VFS. It's completely ignored by OBOS as well as by the fsshell.
2584 		WARN(("Volume::FreeAttrDirCookie(): connection lost, forcing free attr "
2585 			"dir cookie\n"));
2586 		error = B_OK;
2587 		disconnected = true;
2588 	}
2589 
2590 	int32 openAttrDirs = atomic_add(&fOpenAttributeDirectories, -1);
2591 	if (openAttrDirs <= 1 && disconnected)
2592 		_PutAllPendingVNodes();
2593 	return error;
2594 }
2595 
2596 // ReadAttrDir
2597 status_t
2598 Volume::ReadAttrDir(void* _node, void* cookie, void* buffer,
2599 	size_t bufferSize, uint32 count, uint32* countRead)
2600 {
2601 	VNode* vnode = (VNode*)_node;
2602 
2603 	// check capability
2604 	if (!HasVNodeCapability(vnode, FS_VNODE_CAPABILITY_READ_ATTR_DIR))
2605 		return B_BAD_VALUE;
2606 
2607 	*countRead = 0;
2608 	// get a free port
2609 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
2610 	if (!port)
2611 		return B_ERROR;
2612 	PortReleaser _(fFileSystem->GetPortPool(), port);
2613 
2614 	// prepare the request
2615 	RequestAllocator allocator(port->GetPort());
2616 	ReadAttrDirRequest* request;
2617 	status_t error = AllocateRequest(allocator, &request);
2618 	if (error != B_OK)
2619 		return error;
2620 
2621 	request->volume = fUserlandVolume;
2622 	request->node = vnode->clientNode;
2623 	request->attrDirCookie = cookie;
2624 	request->bufferSize = bufferSize;
2625 	request->count = count;
2626 
2627 	// send the request
2628 	KernelRequestHandler handler(this, READ_ATTR_DIR_REPLY);
2629 	ReadAttrDirReply* reply;
2630 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
2631 	if (error != B_OK)
2632 		return error;
2633 	RequestReleaser requestReleaser(port, reply);
2634 
2635 	// process the reply
2636 	if (reply->error != B_OK)
2637 		return reply->error;
2638 	if (reply->count < 0 || reply->count > count)
2639 		return B_BAD_DATA;
2640 	if ((int32)bufferSize < reply->buffer.GetSize())
2641 		return B_BAD_DATA;
2642 
2643 	*countRead = reply->count;
2644 	if (*countRead > 0) {
2645 		// copy the buffer -- limit the number of bytes to copy
2646 		uint32 maxBytes = *countRead
2647 			* (sizeof(struct dirent) + B_ATTR_NAME_LENGTH);
2648 		uint32 copyBytes = reply->buffer.GetSize();
2649 		if (copyBytes > maxBytes)
2650 			copyBytes = maxBytes;
2651 		memcpy(buffer, reply->buffer.GetData(), copyBytes);
2652 	}
2653 	_SendReceiptAck(port);
2654 	return error;
2655 }
2656 
2657 // RewindAttrDir
2658 status_t
2659 Volume::RewindAttrDir(void* _node, void* cookie)
2660 {
2661 	VNode* vnode = (VNode*)_node;
2662 
2663 	// check capability
2664 	if (!HasVNodeCapability(vnode, FS_VNODE_CAPABILITY_REWIND_ATTR_DIR))
2665 		return B_BAD_VALUE;
2666 
2667 	// get a free port
2668 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
2669 	if (!port)
2670 		return B_ERROR;
2671 	PortReleaser _(fFileSystem->GetPortPool(), port);
2672 
2673 	// prepare the request
2674 	RequestAllocator allocator(port->GetPort());
2675 	RewindAttrDirRequest* request;
2676 	status_t error = AllocateRequest(allocator, &request);
2677 	if (error != B_OK)
2678 		return error;
2679 
2680 	request->volume = fUserlandVolume;
2681 	request->node = vnode->clientNode;
2682 	request->attrDirCookie = cookie;
2683 
2684 	// send the request
2685 	KernelRequestHandler handler(this, REWIND_ATTR_DIR_REPLY);
2686 	RewindAttrDirReply* reply;
2687 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
2688 	if (error != B_OK)
2689 		return error;
2690 	RequestReleaser requestReleaser(port, reply);
2691 
2692 	// process the reply
2693 	if (reply->error != B_OK)
2694 		return reply->error;
2695 	return error;
2696 }
2697 
2698 
2699 // #pragma mark - attributes
2700 
2701 // CreateAttr
2702 status_t
2703 Volume::CreateAttr(void* _node, const char* name, uint32 type, int openMode,
2704 	void** cookie)
2705 {
2706 	VNode* vnode = (VNode*)_node;
2707 
2708 	// check capability
2709 	if (!HasVNodeCapability(vnode, FS_VNODE_CAPABILITY_CREATE_ATTR))
2710 		return B_BAD_VALUE;
2711 
2712 	// get a free port
2713 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
2714 	if (!port)
2715 		return B_ERROR;
2716 	PortReleaser _(fFileSystem->GetPortPool(), port);
2717 	AutoIncrementer incrementer(&fOpenAttributes);
2718 
2719 	// prepare the request
2720 	RequestAllocator allocator(port->GetPort());
2721 	CreateAttrRequest* request;
2722 	status_t error = AllocateRequest(allocator, &request);
2723 	if (error != B_OK)
2724 		return error;
2725 
2726 	request->volume = fUserlandVolume;
2727 	request->node = vnode->clientNode;
2728 	error = allocator.AllocateString(request->name, name);
2729 	request->type = type;
2730 	request->openMode = openMode;
2731 	if (error != B_OK)
2732 		return error;
2733 
2734 	// send the request
2735 	KernelRequestHandler handler(this, CREATE_ATTR_REPLY);
2736 	CreateAttrReply* reply;
2737 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
2738 	if (error != B_OK)
2739 		return error;
2740 	RequestReleaser requestReleaser(port, reply);
2741 
2742 	// process the reply
2743 	if (reply->error != B_OK)
2744 		return reply->error;
2745 	incrementer.Keep();
2746 	*cookie = reply->attrCookie;
2747 	return error;
2748 }
2749 
2750 // OpenAttr
2751 status_t
2752 Volume::OpenAttr(void* _node, const char* name, int openMode,
2753 	void** cookie)
2754 {
2755 	VNode* vnode = (VNode*)_node;
2756 
2757 	// check capability
2758 	if (!HasVNodeCapability(vnode, FS_VNODE_CAPABILITY_OPEN_ATTR))
2759 		return B_BAD_VALUE;
2760 
2761 	// get a free port
2762 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
2763 	if (!port)
2764 		return B_ERROR;
2765 	PortReleaser _(fFileSystem->GetPortPool(), port);
2766 	AutoIncrementer incrementer(&fOpenAttributes);
2767 
2768 	// prepare the request
2769 	RequestAllocator allocator(port->GetPort());
2770 	OpenAttrRequest* request;
2771 	status_t error = AllocateRequest(allocator, &request);
2772 	if (error != B_OK)
2773 		return error;
2774 
2775 	request->volume = fUserlandVolume;
2776 	request->node = vnode->clientNode;
2777 	error = allocator.AllocateString(request->name, name);
2778 	request->openMode = openMode;
2779 	if (error != B_OK)
2780 		return error;
2781 
2782 	// send the request
2783 	KernelRequestHandler handler(this, OPEN_ATTR_REPLY);
2784 	OpenAttrReply* reply;
2785 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
2786 	if (error != B_OK)
2787 		return error;
2788 	RequestReleaser requestReleaser(port, reply);
2789 
2790 	// process the reply
2791 	if (reply->error != B_OK)
2792 		return reply->error;
2793 	incrementer.Keep();
2794 	*cookie = reply->attrCookie;
2795 	return error;
2796 }
2797 
2798 // CloseAttr
2799 status_t
2800 Volume::CloseAttr(void* node, void* cookie)
2801 {
2802 	status_t error = _CloseAttr(node, cookie);
2803 	if (error != B_OK && fFileSystem->GetPortPool()->IsDisconnected()) {
2804 		// This isn't really necessary, as the return value is irrelevant to
2805 		// the VFS. OBOS ignores it completely. The fsshell returns it to the
2806 		// userland, but considers the node closed anyway.
2807 		WARN(("Volume::CloseAttr(): connection lost, forcing close attr\n"));
2808 		return B_OK;
2809 	}
2810 	return error;
2811 }
2812 
2813 // FreeAttrCookie
2814 status_t
2815 Volume::FreeAttrCookie(void* node, void* cookie)
2816 {
2817 	status_t error = _FreeAttrCookie(node, cookie);
2818 	bool disconnected = false;
2819 	if (error != B_OK && fFileSystem->GetPortPool()->IsDisconnected()) {
2820 		// This isn't really necessary, as the return value is irrelevant to
2821 		// the VFS. It's completely ignored by OBOS as well as by the fsshell.
2822 		WARN(("Volume::FreeAttrCookie(): connection lost, forcing free attr "
2823 			"cookie\n"));
2824 		error = B_OK;
2825 		disconnected = true;
2826 	}
2827 
2828 	int32 openAttributes = atomic_add(&fOpenAttributes, -1);
2829 	if (openAttributes <= 1 && disconnected)
2830 		_PutAllPendingVNodes();
2831 	return error;
2832 }
2833 
2834 // ReadAttr
2835 status_t
2836 Volume::ReadAttr(void* _node, void* cookie, off_t pos,
2837 	void* buffer, size_t bufferSize, size_t* bytesRead)
2838 {
2839 	VNode* vnode = (VNode*)_node;
2840 
2841 	*bytesRead = 0;
2842 
2843 	// check capability
2844 	if (!HasVNodeCapability(vnode, FS_VNODE_CAPABILITY_READ_ATTR))
2845 		return B_BAD_VALUE;
2846 
2847 	// get a free port
2848 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
2849 	if (!port)
2850 		return B_ERROR;
2851 	PortReleaser _(fFileSystem->GetPortPool(), port);
2852 
2853 	// prepare the request
2854 	RequestAllocator allocator(port->GetPort());
2855 	ReadAttrRequest* request;
2856 	status_t error = AllocateRequest(allocator, &request);
2857 	if (error != B_OK)
2858 		return error;
2859 
2860 	request->volume = fUserlandVolume;
2861 	request->node = vnode->clientNode;
2862 	request->attrCookie = cookie;
2863 	request->pos = pos;
2864 	request->size = bufferSize;
2865 
2866 	// send the request
2867 	KernelRequestHandler handler(this, READ_ATTR_REPLY);
2868 	ReadAttrReply* reply;
2869 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
2870 	if (error != B_OK)
2871 		return error;
2872 	RequestReleaser requestReleaser(port, reply);
2873 
2874 	// process the reply
2875 	if (reply->error != B_OK)
2876 		return reply->error;
2877 	void* readBuffer = reply->buffer.GetData();
2878 	if (reply->bytesRead > (uint32)reply->buffer.GetSize()
2879 		|| reply->bytesRead > bufferSize) {
2880 		return B_BAD_DATA;
2881 	}
2882 	if (reply->bytesRead > 0)
2883 		memcpy(buffer, readBuffer, reply->bytesRead);
2884 	*bytesRead = reply->bytesRead;
2885 	_SendReceiptAck(port);
2886 	return error;
2887 }
2888 
2889 // WriteAttr
2890 status_t
2891 Volume::WriteAttr(void* _node, void* cookie, off_t pos,
2892 	const void* buffer, size_t bufferSize, size_t* bytesWritten)
2893 {
2894 	VNode* vnode = (VNode*)_node;
2895 
2896 	*bytesWritten = 0;
2897 
2898 	// check capability
2899 	if (!HasVNodeCapability(vnode, FS_VNODE_CAPABILITY_WRITE_ATTR))
2900 		return B_BAD_VALUE;
2901 
2902 	// get a free port
2903 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
2904 	if (!port)
2905 		return B_ERROR;
2906 	PortReleaser _(fFileSystem->GetPortPool(), port);
2907 
2908 	// prepare the request
2909 	RequestAllocator allocator(port->GetPort());
2910 	WriteAttrRequest* request;
2911 	status_t error = AllocateRequest(allocator, &request);
2912 	if (error != B_OK)
2913 		return error;
2914 
2915 	request->volume = fUserlandVolume;
2916 	request->node = vnode->clientNode;
2917 	request->attrCookie = cookie;
2918 	request->pos = pos;
2919 	error = allocator.AllocateData(request->buffer, buffer, bufferSize, 1);
2920 	if (error != B_OK)
2921 		return error;
2922 
2923 	// send the request
2924 	KernelRequestHandler handler(this, WRITE_ATTR_REPLY);
2925 	WriteAttrReply* reply;
2926 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
2927 	if (error != B_OK)
2928 		return error;
2929 	RequestReleaser requestReleaser(port, reply);
2930 
2931 	// process the reply
2932 	if (reply->error != B_OK)
2933 		return reply->error;
2934 	*bytesWritten = reply->bytesWritten;
2935 	return error;
2936 }
2937 
2938 // ReadAttrStat
2939 status_t
2940 Volume::ReadAttrStat(void* _node, void* cookie, struct stat *st)
2941 {
2942 	VNode* vnode = (VNode*)_node;
2943 
2944 	// check capability
2945 	if (!HasVNodeCapability(vnode, FS_VNODE_CAPABILITY_READ_ATTR_STAT))
2946 		return B_BAD_VALUE;
2947 
2948 	// get a free port
2949 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
2950 	if (!port)
2951 		return B_ERROR;
2952 	PortReleaser _(fFileSystem->GetPortPool(), port);
2953 
2954 	// prepare the request
2955 	RequestAllocator allocator(port->GetPort());
2956 	ReadAttrStatRequest* request;
2957 	status_t error = AllocateRequest(allocator, &request);
2958 	if (error != B_OK)
2959 		return error;
2960 
2961 	request->volume = fUserlandVolume;
2962 	request->node = vnode->clientNode;
2963 	request->attrCookie = cookie;
2964 
2965 	// send the request
2966 	KernelRequestHandler handler(this, READ_ATTR_STAT_REPLY);
2967 	ReadAttrStatReply* reply;
2968 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
2969 	if (error != B_OK)
2970 		return error;
2971 	RequestReleaser requestReleaser(port, reply);
2972 
2973 	// process the reply
2974 	if (reply->error != B_OK)
2975 		return reply->error;
2976 	*st = reply->st;
2977 	return error;
2978 }
2979 
2980 // WriteAttrStat
2981 status_t
2982 Volume::WriteAttrStat(void* _node, void* cookie, const struct stat *st,
2983 	int statMask)
2984 {
2985 	VNode* vnode = (VNode*)_node;
2986 
2987 	// check capability
2988 	if (!HasVNodeCapability(vnode, FS_VNODE_CAPABILITY_WRITE_ATTR_STAT))
2989 		return B_BAD_VALUE;
2990 
2991 	// get a free port
2992 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
2993 	if (!port)
2994 		return B_ERROR;
2995 	PortReleaser _(fFileSystem->GetPortPool(), port);
2996 
2997 	// prepare the request
2998 	RequestAllocator allocator(port->GetPort());
2999 	WriteAttrStatRequest* request;
3000 	status_t error = AllocateRequest(allocator, &request);
3001 	if (error != B_OK)
3002 		return error;
3003 
3004 	request->volume = fUserlandVolume;
3005 	request->node = vnode->clientNode;
3006 	request->attrCookie = cookie;
3007 	request->st = *st;
3008 	request->mask = statMask;
3009 
3010 	// send the request
3011 	KernelRequestHandler handler(this, WRITE_ATTR_STAT_REPLY);
3012 	WriteAttrStatReply* reply;
3013 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
3014 	if (error != B_OK)
3015 		return error;
3016 	RequestReleaser requestReleaser(port, reply);
3017 
3018 	// process the reply
3019 	if (reply->error != B_OK)
3020 		return reply->error;
3021 	return error;
3022 }
3023 
3024 // RenameAttr
3025 status_t
3026 Volume::RenameAttr(void* _oldNode, const char* oldName, void* _newNode,
3027 	const char* newName)
3028 {
3029 	VNode* oldVNode = (VNode*)_oldNode;
3030 	VNode* newVNode = (VNode*)_newNode;
3031 
3032 	// check capability
3033 	if (!HasVNodeCapability(oldVNode, FS_VNODE_CAPABILITY_RENAME_ATTR))
3034 		return B_BAD_VALUE;
3035 
3036 	// get a free port
3037 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
3038 	if (!port)
3039 		return B_ERROR;
3040 	PortReleaser _(fFileSystem->GetPortPool(), port);
3041 
3042 	// prepare the request
3043 	RequestAllocator allocator(port->GetPort());
3044 	RenameAttrRequest* request;
3045 	status_t error = AllocateRequest(allocator, &request);
3046 	if (error != B_OK)
3047 		return error;
3048 
3049 	request->volume = fUserlandVolume;
3050 	request->oldNode = oldVNode->clientNode;
3051 	request->newNode = newVNode->clientNode;
3052 	error = allocator.AllocateString(request->oldName, oldName);
3053 	if (error == B_OK)
3054 		error = allocator.AllocateString(request->newName, newName);
3055 	if (error != B_OK)
3056 		return error;
3057 
3058 	// send the request
3059 	KernelRequestHandler handler(this, RENAME_ATTR_REPLY);
3060 	RenameAttrReply* reply;
3061 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
3062 	if (error != B_OK)
3063 		return error;
3064 	RequestReleaser requestReleaser(port, reply);
3065 
3066 	// process the reply
3067 	if (reply->error != B_OK)
3068 		return reply->error;
3069 	return error;
3070 }
3071 
3072 // RemoveAttr
3073 status_t
3074 Volume::RemoveAttr(void* _node, const char* name)
3075 {
3076 	VNode* vnode = (VNode*)_node;
3077 
3078 	// check capability
3079 	if (!HasVNodeCapability(vnode, FS_VNODE_CAPABILITY_REMOVE_ATTR))
3080 		return B_BAD_VALUE;
3081 
3082 	// get a free port
3083 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
3084 	if (!port)
3085 		return B_ERROR;
3086 	PortReleaser _(fFileSystem->GetPortPool(), port);
3087 
3088 	// prepare the request
3089 	RequestAllocator allocator(port->GetPort());
3090 	RemoveAttrRequest* request;
3091 	status_t error = AllocateRequest(allocator, &request);
3092 	if (error != B_OK)
3093 		return error;
3094 
3095 	request->volume = fUserlandVolume;
3096 	request->node = vnode->clientNode;
3097 	error = allocator.AllocateString(request->name, name);
3098 	if (error != B_OK)
3099 		return error;
3100 
3101 	// send the request
3102 	KernelRequestHandler handler(this, REMOVE_ATTR_REPLY);
3103 	RemoveAttrReply* reply;
3104 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
3105 	if (error != B_OK)
3106 		return error;
3107 	RequestReleaser requestReleaser(port, reply);
3108 
3109 	// process the reply
3110 	if (reply->error != B_OK)
3111 		return reply->error;
3112 	return error;
3113 }
3114 
3115 
3116 // #pragma mark - indices
3117 
3118 
3119 // OpenIndexDir
3120 status_t
3121 Volume::OpenIndexDir(void** cookie)
3122 {
3123 	// check capability
3124 	if (!HasCapability(FS_VOLUME_CAPABILITY_OPEN_INDEX_DIR))
3125 		return B_BAD_VALUE;
3126 
3127 	// get a free port
3128 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
3129 	if (!port)
3130 		return B_ERROR;
3131 	PortReleaser _(fFileSystem->GetPortPool(), port);
3132 	AutoIncrementer incrementer(&fOpenIndexDirectories);
3133 
3134 	// prepare the request
3135 	RequestAllocator allocator(port->GetPort());
3136 	OpenIndexDirRequest* request;
3137 	status_t error = AllocateRequest(allocator, &request);
3138 	if (error != B_OK)
3139 		return error;
3140 
3141 	request->volume = fUserlandVolume;
3142 
3143 	// send the request
3144 	KernelRequestHandler handler(this, OPEN_INDEX_DIR_REPLY);
3145 	OpenIndexDirReply* reply;
3146 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
3147 	if (error != B_OK)
3148 		return error;
3149 	RequestReleaser requestReleaser(port, reply);
3150 
3151 	// process the reply
3152 	if (reply->error != B_OK)
3153 		return reply->error;
3154 	incrementer.Keep();
3155 	*cookie = reply->indexDirCookie;
3156 	return error;
3157 }
3158 
3159 // CloseIndexDir
3160 status_t
3161 Volume::CloseIndexDir(void* cookie)
3162 {
3163 	status_t error = _CloseIndexDir(cookie);
3164 	if (error != B_OK && fFileSystem->GetPortPool()->IsDisconnected()) {
3165 		// This isn't really necessary, as the return value is irrelevant to
3166 		// the VFS. OBOS ignores it completely. The fsshell returns it to the
3167 		// userland, but considers the node closed anyway.
3168 		WARN(("Volume::CloseIndexDir(): connection lost, forcing close "
3169 			"index dir\n"));
3170 		return B_OK;
3171 	}
3172 	return error;
3173 }
3174 
3175 // FreeIndexDirCookie
3176 status_t
3177 Volume::FreeIndexDirCookie(void* cookie)
3178 {
3179 	status_t error = _FreeIndexDirCookie(cookie);
3180 	bool disconnected = false;
3181 	if (error != B_OK && fFileSystem->GetPortPool()->IsDisconnected()) {
3182 		// This isn't really necessary, as the return value is irrelevant to
3183 		// the VFS. It's completely ignored by OBOS as well as by the fsshell.
3184 		WARN(("Volume::FreeIndexDirCookie(): connection lost, forcing free "
3185 			"index dir cookie\n"));
3186 		error = B_OK;
3187 		disconnected = true;
3188 	}
3189 
3190 	int32 openIndexDirs = atomic_add(&fOpenIndexDirectories, -1);
3191 	if (openIndexDirs <= 1 && disconnected)
3192 		_PutAllPendingVNodes();
3193 	return error;
3194 }
3195 
3196 // ReadIndexDir
3197 status_t
3198 Volume::ReadIndexDir(void* cookie, void* buffer, size_t bufferSize,
3199 	uint32 count, uint32* countRead)
3200 {
3201 	*countRead = 0;
3202 
3203 	// check capability
3204 	if (!HasCapability(FS_VOLUME_CAPABILITY_READ_INDEX_DIR))
3205 		return B_BAD_VALUE;
3206 
3207 	// get a free port
3208 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
3209 	if (!port)
3210 		return B_ERROR;
3211 	PortReleaser _(fFileSystem->GetPortPool(), port);
3212 
3213 	// prepare the request
3214 	RequestAllocator allocator(port->GetPort());
3215 	ReadIndexDirRequest* request;
3216 	status_t error = AllocateRequest(allocator, &request);
3217 	if (error != B_OK)
3218 		return error;
3219 
3220 	request->volume = fUserlandVolume;
3221 	request->indexDirCookie = cookie;
3222 	request->bufferSize = bufferSize;
3223 	request->count = count;
3224 
3225 	// send the request
3226 	KernelRequestHandler handler(this, READ_INDEX_DIR_REPLY);
3227 	ReadIndexDirReply* reply;
3228 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
3229 	if (error != B_OK)
3230 		return error;
3231 	RequestReleaser requestReleaser(port, reply);
3232 
3233 	// process the reply
3234 	if (reply->error != B_OK)
3235 		return reply->error;
3236 	if (reply->count < 0 || reply->count > count)
3237 		return B_BAD_DATA;
3238 	if ((int32)bufferSize < reply->buffer.GetSize())
3239 		return B_BAD_DATA;
3240 
3241 	*countRead = reply->count;
3242 	if (*countRead > 0) {
3243 		// copy the buffer -- limit the number of bytes to copy
3244 		uint32 maxBytes = *countRead
3245 			* (sizeof(struct dirent) + B_FILE_NAME_LENGTH);
3246 		uint32 copyBytes = reply->buffer.GetSize();
3247 		if (copyBytes > maxBytes)
3248 			copyBytes = maxBytes;
3249 		memcpy(buffer, reply->buffer.GetData(), copyBytes);
3250 	}
3251 	_SendReceiptAck(port);
3252 	return error;
3253 }
3254 
3255 // RewindIndexDir
3256 status_t
3257 Volume::RewindIndexDir(void* cookie)
3258 {
3259 	// check capability
3260 	if (!HasCapability(FS_VOLUME_CAPABILITY_REWIND_INDEX_DIR))
3261 		return B_BAD_VALUE;
3262 
3263 	// get a free port
3264 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
3265 	if (!port)
3266 		return B_ERROR;
3267 	PortReleaser _(fFileSystem->GetPortPool(), port);
3268 
3269 	// prepare the request
3270 	RequestAllocator allocator(port->GetPort());
3271 	RewindIndexDirRequest* request;
3272 	status_t error = AllocateRequest(allocator, &request);
3273 	if (error != B_OK)
3274 		return error;
3275 
3276 	request->volume = fUserlandVolume;
3277 	request->indexDirCookie = cookie;
3278 
3279 	// send the request
3280 	KernelRequestHandler handler(this, REWIND_INDEX_DIR_REPLY);
3281 	RewindIndexDirReply* reply;
3282 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
3283 	if (error != B_OK)
3284 		return error;
3285 	RequestReleaser requestReleaser(port, reply);
3286 
3287 	// process the reply
3288 	if (reply->error != B_OK)
3289 		return reply->error;
3290 	return error;
3291 }
3292 
3293 // CreateIndex
3294 status_t
3295 Volume::CreateIndex(const char* name, uint32 type, uint32 flags)
3296 {
3297 	// check capability
3298 	if (!HasCapability(FS_VOLUME_CAPABILITY_CREATE_INDEX))
3299 		return B_BAD_VALUE;
3300 
3301 	// get a free port
3302 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
3303 	if (!port)
3304 		return B_ERROR;
3305 	PortReleaser _(fFileSystem->GetPortPool(), port);
3306 
3307 	// prepare the request
3308 	RequestAllocator allocator(port->GetPort());
3309 	CreateIndexRequest* request;
3310 	status_t error = AllocateRequest(allocator, &request);
3311 	if (error != B_OK)
3312 		return error;
3313 
3314 	request->volume = fUserlandVolume;
3315 	error = allocator.AllocateString(request->name, name);
3316 	request->type = type;
3317 	request->flags = flags;
3318 	if (error != B_OK)
3319 		return error;
3320 
3321 	// send the request
3322 	KernelRequestHandler handler(this, CREATE_INDEX_REPLY);
3323 	CreateIndexReply* reply;
3324 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
3325 	if (error != B_OK)
3326 		return error;
3327 	RequestReleaser requestReleaser(port, reply);
3328 
3329 	// process the reply
3330 	if (reply->error != B_OK)
3331 		return reply->error;
3332 	return error;
3333 }
3334 
3335 // RemoveIndex
3336 status_t
3337 Volume::RemoveIndex(const char* name)
3338 {
3339 	// check capability
3340 	if (!HasCapability(FS_VOLUME_CAPABILITY_REMOVE_INDEX))
3341 		return B_BAD_VALUE;
3342 
3343 	// get a free port
3344 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
3345 	if (!port)
3346 		return B_ERROR;
3347 	PortReleaser _(fFileSystem->GetPortPool(), port);
3348 
3349 	// prepare the request
3350 	RequestAllocator allocator(port->GetPort());
3351 	RemoveIndexRequest* request;
3352 	status_t error = AllocateRequest(allocator, &request);
3353 	if (error != B_OK)
3354 		return error;
3355 
3356 	request->volume = fUserlandVolume;
3357 	error = allocator.AllocateString(request->name, name);
3358 	if (error != B_OK)
3359 		return error;
3360 
3361 	// send the request
3362 	KernelRequestHandler handler(this, REMOVE_INDEX_REPLY);
3363 	RemoveIndexReply* reply;
3364 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
3365 	if (error != B_OK)
3366 		return error;
3367 	RequestReleaser requestReleaser(port, reply);
3368 
3369 	// process the reply
3370 	if (reply->error != B_OK)
3371 		return reply->error;
3372 	return error;
3373 }
3374 
3375 // ReadIndexStat
3376 status_t
3377 Volume::ReadIndexStat(const char* name, struct stat *st)
3378 {
3379 	// check capability
3380 	if (!HasCapability(FS_VOLUME_CAPABILITY_READ_INDEX_STAT))
3381 		return B_BAD_VALUE;
3382 
3383 	// get a free port
3384 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
3385 	if (!port)
3386 		return B_ERROR;
3387 	PortReleaser _(fFileSystem->GetPortPool(), port);
3388 
3389 	// prepare the request
3390 	RequestAllocator allocator(port->GetPort());
3391 	ReadIndexStatRequest* request;
3392 	status_t error = AllocateRequest(allocator, &request);
3393 	if (error != B_OK)
3394 		return error;
3395 
3396 	request->volume = fUserlandVolume;
3397 	error = allocator.AllocateString(request->name, name);
3398 	if (error != B_OK)
3399 		return error;
3400 
3401 	// send the request
3402 	KernelRequestHandler handler(this, READ_INDEX_STAT_REPLY);
3403 	ReadIndexStatReply* reply;
3404 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
3405 	if (error != B_OK)
3406 		return error;
3407 	RequestReleaser requestReleaser(port, reply);
3408 
3409 	// process the reply
3410 	if (reply->error != B_OK)
3411 		return reply->error;
3412 	*st = reply->st;
3413 	return error;
3414 }
3415 
3416 
3417 // #pragma mark - queries
3418 
3419 
3420 // OpenQuery
3421 status_t
3422 Volume::OpenQuery(const char* queryString, uint32 flags, port_id targetPort,
3423 	uint32 token, void** cookie)
3424 {
3425 	// check capability
3426 	if (!HasCapability(FS_VOLUME_CAPABILITY_OPEN_QUERY))
3427 		return B_BAD_VALUE;
3428 
3429 	// get a free port
3430 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
3431 	if (!port)
3432 		return B_ERROR;
3433 	PortReleaser _(fFileSystem->GetPortPool(), port);
3434 	AutoIncrementer incrementer(&fOpenQueries);
3435 
3436 	// prepare the request
3437 	RequestAllocator allocator(port->GetPort());
3438 	OpenQueryRequest* request;
3439 	status_t error = AllocateRequest(allocator, &request);
3440 	if (error != B_OK)
3441 		return error;
3442 
3443 	request->volume = fUserlandVolume;
3444 	error = allocator.AllocateString(request->queryString, queryString);
3445 	if (error != B_OK)
3446 		return error;
3447 	request->flags = flags;
3448 	request->port = targetPort;
3449 	request->token = token;
3450 
3451 	// send the request
3452 	KernelRequestHandler handler(this, OPEN_QUERY_REPLY);
3453 	OpenQueryReply* reply;
3454 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
3455 	if (error != B_OK)
3456 		return error;
3457 	RequestReleaser requestReleaser(port, reply);
3458 
3459 	// process the reply
3460 	if (reply->error != B_OK)
3461 		return reply->error;
3462 	incrementer.Keep();
3463 	*cookie = reply->queryCookie;
3464 	return error;
3465 }
3466 
3467 // CloseQuery
3468 status_t
3469 Volume::CloseQuery(void* cookie)
3470 {
3471 	status_t error = _CloseQuery(cookie);
3472 	if (error != B_OK && fFileSystem->GetPortPool()->IsDisconnected()) {
3473 		// This isn't really necessary, as the return value is irrelevant to
3474 		// the VFS. OBOS ignores it completely. The fsshell returns it to the
3475 		// userland, but considers the node closed anyway.
3476 		WARN(("Volume::CloseQuery(): connection lost, forcing close query\n"));
3477 		return B_OK;
3478 	}
3479 	return error;
3480 }
3481 
3482 // FreeQueryCookie
3483 status_t
3484 Volume::FreeQueryCookie(void* cookie)
3485 {
3486 	status_t error = _FreeQueryCookie(cookie);
3487 	bool disconnected = false;
3488 	if (error != B_OK && fFileSystem->GetPortPool()->IsDisconnected()) {
3489 		// This isn't really necessary, as the return value is irrelevant to
3490 		// the VFS. It's completely ignored by OBOS as well as by the fsshell.
3491 		WARN(("Volume::FreeQueryCookie(): connection lost, forcing free "
3492 			"query cookie\n"));
3493 		error = B_OK;
3494 		disconnected = true;
3495 	}
3496 
3497 	int32 openQueries = atomic_add(&fOpenQueries, -1);
3498 	if (openQueries <= 1 && disconnected)
3499 		_PutAllPendingVNodes();
3500 	return error;
3501 }
3502 
3503 // ReadQuery
3504 status_t
3505 Volume::ReadQuery(void* cookie, void* buffer, size_t bufferSize,
3506 	uint32 count, uint32* countRead)
3507 {
3508 	*countRead = 0;
3509 
3510 	// check capability
3511 	if (!HasCapability(FS_VOLUME_CAPABILITY_READ_QUERY))
3512 		return B_BAD_VALUE;
3513 
3514 	// get a free port
3515 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
3516 	if (!port)
3517 		return B_ERROR;
3518 	PortReleaser _(fFileSystem->GetPortPool(), port);
3519 
3520 	// prepare the request
3521 	RequestAllocator allocator(port->GetPort());
3522 	ReadQueryRequest* request;
3523 	status_t error = AllocateRequest(allocator, &request);
3524 	if (error != B_OK)
3525 		return error;
3526 
3527 	request->volume = fUserlandVolume;
3528 	request->queryCookie = cookie;
3529 	request->bufferSize = bufferSize;
3530 	request->count = count;
3531 
3532 	// send the request
3533 	KernelRequestHandler handler(this, READ_QUERY_REPLY);
3534 	ReadQueryReply* reply;
3535 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
3536 	if (error != B_OK)
3537 		return error;
3538 	RequestReleaser requestReleaser(port, reply);
3539 
3540 	// process the reply
3541 	if (reply->error != B_OK)
3542 		return reply->error;
3543 	if (reply->count < 0 || reply->count > count)
3544 		return B_BAD_DATA;
3545 	if ((int32)bufferSize < reply->buffer.GetSize())
3546 		return B_BAD_DATA;
3547 
3548 	*countRead = reply->count;
3549 	if (*countRead > 0) {
3550 		// copy the buffer -- limit the number of bytes to copy
3551 		uint32 maxBytes = *countRead
3552 			* (sizeof(struct dirent) + B_FILE_NAME_LENGTH);
3553 		uint32 copyBytes = reply->buffer.GetSize();
3554 		if (copyBytes > maxBytes)
3555 			copyBytes = maxBytes;
3556 		memcpy(buffer, reply->buffer.GetData(), copyBytes);
3557 	}
3558 	_SendReceiptAck(port);
3559 	return error;
3560 }
3561 
3562 // RewindQuery
3563 status_t
3564 Volume::RewindQuery(void* cookie)
3565 {
3566 	// check capability
3567 	if (!HasCapability(FS_VOLUME_CAPABILITY_REWIND_QUERY))
3568 		return B_BAD_VALUE;
3569 
3570 	// get a free port
3571 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
3572 	if (!port)
3573 		return B_ERROR;
3574 	PortReleaser _(fFileSystem->GetPortPool(), port);
3575 
3576 	// prepare the request
3577 	RequestAllocator allocator(port->GetPort());
3578 	RewindQueryRequest* request;
3579 	status_t error = AllocateRequest(allocator, &request);
3580 	if (error != B_OK)
3581 		return error;
3582 
3583 	request->volume = fUserlandVolume;
3584 	request->queryCookie = cookie;
3585 
3586 	// send the request
3587 	KernelRequestHandler handler(this, REWIND_QUERY_REPLY);
3588 	RewindQueryReply* reply;
3589 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
3590 	if (error != B_OK)
3591 		return error;
3592 	RequestReleaser requestReleaser(port, reply);
3593 
3594 	// process the reply
3595 	if (reply->error != B_OK)
3596 		return reply->error;
3597 	return error;
3598 }
3599 
3600 // #pragma mark -
3601 // #pragma mark ----- private implementations -----
3602 
3603 
3604 // _InitVolumeOps
3605 void
3606 Volume::_InitVolumeOps()
3607 {
3608 	memcpy(&fVolumeOps, &gUserlandFSVolumeOps, sizeof(fs_volume_ops));
3609 
3610 	#undef CLEAR_UNSUPPORTED
3611 	#define CLEAR_UNSUPPORTED(capability, op) 	\
3612 		if (!fCapabilities.Get(capability))				\
3613 			fVolumeOps.op = NULL
3614 
3615 	// FS operations
3616 	// FS_VOLUME_CAPABILITY_UNMOUNT: unmount
3617 		// always needed
3618 
3619 	// FS_VOLUME_CAPABILITY_READ_FS_INFO: read_fs_info
3620 		// always needed
3621 	CLEAR_UNSUPPORTED(FS_VOLUME_CAPABILITY_WRITE_FS_INFO, write_fs_info);
3622 	CLEAR_UNSUPPORTED(FS_VOLUME_CAPABILITY_SYNC, sync);
3623 
3624 	// vnode operations
3625 	// FS_VOLUME_CAPABILITY_GET_VNODE: get_vnode
3626 		// always needed
3627 
3628 	// index directory & index operations
3629 	CLEAR_UNSUPPORTED(FS_VOLUME_CAPABILITY_OPEN_INDEX_DIR, open_index_dir);
3630 	// FS_VOLUME_CAPABILITY_CLOSE_INDEX_DIR: close_index_dir
3631 		// always needed
3632 	// FS_VOLUME_CAPABILITY_FREE_INDEX_DIR_COOKIE: free_index_dir_cookie
3633 		// always needed
3634 	CLEAR_UNSUPPORTED(FS_VOLUME_CAPABILITY_READ_INDEX_DIR, read_index_dir);
3635 	CLEAR_UNSUPPORTED(FS_VOLUME_CAPABILITY_REWIND_INDEX_DIR, rewind_index_dir);
3636 
3637 	CLEAR_UNSUPPORTED(FS_VOLUME_CAPABILITY_CREATE_INDEX, create_index);
3638 	CLEAR_UNSUPPORTED(FS_VOLUME_CAPABILITY_REMOVE_INDEX, remove_index);
3639 	CLEAR_UNSUPPORTED(FS_VOLUME_CAPABILITY_READ_INDEX_STAT, read_index_stat);
3640 
3641 	// query operations
3642 	CLEAR_UNSUPPORTED(FS_VOLUME_CAPABILITY_OPEN_QUERY, open_query);
3643 	// FS_VOLUME_CAPABILITY_CLOSE_QUERY: close_query
3644 		// always needed
3645 	// FS_VOLUME_CAPABILITY_FREE_QUERY_COOKIE: free_query_cookie
3646 		// always needed
3647 	CLEAR_UNSUPPORTED(FS_VOLUME_CAPABILITY_READ_QUERY, read_query);
3648 	CLEAR_UNSUPPORTED(FS_VOLUME_CAPABILITY_REWIND_QUERY, rewind_query);
3649 
3650 	#undef CLEAR_UNSUPPORTED
3651 }
3652 
3653 
3654 // #pragma mark -
3655 
3656 
3657 // _Mount
3658 status_t
3659 Volume::_Mount(const char* device, uint32 flags, const char* parameters)
3660 {
3661 	// get a free port
3662 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
3663 	if (!port)
3664 		return B_ERROR;
3665 	PortReleaser _(fFileSystem->GetPortPool(), port);
3666 
3667 	// get the current working directory
3668 	char cwd[B_PATH_NAME_LENGTH];
3669 	if (!getcwd(cwd, sizeof(cwd)))
3670 		return errno;
3671 
3672 	// prepare the request
3673 	RequestAllocator allocator(port->GetPort());
3674 	MountVolumeRequest* request;
3675 	status_t error = AllocateRequest(allocator, &request);
3676 	if (error != B_OK)
3677 		return error;
3678 
3679 	request->nsid = GetID();
3680 	error = allocator.AllocateString(request->cwd, cwd);
3681 	if (error == B_OK)
3682 		error = allocator.AllocateString(request->device, device);
3683 	request->flags = flags;
3684 	if (error == B_OK)
3685 		error = allocator.AllocateString(request->parameters, parameters);
3686 	if (error != B_OK)
3687 		return error;
3688 
3689 	// send the request
3690 	KernelRequestHandler handler(this, MOUNT_VOLUME_REPLY);
3691 	MountVolumeReply* reply;
3692 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
3693 	if (error != B_OK)
3694 		return error;
3695 	RequestReleaser requestReleaser(port, reply);
3696 
3697 	// process the reply
3698 	if (reply->error != B_OK)
3699 		return reply->error;
3700 	fRootID = reply->rootID;
3701 	fUserlandVolume = reply->volume;
3702 	fCapabilities = reply->capabilities;
3703 
3704 	return error;
3705 }
3706 
3707 // _Unmount
3708 status_t
3709 Volume::_Unmount()
3710 {
3711 	// get a free port
3712 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
3713 	if (!port)
3714 		return B_ERROR;
3715 	PortReleaser _(fFileSystem->GetPortPool(), port);
3716 
3717 	// prepare the request
3718 	RequestAllocator allocator(port->GetPort());
3719 	UnmountVolumeRequest* request;
3720 	status_t error = AllocateRequest(allocator, &request);
3721 	if (error != B_OK)
3722 		return error;
3723 
3724 	request->volume = fUserlandVolume;
3725 
3726 	// send the request
3727 	KernelRequestHandler handler(this, UNMOUNT_VOLUME_REPLY);
3728 	UnmountVolumeReply* reply;
3729 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
3730 	if (error != B_OK)
3731 		return error;
3732 	RequestReleaser requestReleaser(port, reply);
3733 
3734 	// process the reply
3735 	if (reply->error != B_OK)
3736 		return reply->error;
3737 	return error;
3738 }
3739 
3740 // _ReadFSInfo
3741 status_t
3742 Volume::_ReadFSInfo(fs_info* info)
3743 {
3744 	// check capability
3745 	if (!HasCapability(FS_VOLUME_CAPABILITY_READ_FS_INFO))
3746 		return B_BAD_VALUE;
3747 
3748 	// get a free port
3749 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
3750 	if (!port)
3751 		return B_ERROR;
3752 	PortReleaser _(fFileSystem->GetPortPool(), port);
3753 
3754 	// prepare the request
3755 	RequestAllocator allocator(port->GetPort());
3756 	ReadFSInfoRequest* request;
3757 	status_t error = AllocateRequest(allocator, &request);
3758 	if (error != B_OK)
3759 		return error;
3760 
3761 	request->volume = fUserlandVolume;
3762 
3763 	// send the request
3764 	KernelRequestHandler handler(this, READ_FS_INFO_REPLY);
3765 	ReadFSInfoReply* reply;
3766 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
3767 	if (error != B_OK)
3768 		return error;
3769 	RequestReleaser requestReleaser(port, reply);
3770 
3771 	// process the reply
3772 	if (reply->error != B_OK)
3773 		return reply->error;
3774 	*info = reply->info;
3775 	return error;
3776 }
3777 
3778 // _Lookup
3779 status_t
3780 Volume::_Lookup(void* _dir, const char* entryName, ino_t* vnid)
3781 {
3782 	VNode* vnode = (VNode*)_dir;
3783 
3784 	// get a free port
3785 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
3786 	if (!port)
3787 		return B_ERROR;
3788 	PortReleaser _(fFileSystem->GetPortPool(), port);
3789 
3790 	// prepare the request
3791 	RequestAllocator allocator(port->GetPort());
3792 	LookupRequest* request;
3793 	status_t error = AllocateRequest(allocator, &request);
3794 	if (error != B_OK)
3795 		return error;
3796 	request->volume = fUserlandVolume;
3797 	request->node = vnode->clientNode;
3798 	error = allocator.AllocateString(request->entryName, entryName);
3799 	if (error != B_OK)
3800 		return error;
3801 
3802 	// send the request
3803 	KernelRequestHandler handler(this, LOOKUP_REPLY);
3804 	LookupReply* reply;
3805 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
3806 	if (error != B_OK)
3807 		return error;
3808 	RequestReleaser requestReleaser(port, reply);
3809 
3810 	// process the reply
3811 	if (reply->error != B_OK)
3812 		return reply->error;
3813 	*vnid = reply->vnid;
3814 
3815 	// The VFS will balance the get_vnode() call for the FS.
3816 	_DecrementVNodeCount(*vnid);
3817 	return error;
3818 }
3819 
3820 // _WriteVNode
3821 status_t
3822 Volume::_WriteVNode(void* _node, bool reenter)
3823 {
3824 	VNode* vnode = (VNode*)_node;
3825 
3826 	// At any rate remove the vnode from our map and delete it. We don't do that
3827 	// right now, though, since we might still need to serve file cache requests
3828 	// from the client FS.
3829 	VNodeRemover nodeRemover(this, vnode);
3830 
3831 	void* clientNode = vnode->clientNode;
3832 
3833 	// get a free port
3834 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
3835 	if (!port)
3836 		return B_ERROR;
3837 	PortReleaser _(fFileSystem->GetPortPool(), port);
3838 
3839 	// prepare the request
3840 	RequestAllocator allocator(port->GetPort());
3841 	WriteVNodeRequest* request;
3842 	status_t error = AllocateRequest(allocator, &request);
3843 	if (error != B_OK)
3844 		return error;
3845 	request->volume = fUserlandVolume;
3846 	request->node = clientNode;
3847 	request->reenter = reenter;
3848 
3849 	// send the request
3850 	KernelRequestHandler handler(this, WRITE_VNODE_REPLY);
3851 	WriteVNodeReply* reply;
3852 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
3853 	if (error != B_OK)
3854 		return error;
3855 	RequestReleaser requestReleaser(port, reply);
3856 
3857 	// process the reply
3858 	if (reply->error != B_OK)
3859 		return reply->error;
3860 	return error;
3861 }
3862 
3863 // _ReadStat
3864 status_t
3865 Volume::_ReadStat(void* _node, struct stat* st)
3866 {
3867 	VNode* vnode = (VNode*)_node;
3868 
3869 	// check capability
3870 	if (!HasVNodeCapability(vnode, FS_VNODE_CAPABILITY_READ_STAT))
3871 		return B_BAD_VALUE;
3872 
3873 	// get a free port
3874 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
3875 	if (!port)
3876 		return B_ERROR;
3877 	PortReleaser _(fFileSystem->GetPortPool(), port);
3878 
3879 	// prepare the request
3880 	RequestAllocator allocator(port->GetPort());
3881 	ReadStatRequest* request;
3882 	status_t error = AllocateRequest(allocator, &request);
3883 	if (error != B_OK)
3884 		return error;
3885 
3886 	request->volume = fUserlandVolume;
3887 	request->node = vnode->clientNode;
3888 
3889 	// send the request
3890 	KernelRequestHandler handler(this, READ_STAT_REPLY);
3891 	ReadStatReply* reply;
3892 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
3893 	if (error != B_OK)
3894 		return error;
3895 	RequestReleaser requestReleaser(port, reply);
3896 
3897 	// process the reply
3898 	if (reply->error != B_OK)
3899 		return reply->error;
3900 	*st = reply->st;
3901 	return error;
3902 }
3903 
3904 // _Close
3905 status_t
3906 Volume::_Close(void* _node, void* cookie)
3907 {
3908 	VNode* vnode = (VNode*)_node;
3909 
3910 	// check capability
3911 	if (!HasVNodeCapability(vnode, FS_VNODE_CAPABILITY_CLOSE))
3912 		return B_OK;
3913 
3914 	// get a free port
3915 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
3916 	if (!port)
3917 		return B_ERROR;
3918 	PortReleaser _(fFileSystem->GetPortPool(), port);
3919 
3920 	// prepare the request
3921 	RequestAllocator allocator(port->GetPort());
3922 	CloseRequest* request;
3923 	status_t error = AllocateRequest(allocator, &request);
3924 	if (error != B_OK)
3925 		return error;
3926 
3927 	request->volume = fUserlandVolume;
3928 	request->node = vnode->clientNode;
3929 	request->fileCookie = cookie;
3930 
3931 	// send the request
3932 	KernelRequestHandler handler(this, CLOSE_REPLY);
3933 	CloseReply* reply;
3934 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
3935 	if (error != B_OK)
3936 		return error;
3937 	RequestReleaser requestReleaser(port, reply);
3938 
3939 	// process the reply
3940 	if (reply->error != B_OK)
3941 		return reply->error;
3942 	return error;
3943 }
3944 
3945 // _FreeCookie
3946 status_t
3947 Volume::_FreeCookie(void* _node, void* cookie)
3948 {
3949 	VNode* vnode = (VNode*)_node;
3950 
3951 	// check capability
3952 	if (!HasVNodeCapability(vnode, FS_VNODE_CAPABILITY_FREE_COOKIE))
3953 		return B_OK;
3954 
3955 	// get a free port
3956 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
3957 	if (!port)
3958 		return B_ERROR;
3959 	PortReleaser _(fFileSystem->GetPortPool(), port);
3960 
3961 	// prepare the request
3962 	RequestAllocator allocator(port->GetPort());
3963 	FreeCookieRequest* request;
3964 	status_t error = AllocateRequest(allocator, &request);
3965 	if (error != B_OK)
3966 		return error;
3967 
3968 	request->volume = fUserlandVolume;
3969 	request->node = vnode->clientNode;
3970 	request->fileCookie = cookie;
3971 
3972 	// send the request
3973 	KernelRequestHandler handler(this, FREE_COOKIE_REPLY);
3974 	FreeCookieReply* reply;
3975 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
3976 	if (error != B_OK)
3977 		return error;
3978 	RequestReleaser requestReleaser(port, reply);
3979 
3980 	// process the reply
3981 	if (reply->error != B_OK)
3982 		return reply->error;
3983 	return error;
3984 }
3985 
3986 // _CloseDir
3987 status_t
3988 Volume::_CloseDir(void* _node, void* cookie)
3989 {
3990 	VNode* vnode = (VNode*)_node;
3991 
3992 	// check capability
3993 	if (!HasVNodeCapability(vnode, FS_VNODE_CAPABILITY_CLOSE_DIR))
3994 		return B_OK;
3995 
3996 	// get a free port
3997 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
3998 	if (!port)
3999 		return B_ERROR;
4000 	PortReleaser _(fFileSystem->GetPortPool(), port);
4001 
4002 	// prepare the request
4003 	RequestAllocator allocator(port->GetPort());
4004 	CloseDirRequest* request;
4005 	status_t error = AllocateRequest(allocator, &request);
4006 	if (error != B_OK)
4007 		return error;
4008 
4009 	request->volume = fUserlandVolume;
4010 	request->node = vnode->clientNode;
4011 	request->dirCookie = cookie;
4012 
4013 	// send the request
4014 	KernelRequestHandler handler(this, CLOSE_DIR_REPLY);
4015 	CloseDirReply* reply;
4016 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
4017 	if (error != B_OK)
4018 		return error;
4019 	RequestReleaser requestReleaser(port, reply);
4020 
4021 	// process the reply
4022 	if (reply->error != B_OK)
4023 		return reply->error;
4024 	return error;
4025 }
4026 
4027 // _FreeDirCookie
4028 status_t
4029 Volume::_FreeDirCookie(void* _node, void* cookie)
4030 {
4031 	VNode* vnode = (VNode*)_node;
4032 
4033 	// check capability
4034 	if (!HasVNodeCapability(vnode, FS_VNODE_CAPABILITY_FREE_DIR_COOKIE))
4035 		return B_OK;
4036 
4037 	// get a free port
4038 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
4039 	if (!port)
4040 		return B_ERROR;
4041 	PortReleaser _(fFileSystem->GetPortPool(), port);
4042 
4043 	// prepare the request
4044 	RequestAllocator allocator(port->GetPort());
4045 	FreeDirCookieRequest* request;
4046 	status_t error = AllocateRequest(allocator, &request);
4047 	if (error != B_OK)
4048 		return error;
4049 
4050 	request->volume = fUserlandVolume;
4051 	request->node = vnode->clientNode;
4052 	request->dirCookie = cookie;
4053 
4054 	// send the request
4055 	KernelRequestHandler handler(this, FREE_DIR_COOKIE_REPLY);
4056 	FreeDirCookieReply* reply;
4057 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
4058 	if (error != B_OK)
4059 		return error;
4060 	RequestReleaser requestReleaser(port, reply);
4061 
4062 	// process the reply
4063 	if (reply->error != B_OK)
4064 		return reply->error;
4065 	return error;
4066 }
4067 
4068 // _CloseAttrDir
4069 status_t
4070 Volume::_CloseAttrDir(void* _node, void* cookie)
4071 {
4072 	VNode* vnode = (VNode*)_node;
4073 
4074 	// check capability
4075 	if (!HasVNodeCapability(vnode, FS_VNODE_CAPABILITY_CLOSE_ATTR_DIR))
4076 		return B_OK;
4077 
4078 	// get a free port
4079 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
4080 	if (!port)
4081 		return B_ERROR;
4082 	PortReleaser _(fFileSystem->GetPortPool(), port);
4083 
4084 	// prepare the request
4085 	RequestAllocator allocator(port->GetPort());
4086 	CloseAttrDirRequest* request;
4087 	status_t error = AllocateRequest(allocator, &request);
4088 	if (error != B_OK)
4089 		return error;
4090 
4091 	request->volume = fUserlandVolume;
4092 	request->node = vnode->clientNode;
4093 	request->attrDirCookie = cookie;
4094 
4095 	// send the request
4096 	KernelRequestHandler handler(this, CLOSE_ATTR_DIR_REPLY);
4097 	CloseAttrDirReply* reply;
4098 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
4099 	if (error != B_OK)
4100 		return error;
4101 	RequestReleaser requestReleaser(port, reply);
4102 
4103 	// process the reply
4104 	if (reply->error != B_OK)
4105 		return reply->error;
4106 	return error;
4107 }
4108 
4109 // _FreeAttrDirCookie
4110 status_t
4111 Volume::_FreeAttrDirCookie(void* _node, void* cookie)
4112 {
4113 	VNode* vnode = (VNode*)_node;
4114 
4115 	// check capability
4116 	if (!HasVNodeCapability(vnode, FS_VNODE_CAPABILITY_FREE_ATTR_DIR_COOKIE))
4117 		return B_OK;
4118 
4119 	// get a free port
4120 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
4121 	if (!port)
4122 		return B_ERROR;
4123 	PortReleaser _(fFileSystem->GetPortPool(), port);
4124 
4125 	// prepare the request
4126 	RequestAllocator allocator(port->GetPort());
4127 	FreeAttrDirCookieRequest* request;
4128 	status_t error = AllocateRequest(allocator, &request);
4129 	if (error != B_OK)
4130 		return error;
4131 
4132 	request->volume = fUserlandVolume;
4133 	request->node = vnode->clientNode;
4134 	request->attrDirCookie = cookie;
4135 
4136 	// send the request
4137 	KernelRequestHandler handler(this, FREE_ATTR_DIR_COOKIE_REPLY);
4138 	FreeAttrDirCookieReply* reply;
4139 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
4140 	if (error != B_OK)
4141 		return error;
4142 	RequestReleaser requestReleaser(port, reply);
4143 
4144 	// process the reply
4145 	if (reply->error != B_OK)
4146 		return reply->error;
4147 	return error;
4148 }
4149 
4150 // _CloseAttr
4151 status_t
4152 Volume::_CloseAttr(void* _node, void* cookie)
4153 {
4154 	VNode* vnode = (VNode*)_node;
4155 
4156 	// check capability
4157 	if (!HasVNodeCapability(vnode, FS_VNODE_CAPABILITY_CLOSE_ATTR))
4158 		return B_OK;
4159 
4160 	// get a free port
4161 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
4162 	if (!port)
4163 		return B_ERROR;
4164 	PortReleaser _(fFileSystem->GetPortPool(), port);
4165 
4166 	// prepare the request
4167 	RequestAllocator allocator(port->GetPort());
4168 	CloseAttrRequest* request;
4169 	status_t error = AllocateRequest(allocator, &request);
4170 	if (error != B_OK)
4171 		return error;
4172 
4173 	request->volume = fUserlandVolume;
4174 	request->node = vnode->clientNode;
4175 	request->attrCookie = cookie;
4176 
4177 	// send the request
4178 	KernelRequestHandler handler(this, CLOSE_ATTR_REPLY);
4179 	CloseAttrReply* reply;
4180 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
4181 	if (error != B_OK)
4182 		return error;
4183 	RequestReleaser requestReleaser(port, reply);
4184 
4185 	// process the reply
4186 	if (reply->error != B_OK)
4187 		return reply->error;
4188 	return error;
4189 }
4190 
4191 // _FreeAttrCookie
4192 status_t
4193 Volume::_FreeAttrCookie(void* _node, void* cookie)
4194 {
4195 	VNode* vnode = (VNode*)_node;
4196 
4197 	// check capability
4198 	if (!HasVNodeCapability(vnode, FS_VNODE_CAPABILITY_FREE_ATTR_COOKIE))
4199 		return B_OK;
4200 
4201 	// get a free port
4202 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
4203 	if (!port)
4204 		return B_ERROR;
4205 	PortReleaser _(fFileSystem->GetPortPool(), port);
4206 
4207 	// prepare the request
4208 	RequestAllocator allocator(port->GetPort());
4209 	FreeAttrCookieRequest* request;
4210 	status_t error = AllocateRequest(allocator, &request);
4211 	if (error != B_OK)
4212 		return error;
4213 
4214 	request->volume = fUserlandVolume;
4215 	request->node = vnode->clientNode;
4216 	request->attrCookie = cookie;
4217 
4218 	// send the request
4219 	KernelRequestHandler handler(this, FREE_ATTR_COOKIE_REPLY);
4220 	FreeAttrCookieReply* reply;
4221 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
4222 	if (error != B_OK)
4223 		return error;
4224 	RequestReleaser requestReleaser(port, reply);
4225 
4226 	// process the reply
4227 	if (reply->error != B_OK)
4228 		return reply->error;
4229 	return error;
4230 }
4231 
4232 // _CloseIndexDir
4233 status_t
4234 Volume::_CloseIndexDir(void* cookie)
4235 {
4236 	// check capability
4237 	if (!HasCapability(FS_VOLUME_CAPABILITY_CLOSE_INDEX_DIR))
4238 		return B_OK;
4239 
4240 	// get a free port
4241 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
4242 	if (!port)
4243 		return B_ERROR;
4244 	PortReleaser _(fFileSystem->GetPortPool(), port);
4245 
4246 	// prepare the request
4247 	RequestAllocator allocator(port->GetPort());
4248 	CloseIndexDirRequest* request;
4249 	status_t error = AllocateRequest(allocator, &request);
4250 	if (error != B_OK)
4251 		return error;
4252 
4253 	request->volume = fUserlandVolume;
4254 	request->indexDirCookie = cookie;
4255 
4256 	// send the request
4257 	KernelRequestHandler handler(this, CLOSE_INDEX_DIR_REPLY);
4258 	CloseIndexDirReply* reply;
4259 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
4260 	if (error != B_OK)
4261 		return error;
4262 	RequestReleaser requestReleaser(port, reply);
4263 
4264 	// process the reply
4265 	if (reply->error != B_OK)
4266 		return reply->error;
4267 	return error;
4268 }
4269 
4270 // _FreeIndexDirCookie
4271 status_t
4272 Volume::_FreeIndexDirCookie(void* cookie)
4273 {
4274 	// check capability
4275 	if (!HasCapability(FS_VOLUME_CAPABILITY_FREE_INDEX_DIR_COOKIE))
4276 		return B_OK;
4277 
4278 	// get a free port
4279 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
4280 	if (!port)
4281 		return B_ERROR;
4282 	PortReleaser _(fFileSystem->GetPortPool(), port);
4283 
4284 	// prepare the request
4285 	RequestAllocator allocator(port->GetPort());
4286 	FreeIndexDirCookieRequest* request;
4287 	status_t error = AllocateRequest(allocator, &request);
4288 	if (error != B_OK)
4289 		return error;
4290 
4291 	request->volume = fUserlandVolume;
4292 	request->indexDirCookie = cookie;
4293 
4294 	// send the request
4295 	KernelRequestHandler handler(this, FREE_INDEX_DIR_COOKIE_REPLY);
4296 	FreeIndexDirCookieReply* reply;
4297 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
4298 	if (error != B_OK)
4299 		return error;
4300 	RequestReleaser requestReleaser(port, reply);
4301 
4302 	// process the reply
4303 	if (reply->error != B_OK)
4304 		return reply->error;
4305 	return error;
4306 }
4307 
4308 // _CloseQuery
4309 status_t
4310 Volume::_CloseQuery(void* cookie)
4311 {
4312 	// check capability
4313 	if (!HasCapability(FS_VOLUME_CAPABILITY_CLOSE_QUERY))
4314 		return B_OK;
4315 
4316 	// get a free port
4317 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
4318 	if (!port)
4319 		return B_ERROR;
4320 	PortReleaser _(fFileSystem->GetPortPool(), port);
4321 
4322 	// prepare the request
4323 	RequestAllocator allocator(port->GetPort());
4324 	CloseQueryRequest* request;
4325 	status_t error = AllocateRequest(allocator, &request);
4326 	if (error != B_OK)
4327 		return error;
4328 
4329 	request->volume = fUserlandVolume;
4330 	request->queryCookie = cookie;
4331 
4332 	// send the request
4333 	KernelRequestHandler handler(this, CLOSE_QUERY_REPLY);
4334 	CloseQueryReply* reply;
4335 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
4336 	if (error != B_OK)
4337 		return error;
4338 	RequestReleaser requestReleaser(port, reply);
4339 
4340 	// process the reply
4341 	if (reply->error != B_OK)
4342 		return reply->error;
4343 	return error;
4344 }
4345 
4346 // _FreeQueryCookie
4347 status_t
4348 Volume::_FreeQueryCookie(void* cookie)
4349 {
4350 	// check capability
4351 	if (!HasCapability(FS_VOLUME_CAPABILITY_FREE_QUERY_COOKIE))
4352 		return B_OK;
4353 
4354 	// get a free port
4355 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
4356 	if (!port)
4357 		return B_ERROR;
4358 	PortReleaser _(fFileSystem->GetPortPool(), port);
4359 
4360 	// prepare the request
4361 	RequestAllocator allocator(port->GetPort());
4362 	FreeQueryCookieRequest* request;
4363 	status_t error = AllocateRequest(allocator, &request);
4364 	if (error != B_OK)
4365 		return error;
4366 
4367 	request->volume = fUserlandVolume;
4368 	request->queryCookie = cookie;
4369 
4370 	// send the request
4371 	KernelRequestHandler handler(this, FREE_QUERY_COOKIE_REPLY);
4372 	FreeQueryCookieReply* reply;
4373 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
4374 	if (error != B_OK)
4375 		return error;
4376 	RequestReleaser requestReleaser(port, reply);
4377 
4378 	// process the reply
4379 	if (reply->error != B_OK)
4380 		return reply->error;
4381 	return error;
4382 }
4383 
4384 // _SendRequest
4385 status_t
4386 Volume::_SendRequest(RequestPort* port, RequestAllocator* allocator,
4387 	RequestHandler* handler, Request** reply)
4388 {
4389 	// fill in the caller info
4390 	KernelRequest* request = static_cast<KernelRequest*>(
4391 		allocator->GetRequest());
4392 	Thread* thread = thread_get_current_thread();
4393 	request->team = thread->team->id;
4394 	request->thread = thread->id;
4395 	request->user = geteuid();
4396 	request->group = getegid();
4397 
4398 	if (!fFileSystem->IsUserlandServerThread())
4399 		return port->SendRequest(allocator, handler, reply);
4400 	// Here it gets dangerous: a thread of the userland server team being here
4401 	// calls for trouble. We try receiving the request with a timeout, and
4402 	// close the port -- which will disconnect the whole FS.
4403 	status_t error = port->SendRequest(allocator, handler, reply,
4404 		kUserlandServerlandPortTimeout);
4405 	if (error == B_TIMED_OUT || error == B_WOULD_BLOCK)
4406 		port->Close();
4407 	return error;
4408 }
4409 
4410 // _SendReceiptAck
4411 status_t
4412 Volume::_SendReceiptAck(RequestPort* port)
4413 {
4414 	RequestAllocator allocator(port->GetPort());
4415 	ReceiptAckReply* request;
4416 	status_t error = AllocateRequest(allocator, &request);
4417 	if (error != B_OK)
4418 		return error;
4419 	return port->SendRequest(&allocator);
4420 }
4421 
4422 // _IncrementVNodeCount
4423 void
4424 Volume::_IncrementVNodeCount(ino_t vnid)
4425 {
4426 	MutexLocker _(fLock);
4427 
4428 	if (!fVNodeCountingEnabled)
4429 		return;
4430 
4431 	VNode* vnode = fVNodes->Lookup(vnid);
4432 	if (vnode == NULL) {
4433 		ERROR(("Volume::_IncrementVNodeCount(): Node with ID %" B_PRId64
4434 			" not known!\n", vnid));
4435 		return;
4436 	}
4437 
4438 	vnode->useCount++;
4439 //PRINT(("_IncrementVNodeCount(%Ld): count: %ld, fVNodeCountMap size: %ld\n", vnid, *count, fVNodeCountMap->Size()));
4440 }
4441 
4442 
4443 // _DecrementVNodeCount
4444 void
4445 Volume::_DecrementVNodeCount(ino_t vnid)
4446 {
4447 	MutexLocker _(fLock);
4448 
4449 	if (!fVNodeCountingEnabled)
4450 		return;
4451 
4452 	VNode* vnode = fVNodes->Lookup(vnid);
4453 	if (vnode == NULL) {
4454 		ERROR(("Volume::_DecrementVNodeCount(): Node with ID %" B_PRId64 " not "
4455 			"known!\n", vnid));
4456 		return;
4457 	}
4458 
4459 	vnode->useCount--;
4460 //PRINT(("_DecrementVNodeCount(%Ld): count: %ld, fVNodeCountMap size: %ld\n", vnid, tmpCount, fVNodeCountMap->Size()));
4461 }
4462 
4463 
4464 // _RemoveInvalidVNode
4465 void
4466 Volume::_RemoveInvalidVNode(ino_t vnid)
4467 {
4468 	MutexLocker locker(fLock);
4469 
4470 	VNode* vnode = fVNodes->Lookup(vnid);
4471 	if (vnode == NULL) {
4472 		ERROR(("Volume::_RemoveInvalidVNode(): Node with ID %" B_PRId64
4473 			" not known!\n", vnid));
4474 		return;
4475 	}
4476 
4477 	fVNodes->Remove(vnode);
4478 	locker.Unlock();
4479 
4480 	// release all references acquired so far
4481 	if (fVNodeCountingEnabled) {
4482 		for (; vnode->useCount > 0; vnode->useCount--)
4483 			put_vnode(fFSVolume, vnid);
4484 	}
4485 
4486 	vnode->Delete(this);
4487 }
4488 
4489 
4490 // _InternalIOCtl
4491 status_t
4492 Volume::_InternalIOCtl(userlandfs_ioctl* buffer, int32 bufferSize)
4493 {
4494 	if (buffer->version != USERLAND_IOCTL_CURRENT_VERSION)
4495 		return B_BAD_VALUE;
4496 	status_t result = B_OK;
4497 	switch (buffer->command) {
4498 		case USERLAND_IOCTL_PUT_ALL_PENDING_VNODES:
4499 			result = _PutAllPendingVNodes();
4500 			break;
4501 		default:
4502 			return B_BAD_VALUE;
4503 	}
4504 	buffer->error = result;
4505 	return B_OK;
4506 }
4507 
4508 // _PutAllPendingVNodes
4509 status_t
4510 Volume::_PutAllPendingVNodes()
4511 {
4512 PRINT(("Volume::_PutAllPendingVNodes()\n"));
4513 	if (!fFileSystem->GetPortPool()->IsDisconnected()) {
4514 		PRINT(("Volume::_PutAllPendingVNodes() failed: still connected\n"));
4515 		return USERLAND_IOCTL_STILL_CONNECTED;
4516 	}
4517 
4518 	MutexLocker locker(fLock);
4519 
4520 	if (!fVNodeCountingEnabled) {
4521 		PRINT(("Volume::_PutAllPendingVNodes() failed: vnode counting "
4522 			"disabled\n"));
4523 		return USERLAND_IOCTL_VNODE_COUNTING_DISABLED;
4524 	}
4525 	// Check whether there are open entities at the moment.
4526 	if (atomic_get(&fOpenFiles) > 0) {
4527 		PRINT(("Volume::_PutAllPendingVNodes() failed: open files\n"));
4528 		return USERLAND_IOCTL_OPEN_FILES;
4529 	}
4530 	if (atomic_get(&fOpenDirectories) > 0) {
4531 		PRINT(("Volume::_PutAllPendingVNodes() failed: open dirs\n"));
4532 		return USERLAND_IOCTL_OPEN_DIRECTORIES;
4533 	}
4534 	if (atomic_get(&fOpenAttributeDirectories) > 0) {
4535 		PRINT(("Volume::_PutAllPendingVNodes() failed: open attr dirs\n"));
4536 		return USERLAND_IOCTL_OPEN_ATTRIBUTE_DIRECTORIES;
4537 	}
4538 	if (atomic_get(&fOpenAttributes) > 0) {
4539 		PRINT(("Volume::_PutAllPendingVNodes() failed: open attributes\n"));
4540 		return USERLAND_IOCTL_OPEN_ATTRIBUTES;
4541 	}
4542 	if (atomic_get(&fOpenIndexDirectories) > 0) {
4543 		PRINT(("Volume::_PutAllPendingVNodes() failed: open index dirs\n"));
4544 		return USERLAND_IOCTL_OPEN_INDEX_DIRECTORIES;
4545 	}
4546 	if (atomic_get(&fOpenQueries) > 0) {
4547 		PRINT(("Volume::_PutAllPendingVNodes() failed: open queries\n"));
4548 		return USERLAND_IOCTL_OPEN_QUERIES;
4549 	}
4550 	// No open entities. Since the port pool is disconnected, no new
4551 	// entities can be opened. Disable node counting and put all pending
4552 	// vnodes.
4553 	fVNodeCountingEnabled = false;
4554 
4555 	int32 putVNodeCount = 0;
4556 
4557 	// Since the vnode map can still change, we need to iterate to the first
4558 	// node we need to put, drop the lock, put the node, and restart from the
4559 	// beginning.
4560 	// TODO: Optimize by extracting batches of relevant nodes to an on-stack
4561 	// array.
4562 	bool nodeFound;
4563 	do {
4564 		nodeFound = false;
4565 
4566 		// get the next node to put
4567 		for (VNodeMap::Iterator it = fVNodes->GetIterator();
4568 				VNode* vnode = it.Next();) {
4569 			if (vnode->useCount > 0) {
4570 				ino_t vnid = vnode->id;
4571 				int32 count = vnode->useCount;
4572 				vnode->useCount = 0;
4573 				fs_vnode_ops* ops = vnode->ops->ops;
4574 				bool published = vnode->published;
4575 
4576 				locker.Unlock();
4577 
4578 				// If the node has not yet been published, we have to do that
4579 				// before putting otherwise the VFS will complain that the node
4580 				// is busy when the last reference is gone.
4581 				if (!published)
4582 					publish_vnode(fFSVolume, vnid, vnode, ops, S_IFDIR, 0);
4583 
4584 				for (int32 i = 0; i < count; i++) {
4585 					PutVNode(vnid);
4586 					putVNodeCount++;
4587 				}
4588 
4589 				locker.Lock();
4590 
4591 				nodeFound = true;
4592 				break;
4593 			}
4594 		}
4595 	} while (nodeFound);
4596 
4597 	PRINT(("Volume::_PutAllPendingVNodes() successful: Put %" B_PRId32
4598 		" vnodes\n", putVNodeCount));
4599 
4600 	return B_OK;
4601 }
4602 
4603 
4604 // _RegisterIORequest
4605 status_t
4606 Volume::_RegisterIORequest(io_request* request, int32* requestID)
4607 {
4608 	MutexLocker _(fLock);
4609 
4610 	// get the next free ID
4611 	while (fIORequestInfosByID->Lookup(++fLastIORequestID) != NULL) {
4612 	}
4613 
4614 	// allocate the info
4615 	IORequestInfo* info = new(std::nothrow) IORequestInfo(request,
4616 		++fLastIORequestID);
4617 	if (info == NULL)
4618 		return B_NO_MEMORY;
4619 
4620 	// add the info to the maps
4621 	fIORequestInfosByID->Insert(info);
4622 	fIORequestInfosByStruct->Insert(info);
4623 
4624 	*requestID = info->id;
4625 
4626 	return B_OK;
4627 }
4628 
4629 
4630 // _UnregisterIORequest
4631 status_t
4632 Volume::_UnregisterIORequest(int32 requestID)
4633 {
4634 	MutexLocker _(fLock);
4635 
4636 	if (IORequestInfo* info = fIORequestInfosByID->Lookup(requestID)) {
4637 		fIORequestInfosByID->Remove(info);
4638 		fIORequestInfosByStruct->Remove(info);
4639 		return B_OK;
4640 	}
4641 
4642 	return B_ENTRY_NOT_FOUND;
4643 }
4644 
4645 
4646 // _FindIORequest
4647 status_t
4648 Volume::_FindIORequest(int32 requestID, io_request** request)
4649 {
4650 	MutexLocker _(fLock);
4651 
4652 	if (IORequestInfo* info = fIORequestInfosByID->Lookup(requestID)) {
4653 		*request = info->request;
4654 		return B_OK;
4655 	}
4656 
4657 	return B_ENTRY_NOT_FOUND;
4658 }
4659 
4660 
4661 // _FindIORequest
4662 status_t
4663 Volume::_FindIORequest(io_request* request, int32* requestID)
4664 {
4665 	MutexLocker _(fLock);
4666 
4667 	if (IORequestInfo* info = fIORequestInfosByStruct->Lookup(request)) {
4668 		*requestID = info->id;
4669 		return B_OK;
4670 	}
4671 
4672 	return B_ENTRY_NOT_FOUND;
4673 }
4674 
4675 
4676 /*static*/ status_t
4677 Volume::_IterativeFDIOGetVecs(void* _cookie, io_request* ioRequest,
4678 	off_t offset, size_t size, struct file_io_vec* vecs, size_t* _count)
4679 {
4680 	IterativeFDIOCookie* cookie = (IterativeFDIOCookie*)_cookie;
4681 	Volume* volume = cookie->volume;
4682 
4683 	MutexLocker locker(volume->fLock);
4684 
4685 	// If there are vecs cached in the cookie and the offset matches, return
4686 	// those.
4687 	if (cookie->vecs != NULL) {
4688 		size_t vecCount = 0;
4689 		if (offset == cookie->offset) {
4690 			// good, copy the vecs
4691 			while (size > 0 && vecCount < cookie->vecCount
4692 					&& vecCount < *_count) {
4693 				off_t maxSize = std::min((off_t)size,
4694 					cookie->vecs[vecCount].length);
4695 				vecs[vecCount].offset = cookie->vecs[vecCount].offset;
4696 				vecs[vecCount].length = maxSize;
4697 
4698 				size -= maxSize;
4699 				vecCount++;
4700 			}
4701 		}
4702 
4703 		cookie->vecs = NULL;
4704 		cookie->vecCount = 0;
4705 
4706 		// got some vecs? -- then we're done
4707 		if (vecCount > 0) {
4708 			*_count = vecCount;
4709 			return B_OK;
4710 		}
4711 	}
4712 
4713 	// we have to ask the client FS
4714 	int32 requestID = cookie->requestID;
4715 	void* clientCookie = cookie->clientCookie;
4716 	locker.Unlock();
4717 
4718 	// get a free port
4719 	RequestPort* port = volume->fFileSystem->GetPortPool()->AcquirePort();
4720 	if (!port)
4721 		return B_ERROR;
4722 	PortReleaser _(volume->fFileSystem->GetPortPool(), port);
4723 
4724 	// prepare the request
4725 	RequestAllocator allocator(port->GetPort());
4726 	IterativeIOGetVecsRequest* request;
4727 	status_t error = AllocateRequest(allocator, &request);
4728 	if (error != B_OK)
4729 		return error;
4730 
4731 	request->volume = volume->fUserlandVolume;
4732 	request->cookie = clientCookie;
4733 	request->offset = offset;
4734 	request->request = requestID;
4735 	request->size = size;
4736 	size_t maxVecs = std::min(*_count,
4737 		(size_t)IterativeIOGetVecsReply::MAX_VECS);
4738 	request->vecCount = maxVecs;
4739 
4740 	// send the request
4741 	KernelRequestHandler handler(volume, ITERATIVE_IO_GET_VECS_REPLY);
4742 	IterativeIOGetVecsReply* reply;
4743 	error = volume->_SendRequest(port, &allocator, &handler, (Request**)&reply);
4744 	if (error != B_OK)
4745 		return error;
4746 	RequestReleaser requestReleaser(port, reply);
4747 
4748 	// process the reply
4749 	if (reply->error != B_OK)
4750 		return reply->error;
4751 	uint32 vecCount = reply->vecCount;
4752 	if (vecCount < 0 || vecCount > maxVecs)
4753 		return B_BAD_DATA;
4754 
4755 	memcpy(vecs, reply->vecs, vecCount * sizeof(file_io_vec));
4756 	*_count = vecCount;
4757 
4758 	return B_OK;
4759 }
4760 
4761 
4762 /*static*/ status_t
4763 Volume::_IterativeFDIOFinished(void* _cookie, io_request* ioRequest,
4764 	status_t status, bool partialTransfer, size_t bytesTransferred)
4765 {
4766 	IterativeFDIOCookie* cookie = (IterativeFDIOCookie*)_cookie;
4767 	Volume* volume = cookie->volume;
4768 
4769 	// At any rate, we're done with the cookie after this call -- it will not
4770 	// be used anymore.
4771 	BReference<IterativeFDIOCookie> _(cookie, true);
4772 
4773 	// We also want to dispose of the request.
4774 	IORequestRemover _2(volume, cookie->requestID);
4775 
4776 	// get a free port
4777 	RequestPort* port = volume->fFileSystem->GetPortPool()->AcquirePort();
4778 	if (!port)
4779 		return B_ERROR;
4780 	PortReleaser _3(volume->fFileSystem->GetPortPool(), port);
4781 
4782 	// prepare the request
4783 	RequestAllocator allocator(port->GetPort());
4784 	IterativeIOFinishedRequest* request;
4785 	status_t error = AllocateRequest(allocator, &request);
4786 	if (error != B_OK)
4787 		return error;
4788 
4789 	request->volume = volume->fUserlandVolume;
4790 	request->cookie = cookie->clientCookie;
4791 	request->request = cookie->requestID;
4792 	request->status = status;
4793 	request->partialTransfer = partialTransfer;
4794 	request->bytesTransferred = bytesTransferred;
4795 
4796 	// send the request
4797 	KernelRequestHandler handler(volume, ITERATIVE_IO_FINISHED_REPLY);
4798 	IterativeIOFinishedReply* reply;
4799 	error = volume->_SendRequest(port, &allocator, &handler, (Request**)&reply);
4800 	if (error != B_OK)
4801 		return error;
4802 	RequestReleaser requestReleaser(port, reply);
4803 
4804 	// process the reply
4805 	if (reply->error != B_OK)
4806 		return reply->error;
4807 	return B_OK;
4808 }
4809