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