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