1// Volume.cpp
2
3#include <errno.h>
4#include <unistd.h>
5
6#include "AutoLocker.h"
7#include "Compatibility.h"
8#include "Debug.h"
9#include "FileSystem.h"
10#include "HashMap.h"
11#include "IOCtlInfo.h"
12#include "KernelRequestHandler.h"
13#include "PortReleaser.h"
14#include "RequestAllocator.h"
15#include "RequestPort.h"
16#include "Requests.h"
17#include "userlandfs_ioctl.h"
18#include "Volume.h"
19
20// If a thread of the userland server enters userland FS kernel code and
21// is sending a request, this is the time after which it shall time out
22// waiting for a reply.
23static const bigtime_t kUserlandServerlandPortTimeout = 10000000;	// 10s
24
25// MountVNodeMap
26struct Volume::MountVNodeMap : public HashMap<HashKey64<vnode_id>, void*> {
27};
28
29// VNodeCountMap
30struct Volume::VNodeCountMap
31	: public SynchronizedHashMap<HashKey64<vnode_id>, int32*> {
32};
33
34// AutoIncrementer
35class Volume::AutoIncrementer {
36public:
37	AutoIncrementer(vint32* variable)
38		: fVariable(variable)
39	{
40		if (fVariable)
41			atomic_add(fVariable, 1);
42	}
43
44	~AutoIncrementer()
45	{
46		if (fVariable)
47			atomic_add(fVariable, -1);
48	}
49
50	void Keep()
51	{
52		fVariable = NULL;
53	}
54
55private:
56	vint32*	fVariable;
57};
58
59// constructor
60Volume::Volume(FileSystem* fileSystem, nspace_id id)
61	: Referencable(true),
62	  fFileSystem(fileSystem),
63	  fID(id),
64	  fUserlandVolume(NULL),
65	  fRootID(0),
66	  fRootNode(NULL),
67	  fMountVNodes(NULL),
68	  fOpenFiles(0),
69	  fOpenDirectories(0),
70	  fOpenAttributeDirectories(0),
71	  fOpenIndexDirectories(0),
72	  fOpenQueries(0),
73	  fVNodeCountMap(NULL),
74	  fVNodeCountingEnabled(false)
75{
76}
77
78// destructor
79Volume::~Volume()
80{
81}
82
83// GetFileSystem
84FileSystem*
85Volume::GetFileSystem() const
86{
87	return fFileSystem;
88}
89
90// GetID
91nspace_id
92Volume::GetID() const
93{
94	return fID;
95}
96
97// GetUserlandVolume
98void*
99Volume::GetUserlandVolume() const
100{
101	return fUserlandVolume;
102}
103
104// GetRootID
105vnode_id
106Volume::GetRootID() const
107{
108	return fRootID;
109}
110
111// IsMounting
112bool
113Volume::IsMounting() const
114{
115	return fMountVNodes;
116}
117
118
119// #pragma mark -
120// #pragma mark ----- client methods -----
121
122// GetVNode
123status_t
124Volume::GetVNode(vnode_id vnid, void** node)
125{
126PRINT(("get_vnode(%ld, %Ld)\n", fID, vnid));
127	if (IsMounting() && !fMountVNodes->ContainsKey(vnid)) {
128		ERROR(("Volume::GetVNode(): get_vnode() invoked for unknown vnode "
129			"while mounting!\n"));
130	}
131	status_t error = get_vnode(fID, vnid, node);
132	if (error == B_OK)
133		_IncrementVNodeCount(vnid);
134	return error;
135}
136
137// PutVNode
138status_t
139Volume::PutVNode(vnode_id vnid)
140{
141PRINT(("put_vnode(%ld, %Ld)\n", fID, vnid));
142	status_t error = put_vnode(fID, vnid);
143	if (error == B_OK)
144		_DecrementVNodeCount(vnid);
145	return error;
146}
147
148// NewVNode
149status_t
150Volume::NewVNode(vnode_id vnid, void* node)
151{
152PRINT(("new_vnode(%ld, %Ld)\n", fID, vnid));
153	status_t error = new_vnode(fID, vnid, node);
154	if (error == B_OK) {
155		if (IsMounting()) {
156			error = fMountVNodes->Put(vnid, node);
157			if (error != B_OK) {
158				ERROR(("Volume::NewVNode(): Failed to add vnode to mount "
159					"vnode map!\n"));
160				put_vnode(fID, vnid);
161				return error;
162			}
163		}
164		_IncrementVNodeCount(vnid);
165	}
166	return error;
167}
168
169// RemoveVNode
170status_t
171Volume::RemoveVNode(vnode_id vnid)
172{
173PRINT(("remove_vnode(%ld, %Ld)\n", fID, vnid));
174	return remove_vnode(fID, vnid);
175}
176
177// UnremoveVNode
178status_t
179Volume::UnremoveVNode(vnode_id vnid)
180{
181PRINT(("unremove_vnode(%ld, %Ld)\n", fID, vnid));
182	return unremove_vnode(fID, vnid);
183}
184
185// IsVNodeRemoved
186status_t
187Volume::IsVNodeRemoved(vnode_id vnid)
188{
189PRINT(("is_vnode_removed(%ld, %Ld)\n", fID, vnid));
190	return is_vnode_removed(fID, vnid);
191}
192
193// #pragma mark -
194// #pragma mark ----- FS -----
195
196// Mount
197status_t
198Volume::Mount(const char* device, ulong flags, const char* parameters,
199	int32 len)
200{
201	// Create a map that holds vnode_id->void* mappings of all vnodes
202	// created while mounting. We need it to get the root node.
203	MountVNodeMap vnodeMap;
204	status_t error = vnodeMap.InitCheck();
205	if (error != B_OK)
206		RETURN_ERROR(error);
207	fMountVNodes = &vnodeMap;
208	error = _Mount(device, flags, parameters, len);
209	fMountVNodes = NULL;
210	if (error == B_OK) {
211		// fetch the root node, so that we can serve Walk() requests on it,
212		// after the connection to the userland server is gone
213		if (!vnodeMap.ContainsKey(fRootID)) {
214			// The root node was not added while mounting. That's a serious
215			// problem -- not only because we don't have it, but also because
216			// the VFS requires new_vnode() to be invoked for the root node.
217			ERROR(("Volume::Mount(): new_vnode() was not called for root node! "
218				"Unmounting...\n"));
219			Unmount();
220			return B_ERROR;
221		}
222		fRootNode = vnodeMap.Get(fRootID);
223	}
224	return error;
225}
226
227// Unmount
228status_t
229Volume::Unmount()
230{
231	status_t error = _Unmount();
232	// free the memory associated with the vnode count map
233	if (fVNodeCountMap) {
234		AutoLocker<VNodeCountMap> _(fVNodeCountMap);
235		fVNodeCountingEnabled = false;
236		for (VNodeCountMap::Iterator it = fVNodeCountMap->GetIterator();
237			 it.HasNext();) {
238			VNodeCountMap::Entry entry = it.Next();
239			delete entry.value;
240		}
241		delete fVNodeCountMap;
242		fVNodeCountMap = NULL;
243	}
244	fFileSystem->VolumeUnmounted(this);
245	return error;
246}
247
248// Sync
249status_t
250Volume::Sync()
251{
252	// get a free port
253	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
254	if (!port)
255		return B_ERROR;
256	PortReleaser _(fFileSystem->GetPortPool(), port);
257	// prepare the request
258	RequestAllocator allocator(port->GetPort());
259	SyncVolumeRequest* request;
260	status_t error = AllocateRequest(allocator, &request);
261	if (error != B_OK)
262		return error;
263	request->volume = fUserlandVolume;
264	// send the request
265	KernelRequestHandler handler(this, SYNC_VOLUME_REPLY);
266	SyncVolumeReply* reply;
267	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
268	if (error != B_OK)
269		return error;
270	RequestReleaser requestReleaser(port, reply);
271	// process the reply
272	if (reply->error != B_OK)
273		return reply->error;
274	return error;
275}
276
277// ReadFSStat
278status_t
279Volume::ReadFSStat(fs_info* info)
280{
281	// get a free port
282	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
283	if (!port)
284		return B_ERROR;
285	PortReleaser _(fFileSystem->GetPortPool(), port);
286	// prepare the request
287	RequestAllocator allocator(port->GetPort());
288	ReadFSStatRequest* request;
289	status_t error = AllocateRequest(allocator, &request);
290	if (error != B_OK)
291		return error;
292	request->volume = fUserlandVolume;
293	// send the request
294	KernelRequestHandler handler(this, READ_FS_STAT_REPLY);
295	ReadFSStatReply* reply;
296	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
297	if (error != B_OK)
298		return error;
299	RequestReleaser requestReleaser(port, reply);
300	// process the reply
301	if (reply->error != B_OK)
302		return reply->error;
303	*info = reply->info;
304	return error;
305}
306
307// WriteFSStat
308status_t
309Volume::WriteFSStat(struct fs_info *info, long mask)
310{
311	// get a free port
312	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
313	if (!port)
314		return B_ERROR;
315	PortReleaser _(fFileSystem->GetPortPool(), port);
316	// prepare the request
317	RequestAllocator allocator(port->GetPort());
318	WriteFSStatRequest* request;
319	status_t error = AllocateRequest(allocator, &request);
320	if (error != B_OK)
321		return error;
322	request->volume = fUserlandVolume;
323	request->info = *info;
324	request->mask = mask;
325	// send the request
326	KernelRequestHandler handler(this, WRITE_FS_STAT_REPLY);
327	WriteFSStatReply* reply;
328	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
329	if (error != B_OK)
330		return error;
331	RequestReleaser requestReleaser(port, reply);
332	// process the reply
333	if (reply->error != B_OK)
334		return reply->error;
335	return error;
336}
337
338// #pragma mark -
339// #pragma mark ----- vnodes -----
340
341// ReadVNode
342status_t
343Volume::ReadVNode(vnode_id vnid, char reenter, void** node)
344{
345	// get a free port
346	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
347	if (!port)
348		return B_ERROR;
349	PortReleaser _(fFileSystem->GetPortPool(), port);
350	// prepare the request
351	RequestAllocator allocator(port->GetPort());
352	ReadVNodeRequest* request;
353	status_t error = AllocateRequest(allocator, &request);
354	if (error != B_OK)
355		return error;
356	request->volume = fUserlandVolume;
357	request->vnid = vnid;
358	request->reenter = reenter;
359	// send the request
360	KernelRequestHandler handler(this, READ_VNODE_REPLY);
361	ReadVNodeReply* reply;
362	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
363	if (error != B_OK)
364		return error;
365	RequestReleaser requestReleaser(port, reply);
366	// process the reply
367	if (reply->error != B_OK)
368		return reply->error;
369	*node = reply->node;
370	return error;
371}
372
373// WriteVNode
374status_t
375Volume::WriteVNode(void* node, char reenter)
376{
377	status_t error = _WriteVNode(node, reenter);
378	if (error != B_OK && fFileSystem->GetPortPool()->IsDisconnected()) {
379		// This isn't really necessary, since the VFS basically ignores the
380		// return value -- at least OBOS. The fshell panic()s; didn't check
381		// BeOS. It doesn't harm to appear to behave nicely. :-)
382		WARN(("Volume::WriteVNode(): connection lost, forcing write vnode\n"));
383		return B_OK;
384	}
385	return error;
386}
387
388// RemoveVNode
389status_t
390Volume::RemoveVNode(void* node, char reenter)
391{
392	// get a free port
393	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
394	if (!port)
395		return B_ERROR;
396	PortReleaser _(fFileSystem->GetPortPool(), port);
397	// prepare the request
398	RequestAllocator allocator(port->GetPort());
399	FSRemoveVNodeRequest* request;
400	status_t error = AllocateRequest(allocator, &request);
401	if (error != B_OK)
402		return error;
403	request->volume = fUserlandVolume;
404	request->node = node;
405	request->reenter = reenter;
406	// send the request
407	KernelRequestHandler handler(this, FS_REMOVE_VNODE_REPLY);
408	FSRemoveVNodeReply* reply;
409	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
410	if (error != B_OK)
411		return error;
412	RequestReleaser requestReleaser(port, reply);
413	// process the reply
414	if (reply->error != B_OK)
415		return reply->error;
416	return error;
417}
418
419// #pragma mark -
420// #pragma mark ----- nodes -----
421
422// FSync
423status_t
424Volume::FSync(void* node)
425{
426	// get a free port
427	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
428	if (!port)
429		return B_ERROR;
430	PortReleaser _(fFileSystem->GetPortPool(), port);
431	// prepare the request
432	RequestAllocator allocator(port->GetPort());
433	FSyncRequest* request;
434	status_t error = AllocateRequest(allocator, &request);
435	if (error != B_OK)
436		return error;
437	request->volume = fUserlandVolume;
438	request->node = node;
439	// send the request
440	KernelRequestHandler handler(this, FSYNC_REPLY);
441	FSyncReply* reply;
442	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
443	if (error != B_OK)
444		return error;
445	RequestReleaser requestReleaser(port, reply);
446	// process the reply
447	if (reply->error != B_OK)
448		return reply->error;
449	return error;
450}
451
452// ReadStat
453status_t
454Volume::ReadStat(void* node, struct stat* st)
455{
456	// get a free port
457	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
458	if (!port)
459		return B_ERROR;
460	PortReleaser _(fFileSystem->GetPortPool(), port);
461	// prepare the request
462	RequestAllocator allocator(port->GetPort());
463	ReadStatRequest* request;
464	status_t error = AllocateRequest(allocator, &request);
465	if (error != B_OK)
466		return error;
467	request->volume = fUserlandVolume;
468	request->node = node;
469	// send the request
470	KernelRequestHandler handler(this, READ_STAT_REPLY);
471	ReadStatReply* reply;
472	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
473	if (error != B_OK)
474		return error;
475	RequestReleaser requestReleaser(port, reply);
476	// process the reply
477	if (reply->error != B_OK)
478		return reply->error;
479	*st = reply->st;
480	return error;
481}
482
483// WriteStat
484status_t
485Volume::WriteStat(void* node, struct stat* st, long mask)
486{
487	// get a free port
488	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
489	if (!port)
490		return B_ERROR;
491	PortReleaser _(fFileSystem->GetPortPool(), port);
492	// prepare the request
493	RequestAllocator allocator(port->GetPort());
494	WriteStatRequest* request;
495	status_t error = AllocateRequest(allocator, &request);
496	if (error != B_OK)
497		return error;
498	request->volume = fUserlandVolume;
499	request->node = node;
500	request->st = *st;
501	request->mask = mask;
502	// send the request
503	KernelRequestHandler handler(this, WRITE_STAT_REPLY);
504	WriteStatReply* reply;
505	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
506	if (error != B_OK)
507		return error;
508	RequestReleaser requestReleaser(port, reply);
509	// process the reply
510	if (reply->error != B_OK)
511		return reply->error;
512	return error;
513}
514
515// Access
516status_t
517Volume::Access(void* node, int mode)
518{
519	// get a free port
520	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
521	if (!port)
522		return B_ERROR;
523	PortReleaser _(fFileSystem->GetPortPool(), port);
524	// prepare the request
525	RequestAllocator allocator(port->GetPort());
526	AccessRequest* request;
527	status_t error = AllocateRequest(allocator, &request);
528	if (error != B_OK)
529		return error;
530	request->volume = fUserlandVolume;
531	request->node = node;
532	request->mode = mode;
533	// send the request
534	KernelRequestHandler handler(this, ACCESS_REPLY);
535	AccessReply* reply;
536	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
537	if (error != B_OK)
538		return error;
539	RequestReleaser requestReleaser(port, reply);
540	// process the reply
541	if (reply->error != B_OK)
542		return reply->error;
543	return error;
544}
545
546// #pragma mark -
547// #pragma mark ----- files -----
548
549// Create
550status_t
551Volume::Create(void* dir, const char* name, int openMode, int mode,
552	vnode_id* vnid, void** cookie)
553{
554	// get a free port
555	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
556	if (!port)
557		return B_ERROR;
558	PortReleaser _(fFileSystem->GetPortPool(), port);
559	// prepare the request
560	RequestAllocator allocator(port->GetPort());
561	CreateRequest* request;
562	status_t error = AllocateRequest(allocator, &request);
563	if (error != B_OK)
564		return error;
565	request->volume = fUserlandVolume;
566	request->node = dir;
567	error = allocator.AllocateString(request->name, name);
568	request->openMode = openMode;
569	request->mode = mode;
570	if (error != B_OK)
571		return error;
572	// send the request
573	KernelRequestHandler handler(this, CREATE_REPLY);
574	CreateReply* reply;
575	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
576	if (error != B_OK)
577		return error;
578	RequestReleaser requestReleaser(port, reply);
579	// process the reply
580	if (reply->error != B_OK)
581		return reply->error;
582	*vnid = reply->vnid;
583	*cookie = reply->fileCookie;
584	if (error == B_OK)
585		_DecrementVNodeCount(*vnid);
586			// The VFS will balance the new_vnode() call for the FS.
587	return error;
588}
589
590// Open
591status_t
592Volume::Open(void* node, int openMode, void** cookie)
593{
594	// get a free port
595	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
596	if (!port)
597		return B_ERROR;
598	PortReleaser _(fFileSystem->GetPortPool(), port);
599	AutoIncrementer incrementer(&fOpenFiles);
600	// prepare the request
601	RequestAllocator allocator(port->GetPort());
602	OpenRequest* request;
603	status_t error = AllocateRequest(allocator, &request);
604	if (error != B_OK)
605		return error;
606	request->volume = fUserlandVolume;
607	request->node = node;
608	request->openMode = openMode;
609	// send the request
610	KernelRequestHandler handler(this, OPEN_REPLY);
611	OpenReply* reply;
612	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
613	if (error != B_OK)
614		return error;
615	RequestReleaser requestReleaser(port, reply);
616	// process the reply
617	if (reply->error != B_OK)
618		return reply->error;
619	incrementer.Keep();
620	*cookie = reply->fileCookie;
621	return error;
622}
623
624// Close
625status_t
626Volume::Close(void* node, void* cookie)
627{
628	status_t error = _Close(node, cookie);
629	if (error != B_OK && fFileSystem->GetPortPool()->IsDisconnected()) {
630		// This isn't really necessary, as the return value is irrelevant to
631		// the VFS. OBOS ignores it completely. The fsshell returns it to the
632		// userland, but considers the node closed anyway.
633		WARN(("Volume::Close(): connection lost, forcing close\n"));
634		return B_OK;
635	}
636	return error;
637}
638
639// FreeCookie
640status_t
641Volume::FreeCookie(void* node, void* cookie)
642{
643	status_t error = _FreeCookie(node, cookie);
644	bool disconnected = false;
645	if (error != B_OK && fFileSystem->GetPortPool()->IsDisconnected()) {
646		// This isn't really necessary, as the return value is irrelevant to
647		// the VFS. It's completely ignored by OBOS as well as by the fsshell.
648		WARN(("Volume::FreeCookie(): connection lost, forcing free cookie\n"));
649		error = B_OK;
650		disconnected = true;
651	}
652	int32 openFiles = atomic_add(&fOpenFiles, -1);
653	if (openFiles <= 1 && disconnected)
654		_PutAllPendingVNodes();
655	return error;
656}
657
658// Read
659status_t
660Volume::Read(void* node, void* cookie, off_t pos, void* buffer,
661	size_t bufferSize, size_t* bytesRead)
662{
663	*bytesRead = 0;
664	// get a free port
665	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
666	if (!port)
667		return B_ERROR;
668	PortReleaser _(fFileSystem->GetPortPool(), port);
669	// prepare the request
670	RequestAllocator allocator(port->GetPort());
671	ReadRequest* request;
672	status_t error = AllocateRequest(allocator, &request);
673	if (error != B_OK)
674		return error;
675	request->volume = fUserlandVolume;
676	request->node = node;
677	request->fileCookie = cookie;
678	request->pos = pos;
679	request->size = bufferSize;
680	// send the request
681	KernelRequestHandler handler(this, READ_REPLY);
682	ReadReply* reply;
683	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
684	if (error != B_OK)
685		return error;
686	RequestReleaser requestReleaser(port, reply);
687	// process the reply
688	if (reply->error != B_OK)
689		return reply->error;
690	void* readBuffer = reply->buffer.GetData();
691	if (reply->bytesRead > (uint32)reply->buffer.GetSize()
692		|| reply->bytesRead > bufferSize) {
693		return B_BAD_DATA;
694	}
695	if (reply->bytesRead > 0)
696		memcpy(buffer, readBuffer, reply->bytesRead);
697	*bytesRead = reply->bytesRead;
698	_SendReceiptAck(port);
699	return error;
700}
701
702// Write
703status_t
704Volume::Write(void* node, void* cookie, off_t pos, const void* buffer,
705	size_t size, size_t* bytesWritten)
706{
707	*bytesWritten = 0;
708	// get a free port
709	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
710	if (!port)
711		return B_ERROR;
712	PortReleaser _(fFileSystem->GetPortPool(), port);
713	// prepare the request
714	RequestAllocator allocator(port->GetPort());
715	WriteRequest* request;
716	status_t error = AllocateRequest(allocator, &request);
717	if (error != B_OK)
718		return error;
719	request->volume = fUserlandVolume;
720	request->node = node;
721	request->fileCookie = cookie;
722	request->pos = pos;
723	error = allocator.AllocateData(request->buffer, buffer, size, 1);
724	if (error != B_OK)
725		return error;
726	// send the request
727	KernelRequestHandler handler(this, WRITE_REPLY);
728	WriteReply* reply;
729	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
730	if (error != B_OK)
731		return error;
732	RequestReleaser requestReleaser(port, reply);
733	// process the reply
734	if (reply->error != B_OK)
735		return reply->error;
736	*bytesWritten = reply->bytesWritten;
737	return error;
738}
739
740// IOCtl
741status_t
742Volume::IOCtl(void* node, void* cookie, int command, void *buffer,
743	size_t len)
744{
745	// check the command and its parameters
746	bool isBuffer = false;
747	int32 bufferSize = 0;
748	int32 writeSize = 0;
749	switch (command) {
750		case IOCTL_FILE_UNCACHED_IO:
751			buffer = NULL;
752			break;
753		case IOCTL_CREATE_TIME:
754		case IOCTL_MODIFIED_TIME:
755			isBuffer = 0;
756			bufferSize = 0;
757			writeSize = sizeof(bigtime_t);
758			break;
759		case USERLANDFS_IOCTL:
760			area_id area;
761			area_info info;
762			PRINT(("Volume::IOCtl(): USERLANDFS_IOCTL\n"));
763			if ((area = area_for(buffer)) >= 0) {
764				if (get_area_info(area, &info) == B_OK) {
765					if ((uint8*)buffer - (uint8*)info.address
766							+ sizeof(userlandfs_ioctl) <= info.size) {
767						if (strncmp(((userlandfs_ioctl*)buffer)->magic,
768								kUserlandFSIOCtlMagic,
769								USERLAND_IOCTL_MAGIC_LENGTH) == 0) {
770							return _InternalIOCtl((userlandfs_ioctl*)buffer,
771								bufferSize);
772						} else
773							PRINT(("Volume::IOCtl(): bad magic\n"));
774					} else
775						PRINT(("Volume::IOCtl(): bad buffer size\n"));
776				} else
777					PRINT(("Volume::IOCtl(): failed to get area info\n"));
778			} else
779				PRINT(("Volume::IOCtl(): bad area\n"));
780			// fall through...
781		default:
782		{
783			// We don't know the command. Check whether the FileSystem knows
784			// about it.
785			const IOCtlInfo* info = fFileSystem->GetIOCtlInfo(command);
786			if (!info) {
787				PRINT(("Volume::IOCtl(): unknown command\n"));
788				return B_BAD_VALUE;
789			}
790			isBuffer = info->isBuffer;
791			bufferSize = info->bufferSize;
792			writeSize = info->writeBufferSize;
793			// If the buffer shall indeed specify a buffer, check it.
794			if (info->isBuffer) {
795				if (!buffer) {
796					PRINT(("Volume::IOCtl(): buffer is NULL\n"));
797					return B_BAD_VALUE;
798				}
799				area_id area = area_for(buffer);
800				if (area < 0) {
801					PRINT(("Volume::IOCtl(): bad area\n"));
802					return B_BAD_VALUE;
803				}
804				area_info info;
805				if (get_area_info(area, &info) != B_OK) {
806					PRINT(("Volume::IOCtl(): failed to get area info\n"));
807					return B_BAD_VALUE;
808				}
809				int32 areaSize = info.size - ((uint8*)buffer
810					- (uint8*)info.address);
811				if (bufferSize > areaSize || writeSize > areaSize) {
812					PRINT(("Volume::IOCtl(): bad buffer size\n"));
813					return B_BAD_VALUE;
814				}
815				if (writeSize > 0 && !(info.protection & B_WRITE_AREA)) {
816					PRINT(("Volume::IOCtl(): buffer not writable\n"));
817					return B_BAD_VALUE;
818				}
819			}
820			break;
821		}
822	}
823	// get a free port
824	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
825	if (!port)
826		return B_ERROR;
827	PortReleaser _(fFileSystem->GetPortPool(), port);
828	// prepare the request
829	RequestAllocator allocator(port->GetPort());
830	IOCtlRequest* request;
831	status_t error = AllocateRequest(allocator, &request);
832	if (error != B_OK)
833		return error;
834	request->volume = fUserlandVolume;
835	request->node = node;
836	request->fileCookie = cookie;
837	request->command = command;
838	request->bufferParameter = buffer;
839	request->isBuffer = isBuffer;
840	request->lenParameter = len;
841	request->writeSize = writeSize;
842	if (isBuffer && bufferSize > 0) {
843		error = allocator.AllocateData(request->buffer, buffer, bufferSize, 8);
844		if (error != B_OK)
845			return error;
846	}
847	// send the request
848	KernelRequestHandler handler(this, IOCTL_REPLY);
849	IOCtlReply* reply;
850	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
851	if (error != B_OK)
852		return error;
853	RequestReleaser requestReleaser(port, reply);
854	// process the reply
855	if (reply->error != B_OK)
856		return reply->error;
857	// Copy back the buffer even if the result is not B_OK. The protocol
858	// is defined by the FS developer and may include writing data into
859	// the buffer in some error cases.
860	if (isBuffer && writeSize > 0 && reply->buffer.GetData()) {
861		if (writeSize > reply->buffer.GetSize())
862			writeSize = reply->buffer.GetSize();
863		memcpy(buffer, reply->buffer.GetData(), writeSize);
864		_SendReceiptAck(port);
865	}
866	return reply->ioctlError;
867}
868
869// SetFlags
870status_t
871Volume::SetFlags(void* node, void* cookie, int flags)
872{
873	// get a free port
874	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
875	if (!port)
876		return B_ERROR;
877	PortReleaser _(fFileSystem->GetPortPool(), port);
878	// prepare the request
879	RequestAllocator allocator(port->GetPort());
880	SetFlagsRequest* request;
881	status_t error = AllocateRequest(allocator, &request);
882	if (error != B_OK)
883		return error;
884	request->volume = fUserlandVolume;
885	request->node = node;
886	request->fileCookie = cookie;
887	request->flags = flags;
888	// send the request
889	KernelRequestHandler handler(this, SET_FLAGS_REPLY);
890	SetFlagsReply* reply;
891	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
892	if (error != B_OK)
893		return error;
894	RequestReleaser requestReleaser(port, reply);
895	// process the reply
896	if (reply->error != B_OK)
897		return reply->error;
898	return error;
899}
900
901// Select
902status_t
903Volume::Select(void* node, void* cookie, uint8 event, uint32 ref,
904	selectsync* sync)
905{
906	// get a free port
907	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
908	if (!port)
909		return B_ERROR;
910	PortReleaser _(fFileSystem->GetPortPool(), port);
911	// prepare the request
912	RequestAllocator allocator(port->GetPort());
913	SelectRequest* request;
914	status_t error = AllocateRequest(allocator, &request);
915	if (error != B_OK)
916		return error;
917	request->volume = fUserlandVolume;
918	request->node = node;
919	request->fileCookie = cookie;
920	request->event = event;
921	request->ref = ref;
922	request->sync = sync;
923	// add a selectsync entry
924	error = fFileSystem->AddSelectSyncEntry(sync);
925	if (error != B_OK)
926		return error;
927	// send the request
928	KernelRequestHandler handler(this, SELECT_REPLY);
929	SelectReply* reply;
930	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
931	if (error != B_OK) {
932		fFileSystem->RemoveSelectSyncEntry(sync);
933		return error;
934	}
935	RequestReleaser requestReleaser(port, reply);
936	// process the reply
937	if (reply->error != B_OK) {
938		fFileSystem->RemoveSelectSyncEntry(sync);
939		return reply->error;
940	}
941	return error;
942}
943
944// Deselect
945status_t
946Volume::Deselect(void* node, void* cookie, uint8 event, selectsync* sync)
947{
948	struct SyncRemover {
949		SyncRemover(FileSystem* fs, selectsync* sync)
950			: fs(fs), sync(sync) {}
951		~SyncRemover() { fs->RemoveSelectSyncEntry(sync); }
952
953		FileSystem*	fs;
954		selectsync*	sync;
955	} syncRemover(fFileSystem, sync);
956	// get a free port
957	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
958	if (!port)
959		return B_ERROR;
960	PortReleaser _(fFileSystem->GetPortPool(), port);
961	// prepare the request
962	RequestAllocator allocator(port->GetPort());
963	DeselectRequest* request;
964	status_t error = AllocateRequest(allocator, &request);
965	if (error != B_OK)
966		return error;
967	request->volume = fUserlandVolume;
968	request->node = node;
969	request->fileCookie = cookie;
970	request->event = event;
971	request->sync = sync;
972	// send the request
973	KernelRequestHandler handler(this, DESELECT_REPLY);
974	DeselectReply* reply;
975	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
976	if (error != B_OK)
977		return error;
978	RequestReleaser requestReleaser(port, reply);
979	// process the reply
980	if (reply->error != B_OK)
981		return reply->error;
982	return error;
983}
984
985// #pragma mark -
986// #pragma mark ----- hard links / symlinks -----
987
988// Link
989status_t
990Volume::Link(void* dir, const char* name, void* node)
991{
992	// get a free port
993	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
994	if (!port)
995		return B_ERROR;
996	PortReleaser _(fFileSystem->GetPortPool(), port);
997	// prepare the request
998	RequestAllocator allocator(port->GetPort());
999	LinkRequest* request;
1000	status_t error = AllocateRequest(allocator, &request);
1001	if (error != B_OK)
1002		return error;
1003	request->volume = fUserlandVolume;
1004	request->node = dir;
1005	error = allocator.AllocateString(request->name, name);
1006	request->target = node;
1007	if (error != B_OK)
1008		return error;
1009	// send the request
1010	KernelRequestHandler handler(this, LINK_REPLY);
1011	LinkReply* reply;
1012	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
1013	if (error != B_OK)
1014		return error;
1015	RequestReleaser requestReleaser(port, reply);
1016	// process the reply
1017	if (reply->error != B_OK)
1018		return reply->error;
1019	return error;
1020}
1021
1022// Unlink
1023status_t
1024Volume::Unlink(void* dir, const char* name)
1025{
1026	// get a free port
1027	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
1028	if (!port)
1029		return B_ERROR;
1030	PortReleaser _(fFileSystem->GetPortPool(), port);
1031	// prepare the request
1032	RequestAllocator allocator(port->GetPort());
1033	UnlinkRequest* request;
1034	status_t error = AllocateRequest(allocator, &request);
1035	if (error != B_OK)
1036		return error;
1037	request->volume = fUserlandVolume;
1038	request->node = dir;
1039	error = allocator.AllocateString(request->name, name);
1040	if (error != B_OK)
1041		return error;
1042	// send the request
1043	KernelRequestHandler handler(this, UNLINK_REPLY);
1044	UnlinkReply* reply;
1045	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
1046	if (error != B_OK)
1047		return error;
1048	RequestReleaser requestReleaser(port, reply);
1049	// process the reply
1050	if (reply->error != B_OK)
1051		return reply->error;
1052	return error;
1053}
1054
1055// Symlink
1056status_t
1057Volume::Symlink(void* dir, const char* name, const char* target)
1058{
1059	// get a free port
1060	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
1061	if (!port)
1062		return B_ERROR;
1063	PortReleaser _(fFileSystem->GetPortPool(), port);
1064	// prepare the request
1065	RequestAllocator allocator(port->GetPort());
1066	SymlinkRequest* request;
1067	status_t error = AllocateRequest(allocator, &request);
1068	if (error != B_OK)
1069		return error;
1070	request->volume = fUserlandVolume;
1071	request->node = dir;
1072	error = allocator.AllocateString(request->name, name);
1073	if (error == B_OK)
1074		error = allocator.AllocateString(request->target, target);
1075	if (error != B_OK)
1076		return error;
1077	// send the request
1078	KernelRequestHandler handler(this, SYMLINK_REPLY);
1079	SymlinkReply* reply;
1080	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
1081	if (error != B_OK)
1082		return error;
1083	RequestReleaser requestReleaser(port, reply);
1084	// process the reply
1085	if (reply->error != B_OK)
1086		return reply->error;
1087	return error;
1088}
1089
1090// ReadLink
1091status_t
1092Volume::ReadLink(void* node, char* buffer, size_t bufferSize, size_t* bytesRead)
1093{
1094	*bytesRead = 0;
1095	// get a free port
1096	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
1097	if (!port)
1098		return B_ERROR;
1099	PortReleaser _(fFileSystem->GetPortPool(), port);
1100	// prepare the request
1101	RequestAllocator allocator(port->GetPort());
1102	ReadLinkRequest* request;
1103	status_t error = AllocateRequest(allocator, &request);
1104	if (error != B_OK)
1105		return error;
1106	request->volume = fUserlandVolume;
1107	request->node = node;
1108	request->size = bufferSize;
1109	// send the request
1110	KernelRequestHandler handler(this, READ_LINK_REPLY);
1111	ReadLinkReply* reply;
1112	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
1113	if (error != B_OK)
1114		return error;
1115	RequestReleaser requestReleaser(port, reply);
1116	// process the reply
1117	if (reply->error != B_OK)
1118		return reply->error;
1119	void* readBuffer = reply->buffer.GetData();
1120	if (reply->bytesRead > (uint32)reply->buffer.GetSize()
1121		|| reply->bytesRead > bufferSize) {
1122		return B_BAD_DATA;
1123	}
1124	if (reply->bytesRead > 0)
1125		memcpy(buffer, readBuffer, reply->bytesRead);
1126	*bytesRead = reply->bytesRead;
1127	_SendReceiptAck(port);
1128	return error;
1129}
1130
1131// Rename
1132status_t
1133Volume::Rename(void* oldDir, const char* oldName, void* newDir,
1134	const char* newName)
1135{
1136	// get a free port
1137	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
1138	if (!port)
1139		return B_ERROR;
1140	PortReleaser _(fFileSystem->GetPortPool(), port);
1141	// prepare the request
1142	RequestAllocator allocator(port->GetPort());
1143	RenameRequest* request;
1144	status_t error = AllocateRequest(allocator, &request);
1145	if (error != B_OK)
1146		return error;
1147	request->volume = fUserlandVolume;
1148	request->oldDir = oldDir;
1149	request->newDir = newDir;
1150	error = allocator.AllocateString(request->oldName, oldName);
1151	if (error == B_OK)
1152		error = allocator.AllocateString(request->newName, newName);
1153	if (error != B_OK)
1154		return error;
1155	// send the request
1156	KernelRequestHandler handler(this, RENAME_REPLY);
1157	RenameReply* reply;
1158	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
1159	if (error != B_OK)
1160		return error;
1161	RequestReleaser requestReleaser(port, reply);
1162	// process the reply
1163	if (reply->error != B_OK)
1164		return reply->error;
1165	return error;
1166}
1167
1168// #pragma mark -
1169// #pragma mark ----- directories -----
1170
1171// MkDir
1172status_t
1173Volume::MkDir(void* dir, const char* name, int mode)
1174{
1175	// get a free port
1176	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
1177	if (!port)
1178		return B_ERROR;
1179	PortReleaser _(fFileSystem->GetPortPool(), port);
1180	// prepare the request
1181	RequestAllocator allocator(port->GetPort());
1182	MkDirRequest* request;
1183	status_t error = AllocateRequest(allocator, &request);
1184	if (error != B_OK)
1185		return error;
1186	request->volume = fUserlandVolume;
1187	request->node = dir;
1188	error = allocator.AllocateString(request->name, name);
1189	request->mode = mode;
1190	if (error != B_OK)
1191		return error;
1192	// send the request
1193	KernelRequestHandler handler(this, MKDIR_REPLY);
1194	MkDirReply* reply;
1195	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
1196	if (error != B_OK)
1197		return error;
1198	RequestReleaser requestReleaser(port, reply);
1199	// process the reply
1200	if (reply->error != B_OK)
1201		return reply->error;
1202	return error;
1203}
1204
1205// RmDir
1206status_t
1207Volume::RmDir(void* dir, const char* name)
1208{
1209	// get a free port
1210	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
1211	if (!port)
1212		return B_ERROR;
1213	PortReleaser _(fFileSystem->GetPortPool(), port);
1214	// prepare the request
1215	RequestAllocator allocator(port->GetPort());
1216	RmDirRequest* request;
1217	status_t error = AllocateRequest(allocator, &request);
1218	if (error != B_OK)
1219		return error;
1220	request->volume = fUserlandVolume;
1221	request->node = dir;
1222	error = allocator.AllocateString(request->name, name);
1223	if (error != B_OK)
1224		return error;
1225	// send the request
1226	KernelRequestHandler handler(this, RMDIR_REPLY);
1227	RmDirReply* reply;
1228	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
1229	if (error != B_OK)
1230		return error;
1231	RequestReleaser requestReleaser(port, reply);
1232	// process the reply
1233	if (reply->error != B_OK)
1234		return reply->error;
1235	return error;
1236}
1237
1238// OpenDir
1239status_t
1240Volume::OpenDir(void* node, void** cookie)
1241{
1242	// get a free port
1243	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
1244	if (!port)
1245		return B_ERROR;
1246	PortReleaser _(fFileSystem->GetPortPool(), port);
1247	AutoIncrementer incrementer(&fOpenDirectories);
1248	// prepare the request
1249	RequestAllocator allocator(port->GetPort());
1250	OpenDirRequest* request;
1251	status_t error = AllocateRequest(allocator, &request);
1252	if (error != B_OK)
1253		return error;
1254	request->volume = fUserlandVolume;
1255	request->node = node;
1256	// send the request
1257	KernelRequestHandler handler(this, OPEN_DIR_REPLY);
1258	OpenDirReply* reply;
1259	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
1260	if (error != B_OK)
1261		return error;
1262	RequestReleaser requestReleaser(port, reply);
1263	// process the reply
1264	if (reply->error != B_OK)
1265		return reply->error;
1266	incrementer.Keep();
1267	*cookie = reply->dirCookie;
1268	return error;
1269}
1270
1271// CloseDir
1272status_t
1273Volume::CloseDir(void* node, void* cookie)
1274{
1275	status_t error = _CloseDir(node, cookie);
1276	if (error != B_OK && fFileSystem->GetPortPool()->IsDisconnected()) {
1277		// This isn't really necessary, as the return value is irrelevant to
1278		// the VFS. OBOS ignores it completely. The fsshell returns it to the
1279		// userland, but considers the node closed anyway.
1280		WARN(("Volume::CloseDir(): connection lost, forcing close dir\n"));
1281		return B_OK;
1282	}
1283	return error;
1284}
1285
1286// FreeDirCookie
1287status_t
1288Volume::FreeDirCookie(void* node, void* cookie)
1289{
1290	status_t error = _FreeDirCookie(node, cookie);
1291	bool disconnected = false;
1292	if (error != B_OK && fFileSystem->GetPortPool()->IsDisconnected()) {
1293		// This isn't really necessary, as the return value is irrelevant to
1294		// the VFS. It's completely ignored by OBOS as well as by the fsshell.
1295		WARN(("Volume::FreeDirCookie(): connection lost, forcing free dir "
1296			"cookie\n"));
1297		error = B_OK;
1298		disconnected = true;
1299	}
1300	int32 openDirs = atomic_add(&fOpenDirectories, -1);
1301	if (openDirs <= 1 && disconnected)
1302		_PutAllPendingVNodes();
1303	return error;
1304}
1305
1306// ReadDir
1307status_t
1308Volume::ReadDir(void* node, void* cookie, void* buffer, size_t bufferSize,
1309	int32 count, int32* countRead)
1310{
1311	*countRead = 0;
1312	// get a free port
1313	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
1314	if (!port)
1315		return B_ERROR;
1316	PortReleaser _(fFileSystem->GetPortPool(), port);
1317	// prepare the request
1318	RequestAllocator allocator(port->GetPort());
1319	ReadDirRequest* request;
1320	status_t error = AllocateRequest(allocator, &request);
1321	if (error != B_OK)
1322		return error;
1323	request->volume = fUserlandVolume;
1324	request->node = node;
1325	request->dirCookie = cookie;
1326	request->bufferSize = bufferSize;
1327	request->count = count;
1328	// send the request
1329	KernelRequestHandler handler(this, READ_DIR_REPLY);
1330	ReadDirReply* reply;
1331	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
1332	if (error != B_OK)
1333		return error;
1334	RequestReleaser requestReleaser(port, reply);
1335	// process the reply
1336	if (reply->error != B_OK)
1337		return reply->error;
1338	if (reply->count < 0 || reply->count > count)
1339		return B_BAD_DATA;
1340	if ((int32)bufferSize < reply->buffer.GetSize())
1341		return B_BAD_DATA;
1342PRINT(("Volume::ReadDir(): buffer returned: %ld bytes\n",
1343reply->buffer.GetSize()));
1344	*countRead = reply->count;
1345	if (*countRead > 0) {
1346		// copy the buffer -- limit the number of bytes to copy
1347		int32 maxBytes = *countRead
1348			* (sizeof(struct dirent) + B_FILE_NAME_LENGTH);
1349		int32 copyBytes = reply->buffer.GetSize();
1350		if (copyBytes > maxBytes)
1351			copyBytes = maxBytes;
1352		memcpy(buffer, reply->buffer.GetData(), copyBytes);
1353	}
1354	_SendReceiptAck(port);
1355	return error;
1356}
1357
1358// RewindDir
1359status_t
1360Volume::RewindDir(void* node, void* cookie)
1361{
1362	// get a free port
1363	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
1364	if (!port)
1365		return B_ERROR;
1366	PortReleaser _(fFileSystem->GetPortPool(), port);
1367	// prepare the request
1368	RequestAllocator allocator(port->GetPort());
1369	RewindDirRequest* request;
1370	status_t error = AllocateRequest(allocator, &request);
1371	if (error != B_OK)
1372		return error;
1373	request->volume = fUserlandVolume;
1374	request->node = node;
1375	request->dirCookie = cookie;
1376	// send the request
1377	KernelRequestHandler handler(this, REWIND_DIR_REPLY);
1378	RewindDirReply* reply;
1379	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
1380	if (error != B_OK)
1381		return error;
1382	RequestReleaser requestReleaser(port, reply);
1383	// process the reply
1384	if (reply->error != B_OK)
1385		return reply->error;
1386	return error;
1387}
1388
1389// Walk
1390status_t
1391Volume::Walk(void* dir, const char* entryName, char** resolvedPath,
1392	vnode_id* vnid)
1393{
1394	// When the connection to the userland server is lost, we serve
1395	// walk(fRootNode, `.') requests manually to allow clean unmounting.
1396	status_t error = _Walk(dir, entryName, resolvedPath, vnid);
1397	if (error != B_OK && fFileSystem->GetPortPool()->IsDisconnected()
1398		&& dir == fRootNode && strcmp(entryName, ".") == 0) {
1399		WARN(("Volume::Walk(): connection lost, emulating walk `.'\n"));
1400		void* entryNode;
1401		if (GetVNode(fRootID, &entryNode) != B_OK)
1402			RETURN_ERROR(B_BAD_VALUE);
1403		*vnid = fRootID;
1404		// The VFS will balance the get_vnode() call for the FS.
1405		_DecrementVNodeCount(*vnid);
1406		return B_OK;
1407	}
1408	return error;
1409}
1410
1411// #pragma mark -
1412// #pragma mark ----- attributes -----
1413
1414// OpenAttrDir
1415status_t
1416Volume::OpenAttrDir(void* node, void** cookie)
1417{
1418	// get a free port
1419	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
1420	if (!port)
1421		return B_ERROR;
1422	PortReleaser _(fFileSystem->GetPortPool(), port);
1423	AutoIncrementer incrementer(&fOpenAttributeDirectories);
1424	// prepare the request
1425	RequestAllocator allocator(port->GetPort());
1426	OpenAttrDirRequest* request;
1427	status_t error = AllocateRequest(allocator, &request);
1428	if (error != B_OK)
1429		return error;
1430	request->volume = fUserlandVolume;
1431	request->node = node;
1432	// send the request
1433	KernelRequestHandler handler(this, OPEN_ATTR_DIR_REPLY);
1434	OpenAttrDirReply* reply;
1435	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
1436	if (error != B_OK)
1437		return error;
1438	RequestReleaser requestReleaser(port, reply);
1439	// process the reply
1440	if (reply->error != B_OK)
1441		return reply->error;
1442	incrementer.Keep();
1443	*cookie = reply->attrDirCookie;
1444	return error;
1445}
1446
1447// CloseAttrDir
1448status_t
1449Volume::CloseAttrDir(void* node, void* cookie)
1450{
1451	status_t error = _CloseAttrDir(node, cookie);
1452	if (error != B_OK && fFileSystem->GetPortPool()->IsDisconnected()) {
1453		// This isn't really necessary, as the return value is irrelevant to
1454		// the VFS. OBOS ignores it completely. The fsshell returns it to the
1455		// userland, but considers the node closed anyway.
1456		WARN(("Volume::CloseAttrDir(): connection lost, forcing close attr "
1457			"dir\n"));
1458		return B_OK;
1459	}
1460	return error;
1461}
1462
1463// FreeAttrDirCookie
1464status_t
1465Volume::FreeAttrDirCookie(void* node, void* cookie)
1466{
1467	status_t error = _FreeAttrDirCookie(node, cookie);
1468	bool disconnected = false;
1469	if (error != B_OK && fFileSystem->GetPortPool()->IsDisconnected()) {
1470		// This isn't really necessary, as the return value is irrelevant to
1471		// the VFS. It's completely ignored by OBOS as well as by the fsshell.
1472		WARN(("Volume::FreeAttrDirCookie(): connection lost, forcing free attr "
1473			"dir cookie\n"));
1474		error = B_OK;
1475		disconnected = true;
1476	}
1477	int32 openAttrDirs = atomic_add(&fOpenAttributeDirectories, -1);
1478	if (openAttrDirs <= 1 && disconnected)
1479		_PutAllPendingVNodes();
1480	return error;
1481}
1482
1483// ReadAttrDir
1484status_t
1485Volume::ReadAttrDir(void* node, void* cookie, void* buffer, size_t bufferSize,
1486	int32 count, int32* countRead)
1487{
1488	*countRead = 0;
1489	// get a free port
1490	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
1491	if (!port)
1492		return B_ERROR;
1493	PortReleaser _(fFileSystem->GetPortPool(), port);
1494	// prepare the request
1495	RequestAllocator allocator(port->GetPort());
1496	ReadAttrDirRequest* request;
1497	status_t error = AllocateRequest(allocator, &request);
1498	if (error != B_OK)
1499		return error;
1500	request->volume = fUserlandVolume;
1501	request->node = node;
1502	request->attrDirCookie = cookie;
1503	request->bufferSize = bufferSize;
1504	request->count = count;
1505	// send the request
1506	KernelRequestHandler handler(this, READ_ATTR_DIR_REPLY);
1507	ReadAttrDirReply* reply;
1508	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
1509	if (error != B_OK)
1510		return error;
1511	RequestReleaser requestReleaser(port, reply);
1512	// process the reply
1513	if (reply->error != B_OK)
1514		return reply->error;
1515	if (reply->count < 0 || reply->count > count)
1516		return B_BAD_DATA;
1517	if ((int32)bufferSize < reply->buffer.GetSize())
1518		return B_BAD_DATA;
1519	*countRead = reply->count;
1520	if (*countRead > 0) {
1521		// copy the buffer -- limit the number of bytes to copy
1522		int32 maxBytes = *countRead
1523			* (sizeof(struct dirent) + B_ATTR_NAME_LENGTH);
1524		int32 copyBytes = reply->buffer.GetSize();
1525		if (copyBytes > maxBytes)
1526			copyBytes = maxBytes;
1527		memcpy(buffer, reply->buffer.GetData(), copyBytes);
1528	}
1529	_SendReceiptAck(port);
1530	return error;
1531}
1532
1533// RewindAttrDir
1534status_t
1535Volume::RewindAttrDir(void* node, void* cookie)
1536{
1537	// get a free port
1538	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
1539	if (!port)
1540		return B_ERROR;
1541	PortReleaser _(fFileSystem->GetPortPool(), port);
1542	// prepare the request
1543	RequestAllocator allocator(port->GetPort());
1544	RewindAttrDirRequest* request;
1545	status_t error = AllocateRequest(allocator, &request);
1546	if (error != B_OK)
1547		return error;
1548	request->volume = fUserlandVolume;
1549	request->node = node;
1550	request->attrDirCookie = cookie;
1551	// send the request
1552	KernelRequestHandler handler(this, REWIND_ATTR_DIR_REPLY);
1553	RewindAttrDirReply* reply;
1554	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
1555	if (error != B_OK)
1556		return error;
1557	RequestReleaser requestReleaser(port, reply);
1558	// process the reply
1559	if (reply->error != B_OK)
1560		return reply->error;
1561	return error;
1562}
1563
1564// ReadAttr
1565status_t
1566Volume::ReadAttr(void* node, const char* name, int type, off_t pos,
1567	void* buffer, size_t bufferSize, size_t* bytesRead)
1568{
1569	*bytesRead = 0;
1570	// get a free port
1571	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
1572	if (!port)
1573		return B_ERROR;
1574	PortReleaser _(fFileSystem->GetPortPool(), port);
1575	// prepare the request
1576	RequestAllocator allocator(port->GetPort());
1577	ReadAttrRequest* request;
1578	status_t error = AllocateRequest(allocator, &request);
1579	if (error != B_OK)
1580		return error;
1581	request->volume = fUserlandVolume;
1582	request->node = node;
1583	error = allocator.AllocateString(request->name, name);
1584	request->type = type;
1585	request->pos = pos;
1586	request->size = bufferSize;
1587	if (error != B_OK)
1588		return error;
1589	// send the request
1590	KernelRequestHandler handler(this, READ_ATTR_REPLY);
1591	ReadAttrReply* reply;
1592	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
1593	if (error != B_OK)
1594		return error;
1595	RequestReleaser requestReleaser(port, reply);
1596	// process the reply
1597	if (reply->error != B_OK)
1598		return reply->error;
1599	void* readBuffer = reply->buffer.GetData();
1600	if (reply->bytesRead > (uint32)reply->buffer.GetSize()
1601		|| reply->bytesRead > bufferSize) {
1602		return B_BAD_DATA;
1603	}
1604	if (reply->bytesRead > 0)
1605		memcpy(buffer, readBuffer, reply->bytesRead);
1606	*bytesRead = reply->bytesRead;
1607	_SendReceiptAck(port);
1608	return error;
1609}
1610
1611// WriteAttr
1612status_t
1613Volume::WriteAttr(void* node, const char* name, int type, off_t pos,
1614	const void* buffer, size_t bufferSize, size_t* bytesWritten)
1615{
1616	*bytesWritten = 0;
1617	// get a free port
1618	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
1619	if (!port)
1620		return B_ERROR;
1621	PortReleaser _(fFileSystem->GetPortPool(), port);
1622	// prepare the request
1623	RequestAllocator allocator(port->GetPort());
1624	WriteAttrRequest* request;
1625	status_t error = AllocateRequest(allocator, &request);
1626	if (error != B_OK)
1627		return error;
1628	request->volume = fUserlandVolume;
1629	request->node = node;
1630	error = allocator.AllocateString(request->name, name);
1631	request->type = type;
1632	request->pos = pos;
1633	if (error == B_OK)
1634		error = allocator.AllocateData(request->buffer, buffer, bufferSize, 1);
1635	if (error != B_OK)
1636		return error;
1637	// send the request
1638	KernelRequestHandler handler(this, WRITE_ATTR_REPLY);
1639	WriteAttrReply* reply;
1640	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
1641	if (error != B_OK)
1642		return error;
1643	RequestReleaser requestReleaser(port, reply);
1644	// process the reply
1645	if (reply->error != B_OK)
1646		return reply->error;
1647	*bytesWritten = reply->bytesWritten;
1648	return error;
1649}
1650
1651// RemoveAttr
1652status_t
1653Volume::RemoveAttr(void* node, const char* name)
1654{
1655	// get a free port
1656	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
1657	if (!port)
1658		return B_ERROR;
1659	PortReleaser _(fFileSystem->GetPortPool(), port);
1660	// prepare the request
1661	RequestAllocator allocator(port->GetPort());
1662	RemoveAttrRequest* request;
1663	status_t error = AllocateRequest(allocator, &request);
1664	if (error != B_OK)
1665		return error;
1666	request->volume = fUserlandVolume;
1667	request->node = node;
1668	error = allocator.AllocateString(request->name, name);
1669	if (error != B_OK)
1670		return error;
1671	// send the request
1672	KernelRequestHandler handler(this, REMOVE_ATTR_REPLY);
1673	RemoveAttrReply* reply;
1674	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
1675	if (error != B_OK)
1676		return error;
1677	RequestReleaser requestReleaser(port, reply);
1678	// process the reply
1679	if (reply->error != B_OK)
1680		return reply->error;
1681	return error;
1682}
1683
1684// RenameAttr
1685status_t
1686Volume::RenameAttr(void* node, const char* oldName, const char* newName)
1687{
1688	// get a free port
1689	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
1690	if (!port)
1691		return B_ERROR;
1692	PortReleaser _(fFileSystem->GetPortPool(), port);
1693	// prepare the request
1694	RequestAllocator allocator(port->GetPort());
1695	RenameAttrRequest* request;
1696	status_t error = AllocateRequest(allocator, &request);
1697	if (error != B_OK)
1698		return error;
1699	request->volume = fUserlandVolume;
1700	request->node = node;
1701	error = allocator.AllocateString(request->oldName, oldName);
1702	if (error == B_OK)
1703		error = allocator.AllocateString(request->newName, newName);
1704	if (error != B_OK)
1705		return error;
1706	// send the request
1707	KernelRequestHandler handler(this, RENAME_ATTR_REPLY);
1708	RenameAttrReply* reply;
1709	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
1710	if (error != B_OK)
1711		return error;
1712	RequestReleaser requestReleaser(port, reply);
1713	// process the reply
1714	if (reply->error != B_OK)
1715		return reply->error;
1716	return error;
1717}
1718
1719// StatAttr
1720status_t
1721Volume::StatAttr(void* node, const char* name, struct attr_info* attrInfo)
1722{
1723	// get a free port
1724	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
1725	if (!port)
1726		return B_ERROR;
1727	PortReleaser _(fFileSystem->GetPortPool(), port);
1728	// prepare the request
1729	RequestAllocator allocator(port->GetPort());
1730	StatAttrRequest* request;
1731	status_t error = AllocateRequest(allocator, &request);
1732	if (error != B_OK)
1733		return error;
1734	request->volume = fUserlandVolume;
1735	request->node = node;
1736	error = allocator.AllocateString(request->name, name);
1737	if (error != B_OK)
1738		return error;
1739	// send the request
1740	KernelRequestHandler handler(this, STAT_ATTR_REPLY);
1741	StatAttrReply* reply;
1742	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
1743	if (error != B_OK)
1744		return error;
1745	RequestReleaser requestReleaser(port, reply);
1746	// process the reply
1747	if (reply->error != B_OK)
1748		return reply->error;
1749	*attrInfo = reply->info;
1750	return error;
1751}
1752
1753// #pragma mark -
1754// #pragma mark ----- indices -----
1755
1756// OpenIndexDir
1757status_t
1758Volume::OpenIndexDir(void** cookie)
1759{
1760	// get a free port
1761	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
1762	if (!port)
1763		return B_ERROR;
1764	PortReleaser _(fFileSystem->GetPortPool(), port);
1765	AutoIncrementer incrementer(&fOpenIndexDirectories);
1766	// prepare the request
1767	RequestAllocator allocator(port->GetPort());
1768	OpenIndexDirRequest* request;
1769	status_t error = AllocateRequest(allocator, &request);
1770	if (error != B_OK)
1771		return error;
1772	request->volume = fUserlandVolume;
1773	// send the request
1774	KernelRequestHandler handler(this, OPEN_INDEX_DIR_REPLY);
1775	OpenIndexDirReply* reply;
1776	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
1777	if (error != B_OK)
1778		return error;
1779	RequestReleaser requestReleaser(port, reply);
1780	// process the reply
1781	if (reply->error != B_OK)
1782		return reply->error;
1783	incrementer.Keep();
1784	*cookie = reply->indexDirCookie;
1785	return error;
1786}
1787
1788// CloseIndexDir
1789status_t
1790Volume::CloseIndexDir(void* cookie)
1791{
1792	status_t error = _CloseIndexDir(cookie);
1793	if (error != B_OK && fFileSystem->GetPortPool()->IsDisconnected()) {
1794		// This isn't really necessary, as the return value is irrelevant to
1795		// the VFS. OBOS ignores it completely. The fsshell returns it to the
1796		// userland, but considers the node closed anyway.
1797		WARN(("Volume::CloseIndexDir(): connection lost, forcing close "
1798			"index dir\n"));
1799		return B_OK;
1800	}
1801	return error;
1802}
1803
1804// FreeIndexDirCookie
1805status_t
1806Volume::FreeIndexDirCookie(void* cookie)
1807{
1808	status_t error = _FreeIndexDirCookie(cookie);
1809	bool disconnected = false;
1810	if (error != B_OK && fFileSystem->GetPortPool()->IsDisconnected()) {
1811		// This isn't really necessary, as the return value is irrelevant to
1812		// the VFS. It's completely ignored by OBOS as well as by the fsshell.
1813		WARN(("Volume::FreeIndexDirCookie(): connection lost, forcing free "
1814			"index dir cookie\n"));
1815		error = B_OK;
1816		disconnected = true;
1817	}
1818	int32 openIndexDirs = atomic_add(&fOpenIndexDirectories, -1);
1819	if (openIndexDirs <= 1 && disconnected)
1820		_PutAllPendingVNodes();
1821	return error;
1822}
1823
1824// ReadIndexDir
1825status_t
1826Volume::ReadIndexDir(void* cookie, void* buffer, size_t bufferSize, int32 count,
1827	int32* countRead)
1828{
1829	*countRead = 0;
1830	// get a free port
1831	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
1832	if (!port)
1833		return B_ERROR;
1834	PortReleaser _(fFileSystem->GetPortPool(), port);
1835	// prepare the request
1836	RequestAllocator allocator(port->GetPort());
1837	ReadIndexDirRequest* request;
1838	status_t error = AllocateRequest(allocator, &request);
1839	if (error != B_OK)
1840		return error;
1841	request->volume = fUserlandVolume;
1842	request->indexDirCookie = cookie;
1843	request->bufferSize = bufferSize;
1844	request->count = count;
1845	// send the request
1846	KernelRequestHandler handler(this, READ_INDEX_DIR_REPLY);
1847	ReadIndexDirReply* reply;
1848	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
1849	if (error != B_OK)
1850		return error;
1851	RequestReleaser requestReleaser(port, reply);
1852	// process the reply
1853	if (reply->error != B_OK)
1854		return reply->error;
1855	if (reply->count < 0 || reply->count > count)
1856		return B_BAD_DATA;
1857	if ((int32)bufferSize < reply->buffer.GetSize())
1858		return B_BAD_DATA;
1859	*countRead = reply->count;
1860	if (*countRead > 0) {
1861		// copy the buffer -- limit the number of bytes to copy
1862		int32 maxBytes = *countRead
1863			* (sizeof(struct dirent) + B_FILE_NAME_LENGTH);
1864		int32 copyBytes = reply->buffer.GetSize();
1865		if (copyBytes > maxBytes)
1866			copyBytes = maxBytes;
1867		memcpy(buffer, reply->buffer.GetData(), copyBytes);
1868	}
1869	_SendReceiptAck(port);
1870	return error;
1871}
1872
1873// RewindIndexDir
1874status_t
1875Volume::RewindIndexDir(void* cookie)
1876{
1877	// get a free port
1878	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
1879	if (!port)
1880		return B_ERROR;
1881	PortReleaser _(fFileSystem->GetPortPool(), port);
1882	// prepare the request
1883	RequestAllocator allocator(port->GetPort());
1884	RewindIndexDirRequest* request;
1885	status_t error = AllocateRequest(allocator, &request);
1886	if (error != B_OK)
1887		return error;
1888	request->volume = fUserlandVolume;
1889	request->indexDirCookie = cookie;
1890	// send the request
1891	KernelRequestHandler handler(this, REWIND_INDEX_DIR_REPLY);
1892	RewindIndexDirReply* reply;
1893	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
1894	if (error != B_OK)
1895		return error;
1896	RequestReleaser requestReleaser(port, reply);
1897	// process the reply
1898	if (reply->error != B_OK)
1899		return reply->error;
1900	return error;
1901}
1902
1903// CreateIndex
1904status_t
1905Volume::CreateIndex(const char* name, int type, int flags)
1906{
1907	// get a free port
1908	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
1909	if (!port)
1910		return B_ERROR;
1911	PortReleaser _(fFileSystem->GetPortPool(), port);
1912	// prepare the request
1913	RequestAllocator allocator(port->GetPort());
1914	CreateIndexRequest* request;
1915	status_t error = AllocateRequest(allocator, &request);
1916	if (error != B_OK)
1917		return error;
1918	request->volume = fUserlandVolume;
1919	error = allocator.AllocateString(request->name, name);
1920	request->type = type;
1921	request->flags = flags;
1922	if (error != B_OK)
1923		return error;
1924	// send the request
1925	KernelRequestHandler handler(this, CREATE_INDEX_REPLY);
1926	CreateIndexReply* reply;
1927	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
1928	if (error != B_OK)
1929		return error;
1930	RequestReleaser requestReleaser(port, reply);
1931	// process the reply
1932	if (reply->error != B_OK)
1933		return reply->error;
1934	return error;
1935}
1936
1937// RemoveIndex
1938status_t
1939Volume::RemoveIndex(const char* name)
1940{
1941	// get a free port
1942	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
1943	if (!port)
1944		return B_ERROR;
1945	PortReleaser _(fFileSystem->GetPortPool(), port);
1946	// prepare the request
1947	RequestAllocator allocator(port->GetPort());
1948	RemoveIndexRequest* request;
1949	status_t error = AllocateRequest(allocator, &request);
1950	if (error != B_OK)
1951		return error;
1952	request->volume = fUserlandVolume;
1953	error = allocator.AllocateString(request->name, name);
1954	if (error != B_OK)
1955		return error;
1956	// send the request
1957	KernelRequestHandler handler(this, REMOVE_INDEX_REPLY);
1958	RemoveIndexReply* reply;
1959	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
1960	if (error != B_OK)
1961		return error;
1962	RequestReleaser requestReleaser(port, reply);
1963	// process the reply
1964	if (reply->error != B_OK)
1965		return reply->error;
1966	return error;
1967}
1968
1969// RenameIndex
1970status_t
1971Volume::RenameIndex(const char* oldName, const char* newName)
1972{
1973	// get a free port
1974	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
1975	if (!port)
1976		return B_ERROR;
1977	PortReleaser _(fFileSystem->GetPortPool(), port);
1978	// prepare the request
1979	RequestAllocator allocator(port->GetPort());
1980	RenameIndexRequest* request;
1981	status_t error = AllocateRequest(allocator, &request);
1982	if (error != B_OK)
1983		return error;
1984	request->volume = fUserlandVolume;
1985	error = allocator.AllocateString(request->oldName, oldName);
1986	if (error == B_OK)
1987		error = allocator.AllocateString(request->newName, newName);
1988	if (error != B_OK)
1989		return error;
1990	// send the request
1991	KernelRequestHandler handler(this, RENAME_INDEX_REPLY);
1992	RenameIndexReply* reply;
1993	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
1994	if (error != B_OK)
1995		return error;
1996	RequestReleaser requestReleaser(port, reply);
1997	// process the reply
1998	if (reply->error != B_OK)
1999		return reply->error;
2000	return error;
2001}
2002
2003// StatIndex
2004status_t
2005Volume::StatIndex(const char *name, struct index_info* indexInfo)
2006{
2007	// get a free port
2008	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
2009	if (!port)
2010		return B_ERROR;
2011	PortReleaser _(fFileSystem->GetPortPool(), port);
2012	// prepare the request
2013	RequestAllocator allocator(port->GetPort());
2014	StatIndexRequest* request;
2015	status_t error = AllocateRequest(allocator, &request);
2016	if (error != B_OK)
2017		return error;
2018	request->volume = fUserlandVolume;
2019	error = allocator.AllocateString(request->name, name);
2020	if (error != B_OK)
2021		return error;
2022	// send the request
2023	KernelRequestHandler handler(this, STAT_INDEX_REPLY);
2024	StatIndexReply* reply;
2025	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
2026	if (error != B_OK)
2027		return error;
2028	RequestReleaser requestReleaser(port, reply);
2029	// process the reply
2030	if (reply->error != B_OK)
2031		return reply->error;
2032	*indexInfo = reply->info;
2033	return error;
2034}
2035
2036// #pragma mark -
2037// #pragma mark ----- queries -----
2038
2039// OpenQuery
2040status_t
2041Volume::OpenQuery(const char* queryString, ulong flags, port_id targetPort,
2042	long token, void** cookie)
2043{
2044	// get a free port
2045	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
2046	if (!port)
2047		return B_ERROR;
2048	PortReleaser _(fFileSystem->GetPortPool(), port);
2049	AutoIncrementer incrementer(&fOpenQueries);
2050	// prepare the request
2051	RequestAllocator allocator(port->GetPort());
2052	OpenQueryRequest* request;
2053	status_t error = AllocateRequest(allocator, &request);
2054	if (error != B_OK)
2055		return error;
2056	request->volume = fUserlandVolume;
2057	error = allocator.AllocateString(request->queryString, queryString);
2058	if (error != B_OK)
2059		return error;
2060	request->flags = flags;
2061	request->port = targetPort;
2062	request->token = token;
2063	// send the request
2064	KernelRequestHandler handler(this, OPEN_QUERY_REPLY);
2065	OpenQueryReply* reply;
2066	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
2067	if (error != B_OK)
2068		return error;
2069	RequestReleaser requestReleaser(port, reply);
2070	// process the reply
2071	if (reply->error != B_OK)
2072		return reply->error;
2073	incrementer.Keep();
2074	*cookie = reply->queryCookie;
2075	return error;
2076}
2077
2078// CloseQuery
2079status_t
2080Volume::CloseQuery(void* cookie)
2081{
2082	status_t error = _CloseQuery(cookie);
2083	if (error != B_OK && fFileSystem->GetPortPool()->IsDisconnected()) {
2084		// This isn't really necessary, as the return value is irrelevant to
2085		// the VFS. OBOS ignores it completely. The fsshell returns it to the
2086		// userland, but considers the node closed anyway.
2087		WARN(("Volume::CloseQuery(): connection lost, forcing close query\n"));
2088		return B_OK;
2089	}
2090	return error;
2091}
2092
2093// FreeQueryCookie
2094status_t
2095Volume::FreeQueryCookie(void* cookie)
2096{
2097	status_t error = _FreeQueryCookie(cookie);
2098	bool disconnected = false;
2099	if (error != B_OK && fFileSystem->GetPortPool()->IsDisconnected()) {
2100		// This isn't really necessary, as the return value is irrelevant to
2101		// the VFS. It's completely ignored by OBOS as well as by the fsshell.
2102		WARN(("Volume::FreeQueryCookie(): connection lost, forcing free "
2103			"query cookie\n"));
2104		error = B_OK;
2105		disconnected = true;
2106	}
2107	int32 openQueries = atomic_add(&fOpenQueries, -1);
2108	if (openQueries <= 1 && disconnected)
2109		_PutAllPendingVNodes();
2110	return error;
2111}
2112
2113// ReadQuery
2114status_t
2115Volume::ReadQuery(void* cookie, void* buffer, size_t bufferSize, int32 count,
2116	int32* countRead)
2117{
2118	*countRead = 0;
2119	// get a free port
2120	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
2121	if (!port)
2122		return B_ERROR;
2123	PortReleaser _(fFileSystem->GetPortPool(), port);
2124	// prepare the request
2125	RequestAllocator allocator(port->GetPort());
2126	ReadQueryRequest* request;
2127	status_t error = AllocateRequest(allocator, &request);
2128	if (error != B_OK)
2129		return error;
2130	request->volume = fUserlandVolume;
2131	request->queryCookie = cookie;
2132	request->bufferSize = bufferSize;
2133	request->count = count;
2134	// send the request
2135	KernelRequestHandler handler(this, READ_QUERY_REPLY);
2136	ReadQueryReply* reply;
2137	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
2138	if (error != B_OK)
2139		return error;
2140	RequestReleaser requestReleaser(port, reply);
2141	// process the reply
2142	if (reply->error != B_OK)
2143		return reply->error;
2144	if (reply->count < 0 || reply->count > count)
2145		return B_BAD_DATA;
2146	if ((int32)bufferSize < reply->buffer.GetSize())
2147		return B_BAD_DATA;
2148	*countRead = reply->count;
2149	if (*countRead > 0) {
2150		// copy the buffer -- limit the number of bytes to copy
2151		int32 maxBytes = *countRead
2152			* (sizeof(struct dirent) + B_FILE_NAME_LENGTH);
2153		int32 copyBytes = reply->buffer.GetSize();
2154		if (copyBytes > maxBytes)
2155			copyBytes = maxBytes;
2156		memcpy(buffer, reply->buffer.GetData(), copyBytes);
2157	}
2158	_SendReceiptAck(port);
2159	return error;
2160}
2161
2162// #pragma mark -
2163// #pragma mark ----- private implementations -----
2164
2165// _Mount
2166status_t
2167Volume::_Mount(const char* device, ulong flags, const char* parameters,
2168	int32 len)
2169{
2170	// get a free port
2171	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
2172	if (!port)
2173		return B_ERROR;
2174	PortReleaser _(fFileSystem->GetPortPool(), port);
2175
2176	// get the current working directory
2177	char cwd[B_PATH_NAME_LENGTH];
2178	if (!getcwd(cwd, sizeof(cwd)))
2179		return errno;
2180
2181	// prepare the request
2182	RequestAllocator allocator(port->GetPort());
2183	MountVolumeRequest* request;
2184	status_t error = AllocateRequest(allocator, &request);
2185	if (error != B_OK)
2186		return error;
2187	request->nsid = fID;
2188	error = allocator.AllocateString(request->cwd, cwd);
2189	if (error == B_OK)
2190		error = allocator.AllocateString(request->device, device);
2191	request->flags = flags;
2192	if (error == B_OK)
2193		error = allocator.AllocateData(request->parameters, parameters, len, 1);
2194	if (error != B_OK)
2195		return error;
2196
2197	// send the request
2198	KernelRequestHandler handler(this, MOUNT_VOLUME_REPLY);
2199	MountVolumeReply* reply;
2200	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
2201	if (error != B_OK)
2202		return error;
2203	RequestReleaser requestReleaser(port, reply);
2204
2205	// process the reply
2206	if (reply->error != B_OK)
2207		return reply->error;
2208	fRootID = reply->rootID;
2209	fUserlandVolume = reply->volume;
2210
2211	// enable vnode counting
2212	fVNodeCountMap = new(nothrow) VNodeCountMap;
2213	if (fVNodeCountMap)
2214		fVNodeCountingEnabled = true;
2215	else
2216		ERROR(("Failed to allocate vnode count map."));
2217	return error;
2218}
2219
2220// _Unmount
2221status_t
2222Volume::_Unmount()
2223{
2224	// get a free port
2225	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
2226	if (!port)
2227		return B_ERROR;
2228	PortReleaser _(fFileSystem->GetPortPool(), port);
2229	// prepare the request
2230	RequestAllocator allocator(port->GetPort());
2231	UnmountVolumeRequest* request;
2232	status_t error = AllocateRequest(allocator, &request);
2233	if (error != B_OK)
2234		return error;
2235	request->volume = fUserlandVolume;
2236	// send the request
2237	KernelRequestHandler handler(this, UNMOUNT_VOLUME_REPLY);
2238	UnmountVolumeReply* reply;
2239	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
2240	if (error != B_OK)
2241		return error;
2242	RequestReleaser requestReleaser(port, reply);
2243	// process the reply
2244	if (reply->error != B_OK)
2245		return reply->error;
2246	return error;
2247}
2248
2249// _WriteVNode
2250status_t
2251Volume::_WriteVNode(void* node, char reenter)
2252{
2253	// get a free port
2254	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
2255	if (!port)
2256		return B_ERROR;
2257	PortReleaser _(fFileSystem->GetPortPool(), port);
2258	// prepare the request
2259	RequestAllocator allocator(port->GetPort());
2260	WriteVNodeRequest* request;
2261	status_t error = AllocateRequest(allocator, &request);
2262	if (error != B_OK)
2263		return error;
2264	request->volume = fUserlandVolume;
2265	request->node = node;
2266	request->reenter = reenter;
2267	// send the request
2268	KernelRequestHandler handler(this, WRITE_VNODE_REPLY);
2269	WriteVNodeReply* reply;
2270	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
2271	if (error != B_OK)
2272		return error;
2273	RequestReleaser requestReleaser(port, reply);
2274	// process the reply
2275	if (reply->error != B_OK)
2276		return reply->error;
2277	return error;
2278}
2279
2280// _Close
2281status_t
2282Volume::_Close(void* node, void* cookie)
2283{
2284	// get a free port
2285	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
2286	if (!port)
2287		return B_ERROR;
2288	PortReleaser _(fFileSystem->GetPortPool(), port);
2289	// prepare the request
2290	RequestAllocator allocator(port->GetPort());
2291	CloseRequest* request;
2292	status_t error = AllocateRequest(allocator, &request);
2293	if (error != B_OK)
2294		return error;
2295	request->volume = fUserlandVolume;
2296	request->node = node;
2297	request->fileCookie = cookie;
2298	// send the request
2299	KernelRequestHandler handler(this, CLOSE_REPLY);
2300	CloseReply* reply;
2301	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
2302	if (error != B_OK)
2303		return error;
2304	RequestReleaser requestReleaser(port, reply);
2305	// process the reply
2306	if (reply->error != B_OK)
2307		return reply->error;
2308	return error;
2309}
2310
2311// _FreeCookie
2312status_t
2313Volume::_FreeCookie(void* node, void* cookie)
2314{
2315	// get a free port
2316	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
2317	if (!port)
2318		return B_ERROR;
2319	PortReleaser _(fFileSystem->GetPortPool(), port);
2320	// prepare the request
2321	RequestAllocator allocator(port->GetPort());
2322	FreeCookieRequest* request;
2323	status_t error = AllocateRequest(allocator, &request);
2324	if (error != B_OK)
2325		return error;
2326	request->volume = fUserlandVolume;
2327	request->node = node;
2328	request->fileCookie = cookie;
2329	// send the request
2330	KernelRequestHandler handler(this, FREE_COOKIE_REPLY);
2331	FreeCookieReply* reply;
2332	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
2333	if (error != B_OK)
2334		return error;
2335	RequestReleaser requestReleaser(port, reply);
2336	// process the reply
2337	if (reply->error != B_OK)
2338		return reply->error;
2339	return error;
2340}
2341
2342// _CloseDir
2343status_t
2344Volume::_CloseDir(void* node, void* cookie)
2345{
2346	// get a free port
2347	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
2348	if (!port)
2349		return B_ERROR;
2350	PortReleaser _(fFileSystem->GetPortPool(), port);
2351	// prepare the request
2352	RequestAllocator allocator(port->GetPort());
2353	CloseDirRequest* request;
2354	status_t error = AllocateRequest(allocator, &request);
2355	if (error != B_OK)
2356		return error;
2357	request->volume = fUserlandVolume;
2358	request->node = node;
2359	request->dirCookie = cookie;
2360	// send the request
2361	KernelRequestHandler handler(this, CLOSE_DIR_REPLY);
2362	CloseDirReply* reply;
2363	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
2364	if (error != B_OK)
2365		return error;
2366	RequestReleaser requestReleaser(port, reply);
2367	// process the reply
2368	if (reply->error != B_OK)
2369		return reply->error;
2370	return error;
2371}
2372
2373// _FreeDirCookie
2374status_t
2375Volume::_FreeDirCookie(void* node, void* cookie)
2376{
2377	// get a free port
2378	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
2379	if (!port)
2380		return B_ERROR;
2381	PortReleaser _(fFileSystem->GetPortPool(), port);
2382	// prepare the request
2383	RequestAllocator allocator(port->GetPort());
2384	FreeDirCookieRequest* request;
2385	status_t error = AllocateRequest(allocator, &request);
2386	if (error != B_OK)
2387		return error;
2388	request->volume = fUserlandVolume;
2389	request->node = node;
2390	request->dirCookie = cookie;
2391	// send the request
2392	KernelRequestHandler handler(this, FREE_DIR_COOKIE_REPLY);
2393	FreeDirCookieReply* reply;
2394	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
2395	if (error != B_OK)
2396		return error;
2397	RequestReleaser requestReleaser(port, reply);
2398	// process the reply
2399	if (reply->error != B_OK)
2400		return reply->error;
2401	return error;
2402}
2403
2404// _Walk
2405status_t
2406Volume::_Walk(void* dir, const char* entryName, char** resolvedPath,
2407	vnode_id* vnid)
2408{
2409	// get a free port
2410	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
2411	if (!port)
2412		return B_ERROR;
2413	PortReleaser _(fFileSystem->GetPortPool(), port);
2414	// prepare the request
2415	RequestAllocator allocator(port->GetPort());
2416	WalkRequest* request;
2417	status_t error = AllocateRequest(allocator, &request);
2418	if (error != B_OK)
2419		return error;
2420	request->volume = fUserlandVolume;
2421	request->node = dir;
2422	error = allocator.AllocateString(request->entryName, entryName);
2423	request->traverseLink = resolvedPath;
2424	if (error != B_OK)
2425		return error;
2426	// send the request
2427	KernelRequestHandler handler(this, WALK_REPLY);
2428	WalkReply* reply;
2429	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
2430	if (error != B_OK)
2431		return error;
2432	RequestReleaser requestReleaser(port, reply);
2433	// process the reply
2434	if (reply->error != B_OK)
2435		return reply->error;
2436	*vnid = reply->vnid;
2437	if (resolvedPath) {
2438		const char* readPath = (const char*)reply->resolvedPath.GetData();
2439		if (readPath) {
2440			int32 len = strnlen(readPath, reply->resolvedPath.GetSize());
2441			*resolvedPath = (char*)malloc(len + 1);
2442			if (*resolvedPath) {
2443				memcpy(*resolvedPath, readPath, len);
2444				(*resolvedPath)[len] = '\0';
2445			} else
2446				error = B_NO_MEMORY;
2447			_SendReceiptAck(port);
2448		} else
2449			_DecrementVNodeCount(*vnid);
2450	} else
2451		_DecrementVNodeCount(*vnid);
2452			// The VFS will balance the get_vnode() call for the FS.
2453	return error;
2454}
2455
2456// _CloseAttrDir
2457status_t
2458Volume::_CloseAttrDir(void* node, void* cookie)
2459{
2460	// get a free port
2461	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
2462	if (!port)
2463		return B_ERROR;
2464	PortReleaser _(fFileSystem->GetPortPool(), port);
2465	// prepare the request
2466	RequestAllocator allocator(port->GetPort());
2467	CloseAttrDirRequest* request;
2468	status_t error = AllocateRequest(allocator, &request);
2469	if (error != B_OK)
2470		return error;
2471	request->volume = fUserlandVolume;
2472	request->node = node;
2473	request->attrDirCookie = cookie;
2474	// send the request
2475	KernelRequestHandler handler(this, CLOSE_ATTR_DIR_REPLY);
2476	CloseAttrDirReply* reply;
2477	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
2478	if (error != B_OK)
2479		return error;
2480	RequestReleaser requestReleaser(port, reply);
2481	// process the reply
2482	if (reply->error != B_OK)
2483		return reply->error;
2484	return error;
2485}
2486
2487// _FreeAttrDirCookie
2488status_t
2489Volume::_FreeAttrDirCookie(void* node, void* cookie)
2490{
2491	// get a free port
2492	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
2493	if (!port)
2494		return B_ERROR;
2495	PortReleaser _(fFileSystem->GetPortPool(), port);
2496	// prepare the request
2497	RequestAllocator allocator(port->GetPort());
2498	FreeAttrDirCookieRequest* request;
2499	status_t error = AllocateRequest(allocator, &request);
2500	if (error != B_OK)
2501		return error;
2502	request->volume = fUserlandVolume;
2503	request->node = node;
2504	request->attrDirCookie = cookie;
2505	// send the request
2506	KernelRequestHandler handler(this, FREE_ATTR_DIR_COOKIE_REPLY);
2507	FreeAttrDirCookieReply* reply;
2508	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
2509	if (error != B_OK)
2510		return error;
2511	RequestReleaser requestReleaser(port, reply);
2512	// process the reply
2513	if (reply->error != B_OK)
2514		return reply->error;
2515	return error;
2516}
2517
2518// _CloseIndexDir
2519status_t
2520Volume::_CloseIndexDir(void* cookie)
2521{
2522	// get a free port
2523	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
2524	if (!port)
2525		return B_ERROR;
2526	PortReleaser _(fFileSystem->GetPortPool(), port);
2527	// prepare the request
2528	RequestAllocator allocator(port->GetPort());
2529	CloseIndexDirRequest* request;
2530	status_t error = AllocateRequest(allocator, &request);
2531	if (error != B_OK)
2532		return error;
2533	request->volume = fUserlandVolume;
2534	request->indexDirCookie = cookie;
2535	// send the request
2536	KernelRequestHandler handler(this, CLOSE_INDEX_DIR_REPLY);
2537	CloseIndexDirReply* reply;
2538	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
2539	if (error != B_OK)
2540		return error;
2541	RequestReleaser requestReleaser(port, reply);
2542	// process the reply
2543	if (reply->error != B_OK)
2544		return reply->error;
2545	return error;
2546}
2547
2548// _FreeIndexDirCookie
2549status_t
2550Volume::_FreeIndexDirCookie(void* cookie)
2551{
2552	// get a free port
2553	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
2554	if (!port)
2555		return B_ERROR;
2556	PortReleaser _(fFileSystem->GetPortPool(), port);
2557	// prepare the request
2558	RequestAllocator allocator(port->GetPort());
2559	FreeIndexDirCookieRequest* request;
2560	status_t error = AllocateRequest(allocator, &request);
2561	if (error != B_OK)
2562		return error;
2563	request->volume = fUserlandVolume;
2564	request->indexDirCookie = cookie;
2565	// send the request
2566	KernelRequestHandler handler(this, FREE_INDEX_DIR_COOKIE_REPLY);
2567	FreeIndexDirCookieReply* reply;
2568	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
2569	if (error != B_OK)
2570		return error;
2571	RequestReleaser requestReleaser(port, reply);
2572	// process the reply
2573	if (reply->error != B_OK)
2574		return reply->error;
2575	return error;
2576}
2577
2578// _CloseQuery
2579status_t
2580Volume::_CloseQuery(void* cookie)
2581{
2582	// get a free port
2583	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
2584	if (!port)
2585		return B_ERROR;
2586	PortReleaser _(fFileSystem->GetPortPool(), port);
2587	// prepare the request
2588	RequestAllocator allocator(port->GetPort());
2589	CloseQueryRequest* request;
2590	status_t error = AllocateRequest(allocator, &request);
2591	if (error != B_OK)
2592		return error;
2593	request->volume = fUserlandVolume;
2594	request->queryCookie = cookie;
2595	// send the request
2596	KernelRequestHandler handler(this, CLOSE_QUERY_REPLY);
2597	CloseQueryReply* reply;
2598	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
2599	if (error != B_OK)
2600		return error;
2601	RequestReleaser requestReleaser(port, reply);
2602	// process the reply
2603	if (reply->error != B_OK)
2604		return reply->error;
2605	return error;
2606}
2607
2608// _FreeQueryCookie
2609status_t
2610Volume::_FreeQueryCookie(void* cookie)
2611{
2612	// get a free port
2613	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
2614	if (!port)
2615		return B_ERROR;
2616	PortReleaser _(fFileSystem->GetPortPool(), port);
2617	// prepare the request
2618	RequestAllocator allocator(port->GetPort());
2619	FreeQueryCookieRequest* request;
2620	status_t error = AllocateRequest(allocator, &request);
2621	if (error != B_OK)
2622		return error;
2623	request->volume = fUserlandVolume;
2624	request->queryCookie = cookie;
2625	// send the request
2626	KernelRequestHandler handler(this, FREE_QUERY_COOKIE_REPLY);
2627	FreeQueryCookieReply* reply;
2628	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
2629	if (error != B_OK)
2630		return error;
2631	RequestReleaser requestReleaser(port, reply);
2632	// process the reply
2633	if (reply->error != B_OK)
2634		return reply->error;
2635	return error;
2636}
2637
2638// _SendRequest
2639status_t
2640Volume::_SendRequest(RequestPort* port, RequestAllocator* allocator,
2641	RequestHandler* handler, Request** reply)
2642{
2643	if (!fFileSystem->IsUserlandServerThread())
2644		return port->SendRequest(allocator, handler, reply);
2645	// Here it gets dangerous: a thread of the userland server team being here
2646	// calls for trouble. We try receiving the request with a timeout, and
2647	// close the port -- which will disconnect the whole FS.
2648	status_t error = port->SendRequest(allocator, handler, reply,
2649		kUserlandServerlandPortTimeout);
2650	if (error == B_TIMED_OUT || error == B_WOULD_BLOCK)
2651		port->Close();
2652	return error;
2653}
2654
2655// _SendReceiptAck
2656status_t
2657Volume::_SendReceiptAck(RequestPort* port)
2658{
2659	RequestAllocator allocator(port->GetPort());
2660	ReceiptAckReply* request;
2661	status_t error = AllocateRequest(allocator, &request);
2662	if (error != B_OK)
2663		return error;
2664	return port->SendRequest(&allocator);
2665}
2666
2667// _IncrementVNodeCount
2668void
2669Volume::_IncrementVNodeCount(vnode_id vnid)
2670{
2671	if (!fVNodeCountingEnabled)
2672		return;
2673	AutoLocker<VNodeCountMap> _(fVNodeCountMap);
2674	if (!fVNodeCountingEnabled)	// someone may have changed it
2675		return;
2676	// get the counter
2677	int32* count = fVNodeCountMap->Get(vnid);
2678	if (!count) {
2679		// vnode not known yet: create and add a new counter
2680		count = new(nothrow) int32(0);
2681		if (!count) {
2682			ERROR(("Volume::_IncrementVNodeCount(): Failed to allocate "
2683				"counter. Disabling vnode counting.\n"));
2684			fVNodeCountingEnabled = false;
2685			return;
2686		}
2687		if (fVNodeCountMap->Put(vnid, count) != B_OK) {
2688			ERROR(("Volume::_IncrementVNodeCount(): Failed to add counter. "
2689				"Disabling vnode counting.\n"));
2690			delete count;
2691			fVNodeCountingEnabled = false;
2692			return;
2693		}
2694	}
2695	// increment the counter
2696	(*count)++;
2697//PRINT(("_IncrementVNodeCount(%Ld): count: %ld, fVNodeCountMap size: %ld\n", vnid, *count, fVNodeCountMap->Size()));
2698}
2699
2700// _DecrementVNodeCount
2701void
2702Volume::_DecrementVNodeCount(vnode_id vnid)
2703{
2704	if (!fVNodeCountingEnabled)
2705		return;
2706	AutoLocker<VNodeCountMap> _(fVNodeCountMap);
2707	if (!fVNodeCountingEnabled)	// someone may have changed it
2708		return;
2709	int32* count = fVNodeCountMap->Get(vnid);
2710	if (!count) {
2711		// that should never happen
2712		ERROR(("Volume::_DecrementVNodeCount(): Failed to get counter. "
2713			"Disabling vnode counting.\n"));
2714		fVNodeCountingEnabled = false;
2715		return;
2716	}
2717	(*count)--;
2718//int32 tmpCount = *count;
2719	if (*count == 0)
2720		fVNodeCountMap->Remove(vnid);
2721//PRINT(("_DecrementVNodeCount(%Ld): count: %ld, fVNodeCountMap size: %ld\n", vnid, tmpCount, fVNodeCountMap->Size()));
2722}
2723
2724// _InternalIOCtl
2725status_t
2726Volume::_InternalIOCtl(userlandfs_ioctl* buffer, int32 bufferSize)
2727{
2728	if (buffer->version != USERLAND_IOCTL_CURRENT_VERSION)
2729		return B_BAD_VALUE;
2730	status_t result = B_OK;
2731	switch (buffer->command) {
2732		case USERLAND_IOCTL_PUT_ALL_PENDING_VNODES:
2733			result = _PutAllPendingVNodes();
2734			break;
2735		default:
2736			return B_BAD_VALUE;
2737	}
2738	buffer->error = result;
2739	return B_OK;
2740}
2741
2742// _PutAllPendingVNodes
2743status_t
2744Volume::_PutAllPendingVNodes()
2745{
2746PRINT(("Volume::_PutAllPendingVNodes()\n"));
2747	if (!fFileSystem->GetPortPool()->IsDisconnected()) {
2748		PRINT(("Volume::_PutAllPendingVNodes() failed: still connected\n"));
2749		return USERLAND_IOCTL_STILL_CONNECTED;
2750	}
2751	if (!fVNodeCountingEnabled) {
2752		PRINT(("Volume::_PutAllPendingVNodes() failed: vnode counting "
2753			"disabled\n"));
2754		return USERLAND_IOCTL_VNODE_COUNTING_DISABLED;
2755	}
2756	{
2757		AutoLocker<VNodeCountMap> _(fVNodeCountMap);
2758		if (!fVNodeCountingEnabled)	{// someone may have changed it
2759			PRINT(("Volume::_PutAllPendingVNodes() failed: vnode counting "
2760				"disabled\n"));
2761			return USERLAND_IOCTL_VNODE_COUNTING_DISABLED;
2762		}
2763		// Check whether there are open entities at the moment.
2764		if (fOpenFiles > 0) {
2765			PRINT(("Volume::_PutAllPendingVNodes() failed: open files\n"));
2766			return USERLAND_IOCTL_OPEN_FILES;
2767		}
2768		if (fOpenDirectories > 0) {
2769			PRINT(("Volume::_PutAllPendingVNodes() failed: open dirs\n"));
2770			return USERLAND_IOCTL_OPEN_DIRECTORIES;
2771		}
2772		if (fOpenAttributeDirectories > 0) {
2773			PRINT(("Volume::_PutAllPendingVNodes() failed: open attr dirs\n"));
2774			return USERLAND_IOCTL_OPEN_ATTRIBUTE_DIRECTORIES;
2775		}
2776		if (fOpenIndexDirectories > 0) {
2777			PRINT(("Volume::_PutAllPendingVNodes() failed: open index dirs\n"));
2778			return USERLAND_IOCTL_OPEN_INDEX_DIRECTORIES;
2779		}
2780		if (fOpenQueries > 0) {
2781			PRINT(("Volume::_PutAllPendingVNodes() failed: open queries\n"));
2782			return USERLAND_IOCTL_OPEN_QUERIES;
2783		}
2784		// No open entities. Since the port pool is disconnected, no new
2785		// entities can be opened. Disable node counting and put all pending
2786		// vnodes.
2787		fVNodeCountingEnabled = false;
2788	}
2789	int32 putVNodeCount = 0;
2790	for (VNodeCountMap::Iterator it = fVNodeCountMap->GetIterator();
2791		 it.HasNext();) {
2792		VNodeCountMap::Entry entry = it.Next();
2793		int32 count = *entry.value;
2794		for (int32 i = 0; i < count; i++) {
2795			PutVNode(entry.key.value);
2796			putVNodeCount++;
2797		}
2798	}
2799	PRINT(("Volume::_PutAllPendingVNodes() successful: Put %ld vnodes\n",
2800		putVNodeCount));
2801	return B_OK;
2802}
2803
2804