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