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