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