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