xref: /haiku/src/add-ons/kernel/file_systems/userlandfs/kernel_add_on/Volume.cpp (revision a4ef4a49150f118d47324242917a596a3f8f8bd5)
1 // Volume.cpp
2 
3 #include "Volume.h"
4 
5 #include <errno.h>
6 #include <string.h>
7 #include <unistd.h>
8 #include <sys/stat.h>
9 
10 #include "AutoLocker.h"
11 #include "Compatibility.h"
12 #include "Debug.h"
13 #include "FileSystem.h"
14 #include "HashMap.h"
15 #include "IOCtlInfo.h"
16 #include "KernelRequestHandler.h"
17 #include "PortReleaser.h"
18 #include "RequestAllocator.h"
19 #include "RequestPort.h"
20 #include "Requests.h"
21 #include "userlandfs_ioctl.h"
22 
23 // missing ioctl()s
24 // TODO: Place somewhere else.
25 #define		IOCTL_FILE_UNCACHED_IO	10000
26 #define		IOCTL_CREATE_TIME		10002
27 #define		IOCTL_MODIFIED_TIME		10003
28 
29 // If a thread of the userland server enters userland FS kernel code and
30 // is sending a request, this is the time after which it shall time out
31 // waiting for a reply.
32 static const bigtime_t kUserlandServerlandPortTimeout = 10000000;	// 10s
33 
34 // MountVNodeMap
35 struct Volume::MountVNodeMap : public HashMap<HashKey64<ino_t>, void*> {
36 };
37 
38 // VNodeCountMap
39 struct Volume::VNodeCountMap
40 	: public SynchronizedHashMap<HashKey64<ino_t>, int32*> {
41 };
42 
43 // AutoIncrementer
44 class Volume::AutoIncrementer {
45 public:
46 	AutoIncrementer(vint32* variable)
47 		: fVariable(variable)
48 	{
49 		if (fVariable)
50 			atomic_add(fVariable, 1);
51 	}
52 
53 	~AutoIncrementer()
54 	{
55 		if (fVariable)
56 			atomic_add(fVariable, -1);
57 	}
58 
59 	void Keep()
60 	{
61 		fVariable = NULL;
62 	}
63 
64 private:
65 	vint32*	fVariable;
66 };
67 
68 // constructor
69 Volume::Volume(FileSystem* fileSystem, dev_t id)
70 	: Referencable(true),
71 	  fFileSystem(fileSystem),
72 	  fID(id),
73 	  fUserlandVolume(NULL),
74 	  fRootID(0),
75 	  fRootNode(NULL),
76 	  fMountVNodes(NULL),
77 	  fOpenFiles(0),
78 	  fOpenDirectories(0),
79 	  fOpenAttributeDirectories(0),
80 	  fOpenAttributes(0),
81 	  fOpenIndexDirectories(0),
82 	  fOpenQueries(0),
83 	  fVNodeCountMap(NULL),
84 	  fVNodeCountingEnabled(false)
85 {
86 }
87 
88 // destructor
89 Volume::~Volume()
90 {
91 }
92 
93 // GetFileSystem
94 FileSystem*
95 Volume::GetFileSystem() const
96 {
97 	return fFileSystem;
98 }
99 
100 // GetID
101 dev_t
102 Volume::GetID() const
103 {
104 	return fID;
105 }
106 
107 // GetUserlandVolume
108 void*
109 Volume::GetUserlandVolume() const
110 {
111 	return fUserlandVolume;
112 }
113 
114 // GetRootID
115 ino_t
116 Volume::GetRootID() const
117 {
118 	return fRootID;
119 }
120 
121 // IsMounting
122 bool
123 Volume::IsMounting() const
124 {
125 	return fMountVNodes;
126 }
127 
128 
129 // #pragma mark - client methods
130 
131 // GetVNode
132 status_t
133 Volume::GetVNode(ino_t vnid, fs_vnode* node)
134 {
135 PRINT(("get_vnode(%ld, %lld)\n", fID, vnid));
136 	if (IsMounting() && !fMountVNodes->ContainsKey(vnid)) {
137 		ERROR(("Volume::GetVNode(): get_vnode() invoked for unknown vnode "
138 			"while mounting!\n"));
139 	}
140 	status_t error = get_vnode(fID, vnid, node);
141 	if (error == B_OK)
142 		_IncrementVNodeCount(vnid);
143 	return error;
144 }
145 
146 // PutVNode
147 status_t
148 Volume::PutVNode(ino_t vnid)
149 {
150 PRINT(("put_vnode(%ld, %lld)\n", fID, vnid));
151 	status_t error = put_vnode(fID, vnid);
152 	if (error == B_OK)
153 		_DecrementVNodeCount(vnid);
154 	return error;
155 }
156 
157 // NewVNode
158 status_t
159 Volume::NewVNode(ino_t vnid, fs_vnode node)
160 {
161 PRINT(("new_vnode(%ld, %lld)\n", fID, vnid));
162 	status_t error = new_vnode(fID, vnid, node);
163 	if (error == B_OK) {
164 		if (IsMounting()) {
165 			error = fMountVNodes->Put(vnid, node);
166 			if (error != B_OK) {
167 				ERROR(("Volume::NewVNode(): Failed to add vnode to mount "
168 					"vnode map!\n"));
169 				publish_vnode(fID, vnid, node);
170 				put_vnode(fID, vnid);
171 				return error;
172 			}
173 		}
174 // TODO: Check what we need to do according to the new semantics.
175 //		_IncrementVNodeCount(vnid);
176 	}
177 	return error;
178 }
179 
180 // PublishVNode
181 status_t
182 Volume::PublishVNode(ino_t vnid, fs_vnode node)
183 {
184 PRINT(("publish_vnode(%ld, %lld, %p)\n", fID, vnid, node));
185 	status_t error = publish_vnode(fID, vnid, node);
186 	if (error == B_OK) {
187 		if (IsMounting()) {
188 			error = fMountVNodes->Put(vnid, node);
189 			if (error != B_OK) {
190 				ERROR(("Volume::PublishVNode(): Failed to add vnode to mount "
191 					"vnode map!\n"));
192 				put_vnode(fID, vnid);
193 				return error;
194 			}
195 		}
196 		_IncrementVNodeCount(vnid);
197 	}
198 	return error;
199 }
200 
201 // RemoveVNode
202 status_t
203 Volume::RemoveVNode(ino_t vnid)
204 {
205 PRINT(("remove_vnode(%ld, %lld)\n", fID, vnid));
206 	return remove_vnode(fID, vnid);
207 }
208 
209 // UnremoveVNode
210 status_t
211 Volume::UnremoveVNode(ino_t vnid)
212 {
213 PRINT(("unremove_vnode(%ld, %lld)\n", fID, vnid));
214 	return unremove_vnode(fID, vnid);
215 }
216 
217 // GetVNodeRemoved
218 status_t
219 Volume::GetVNodeRemoved(ino_t vnid, bool* removed)
220 {
221 PRINT(("get_vnode_removed(%ld, %lld, %p)\n", fID, vnid, removed));
222 	return get_vnode_removed(fID, vnid, removed);
223 }
224 
225 
226 // #pragma mark - FS
227 
228 
229 // Mount
230 status_t
231 Volume::Mount(const char* device, uint32 flags, const char* parameters)
232 {
233 	// Create a map that holds ino_t->void* mappings of all vnodes
234 	// created while mounting. We need it to get the root node.
235 	MountVNodeMap vnodeMap;
236 	status_t error = vnodeMap.InitCheck();
237 	if (error != B_OK)
238 		RETURN_ERROR(error);
239 
240 	fMountVNodes = &vnodeMap;
241 	error = _Mount(device, flags, parameters);
242 	fMountVNodes = NULL;
243 	if (error == B_OK) {
244 		// fetch the root node, so that we can serve Walk() requests on it,
245 		// after the connection to the userland server is gone
246 		if (!vnodeMap.ContainsKey(fRootID)) {
247 			// The root node was not added while mounting. That's a serious
248 			// problem -- not only because we don't have it, but also because
249 			// the VFS requires new_vnode() to be invoked for the root node.
250 			ERROR(("Volume::Mount(): new_vnode() was not called for root node! "
251 				"Unmounting...\n"));
252 			Unmount();
253 			return B_ERROR;
254 		}
255 		fRootNode = vnodeMap.Get(fRootID);
256 	}
257 	return error;
258 }
259 
260 // Unmount
261 status_t
262 Volume::Unmount()
263 {
264 	status_t error = _Unmount();
265 	// free the memory associated with the vnode count map
266 	if (fVNodeCountMap) {
267 		AutoLocker<VNodeCountMap> _(fVNodeCountMap);
268 		fVNodeCountingEnabled = false;
269 		for (VNodeCountMap::Iterator it = fVNodeCountMap->GetIterator();
270 			 it.HasNext();) {
271 			VNodeCountMap::Entry entry = it.Next();
272 			delete entry.value;
273 		}
274 		delete fVNodeCountMap;
275 		fVNodeCountMap = NULL;
276 	}
277 	fFileSystem->VolumeUnmounted(this);
278 	return error;
279 }
280 
281 // Sync
282 status_t
283 Volume::Sync()
284 {
285 	// check capability
286 	if (!fFileSystem->HasCapability(FS_CAPABILITY_SYNC))
287 		return B_BAD_VALUE;
288 
289 	// get a free port
290 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
291 	if (!port)
292 		return B_ERROR;
293 	PortReleaser _(fFileSystem->GetPortPool(), port);
294 
295 	// prepare the request
296 	RequestAllocator allocator(port->GetPort());
297 	SyncVolumeRequest* request;
298 	status_t error = AllocateRequest(allocator, &request);
299 	if (error != B_OK)
300 		return error;
301 
302 	request->volume = fUserlandVolume;
303 
304 	// send the request
305 	KernelRequestHandler handler(this, SYNC_VOLUME_REPLY);
306 	SyncVolumeReply* reply;
307 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
308 	if (error != B_OK)
309 		return error;
310 	RequestReleaser requestReleaser(port, reply);
311 
312 	// process the reply
313 	if (reply->error != B_OK)
314 		return reply->error;
315 	return error;
316 }
317 
318 // ReadFSInfo
319 status_t
320 Volume::ReadFSInfo(fs_info* info)
321 {
322 	// When the connection to the userland server is lost, we serve
323 	// read_fs_info() requests manually.
324 	status_t error = _ReadFSInfo(info);
325 	if (error != B_OK && fFileSystem->GetPortPool()->IsDisconnected()) {
326 		WARN(("Volume::Lookup(): connection lost, emulating lookup `.'\n"));
327 
328 		info->flags = B_FS_IS_PERSISTENT | B_FS_IS_READONLY;
329 		info->block_size = 512;
330 		info->io_size = 512;
331 		info->total_blocks = 0;
332 		info->free_blocks = 0;
333 		strlcpy(info->volume_name, fFileSystem->GetName(),
334 			sizeof(info->volume_name));
335 		strlcat(info->volume_name, ":disconnected", sizeof(info->volume_name));
336 
337 		error = B_OK;
338 	}
339 	return error;
340 }
341 
342 // WriteFSInfo
343 status_t
344 Volume::WriteFSInfo(const struct fs_info *info, uint32 mask)
345 {
346 	// check capability
347 	if (!fFileSystem->HasCapability(FS_CAPABILITY_WRITE_FS_INFO))
348 		return B_BAD_VALUE;
349 
350 	// get a free port
351 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
352 	if (!port)
353 		return B_ERROR;
354 	PortReleaser _(fFileSystem->GetPortPool(), port);
355 
356 	// prepare the request
357 	RequestAllocator allocator(port->GetPort());
358 	WriteFSInfoRequest* request;
359 	status_t error = AllocateRequest(allocator, &request);
360 	if (error != B_OK)
361 		return error;
362 
363 	request->volume = fUserlandVolume;
364 	request->info = *info;
365 	request->mask = mask;
366 
367 	// send the request
368 	KernelRequestHandler handler(this, WRITE_FS_INFO_REPLY);
369 	WriteFSInfoReply* reply;
370 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
371 	if (error != B_OK)
372 		return error;
373 	RequestReleaser requestReleaser(port, reply);
374 
375 	// process the reply
376 	if (reply->error != B_OK)
377 		return reply->error;
378 	return error;
379 }
380 
381 
382 // #pragma mark - vnodes
383 
384 
385 // Lookup
386 status_t
387 Volume::Lookup(fs_vnode dir, const char* entryName, ino_t* vnid, int* type)
388 {
389 	// When the connection to the userland server is lost, we serve
390 	// lookup(fRootNode, `.') requests manually to allow clean unmounting.
391 	status_t error = _Lookup(dir, entryName, vnid, type);
392 	if (error != B_OK && fFileSystem->GetPortPool()->IsDisconnected()
393 		&& dir == fRootNode && strcmp(entryName, ".") == 0) {
394 		WARN(("Volume::Lookup(): connection lost, emulating lookup `.'\n"));
395 		void* entryNode;
396 		if (GetVNode(fRootID, &entryNode) != B_OK)
397 			RETURN_ERROR(B_BAD_VALUE);
398 		*vnid = fRootID;
399 		*type = S_IFDIR;
400 		// The VFS will balance the get_vnode() call for the FS.
401 		_DecrementVNodeCount(*vnid);
402 		return B_OK;
403 	}
404 	return error;
405 }
406 
407 // GetVNodeName
408 status_t
409 Volume::GetVNodeName(fs_vnode node, char* buffer, size_t bufferSize)
410 {
411 	// We don't check the capability -- if not implemented by the client FS,
412 	// the functionality is emulated in userland.
413 
414 	// get a free port
415 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
416 	if (!port)
417 		return B_ERROR;
418 	PortReleaser _(fFileSystem->GetPortPool(), port);
419 
420 	// prepare the request
421 	RequestAllocator allocator(port->GetPort());
422 	GetVNodeNameRequest* request;
423 	status_t error = AllocateRequest(allocator, &request);
424 	if (error != B_OK)
425 		return error;
426 
427 	request->volume = fUserlandVolume;
428 	request->node = node;
429 	request->size = bufferSize;
430 
431 	// send the request
432 	KernelRequestHandler handler(this, GET_VNODE_NAME_REPLY);
433 	GetVNodeNameReply* reply;
434 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
435 	if (error != B_OK)
436 		return error;
437 	RequestReleaser requestReleaser(port, reply);
438 
439 	// process the reply
440 	if (reply->error != B_OK)
441 		return reply->error;
442 
443 	char* readBuffer = (char*)reply->buffer.GetData();
444 	size_t nameLen = reply->buffer.GetSize();
445 	nameLen = strnlen(readBuffer, nameLen);
446 	if (nameLen <= 1 || nameLen >= bufferSize)
447 		RETURN_ERROR(B_BAD_DATA);
448 
449 	memcpy(buffer, readBuffer, nameLen);
450 	buffer[nameLen] = '\0';
451 
452 	_SendReceiptAck(port);
453 	return error;
454 }
455 
456 // ReadVNode
457 status_t
458 Volume::ReadVNode(ino_t vnid, bool reenter, fs_vnode* node)
459 {
460 	// get a free port
461 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
462 	if (!port)
463 		return B_ERROR;
464 	PortReleaser _(fFileSystem->GetPortPool(), port);
465 
466 	// prepare the request
467 	RequestAllocator allocator(port->GetPort());
468 	ReadVNodeRequest* request;
469 	status_t error = AllocateRequest(allocator, &request);
470 	if (error != B_OK)
471 		return error;
472 
473 	request->volume = fUserlandVolume;
474 	request->vnid = vnid;
475 	request->reenter = reenter;
476 
477 	// send the request
478 	KernelRequestHandler handler(this, READ_VNODE_REPLY);
479 	ReadVNodeReply* reply;
480 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
481 	if (error != B_OK)
482 		return error;
483 	RequestReleaser requestReleaser(port, reply);
484 
485 	// process the reply
486 	if (reply->error != B_OK)
487 		return reply->error;
488 	*node = reply->node;
489 	return error;
490 }
491 
492 // WriteVNode
493 status_t
494 Volume::WriteVNode(fs_vnode node, bool reenter)
495 {
496 	status_t error = _WriteVNode(node, reenter);
497 	if (error != B_OK && fFileSystem->GetPortPool()->IsDisconnected()) {
498 		// This isn't really necessary, since the VFS basically ignores the
499 		// return value -- at least OBOS. The fshell panic()s; didn't check
500 		// BeOS. It doesn't harm to appear to behave nicely. :-)
501 		WARN(("Volume::WriteVNode(): connection lost, forcing write vnode\n"));
502 		return B_OK;
503 	}
504 	return error;
505 }
506 
507 // RemoveVNode
508 status_t
509 Volume::RemoveVNode(fs_vnode node, bool reenter)
510 {
511 	// get a free port
512 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
513 	if (!port)
514 		return B_ERROR;
515 	PortReleaser _(fFileSystem->GetPortPool(), port);
516 
517 	// prepare the request
518 	RequestAllocator allocator(port->GetPort());
519 	FSRemoveVNodeRequest* request;
520 	status_t error = AllocateRequest(allocator, &request);
521 	if (error != B_OK)
522 		return error;
523 
524 	request->volume = fUserlandVolume;
525 	request->node = node;
526 	request->reenter = reenter;
527 
528 	// send the request
529 	KernelRequestHandler handler(this, FS_REMOVE_VNODE_REPLY);
530 	FSRemoveVNodeReply* reply;
531 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
532 	if (error != B_OK)
533 		return error;
534 	RequestReleaser requestReleaser(port, reply);
535 
536 	// process the reply
537 	if (reply->error != B_OK)
538 		return reply->error;
539 	return error;
540 }
541 
542 
543 // #pragma mark - nodes
544 
545 
546 // IOCtl
547 status_t
548 Volume::IOCtl(fs_vnode node, fs_cookie cookie, uint32 command, void *buffer,
549 	size_t len)
550 {
551 	// check the command and its parameters
552 	bool isBuffer = false;
553 	int32 bufferSize = 0;
554 	int32 writeSize = 0;
555 	switch (command) {
556 		case IOCTL_FILE_UNCACHED_IO:
557 			buffer = NULL;
558 			break;
559 		case IOCTL_CREATE_TIME:
560 		case IOCTL_MODIFIED_TIME:
561 			isBuffer = 0;
562 			bufferSize = 0;
563 			writeSize = sizeof(bigtime_t);
564 			break;
565 		case USERLANDFS_IOCTL:
566 			area_id area;
567 			area_info info;
568 			PRINT(("Volume::IOCtl(): USERLANDFS_IOCTL\n"));
569 			if ((area = area_for(buffer)) >= 0) {
570 				if (get_area_info(area, &info) == B_OK) {
571 					if ((uint8*)buffer - (uint8*)info.address
572 							+ sizeof(userlandfs_ioctl) <= info.size) {
573 						if (strncmp(((userlandfs_ioctl*)buffer)->magic,
574 								kUserlandFSIOCtlMagic,
575 								USERLAND_IOCTL_MAGIC_LENGTH) == 0) {
576 							return _InternalIOCtl((userlandfs_ioctl*)buffer,
577 								bufferSize);
578 						} else
579 							PRINT(("Volume::IOCtl(): bad magic\n"));
580 					} else
581 						PRINT(("Volume::IOCtl(): bad buffer size\n"));
582 				} else
583 					PRINT(("Volume::IOCtl(): failed to get area info\n"));
584 			} else
585 				PRINT(("Volume::IOCtl(): bad area\n"));
586 			// fall through...
587 		default:
588 		{
589 			// We don't know the command. Check whether the FileSystem knows
590 			// about it.
591 			const IOCtlInfo* info = fFileSystem->GetIOCtlInfo(command);
592 			if (!info) {
593 				PRINT(("Volume::IOCtl(): unknown command\n"));
594 				return B_BAD_VALUE;
595 			}
596 
597 			isBuffer = info->isBuffer;
598 			bufferSize = info->bufferSize;
599 			writeSize = info->writeBufferSize;
600 
601 			// If the buffer shall indeed specify a buffer, check it.
602 			if (info->isBuffer) {
603 				if (!buffer) {
604 					PRINT(("Volume::IOCtl(): buffer is NULL\n"));
605 					return B_BAD_VALUE;
606 				}
607 
608 				area_id area = area_for(buffer);
609 				if (area < 0) {
610 					PRINT(("Volume::IOCtl(): bad area\n"));
611 					return B_BAD_VALUE;
612 				}
613 
614 				area_info info;
615 				if (get_area_info(area, &info) != B_OK) {
616 					PRINT(("Volume::IOCtl(): failed to get area info\n"));
617 					return B_BAD_VALUE;
618 				}
619 
620 				int32 areaSize = info.size - ((uint8*)buffer
621 					- (uint8*)info.address);
622 				if (bufferSize > areaSize || writeSize > areaSize) {
623 					PRINT(("Volume::IOCtl(): bad buffer size\n"));
624 					return B_BAD_VALUE;
625 				}
626 
627 				if (writeSize > 0 && !(info.protection & B_WRITE_AREA)) {
628 					PRINT(("Volume::IOCtl(): buffer not writable\n"));
629 					return B_BAD_VALUE;
630 				}
631 			}
632 			break;
633 		}
634 	}
635 
636 	// check capability
637 	if (!fFileSystem->HasCapability(FS_CAPABILITY_IOCTL))
638 		return B_BAD_VALUE;
639 
640 	// get a free port
641 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
642 	if (!port)
643 		return B_ERROR;
644 	PortReleaser _(fFileSystem->GetPortPool(), port);
645 
646 	// prepare the request
647 	RequestAllocator allocator(port->GetPort());
648 	IOCtlRequest* request;
649 	status_t error = AllocateRequest(allocator, &request);
650 	if (error != B_OK)
651 		return error;
652 
653 	request->volume = fUserlandVolume;
654 	request->node = node;
655 	request->fileCookie = cookie;
656 	request->command = command;
657 	request->bufferParameter = buffer;
658 	request->isBuffer = isBuffer;
659 	request->lenParameter = len;
660 	request->writeSize = writeSize;
661 
662 	if (isBuffer && bufferSize > 0) {
663 		error = allocator.AllocateData(request->buffer, buffer, bufferSize, 8);
664 		if (error != B_OK)
665 			return error;
666 	}
667 
668 	// send the request
669 	KernelRequestHandler handler(this, IOCTL_REPLY);
670 	IOCtlReply* reply;
671 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
672 	if (error != B_OK)
673 		return error;
674 	RequestReleaser requestReleaser(port, reply);
675 
676 	// process the reply
677 	if (reply->error != B_OK)
678 		return reply->error;
679 
680 	// Copy back the buffer even if the result is not B_OK. The protocol
681 	// is defined by the FS developer and may include writing data into
682 	// the buffer in some error cases.
683 	if (isBuffer && writeSize > 0 && reply->buffer.GetData()) {
684 		if (writeSize > reply->buffer.GetSize())
685 			writeSize = reply->buffer.GetSize();
686 		memcpy(buffer, reply->buffer.GetData(), writeSize);
687 		_SendReceiptAck(port);
688 	}
689 	return reply->ioctlError;
690 }
691 
692 // SetFlags
693 status_t
694 Volume::SetFlags(fs_vnode node, fs_cookie cookie, int flags)
695 {
696 	// check capability
697 	if (!fFileSystem->HasCapability(FS_CAPABILITY_SET_FLAGS))
698 		return B_BAD_VALUE;
699 
700 	// get a free port
701 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
702 	if (!port)
703 		return B_ERROR;
704 	PortReleaser _(fFileSystem->GetPortPool(), port);
705 
706 	// prepare the request
707 	RequestAllocator allocator(port->GetPort());
708 	SetFlagsRequest* request;
709 	status_t error = AllocateRequest(allocator, &request);
710 	if (error != B_OK)
711 		return error;
712 
713 	request->volume = fUserlandVolume;
714 	request->node = node;
715 	request->fileCookie = cookie;
716 	request->flags = flags;
717 
718 	// send the request
719 	KernelRequestHandler handler(this, SET_FLAGS_REPLY);
720 	SetFlagsReply* reply;
721 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
722 	if (error != B_OK)
723 		return error;
724 	RequestReleaser requestReleaser(port, reply);
725 
726 	// process the reply
727 	if (reply->error != B_OK)
728 		return reply->error;
729 	return error;
730 }
731 
732 // Select
733 status_t
734 Volume::Select(fs_vnode node, fs_cookie cookie, uint8 event, uint32 ref,
735 	selectsync* sync)
736 {
737 	// check capability
738 	if (!fFileSystem->HasCapability(FS_CAPABILITY_SELECT)) {
739 		notify_select_event(sync, event);
740 		return B_OK;
741 	}
742 
743 	// get a free port
744 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
745 	if (!port)
746 		return B_ERROR;
747 	PortReleaser _(fFileSystem->GetPortPool(), port);
748 
749 	// prepare the request
750 	RequestAllocator allocator(port->GetPort());
751 	SelectRequest* request;
752 	status_t error = AllocateRequest(allocator, &request);
753 	if (error != B_OK)
754 		return error;
755 
756 	request->volume = fUserlandVolume;
757 	request->node = node;
758 	request->fileCookie = cookie;
759 	request->event = event;
760 	request->sync = sync;
761 
762 	// add a selectsync entry
763 	error = fFileSystem->AddSelectSyncEntry(sync);
764 	if (error != B_OK)
765 		return error;
766 
767 	// send the request
768 	KernelRequestHandler handler(this, SELECT_REPLY);
769 	SelectReply* reply;
770 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
771 	if (error != B_OK) {
772 		fFileSystem->RemoveSelectSyncEntry(sync);
773 		return error;
774 	}
775 	RequestReleaser requestReleaser(port, reply);
776 
777 	// process the reply
778 	if (reply->error != B_OK) {
779 		fFileSystem->RemoveSelectSyncEntry(sync);
780 		return reply->error;
781 	}
782 	return error;
783 }
784 
785 // Deselect
786 status_t
787 Volume::Deselect(fs_vnode node, fs_cookie cookie, uint8 event, selectsync* sync)
788 {
789 	// check capability
790 	if (!fFileSystem->HasCapability(FS_CAPABILITY_DESELECT))
791 		return B_OK;
792 
793 	struct SyncRemover {
794 		SyncRemover(FileSystem* fs, selectsync* sync)
795 			: fs(fs), sync(sync) {}
796 		~SyncRemover() { fs->RemoveSelectSyncEntry(sync); }
797 
798 		FileSystem*	fs;
799 		selectsync*	sync;
800 	} syncRemover(fFileSystem, sync);
801 
802 	// get a free port
803 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
804 	if (!port)
805 		return B_ERROR;
806 	PortReleaser _(fFileSystem->GetPortPool(), port);
807 
808 	// prepare the request
809 	RequestAllocator allocator(port->GetPort());
810 	DeselectRequest* request;
811 	status_t error = AllocateRequest(allocator, &request);
812 	if (error != B_OK)
813 		return error;
814 
815 	request->volume = fUserlandVolume;
816 	request->node = node;
817 	request->fileCookie = cookie;
818 	request->event = event;
819 	request->sync = sync;
820 
821 	// send the request
822 	KernelRequestHandler handler(this, DESELECT_REPLY);
823 	DeselectReply* reply;
824 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
825 	if (error != B_OK)
826 		return error;
827 	RequestReleaser requestReleaser(port, reply);
828 
829 	// process the reply
830 	if (reply->error != B_OK)
831 		return reply->error;
832 	return error;
833 }
834 
835 // FSync
836 status_t
837 Volume::FSync(fs_vnode node)
838 {
839 	// check capability
840 	if (!fFileSystem->HasCapability(FS_CAPABILITY_FSYNC))
841 		return B_BAD_VALUE;
842 
843 	// get a free port
844 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
845 	if (!port)
846 		return B_ERROR;
847 	PortReleaser _(fFileSystem->GetPortPool(), port);
848 
849 	// prepare the request
850 	RequestAllocator allocator(port->GetPort());
851 	FSyncRequest* request;
852 	status_t error = AllocateRequest(allocator, &request);
853 	if (error != B_OK)
854 		return error;
855 
856 	request->volume = fUserlandVolume;
857 	request->node = node;
858 
859 	// send the request
860 	KernelRequestHandler handler(this, FSYNC_REPLY);
861 	FSyncReply* reply;
862 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
863 	if (error != B_OK)
864 		return error;
865 	RequestReleaser requestReleaser(port, reply);
866 
867 	// process the reply
868 	if (reply->error != B_OK)
869 		return reply->error;
870 	return error;
871 }
872 
873 // ReadSymlink
874 status_t
875 Volume::ReadSymlink(fs_vnode node, char* buffer, size_t bufferSize,
876 	size_t* bytesRead)
877 {
878 	*bytesRead = 0;
879 
880 	// check capability
881 	if (!fFileSystem->HasCapability(FS_CAPABILITY_READ_SYMLINK))
882 		return B_BAD_VALUE;
883 
884 	// get a free port
885 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
886 	if (!port)
887 		return B_ERROR;
888 	PortReleaser _(fFileSystem->GetPortPool(), port);
889 
890 	// prepare the request
891 	RequestAllocator allocator(port->GetPort());
892 	ReadSymlinkRequest* request;
893 	status_t error = AllocateRequest(allocator, &request);
894 	if (error != B_OK)
895 		return error;
896 
897 	request->volume = fUserlandVolume;
898 	request->node = node;
899 	request->size = bufferSize;
900 
901 	// send the request
902 	KernelRequestHandler handler(this, READ_SYMLINK_REPLY);
903 	ReadSymlinkReply* reply;
904 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
905 	if (error != B_OK)
906 		return error;
907 	RequestReleaser requestReleaser(port, reply);
908 
909 	// process the reply
910 	if (reply->error != B_OK)
911 		return reply->error;
912 	void* readBuffer = reply->buffer.GetData();
913 	if (reply->bytesRead > (uint32)reply->buffer.GetSize()
914 		|| reply->bytesRead > bufferSize) {
915 		return B_BAD_DATA;
916 	}
917 	if (reply->bytesRead > 0)
918 		memcpy(buffer, readBuffer, reply->bytesRead);
919 	*bytesRead = reply->bytesRead;
920 	_SendReceiptAck(port);
921 	return error;
922 }
923 
924 // CreateSymlink
925 status_t
926 Volume::CreateSymlink(fs_vnode dir, const char* name, const char* target,
927 	int mode)
928 {
929 	// check capability
930 	if (!fFileSystem->HasCapability(FS_CAPABILITY_CREATE_SYMLINK))
931 		return B_BAD_VALUE;
932 
933 	// get a free port
934 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
935 	if (!port)
936 		return B_ERROR;
937 	PortReleaser _(fFileSystem->GetPortPool(), port);
938 
939 	// prepare the request
940 	RequestAllocator allocator(port->GetPort());
941 	CreateSymlinkRequest* request;
942 	status_t error = AllocateRequest(allocator, &request);
943 	if (error != B_OK)
944 		return error;
945 
946 	request->volume = fUserlandVolume;
947 	request->node = dir;
948 	error = allocator.AllocateString(request->name, name);
949 	if (error == B_OK)
950 		error = allocator.AllocateString(request->target, target);
951 	if (error != B_OK)
952 		return error;
953 	request->mode = mode;
954 
955 	// send the request
956 	KernelRequestHandler handler(this, CREATE_SYMLINK_REPLY);
957 	CreateSymlinkReply* reply;
958 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
959 	if (error != B_OK)
960 		return error;
961 	RequestReleaser requestReleaser(port, reply);
962 
963 	// process the reply
964 	if (reply->error != B_OK)
965 		return reply->error;
966 	return error;
967 }
968 
969 // Link
970 status_t
971 Volume::Link(fs_vnode dir, const char* name, fs_vnode node)
972 {
973 	// check capability
974 	if (!fFileSystem->HasCapability(FS_CAPABILITY_LINK))
975 		return B_BAD_VALUE;
976 
977 	// get a free port
978 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
979 	if (!port)
980 		return B_ERROR;
981 	PortReleaser _(fFileSystem->GetPortPool(), port);
982 
983 	// prepare the request
984 	RequestAllocator allocator(port->GetPort());
985 	LinkRequest* request;
986 	status_t error = AllocateRequest(allocator, &request);
987 	if (error != B_OK)
988 		return error;
989 
990 	request->volume = fUserlandVolume;
991 	request->node = dir;
992 	error = allocator.AllocateString(request->name, name);
993 	request->target = node;
994 	if (error != B_OK)
995 		return error;
996 
997 	// send the request
998 	KernelRequestHandler handler(this, LINK_REPLY);
999 	LinkReply* reply;
1000 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
1001 	if (error != B_OK)
1002 		return error;
1003 	RequestReleaser requestReleaser(port, reply);
1004 
1005 	// process the reply
1006 	if (reply->error != B_OK)
1007 		return reply->error;
1008 	return error;
1009 }
1010 
1011 // Unlink
1012 status_t
1013 Volume::Unlink(fs_vnode dir, const char* name)
1014 {
1015 	// check capability
1016 	if (!fFileSystem->HasCapability(FS_CAPABILITY_UNLINK))
1017 		return B_BAD_VALUE;
1018 
1019 	// get a free port
1020 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
1021 	if (!port)
1022 		return B_ERROR;
1023 	PortReleaser _(fFileSystem->GetPortPool(), port);
1024 
1025 	// prepare the request
1026 	RequestAllocator allocator(port->GetPort());
1027 	UnlinkRequest* request;
1028 	status_t error = AllocateRequest(allocator, &request);
1029 	if (error != B_OK)
1030 		return error;
1031 
1032 	request->volume = fUserlandVolume;
1033 	request->node = dir;
1034 	error = allocator.AllocateString(request->name, name);
1035 	if (error != B_OK)
1036 		return error;
1037 
1038 	// send the request
1039 	KernelRequestHandler handler(this, UNLINK_REPLY);
1040 	UnlinkReply* reply;
1041 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
1042 	if (error != B_OK)
1043 		return error;
1044 	RequestReleaser requestReleaser(port, reply);
1045 
1046 	// process the reply
1047 	if (reply->error != B_OK)
1048 		return reply->error;
1049 	return error;
1050 }
1051 
1052 // Rename
1053 status_t
1054 Volume::Rename(fs_vnode oldDir, const char* oldName, fs_vnode newDir,
1055 	const char* newName)
1056 {
1057 	// check capability
1058 	if (!fFileSystem->HasCapability(FS_CAPABILITY_RENAME))
1059 		return B_BAD_VALUE;
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 	RenameRequest* request;
1070 	status_t error = AllocateRequest(allocator, &request);
1071 	if (error != B_OK)
1072 		return error;
1073 
1074 	request->volume = fUserlandVolume;
1075 	request->oldDir = oldDir;
1076 	request->newDir = newDir;
1077 	error = allocator.AllocateString(request->oldName, oldName);
1078 	if (error == B_OK)
1079 		error = allocator.AllocateString(request->newName, newName);
1080 	if (error != B_OK)
1081 		return error;
1082 
1083 	// send the request
1084 	KernelRequestHandler handler(this, RENAME_REPLY);
1085 	RenameReply* reply;
1086 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
1087 	if (error != B_OK)
1088 		return error;
1089 	RequestReleaser requestReleaser(port, reply);
1090 
1091 	// process the reply
1092 	if (reply->error != B_OK)
1093 		return reply->error;
1094 	return error;
1095 }
1096 
1097 // Access
1098 status_t
1099 Volume::Access(fs_vnode node, int mode)
1100 {
1101 	// check capability
1102 	if (!fFileSystem->HasCapability(FS_CAPABILITY_ACCESS))
1103 		return B_OK;
1104 
1105 	// get a free port
1106 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
1107 	if (!port)
1108 		return B_ERROR;
1109 	PortReleaser _(fFileSystem->GetPortPool(), port);
1110 
1111 	// prepare the request
1112 	RequestAllocator allocator(port->GetPort());
1113 	AccessRequest* request;
1114 	status_t error = AllocateRequest(allocator, &request);
1115 	if (error != B_OK)
1116 		return error;
1117 
1118 	request->volume = fUserlandVolume;
1119 	request->node = node;
1120 	request->mode = mode;
1121 
1122 	// send the request
1123 	KernelRequestHandler handler(this, ACCESS_REPLY);
1124 	AccessReply* reply;
1125 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
1126 	if (error != B_OK)
1127 		return error;
1128 	RequestReleaser requestReleaser(port, reply);
1129 
1130 	// process the reply
1131 	if (reply->error != B_OK)
1132 		return reply->error;
1133 	return error;
1134 }
1135 
1136 // ReadStat
1137 status_t
1138 Volume::ReadStat(fs_vnode node, struct stat* st)
1139 {
1140 	// When the connection to the userland server is lost, we serve
1141 	// read_stat(fRootNode) requests manually to allow clean unmounting.
1142 	status_t error = _ReadStat(node, st);
1143 	if (error != B_OK && fFileSystem->GetPortPool()->IsDisconnected()
1144 		&& node == fRootNode) {
1145 		WARN(("Volume::ReadStat(): connection lost, emulating stat for the "
1146 			"root node\n"));
1147 
1148 		st->st_dev = fID;
1149 		st->st_ino = fRootID;
1150 		st->st_mode = ACCESSPERMS;
1151 		st->st_nlink = 1;
1152 		st->st_uid = 0;
1153 		st->st_gid = 0;
1154 		st->st_size = 512;
1155 		st->st_blksize = 512;
1156 		st->st_atime = 0;
1157 		st->st_mtime = 0;
1158 		st->st_ctime = 0;
1159 		st->st_crtime = 0;
1160 
1161 		error = B_OK;
1162 	}
1163 	return error;
1164 }
1165 
1166 // WriteStat
1167 status_t
1168 Volume::WriteStat(fs_vnode node, const struct stat* st, uint32 mask)
1169 {
1170 	// check capability
1171 	if (!fFileSystem->HasCapability(FS_CAPABILITY_WRITE_STAT))
1172 		return B_BAD_VALUE;
1173 
1174 	// get a free port
1175 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
1176 	if (!port)
1177 		return B_ERROR;
1178 	PortReleaser _(fFileSystem->GetPortPool(), port);
1179 
1180 	// prepare the request
1181 	RequestAllocator allocator(port->GetPort());
1182 	WriteStatRequest* request;
1183 	status_t error = AllocateRequest(allocator, &request);
1184 	if (error != B_OK)
1185 		return error;
1186 
1187 	request->volume = fUserlandVolume;
1188 	request->node = node;
1189 	request->st = *st;
1190 	request->mask = mask;
1191 
1192 	// send the request
1193 	KernelRequestHandler handler(this, WRITE_STAT_REPLY);
1194 	WriteStatReply* reply;
1195 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
1196 	if (error != B_OK)
1197 		return error;
1198 	RequestReleaser requestReleaser(port, reply);
1199 
1200 	// process the reply
1201 	if (reply->error != B_OK)
1202 		return reply->error;
1203 	return error;
1204 }
1205 
1206 
1207 // #pragma mark - files
1208 
1209 // Create
1210 status_t
1211 Volume::Create(fs_vnode dir, const char* name, int openMode, int mode,
1212 	void** cookie, ino_t* vnid)
1213 {
1214 	// check capability
1215 	if (!fFileSystem->HasCapability(FS_CAPABILITY_CREATE))
1216 		return B_BAD_VALUE;
1217 
1218 	// get a free port
1219 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
1220 	if (!port)
1221 		return B_ERROR;
1222 	PortReleaser _(fFileSystem->GetPortPool(), port);
1223 	AutoIncrementer incrementer(&fOpenFiles);
1224 
1225 	// prepare the request
1226 	RequestAllocator allocator(port->GetPort());
1227 	CreateRequest* request;
1228 	status_t error = AllocateRequest(allocator, &request);
1229 	if (error != B_OK)
1230 		return error;
1231 
1232 	request->volume = fUserlandVolume;
1233 	request->node = dir;
1234 	error = allocator.AllocateString(request->name, name);
1235 	request->openMode = openMode;
1236 	request->mode = mode;
1237 	if (error != B_OK)
1238 		return error;
1239 
1240 	// send the request
1241 	KernelRequestHandler handler(this, CREATE_REPLY);
1242 	CreateReply* reply;
1243 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
1244 	if (error != B_OK)
1245 		return error;
1246 	RequestReleaser requestReleaser(port, reply);
1247 
1248 	// process the reply
1249 	if (reply->error != B_OK)
1250 		return reply->error;
1251 	incrementer.Keep();
1252 	*vnid = reply->vnid;
1253 	*cookie = reply->fileCookie;
1254 	// The VFS will balance the new_vnode() call for the FS.
1255 	if (error == B_OK)
1256 		_DecrementVNodeCount(*vnid);
1257 	return error;
1258 }
1259 
1260 // Open
1261 status_t
1262 Volume::Open(fs_vnode node, int openMode, fs_cookie* cookie)
1263 {
1264 	// check capability
1265 	if (!fFileSystem->HasCapability(FS_CAPABILITY_OPEN))
1266 		return B_BAD_VALUE;
1267 
1268 	// get a free port
1269 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
1270 	if (!port)
1271 		return B_ERROR;
1272 	PortReleaser _(fFileSystem->GetPortPool(), port);
1273 	AutoIncrementer incrementer(&fOpenFiles);
1274 
1275 	// prepare the request
1276 	RequestAllocator allocator(port->GetPort());
1277 	OpenRequest* request;
1278 	status_t error = AllocateRequest(allocator, &request);
1279 	if (error != B_OK)
1280 		return error;
1281 	request->volume = fUserlandVolume;
1282 	request->node = node;
1283 	request->openMode = openMode;
1284 
1285 	// send the request
1286 	KernelRequestHandler handler(this, OPEN_REPLY);
1287 	OpenReply* reply;
1288 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
1289 	if (error != B_OK)
1290 		return error;
1291 	RequestReleaser requestReleaser(port, reply);
1292 
1293 	// process the reply
1294 	if (reply->error != B_OK)
1295 		return reply->error;
1296 	incrementer.Keep();
1297 	*cookie = reply->fileCookie;
1298 	return error;
1299 }
1300 
1301 // Close
1302 status_t
1303 Volume::Close(fs_vnode node, fs_cookie cookie)
1304 {
1305 	status_t error = _Close(node, cookie);
1306 	if (error != B_OK && fFileSystem->GetPortPool()->IsDisconnected()) {
1307 		// This isn't really necessary, as the return value is irrelevant to
1308 		// the VFS. OBOS ignores it completely. The fsshell returns it to the
1309 		// userland, but considers the node closed anyway.
1310 		WARN(("Volume::Close(): connection lost, forcing close\n"));
1311 		return B_OK;
1312 	}
1313 	return error;
1314 }
1315 
1316 // FreeCookie
1317 status_t
1318 Volume::FreeCookie(fs_vnode node, fs_cookie cookie)
1319 {
1320 	status_t error = _FreeCookie(node, cookie);
1321 	bool disconnected = false;
1322 	if (error != B_OK && fFileSystem->GetPortPool()->IsDisconnected()) {
1323 		// This isn't really necessary, as the return value is irrelevant to
1324 		// the VFS. It's completely ignored by OBOS as well as by the fsshell.
1325 		WARN(("Volume::FreeCookie(): connection lost, forcing free cookie\n"));
1326 		error = B_OK;
1327 		disconnected = true;
1328 	}
1329 
1330 	int32 openFiles = atomic_add(&fOpenFiles, -1);
1331 	if (openFiles <= 1 && disconnected)
1332 		_PutAllPendingVNodes();
1333 	return error;
1334 }
1335 
1336 // Read
1337 status_t
1338 Volume::Read(fs_vnode node, fs_cookie cookie, off_t pos, void* buffer,
1339 	size_t bufferSize, size_t* bytesRead)
1340 {
1341 	*bytesRead = 0;
1342 
1343 	// check capability
1344 	if (!fFileSystem->HasCapability(FS_CAPABILITY_READ))
1345 		return B_BAD_VALUE;
1346 
1347 	// get a free port
1348 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
1349 	if (!port)
1350 		return B_ERROR;
1351 	PortReleaser _(fFileSystem->GetPortPool(), port);
1352 
1353 	// prepare the request
1354 	RequestAllocator allocator(port->GetPort());
1355 	ReadRequest* request;
1356 	status_t error = AllocateRequest(allocator, &request);
1357 	if (error != B_OK)
1358 		return error;
1359 
1360 	request->volume = fUserlandVolume;
1361 	request->node = node;
1362 	request->fileCookie = cookie;
1363 	request->pos = pos;
1364 	request->size = bufferSize;
1365 
1366 	// send the request
1367 	KernelRequestHandler handler(this, READ_REPLY);
1368 	ReadReply* reply;
1369 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
1370 	if (error != B_OK)
1371 		return error;
1372 	RequestReleaser requestReleaser(port, reply);
1373 
1374 	// process the reply
1375 	if (reply->error != B_OK)
1376 		return reply->error;
1377 	void* readBuffer = reply->buffer.GetData();
1378 	if (reply->bytesRead > (uint32)reply->buffer.GetSize()
1379 		|| reply->bytesRead > bufferSize) {
1380 		return B_BAD_DATA;
1381 	}
1382 	if (reply->bytesRead > 0)
1383 		memcpy(buffer, readBuffer, reply->bytesRead);
1384 	*bytesRead = reply->bytesRead;
1385 	_SendReceiptAck(port);
1386 	return error;
1387 }
1388 
1389 // Write
1390 status_t
1391 Volume::Write(fs_vnode node, fs_cookie cookie, off_t pos, const void* buffer,
1392 	size_t size, size_t* bytesWritten)
1393 {
1394 	*bytesWritten = 0;
1395 
1396 	// check capability
1397 	if (!fFileSystem->HasCapability(FS_CAPABILITY_WRITE))
1398 		return B_BAD_VALUE;
1399 
1400 	// get a free port
1401 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
1402 	if (!port)
1403 		return B_ERROR;
1404 	PortReleaser _(fFileSystem->GetPortPool(), port);
1405 
1406 	// prepare the request
1407 	RequestAllocator allocator(port->GetPort());
1408 	WriteRequest* request;
1409 	status_t error = AllocateRequest(allocator, &request);
1410 	if (error != B_OK)
1411 		return error;
1412 
1413 	request->volume = fUserlandVolume;
1414 	request->node = node;
1415 	request->fileCookie = cookie;
1416 	request->pos = pos;
1417 	error = allocator.AllocateData(request->buffer, buffer, size, 1);
1418 	if (error != B_OK)
1419 		return error;
1420 
1421 	// send the request
1422 	KernelRequestHandler handler(this, WRITE_REPLY);
1423 	WriteReply* reply;
1424 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
1425 	if (error != B_OK)
1426 		return error;
1427 	RequestReleaser requestReleaser(port, reply);
1428 
1429 	// process the reply
1430 	if (reply->error != B_OK)
1431 		return reply->error;
1432 	*bytesWritten = reply->bytesWritten;
1433 	return error;
1434 }
1435 
1436 
1437 // #pragma mark - directories
1438 
1439 // CreateDir
1440 status_t
1441 Volume::CreateDir(fs_vnode dir, const char* name, int mode, ino_t *newDir)
1442 {
1443 	// check capability
1444 	if (!fFileSystem->HasCapability(FS_CAPABILITY_CREATE_DIR))
1445 		return B_BAD_VALUE;
1446 
1447 	// get a free port
1448 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
1449 	if (!port)
1450 		return B_ERROR;
1451 	PortReleaser _(fFileSystem->GetPortPool(), port);
1452 
1453 	// prepare the request
1454 	RequestAllocator allocator(port->GetPort());
1455 	CreateDirRequest* request;
1456 	status_t error = AllocateRequest(allocator, &request);
1457 	if (error != B_OK)
1458 		return error;
1459 
1460 	request->volume = fUserlandVolume;
1461 	request->node = dir;
1462 	error = allocator.AllocateString(request->name, name);
1463 	request->mode = mode;
1464 	if (error != B_OK)
1465 		return error;
1466 
1467 	// send the request
1468 	KernelRequestHandler handler(this, CREATE_DIR_REPLY);
1469 	CreateDirReply* reply;
1470 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
1471 	if (error != B_OK)
1472 		return error;
1473 	RequestReleaser requestReleaser(port, reply);
1474 
1475 	// process the reply
1476 	if (reply->error != B_OK)
1477 		return reply->error;
1478 	*newDir = reply->newDir;
1479 	return error;
1480 }
1481 
1482 // RemoveDir
1483 status_t
1484 Volume::RemoveDir(fs_vnode dir, const char* name)
1485 {
1486 	// check capability
1487 	if (!fFileSystem->HasCapability(FS_CAPABILITY_REMOVE_DIR))
1488 		return B_BAD_VALUE;
1489 
1490 	// get a free port
1491 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
1492 	if (!port)
1493 		return B_ERROR;
1494 	PortReleaser _(fFileSystem->GetPortPool(), port);
1495 
1496 	// prepare the request
1497 	RequestAllocator allocator(port->GetPort());
1498 	RemoveDirRequest* request;
1499 	status_t error = AllocateRequest(allocator, &request);
1500 	if (error != B_OK)
1501 		return error;
1502 
1503 	request->volume = fUserlandVolume;
1504 	request->node = dir;
1505 	error = allocator.AllocateString(request->name, name);
1506 	if (error != B_OK)
1507 		return error;
1508 
1509 	// send the request
1510 	KernelRequestHandler handler(this, REMOVE_DIR_REPLY);
1511 	RemoveDirReply* reply;
1512 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
1513 	if (error != B_OK)
1514 		return error;
1515 	RequestReleaser requestReleaser(port, reply);
1516 
1517 	// process the reply
1518 	if (reply->error != B_OK)
1519 		return reply->error;
1520 	return error;
1521 }
1522 
1523 // OpenDir
1524 status_t
1525 Volume::OpenDir(fs_vnode node, fs_cookie* cookie)
1526 {
1527 	// check capability
1528 	if (!fFileSystem->HasCapability(FS_CAPABILITY_OPEN_DIR))
1529 		return B_BAD_VALUE;
1530 
1531 	// get a free port
1532 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
1533 	if (!port)
1534 		return B_ERROR;
1535 	PortReleaser _(fFileSystem->GetPortPool(), port);
1536 	AutoIncrementer incrementer(&fOpenDirectories);
1537 
1538 	// prepare the request
1539 	RequestAllocator allocator(port->GetPort());
1540 	OpenDirRequest* request;
1541 	status_t error = AllocateRequest(allocator, &request);
1542 	if (error != B_OK)
1543 		return error;
1544 
1545 	request->volume = fUserlandVolume;
1546 	request->node = node;
1547 
1548 	// send the request
1549 	KernelRequestHandler handler(this, OPEN_DIR_REPLY);
1550 	OpenDirReply* reply;
1551 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
1552 	if (error != B_OK)
1553 		return error;
1554 	RequestReleaser requestReleaser(port, reply);
1555 
1556 	// process the reply
1557 	if (reply->error != B_OK)
1558 		return reply->error;
1559 	incrementer.Keep();
1560 	*cookie = reply->dirCookie;
1561 	return error;
1562 }
1563 
1564 // CloseDir
1565 status_t
1566 Volume::CloseDir(fs_vnode node, fs_vnode cookie)
1567 {
1568 	status_t error = _CloseDir(node, cookie);
1569 	if (error != B_OK && fFileSystem->GetPortPool()->IsDisconnected()) {
1570 		// This isn't really necessary, as the return value is irrelevant to
1571 		// the VFS. OBOS ignores it completely. The fsshell returns it to the
1572 		// userland, but considers the node closed anyway.
1573 		WARN(("Volume::CloseDir(): connection lost, forcing close dir\n"));
1574 		return B_OK;
1575 	}
1576 	return error;
1577 }
1578 
1579 // FreeDirCookie
1580 status_t
1581 Volume::FreeDirCookie(void* node, void* cookie)
1582 {
1583 	status_t error = _FreeDirCookie(node, cookie);
1584 	bool disconnected = false;
1585 	if (error != B_OK && fFileSystem->GetPortPool()->IsDisconnected()) {
1586 		// This isn't really necessary, as the return value is irrelevant to
1587 		// the VFS. It's completely ignored by OBOS as well as by the fsshell.
1588 		WARN(("Volume::FreeDirCookie(): connection lost, forcing free dir "
1589 			"cookie\n"));
1590 		error = B_OK;
1591 		disconnected = true;
1592 	}
1593 	int32 openDirs = atomic_add(&fOpenDirectories, -1);
1594 	if (openDirs <= 1 && disconnected)
1595 		_PutAllPendingVNodes();
1596 	return error;
1597 }
1598 
1599 // ReadDir
1600 status_t
1601 Volume::ReadDir(fs_vnode node, fs_vnode cookie, void* buffer, size_t bufferSize,
1602 	uint32 count, uint32* countRead)
1603 {
1604 	*countRead = 0;
1605 
1606 	// check capability
1607 	if (!fFileSystem->HasCapability(FS_CAPABILITY_READ_DIR))
1608 		return B_BAD_VALUE;
1609 
1610 	// get a free port
1611 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
1612 	if (!port)
1613 		return B_ERROR;
1614 	PortReleaser _(fFileSystem->GetPortPool(), port);
1615 
1616 	// prepare the request
1617 	RequestAllocator allocator(port->GetPort());
1618 	ReadDirRequest* request;
1619 	status_t error = AllocateRequest(allocator, &request);
1620 	if (error != B_OK)
1621 		return error;
1622 
1623 	request->volume = fUserlandVolume;
1624 	request->node = node;
1625 	request->dirCookie = cookie;
1626 	request->bufferSize = bufferSize;
1627 	request->count = count;
1628 
1629 	// send the request
1630 	KernelRequestHandler handler(this, READ_DIR_REPLY);
1631 	ReadDirReply* reply;
1632 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
1633 	if (error != B_OK)
1634 		return error;
1635 	RequestReleaser requestReleaser(port, reply);
1636 
1637 	// process the reply
1638 	if (reply->error != B_OK)
1639 		return reply->error;
1640 	if (reply->count < 0 || reply->count > count)
1641 		return B_BAD_DATA;
1642 	if ((int32)bufferSize < reply->buffer.GetSize())
1643 		return B_BAD_DATA;
1644 PRINT(("Volume::ReadDir(): buffer returned: %ld bytes\n",
1645 reply->buffer.GetSize()));
1646 
1647 	*countRead = reply->count;
1648 	if (*countRead > 0) {
1649 		// copy the buffer -- limit the number of bytes to copy
1650 		uint32 maxBytes = *countRead
1651 			* (sizeof(struct dirent) + B_FILE_NAME_LENGTH);
1652 		uint32 copyBytes = reply->buffer.GetSize();
1653 		if (copyBytes > maxBytes)
1654 			copyBytes = maxBytes;
1655 		memcpy(buffer, reply->buffer.GetData(), copyBytes);
1656 	}
1657 	_SendReceiptAck(port);
1658 	return error;
1659 }
1660 
1661 // RewindDir
1662 status_t
1663 Volume::RewindDir(fs_vnode node, fs_vnode cookie)
1664 {
1665 	// check capability
1666 	if (!fFileSystem->HasCapability(FS_CAPABILITY_REWIND_DIR))
1667 		return B_BAD_VALUE;
1668 
1669 	// get a free port
1670 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
1671 	if (!port)
1672 		return B_ERROR;
1673 	PortReleaser _(fFileSystem->GetPortPool(), port);
1674 
1675 	// prepare the request
1676 	RequestAllocator allocator(port->GetPort());
1677 	RewindDirRequest* request;
1678 	status_t error = AllocateRequest(allocator, &request);
1679 	if (error != B_OK)
1680 		return error;
1681 
1682 	request->volume = fUserlandVolume;
1683 	request->node = node;
1684 	request->dirCookie = cookie;
1685 
1686 	// send the request
1687 	KernelRequestHandler handler(this, REWIND_DIR_REPLY);
1688 	RewindDirReply* reply;
1689 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
1690 	if (error != B_OK)
1691 		return error;
1692 	RequestReleaser requestReleaser(port, reply);
1693 
1694 	// process the reply
1695 	if (reply->error != B_OK)
1696 		return reply->error;
1697 	return error;
1698 }
1699 
1700 
1701 // #pragma mark - attribute directories
1702 
1703 
1704 // OpenAttrDir
1705 status_t
1706 Volume::OpenAttrDir(fs_vnode node, fs_cookie *cookie)
1707 {
1708 	// check capability
1709 	if (!fFileSystem->HasCapability(FS_CAPABILITY_OPEN_ATTR_DIR))
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 	AutoIncrementer incrementer(&fOpenAttributeDirectories);
1718 
1719 	// prepare the request
1720 	RequestAllocator allocator(port->GetPort());
1721 	OpenAttrDirRequest* request;
1722 	status_t error = AllocateRequest(allocator, &request);
1723 	if (error != B_OK)
1724 		return error;
1725 
1726 	request->volume = fUserlandVolume;
1727 	request->node = node;
1728 
1729 	// send the request
1730 	KernelRequestHandler handler(this, OPEN_ATTR_DIR_REPLY);
1731 	OpenAttrDirReply* reply;
1732 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
1733 	if (error != B_OK)
1734 		return error;
1735 	RequestReleaser requestReleaser(port, reply);
1736 
1737 	// process the reply
1738 	if (reply->error != B_OK)
1739 		return reply->error;
1740 	incrementer.Keep();
1741 	*cookie = reply->attrDirCookie;
1742 	return error;
1743 }
1744 
1745 // CloseAttrDir
1746 status_t
1747 Volume::CloseAttrDir(fs_vnode node, fs_cookie cookie)
1748 {
1749 	status_t error = _CloseAttrDir(node, cookie);
1750 	if (error != B_OK && fFileSystem->GetPortPool()->IsDisconnected()) {
1751 		// This isn't really necessary, as the return value is irrelevant to
1752 		// the VFS. OBOS ignores it completely. The fsshell returns it to the
1753 		// userland, but considers the node closed anyway.
1754 		WARN(("Volume::CloseAttrDir(): connection lost, forcing close attr "
1755 			"dir\n"));
1756 		return B_OK;
1757 	}
1758 	return error;
1759 }
1760 
1761 // FreeAttrDirCookie
1762 status_t
1763 Volume::FreeAttrDirCookie(void* node, void* cookie)
1764 {
1765 	status_t error = _FreeAttrDirCookie(node, cookie);
1766 	bool disconnected = false;
1767 	if (error != B_OK && fFileSystem->GetPortPool()->IsDisconnected()) {
1768 		// This isn't really necessary, as the return value is irrelevant to
1769 		// the VFS. It's completely ignored by OBOS as well as by the fsshell.
1770 		WARN(("Volume::FreeAttrDirCookie(): connection lost, forcing free attr "
1771 			"dir cookie\n"));
1772 		error = B_OK;
1773 		disconnected = true;
1774 	}
1775 
1776 	int32 openAttrDirs = atomic_add(&fOpenAttributeDirectories, -1);
1777 	if (openAttrDirs <= 1 && disconnected)
1778 		_PutAllPendingVNodes();
1779 	return error;
1780 }
1781 
1782 // ReadAttrDir
1783 status_t
1784 Volume::ReadAttrDir(fs_vnode node, fs_cookie cookie, void* buffer,
1785 	size_t bufferSize, uint32 count, uint32* countRead)
1786 {
1787 	// check capability
1788 	if (!fFileSystem->HasCapability(FS_CAPABILITY_READ_ATTR_DIR))
1789 		return B_BAD_VALUE;
1790 
1791 	*countRead = 0;
1792 	// get a free port
1793 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
1794 	if (!port)
1795 		return B_ERROR;
1796 	PortReleaser _(fFileSystem->GetPortPool(), port);
1797 
1798 	// prepare the request
1799 	RequestAllocator allocator(port->GetPort());
1800 	ReadAttrDirRequest* request;
1801 	status_t error = AllocateRequest(allocator, &request);
1802 	if (error != B_OK)
1803 		return error;
1804 
1805 	request->volume = fUserlandVolume;
1806 	request->node = node;
1807 	request->attrDirCookie = cookie;
1808 	request->bufferSize = bufferSize;
1809 	request->count = count;
1810 
1811 	// send the request
1812 	KernelRequestHandler handler(this, READ_ATTR_DIR_REPLY);
1813 	ReadAttrDirReply* reply;
1814 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
1815 	if (error != B_OK)
1816 		return error;
1817 	RequestReleaser requestReleaser(port, reply);
1818 
1819 	// process the reply
1820 	if (reply->error != B_OK)
1821 		return reply->error;
1822 	if (reply->count < 0 || reply->count > count)
1823 		return B_BAD_DATA;
1824 	if ((int32)bufferSize < reply->buffer.GetSize())
1825 		return B_BAD_DATA;
1826 
1827 	*countRead = reply->count;
1828 	if (*countRead > 0) {
1829 		// copy the buffer -- limit the number of bytes to copy
1830 		uint32 maxBytes = *countRead
1831 			* (sizeof(struct dirent) + B_ATTR_NAME_LENGTH);
1832 		uint32 copyBytes = reply->buffer.GetSize();
1833 		if (copyBytes > maxBytes)
1834 			copyBytes = maxBytes;
1835 		memcpy(buffer, reply->buffer.GetData(), copyBytes);
1836 	}
1837 	_SendReceiptAck(port);
1838 	return error;
1839 }
1840 
1841 // RewindAttrDir
1842 status_t
1843 Volume::RewindAttrDir(fs_vnode node, fs_cookie cookie)
1844 {
1845 	// check capability
1846 	if (!fFileSystem->HasCapability(FS_CAPABILITY_REWIND_ATTR_DIR))
1847 		return B_BAD_VALUE;
1848 
1849 	// get a free port
1850 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
1851 	if (!port)
1852 		return B_ERROR;
1853 	PortReleaser _(fFileSystem->GetPortPool(), port);
1854 
1855 	// prepare the request
1856 	RequestAllocator allocator(port->GetPort());
1857 	RewindAttrDirRequest* request;
1858 	status_t error = AllocateRequest(allocator, &request);
1859 	if (error != B_OK)
1860 		return error;
1861 
1862 	request->volume = fUserlandVolume;
1863 	request->node = node;
1864 	request->attrDirCookie = cookie;
1865 
1866 	// send the request
1867 	KernelRequestHandler handler(this, REWIND_ATTR_DIR_REPLY);
1868 	RewindAttrDirReply* reply;
1869 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
1870 	if (error != B_OK)
1871 		return error;
1872 	RequestReleaser requestReleaser(port, reply);
1873 
1874 	// process the reply
1875 	if (reply->error != B_OK)
1876 		return reply->error;
1877 	return error;
1878 }
1879 
1880 
1881 // #pragma mark - attributes
1882 
1883 // CreateAttr
1884 status_t
1885 Volume::CreateAttr(fs_vnode node, const char* name, uint32 type, int openMode,
1886 	fs_cookie* cookie)
1887 {
1888 	// check capability
1889 	if (!fFileSystem->HasCapability(FS_CAPABILITY_CREATE_ATTR))
1890 		return B_BAD_VALUE;
1891 
1892 	// get a free port
1893 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
1894 	if (!port)
1895 		return B_ERROR;
1896 	PortReleaser _(fFileSystem->GetPortPool(), port);
1897 	AutoIncrementer incrementer(&fOpenAttributes);
1898 
1899 	// prepare the request
1900 	RequestAllocator allocator(port->GetPort());
1901 	CreateAttrRequest* request;
1902 	status_t error = AllocateRequest(allocator, &request);
1903 	if (error != B_OK)
1904 		return error;
1905 
1906 	request->volume = fUserlandVolume;
1907 	request->node = node;
1908 	error = allocator.AllocateString(request->name, name);
1909 	request->type = type;
1910 	request->openMode = openMode;
1911 	if (error != B_OK)
1912 		return error;
1913 
1914 	// send the request
1915 	KernelRequestHandler handler(this, CREATE_ATTR_REPLY);
1916 	CreateAttrReply* reply;
1917 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
1918 	if (error != B_OK)
1919 		return error;
1920 	RequestReleaser requestReleaser(port, reply);
1921 
1922 	// process the reply
1923 	if (reply->error != B_OK)
1924 		return reply->error;
1925 	incrementer.Keep();
1926 	*cookie = reply->attrCookie;
1927 	return error;
1928 }
1929 
1930 // OpenAttr
1931 status_t
1932 Volume::OpenAttr(fs_vnode node, const char* name, int openMode,
1933 	fs_cookie* cookie)
1934 {
1935 	// check capability
1936 	if (!fFileSystem->HasCapability(FS_CAPABILITY_OPEN_ATTR))
1937 		return B_BAD_VALUE;
1938 
1939 	// get a free port
1940 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
1941 	if (!port)
1942 		return B_ERROR;
1943 	PortReleaser _(fFileSystem->GetPortPool(), port);
1944 	AutoIncrementer incrementer(&fOpenAttributes);
1945 
1946 	// prepare the request
1947 	RequestAllocator allocator(port->GetPort());
1948 	OpenAttrRequest* request;
1949 	status_t error = AllocateRequest(allocator, &request);
1950 	if (error != B_OK)
1951 		return error;
1952 
1953 	request->volume = fUserlandVolume;
1954 	request->node = node;
1955 	error = allocator.AllocateString(request->name, name);
1956 	request->openMode = openMode;
1957 	if (error != B_OK)
1958 		return error;
1959 
1960 	// send the request
1961 	KernelRequestHandler handler(this, OPEN_ATTR_REPLY);
1962 	OpenAttrReply* reply;
1963 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
1964 	if (error != B_OK)
1965 		return error;
1966 	RequestReleaser requestReleaser(port, reply);
1967 
1968 	// process the reply
1969 	if (reply->error != B_OK)
1970 		return reply->error;
1971 	incrementer.Keep();
1972 	*cookie = reply->attrCookie;
1973 	return error;
1974 }
1975 
1976 // CloseAttr
1977 status_t
1978 Volume::CloseAttr(fs_vnode node, fs_cookie cookie)
1979 {
1980 	status_t error = _CloseAttr(node, cookie);
1981 	if (error != B_OK && fFileSystem->GetPortPool()->IsDisconnected()) {
1982 		// This isn't really necessary, as the return value is irrelevant to
1983 		// the VFS. OBOS ignores it completely. The fsshell returns it to the
1984 		// userland, but considers the node closed anyway.
1985 		WARN(("Volume::CloseAttr(): connection lost, forcing close attr\n"));
1986 		return B_OK;
1987 	}
1988 	return error;
1989 }
1990 
1991 // FreeAttrCookie
1992 status_t
1993 Volume::FreeAttrCookie(fs_vnode node, fs_cookie cookie)
1994 {
1995 	status_t error = _FreeAttrCookie(node, cookie);
1996 	bool disconnected = false;
1997 	if (error != B_OK && fFileSystem->GetPortPool()->IsDisconnected()) {
1998 		// This isn't really necessary, as the return value is irrelevant to
1999 		// the VFS. It's completely ignored by OBOS as well as by the fsshell.
2000 		WARN(("Volume::FreeAttrCookie(): connection lost, forcing free attr "
2001 			"cookie\n"));
2002 		error = B_OK;
2003 		disconnected = true;
2004 	}
2005 
2006 	int32 openAttributes = atomic_add(&fOpenAttributes, -1);
2007 	if (openAttributes <= 1 && disconnected)
2008 		_PutAllPendingVNodes();
2009 	return error;
2010 }
2011 
2012 // ReadAttr
2013 status_t
2014 Volume::ReadAttr(fs_vnode node, fs_cookie cookie, off_t pos,
2015 	void* buffer, size_t bufferSize, size_t* bytesRead)
2016 {
2017 	*bytesRead = 0;
2018 
2019 	// check capability
2020 	if (!fFileSystem->HasCapability(FS_CAPABILITY_READ_ATTR))
2021 		return B_BAD_VALUE;
2022 
2023 	// get a free port
2024 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
2025 	if (!port)
2026 		return B_ERROR;
2027 	PortReleaser _(fFileSystem->GetPortPool(), port);
2028 
2029 	// prepare the request
2030 	RequestAllocator allocator(port->GetPort());
2031 	ReadAttrRequest* request;
2032 	status_t error = AllocateRequest(allocator, &request);
2033 	if (error != B_OK)
2034 		return error;
2035 
2036 	request->volume = fUserlandVolume;
2037 	request->node = node;
2038 	request->attrCookie = cookie;
2039 	request->pos = pos;
2040 	request->size = bufferSize;
2041 
2042 	// send the request
2043 	KernelRequestHandler handler(this, READ_ATTR_REPLY);
2044 	ReadAttrReply* reply;
2045 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
2046 	if (error != B_OK)
2047 		return error;
2048 	RequestReleaser requestReleaser(port, reply);
2049 
2050 	// process the reply
2051 	if (reply->error != B_OK)
2052 		return reply->error;
2053 	void* readBuffer = reply->buffer.GetData();
2054 	if (reply->bytesRead > (uint32)reply->buffer.GetSize()
2055 		|| reply->bytesRead > bufferSize) {
2056 		return B_BAD_DATA;
2057 	}
2058 	if (reply->bytesRead > 0)
2059 		memcpy(buffer, readBuffer, reply->bytesRead);
2060 	*bytesRead = reply->bytesRead;
2061 	_SendReceiptAck(port);
2062 	return error;
2063 }
2064 
2065 // WriteAttr
2066 status_t
2067 Volume::WriteAttr(fs_vnode node, fs_cookie cookie, off_t pos,
2068 	const void* buffer, size_t bufferSize, size_t* bytesWritten)
2069 {
2070 	*bytesWritten = 0;
2071 
2072 	// check capability
2073 	if (!fFileSystem->HasCapability(FS_CAPABILITY_WRITE_ATTR))
2074 		return B_BAD_VALUE;
2075 
2076 	// get a free port
2077 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
2078 	if (!port)
2079 		return B_ERROR;
2080 	PortReleaser _(fFileSystem->GetPortPool(), port);
2081 
2082 	// prepare the request
2083 	RequestAllocator allocator(port->GetPort());
2084 	WriteAttrRequest* request;
2085 	status_t error = AllocateRequest(allocator, &request);
2086 	if (error != B_OK)
2087 		return error;
2088 
2089 	request->volume = fUserlandVolume;
2090 	request->node = node;
2091 	request->attrCookie = cookie;
2092 	request->pos = pos;
2093 	error = allocator.AllocateData(request->buffer, buffer, bufferSize, 1);
2094 	if (error != B_OK)
2095 		return error;
2096 
2097 	// send the request
2098 	KernelRequestHandler handler(this, WRITE_ATTR_REPLY);
2099 	WriteAttrReply* reply;
2100 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
2101 	if (error != B_OK)
2102 		return error;
2103 	RequestReleaser requestReleaser(port, reply);
2104 
2105 	// process the reply
2106 	if (reply->error != B_OK)
2107 		return reply->error;
2108 	*bytesWritten = reply->bytesWritten;
2109 	return error;
2110 }
2111 
2112 // ReadAttrStat
2113 status_t
2114 Volume::ReadAttrStat(fs_vnode node, fs_cookie cookie, struct stat *st)
2115 {
2116 	// check capability
2117 	if (!fFileSystem->HasCapability(FS_CAPABILITY_READ_ATTR_STAT))
2118 		return B_BAD_VALUE;
2119 
2120 	// get a free port
2121 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
2122 	if (!port)
2123 		return B_ERROR;
2124 	PortReleaser _(fFileSystem->GetPortPool(), port);
2125 
2126 	// prepare the request
2127 	RequestAllocator allocator(port->GetPort());
2128 	ReadAttrStatRequest* request;
2129 	status_t error = AllocateRequest(allocator, &request);
2130 	if (error != B_OK)
2131 		return error;
2132 
2133 	request->volume = fUserlandVolume;
2134 	request->node = node;
2135 	request->attrCookie = cookie;
2136 
2137 	// send the request
2138 	KernelRequestHandler handler(this, READ_ATTR_STAT_REPLY);
2139 	ReadAttrStatReply* reply;
2140 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
2141 	if (error != B_OK)
2142 		return error;
2143 	RequestReleaser requestReleaser(port, reply);
2144 
2145 	// process the reply
2146 	if (reply->error != B_OK)
2147 		return reply->error;
2148 	*st = reply->st;
2149 	return error;
2150 }
2151 
2152 // WriteAttrStat
2153 status_t
2154 Volume::WriteAttrStat(fs_vnode node, fs_cookie cookie, const struct stat *st,
2155 	int statMask)
2156 {
2157 	// check capability
2158 	if (!fFileSystem->HasCapability(FS_CAPABILITY_WRITE_ATTR_STAT))
2159 		return B_BAD_VALUE;
2160 
2161 	// get a free port
2162 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
2163 	if (!port)
2164 		return B_ERROR;
2165 	PortReleaser _(fFileSystem->GetPortPool(), port);
2166 
2167 	// prepare the request
2168 	RequestAllocator allocator(port->GetPort());
2169 	WriteAttrStatRequest* request;
2170 	status_t error = AllocateRequest(allocator, &request);
2171 	if (error != B_OK)
2172 		return error;
2173 
2174 	request->volume = fUserlandVolume;
2175 	request->node = node;
2176 	request->attrCookie = cookie;
2177 	request->st = *st;
2178 	request->mask = statMask;
2179 
2180 	// send the request
2181 	KernelRequestHandler handler(this, WRITE_ATTR_STAT_REPLY);
2182 	WriteAttrStatReply* reply;
2183 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
2184 	if (error != B_OK)
2185 		return error;
2186 	RequestReleaser requestReleaser(port, reply);
2187 
2188 	// process the reply
2189 	if (reply->error != B_OK)
2190 		return reply->error;
2191 	return error;
2192 }
2193 
2194 // RenameAttr
2195 status_t
2196 Volume::RenameAttr(fs_vnode oldNode, const char* oldName, fs_vnode newNode,
2197 	const char* newName)
2198 {
2199 	// check capability
2200 	if (!fFileSystem->HasCapability(FS_CAPABILITY_RENAME_ATTR))
2201 		return B_BAD_VALUE;
2202 
2203 	// get a free port
2204 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
2205 	if (!port)
2206 		return B_ERROR;
2207 	PortReleaser _(fFileSystem->GetPortPool(), port);
2208 
2209 	// prepare the request
2210 	RequestAllocator allocator(port->GetPort());
2211 	RenameAttrRequest* request;
2212 	status_t error = AllocateRequest(allocator, &request);
2213 	if (error != B_OK)
2214 		return error;
2215 
2216 	request->volume = fUserlandVolume;
2217 	request->oldNode = oldNode;
2218 	request->newNode = newNode;
2219 	error = allocator.AllocateString(request->oldName, oldName);
2220 	if (error == B_OK)
2221 		error = allocator.AllocateString(request->newName, newName);
2222 	if (error != B_OK)
2223 		return error;
2224 
2225 	// send the request
2226 	KernelRequestHandler handler(this, RENAME_ATTR_REPLY);
2227 	RenameAttrReply* reply;
2228 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
2229 	if (error != B_OK)
2230 		return error;
2231 	RequestReleaser requestReleaser(port, reply);
2232 
2233 	// process the reply
2234 	if (reply->error != B_OK)
2235 		return reply->error;
2236 	return error;
2237 }
2238 
2239 // RemoveAttr
2240 status_t
2241 Volume::RemoveAttr(fs_vnode node, const char* name)
2242 {
2243 	// check capability
2244 	if (!fFileSystem->HasCapability(FS_CAPABILITY_REMOVE_ATTR))
2245 		return B_BAD_VALUE;
2246 
2247 	// get a free port
2248 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
2249 	if (!port)
2250 		return B_ERROR;
2251 	PortReleaser _(fFileSystem->GetPortPool(), port);
2252 
2253 	// prepare the request
2254 	RequestAllocator allocator(port->GetPort());
2255 	RemoveAttrRequest* request;
2256 	status_t error = AllocateRequest(allocator, &request);
2257 	if (error != B_OK)
2258 		return error;
2259 
2260 	request->volume = fUserlandVolume;
2261 	request->node = node;
2262 	error = allocator.AllocateString(request->name, name);
2263 	if (error != B_OK)
2264 		return error;
2265 
2266 	// send the request
2267 	KernelRequestHandler handler(this, REMOVE_ATTR_REPLY);
2268 	RemoveAttrReply* reply;
2269 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
2270 	if (error != B_OK)
2271 		return error;
2272 	RequestReleaser requestReleaser(port, reply);
2273 
2274 	// process the reply
2275 	if (reply->error != B_OK)
2276 		return reply->error;
2277 	return error;
2278 }
2279 
2280 
2281 // #pragma mark - indices
2282 
2283 
2284 // OpenIndexDir
2285 status_t
2286 Volume::OpenIndexDir(fs_cookie *cookie)
2287 {
2288 	// check capability
2289 	if (!fFileSystem->HasCapability(FS_CAPABILITY_OPEN_INDEX_DIR))
2290 		return B_BAD_VALUE;
2291 
2292 	// get a free port
2293 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
2294 	if (!port)
2295 		return B_ERROR;
2296 	PortReleaser _(fFileSystem->GetPortPool(), port);
2297 	AutoIncrementer incrementer(&fOpenIndexDirectories);
2298 
2299 	// prepare the request
2300 	RequestAllocator allocator(port->GetPort());
2301 	OpenIndexDirRequest* request;
2302 	status_t error = AllocateRequest(allocator, &request);
2303 	if (error != B_OK)
2304 		return error;
2305 
2306 	request->volume = fUserlandVolume;
2307 
2308 	// send the request
2309 	KernelRequestHandler handler(this, OPEN_INDEX_DIR_REPLY);
2310 	OpenIndexDirReply* reply;
2311 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
2312 	if (error != B_OK)
2313 		return error;
2314 	RequestReleaser requestReleaser(port, reply);
2315 
2316 	// process the reply
2317 	if (reply->error != B_OK)
2318 		return reply->error;
2319 	incrementer.Keep();
2320 	*cookie = reply->indexDirCookie;
2321 	return error;
2322 }
2323 
2324 // CloseIndexDir
2325 status_t
2326 Volume::CloseIndexDir(fs_cookie cookie)
2327 {
2328 	status_t error = _CloseIndexDir(cookie);
2329 	if (error != B_OK && fFileSystem->GetPortPool()->IsDisconnected()) {
2330 		// This isn't really necessary, as the return value is irrelevant to
2331 		// the VFS. OBOS ignores it completely. The fsshell returns it to the
2332 		// userland, but considers the node closed anyway.
2333 		WARN(("Volume::CloseIndexDir(): connection lost, forcing close "
2334 			"index dir\n"));
2335 		return B_OK;
2336 	}
2337 	return error;
2338 }
2339 
2340 // FreeIndexDirCookie
2341 status_t
2342 Volume::FreeIndexDirCookie(fs_cookie cookie)
2343 {
2344 	status_t error = _FreeIndexDirCookie(cookie);
2345 	bool disconnected = false;
2346 	if (error != B_OK && fFileSystem->GetPortPool()->IsDisconnected()) {
2347 		// This isn't really necessary, as the return value is irrelevant to
2348 		// the VFS. It's completely ignored by OBOS as well as by the fsshell.
2349 		WARN(("Volume::FreeIndexDirCookie(): connection lost, forcing free "
2350 			"index dir cookie\n"));
2351 		error = B_OK;
2352 		disconnected = true;
2353 	}
2354 
2355 	int32 openIndexDirs = atomic_add(&fOpenIndexDirectories, -1);
2356 	if (openIndexDirs <= 1 && disconnected)
2357 		_PutAllPendingVNodes();
2358 	return error;
2359 }
2360 
2361 // ReadIndexDir
2362 status_t
2363 Volume::ReadIndexDir(fs_cookie cookie, void* buffer, size_t bufferSize,
2364 	uint32 count, uint32* countRead)
2365 {
2366 	*countRead = 0;
2367 
2368 	// check capability
2369 	if (!fFileSystem->HasCapability(FS_CAPABILITY_READ_INDEX_DIR))
2370 		return B_BAD_VALUE;
2371 
2372 	// get a free port
2373 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
2374 	if (!port)
2375 		return B_ERROR;
2376 	PortReleaser _(fFileSystem->GetPortPool(), port);
2377 
2378 	// prepare the request
2379 	RequestAllocator allocator(port->GetPort());
2380 	ReadIndexDirRequest* request;
2381 	status_t error = AllocateRequest(allocator, &request);
2382 	if (error != B_OK)
2383 		return error;
2384 
2385 	request->volume = fUserlandVolume;
2386 	request->indexDirCookie = cookie;
2387 	request->bufferSize = bufferSize;
2388 	request->count = count;
2389 
2390 	// send the request
2391 	KernelRequestHandler handler(this, READ_INDEX_DIR_REPLY);
2392 	ReadIndexDirReply* reply;
2393 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
2394 	if (error != B_OK)
2395 		return error;
2396 	RequestReleaser requestReleaser(port, reply);
2397 
2398 	// process the reply
2399 	if (reply->error != B_OK)
2400 		return reply->error;
2401 	if (reply->count < 0 || reply->count > count)
2402 		return B_BAD_DATA;
2403 	if ((int32)bufferSize < reply->buffer.GetSize())
2404 		return B_BAD_DATA;
2405 
2406 	*countRead = reply->count;
2407 	if (*countRead > 0) {
2408 		// copy the buffer -- limit the number of bytes to copy
2409 		uint32 maxBytes = *countRead
2410 			* (sizeof(struct dirent) + B_FILE_NAME_LENGTH);
2411 		uint32 copyBytes = reply->buffer.GetSize();
2412 		if (copyBytes > maxBytes)
2413 			copyBytes = maxBytes;
2414 		memcpy(buffer, reply->buffer.GetData(), copyBytes);
2415 	}
2416 	_SendReceiptAck(port);
2417 	return error;
2418 }
2419 
2420 // RewindIndexDir
2421 status_t
2422 Volume::RewindIndexDir(fs_cookie cookie)
2423 {
2424 	// check capability
2425 	if (!fFileSystem->HasCapability(FS_CAPABILITY_REWIND_INDEX_DIR))
2426 		return B_BAD_VALUE;
2427 
2428 	// get a free port
2429 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
2430 	if (!port)
2431 		return B_ERROR;
2432 	PortReleaser _(fFileSystem->GetPortPool(), port);
2433 
2434 	// prepare the request
2435 	RequestAllocator allocator(port->GetPort());
2436 	RewindIndexDirRequest* request;
2437 	status_t error = AllocateRequest(allocator, &request);
2438 	if (error != B_OK)
2439 		return error;
2440 
2441 	request->volume = fUserlandVolume;
2442 	request->indexDirCookie = cookie;
2443 
2444 	// send the request
2445 	KernelRequestHandler handler(this, REWIND_INDEX_DIR_REPLY);
2446 	RewindIndexDirReply* reply;
2447 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
2448 	if (error != B_OK)
2449 		return error;
2450 	RequestReleaser requestReleaser(port, reply);
2451 
2452 	// process the reply
2453 	if (reply->error != B_OK)
2454 		return reply->error;
2455 	return error;
2456 }
2457 
2458 // CreateIndex
2459 status_t
2460 Volume::CreateIndex(const char* name, uint32 type, uint32 flags)
2461 {
2462 	// check capability
2463 	if (!fFileSystem->HasCapability(FS_CAPABILITY_CREATE_INDEX))
2464 		return B_BAD_VALUE;
2465 
2466 	// get a free port
2467 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
2468 	if (!port)
2469 		return B_ERROR;
2470 	PortReleaser _(fFileSystem->GetPortPool(), port);
2471 
2472 	// prepare the request
2473 	RequestAllocator allocator(port->GetPort());
2474 	CreateIndexRequest* request;
2475 	status_t error = AllocateRequest(allocator, &request);
2476 	if (error != B_OK)
2477 		return error;
2478 
2479 	request->volume = fUserlandVolume;
2480 	error = allocator.AllocateString(request->name, name);
2481 	request->type = type;
2482 	request->flags = flags;
2483 	if (error != B_OK)
2484 		return error;
2485 
2486 	// send the request
2487 	KernelRequestHandler handler(this, CREATE_INDEX_REPLY);
2488 	CreateIndexReply* reply;
2489 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
2490 	if (error != B_OK)
2491 		return error;
2492 	RequestReleaser requestReleaser(port, reply);
2493 
2494 	// process the reply
2495 	if (reply->error != B_OK)
2496 		return reply->error;
2497 	return error;
2498 }
2499 
2500 // RemoveIndex
2501 status_t
2502 Volume::RemoveIndex(const char* name)
2503 {
2504 	// check capability
2505 	if (!fFileSystem->HasCapability(FS_CAPABILITY_REMOVE_INDEX))
2506 		return B_BAD_VALUE;
2507 
2508 	// get a free port
2509 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
2510 	if (!port)
2511 		return B_ERROR;
2512 	PortReleaser _(fFileSystem->GetPortPool(), port);
2513 
2514 	// prepare the request
2515 	RequestAllocator allocator(port->GetPort());
2516 	RemoveIndexRequest* request;
2517 	status_t error = AllocateRequest(allocator, &request);
2518 	if (error != B_OK)
2519 		return error;
2520 
2521 	request->volume = fUserlandVolume;
2522 	error = allocator.AllocateString(request->name, name);
2523 	if (error != B_OK)
2524 		return error;
2525 
2526 	// send the request
2527 	KernelRequestHandler handler(this, REMOVE_INDEX_REPLY);
2528 	RemoveIndexReply* reply;
2529 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
2530 	if (error != B_OK)
2531 		return error;
2532 	RequestReleaser requestReleaser(port, reply);
2533 
2534 	// process the reply
2535 	if (reply->error != B_OK)
2536 		return reply->error;
2537 	return error;
2538 }
2539 
2540 // ReadIndexStat
2541 status_t
2542 Volume::ReadIndexStat(const char* name, struct stat *st)
2543 {
2544 	// check capability
2545 	if (!fFileSystem->HasCapability(FS_CAPABILITY_READ_INDEX_STAT))
2546 		return B_BAD_VALUE;
2547 
2548 	// get a free port
2549 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
2550 	if (!port)
2551 		return B_ERROR;
2552 	PortReleaser _(fFileSystem->GetPortPool(), port);
2553 
2554 	// prepare the request
2555 	RequestAllocator allocator(port->GetPort());
2556 	ReadIndexStatRequest* request;
2557 	status_t error = AllocateRequest(allocator, &request);
2558 	if (error != B_OK)
2559 		return error;
2560 
2561 	request->volume = fUserlandVolume;
2562 	error = allocator.AllocateString(request->name, name);
2563 	if (error != B_OK)
2564 		return error;
2565 
2566 	// send the request
2567 	KernelRequestHandler handler(this, READ_INDEX_STAT_REPLY);
2568 	ReadIndexStatReply* reply;
2569 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
2570 	if (error != B_OK)
2571 		return error;
2572 	RequestReleaser requestReleaser(port, reply);
2573 
2574 	// process the reply
2575 	if (reply->error != B_OK)
2576 		return reply->error;
2577 	*st = reply->st;
2578 	return error;
2579 }
2580 
2581 
2582 // #pragma mark - queries
2583 
2584 
2585 // OpenQuery
2586 status_t
2587 Volume::OpenQuery(const char* queryString, uint32 flags, port_id targetPort,
2588 	uint32 token, fs_cookie *cookie)
2589 {
2590 	// check capability
2591 	if (!fFileSystem->HasCapability(FS_CAPABILITY_OPEN_QUERY))
2592 		return B_BAD_VALUE;
2593 
2594 	// get a free port
2595 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
2596 	if (!port)
2597 		return B_ERROR;
2598 	PortReleaser _(fFileSystem->GetPortPool(), port);
2599 	AutoIncrementer incrementer(&fOpenQueries);
2600 
2601 	// prepare the request
2602 	RequestAllocator allocator(port->GetPort());
2603 	OpenQueryRequest* request;
2604 	status_t error = AllocateRequest(allocator, &request);
2605 	if (error != B_OK)
2606 		return error;
2607 
2608 	request->volume = fUserlandVolume;
2609 	error = allocator.AllocateString(request->queryString, queryString);
2610 	if (error != B_OK)
2611 		return error;
2612 	request->flags = flags;
2613 	request->port = targetPort;
2614 	request->token = token;
2615 
2616 	// send the request
2617 	KernelRequestHandler handler(this, OPEN_QUERY_REPLY);
2618 	OpenQueryReply* reply;
2619 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
2620 	if (error != B_OK)
2621 		return error;
2622 	RequestReleaser requestReleaser(port, reply);
2623 
2624 	// process the reply
2625 	if (reply->error != B_OK)
2626 		return reply->error;
2627 	incrementer.Keep();
2628 	*cookie = reply->queryCookie;
2629 	return error;
2630 }
2631 
2632 // CloseQuery
2633 status_t
2634 Volume::CloseQuery(fs_cookie cookie)
2635 {
2636 	status_t error = _CloseQuery(cookie);
2637 	if (error != B_OK && fFileSystem->GetPortPool()->IsDisconnected()) {
2638 		// This isn't really necessary, as the return value is irrelevant to
2639 		// the VFS. OBOS ignores it completely. The fsshell returns it to the
2640 		// userland, but considers the node closed anyway.
2641 		WARN(("Volume::CloseQuery(): connection lost, forcing close query\n"));
2642 		return B_OK;
2643 	}
2644 	return error;
2645 }
2646 
2647 // FreeQueryCookie
2648 status_t
2649 Volume::FreeQueryCookie(fs_cookie cookie)
2650 {
2651 	status_t error = _FreeQueryCookie(cookie);
2652 	bool disconnected = false;
2653 	if (error != B_OK && fFileSystem->GetPortPool()->IsDisconnected()) {
2654 		// This isn't really necessary, as the return value is irrelevant to
2655 		// the VFS. It's completely ignored by OBOS as well as by the fsshell.
2656 		WARN(("Volume::FreeQueryCookie(): connection lost, forcing free "
2657 			"query cookie\n"));
2658 		error = B_OK;
2659 		disconnected = true;
2660 	}
2661 
2662 	int32 openQueries = atomic_add(&fOpenQueries, -1);
2663 	if (openQueries <= 1 && disconnected)
2664 		_PutAllPendingVNodes();
2665 	return error;
2666 }
2667 
2668 // ReadQuery
2669 status_t
2670 Volume::ReadQuery(fs_cookie cookie, void* buffer, size_t bufferSize,
2671 	uint32 count, uint32* countRead)
2672 {
2673 	*countRead = 0;
2674 
2675 	// check capability
2676 	if (!fFileSystem->HasCapability(FS_CAPABILITY_READ_QUERY))
2677 		return B_BAD_VALUE;
2678 
2679 	// get a free port
2680 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
2681 	if (!port)
2682 		return B_ERROR;
2683 	PortReleaser _(fFileSystem->GetPortPool(), port);
2684 
2685 	// prepare the request
2686 	RequestAllocator allocator(port->GetPort());
2687 	ReadQueryRequest* request;
2688 	status_t error = AllocateRequest(allocator, &request);
2689 	if (error != B_OK)
2690 		return error;
2691 
2692 	request->volume = fUserlandVolume;
2693 	request->queryCookie = cookie;
2694 	request->bufferSize = bufferSize;
2695 	request->count = count;
2696 
2697 	// send the request
2698 	KernelRequestHandler handler(this, READ_QUERY_REPLY);
2699 	ReadQueryReply* reply;
2700 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
2701 	if (error != B_OK)
2702 		return error;
2703 	RequestReleaser requestReleaser(port, reply);
2704 
2705 	// process the reply
2706 	if (reply->error != B_OK)
2707 		return reply->error;
2708 	if (reply->count < 0 || reply->count > count)
2709 		return B_BAD_DATA;
2710 	if ((int32)bufferSize < reply->buffer.GetSize())
2711 		return B_BAD_DATA;
2712 
2713 	*countRead = reply->count;
2714 	if (*countRead > 0) {
2715 		// copy the buffer -- limit the number of bytes to copy
2716 		uint32 maxBytes = *countRead
2717 			* (sizeof(struct dirent) + B_FILE_NAME_LENGTH);
2718 		uint32 copyBytes = reply->buffer.GetSize();
2719 		if (copyBytes > maxBytes)
2720 			copyBytes = maxBytes;
2721 		memcpy(buffer, reply->buffer.GetData(), copyBytes);
2722 	}
2723 	_SendReceiptAck(port);
2724 	return error;
2725 }
2726 
2727 // RewindQuery
2728 status_t
2729 Volume::RewindQuery(fs_cookie cookie)
2730 {
2731 	// check capability
2732 	if (!fFileSystem->HasCapability(FS_CAPABILITY_REWIND_QUERY))
2733 		return B_BAD_VALUE;
2734 
2735 	// get a free port
2736 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
2737 	if (!port)
2738 		return B_ERROR;
2739 	PortReleaser _(fFileSystem->GetPortPool(), port);
2740 
2741 	// prepare the request
2742 	RequestAllocator allocator(port->GetPort());
2743 	RewindQueryRequest* request;
2744 	status_t error = AllocateRequest(allocator, &request);
2745 	if (error != B_OK)
2746 		return error;
2747 
2748 	request->volume = fUserlandVolume;
2749 	request->queryCookie = cookie;
2750 
2751 	// send the request
2752 	KernelRequestHandler handler(this, REWIND_QUERY_REPLY);
2753 	RewindQueryReply* reply;
2754 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
2755 	if (error != B_OK)
2756 		return error;
2757 	RequestReleaser requestReleaser(port, reply);
2758 
2759 	// process the reply
2760 	if (reply->error != B_OK)
2761 		return reply->error;
2762 	return error;
2763 }
2764 
2765 // #pragma mark -
2766 // #pragma mark ----- private implementations -----
2767 
2768 // _Mount
2769 status_t
2770 Volume::_Mount(const char* device, uint32 flags, const char* parameters)
2771 {
2772 	// get a free port
2773 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
2774 	if (!port)
2775 		return B_ERROR;
2776 	PortReleaser _(fFileSystem->GetPortPool(), port);
2777 
2778 	// get the current working directory
2779 	char cwd[B_PATH_NAME_LENGTH];
2780 	if (!getcwd(cwd, sizeof(cwd)))
2781 		return errno;
2782 
2783 	// prepare the request
2784 	RequestAllocator allocator(port->GetPort());
2785 	MountVolumeRequest* request;
2786 	status_t error = AllocateRequest(allocator, &request);
2787 	if (error != B_OK)
2788 		return error;
2789 
2790 	request->nsid = fID;
2791 	error = allocator.AllocateString(request->cwd, cwd);
2792 	if (error == B_OK)
2793 		error = allocator.AllocateString(request->device, device);
2794 	request->flags = flags;
2795 	if (error == B_OK)
2796 		error = allocator.AllocateString(request->parameters, parameters);
2797 	if (error != B_OK)
2798 		return error;
2799 
2800 	// send the request
2801 	KernelRequestHandler handler(this, MOUNT_VOLUME_REPLY);
2802 	MountVolumeReply* reply;
2803 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
2804 	if (error != B_OK)
2805 		return error;
2806 	RequestReleaser requestReleaser(port, reply);
2807 
2808 	// process the reply
2809 	if (reply->error != B_OK)
2810 		return reply->error;
2811 	fRootID = reply->rootID;
2812 	fUserlandVolume = reply->volume;
2813 
2814 	// enable vnode counting
2815 	fVNodeCountMap = new(nothrow) VNodeCountMap;
2816 	if (fVNodeCountMap)
2817 		fVNodeCountingEnabled = true;
2818 	else
2819 		ERROR(("Failed to allocate vnode count map."));
2820 	return error;
2821 }
2822 
2823 // _Unmount
2824 status_t
2825 Volume::_Unmount()
2826 {
2827 	// get a free port
2828 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
2829 	if (!port)
2830 		return B_ERROR;
2831 	PortReleaser _(fFileSystem->GetPortPool(), port);
2832 
2833 	// prepare the request
2834 	RequestAllocator allocator(port->GetPort());
2835 	UnmountVolumeRequest* request;
2836 	status_t error = AllocateRequest(allocator, &request);
2837 	if (error != B_OK)
2838 		return error;
2839 
2840 	request->volume = fUserlandVolume;
2841 
2842 	// send the request
2843 	KernelRequestHandler handler(this, UNMOUNT_VOLUME_REPLY);
2844 	UnmountVolumeReply* reply;
2845 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
2846 	if (error != B_OK)
2847 		return error;
2848 	RequestReleaser requestReleaser(port, reply);
2849 
2850 	// process the reply
2851 	if (reply->error != B_OK)
2852 		return reply->error;
2853 	return error;
2854 }
2855 
2856 // _ReadFSInfo
2857 status_t
2858 Volume::_ReadFSInfo(fs_info* info)
2859 {
2860 	// check capability
2861 	if (!fFileSystem->HasCapability(FS_CAPABILITY_READ_FS_INFO))
2862 		return B_BAD_VALUE;
2863 
2864 	// get a free port
2865 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
2866 	if (!port)
2867 		return B_ERROR;
2868 	PortReleaser _(fFileSystem->GetPortPool(), port);
2869 
2870 	// prepare the request
2871 	RequestAllocator allocator(port->GetPort());
2872 	ReadFSInfoRequest* request;
2873 	status_t error = AllocateRequest(allocator, &request);
2874 	if (error != B_OK)
2875 		return error;
2876 
2877 	request->volume = fUserlandVolume;
2878 
2879 	// send the request
2880 	KernelRequestHandler handler(this, READ_FS_INFO_REPLY);
2881 	ReadFSInfoReply* reply;
2882 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
2883 	if (error != B_OK)
2884 		return error;
2885 	RequestReleaser requestReleaser(port, reply);
2886 
2887 	// process the reply
2888 	if (reply->error != B_OK)
2889 		return reply->error;
2890 	*info = reply->info;
2891 	return error;
2892 }
2893 
2894 // _Lookup
2895 status_t
2896 Volume::_Lookup(fs_vnode dir, const char* entryName, ino_t* vnid, int* type)
2897 {
2898 	// get a free port
2899 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
2900 	if (!port)
2901 		return B_ERROR;
2902 	PortReleaser _(fFileSystem->GetPortPool(), port);
2903 
2904 	// prepare the request
2905 	RequestAllocator allocator(port->GetPort());
2906 	LookupRequest* request;
2907 	status_t error = AllocateRequest(allocator, &request);
2908 	if (error != B_OK)
2909 		return error;
2910 	request->volume = fUserlandVolume;
2911 	request->node = dir;
2912 	error = allocator.AllocateString(request->entryName, entryName);
2913 	if (error != B_OK)
2914 		return error;
2915 
2916 	// send the request
2917 	KernelRequestHandler handler(this, LOOKUP_REPLY);
2918 	LookupReply* reply;
2919 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
2920 	if (error != B_OK)
2921 		return error;
2922 	RequestReleaser requestReleaser(port, reply);
2923 
2924 	// process the reply
2925 	if (reply->error != B_OK)
2926 		return reply->error;
2927 	*vnid = reply->vnid;
2928 	*type = reply->type;
2929 
2930 	// The VFS will balance the get_vnode() call for the FS.
2931 	_DecrementVNodeCount(*vnid);
2932 	return error;
2933 }
2934 
2935 // _WriteVNode
2936 status_t
2937 Volume::_WriteVNode(fs_vnode node, bool reenter)
2938 {
2939 	// get a free port
2940 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
2941 	if (!port)
2942 		return B_ERROR;
2943 	PortReleaser _(fFileSystem->GetPortPool(), port);
2944 
2945 	// prepare the request
2946 	RequestAllocator allocator(port->GetPort());
2947 	WriteVNodeRequest* request;
2948 	status_t error = AllocateRequest(allocator, &request);
2949 	if (error != B_OK)
2950 		return error;
2951 	request->volume = fUserlandVolume;
2952 	request->node = node;
2953 	request->reenter = reenter;
2954 
2955 	// send the request
2956 	KernelRequestHandler handler(this, WRITE_VNODE_REPLY);
2957 	WriteVNodeReply* reply;
2958 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
2959 	if (error != B_OK)
2960 		return error;
2961 	RequestReleaser requestReleaser(port, reply);
2962 
2963 	// process the reply
2964 	if (reply->error != B_OK)
2965 		return reply->error;
2966 	return error;
2967 }
2968 
2969 // _ReadStat
2970 status_t
2971 Volume::_ReadStat(fs_vnode node, struct stat* st)
2972 {
2973 	// check capability
2974 	if (!fFileSystem->HasCapability(FS_CAPABILITY_READ_STAT))
2975 		return B_BAD_VALUE;
2976 
2977 	// get a free port
2978 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
2979 	if (!port)
2980 		return B_ERROR;
2981 	PortReleaser _(fFileSystem->GetPortPool(), port);
2982 
2983 	// prepare the request
2984 	RequestAllocator allocator(port->GetPort());
2985 	ReadStatRequest* request;
2986 	status_t error = AllocateRequest(allocator, &request);
2987 	if (error != B_OK)
2988 		return error;
2989 
2990 	request->volume = fUserlandVolume;
2991 	request->node = node;
2992 
2993 	// send the request
2994 	KernelRequestHandler handler(this, READ_STAT_REPLY);
2995 	ReadStatReply* reply;
2996 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
2997 	if (error != B_OK)
2998 		return error;
2999 	RequestReleaser requestReleaser(port, reply);
3000 
3001 	// process the reply
3002 	if (reply->error != B_OK)
3003 		return reply->error;
3004 	*st = reply->st;
3005 	return error;
3006 }
3007 
3008 // _Close
3009 status_t
3010 Volume::_Close(fs_vnode node, fs_cookie cookie)
3011 {
3012 	// check capability
3013 	if (!fFileSystem->HasCapability(FS_CAPABILITY_CLOSE))
3014 		return B_OK;
3015 
3016 	// get a free port
3017 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
3018 	if (!port)
3019 		return B_ERROR;
3020 	PortReleaser _(fFileSystem->GetPortPool(), port);
3021 
3022 	// prepare the request
3023 	RequestAllocator allocator(port->GetPort());
3024 	CloseRequest* request;
3025 	status_t error = AllocateRequest(allocator, &request);
3026 	if (error != B_OK)
3027 		return error;
3028 
3029 	request->volume = fUserlandVolume;
3030 	request->node = node;
3031 	request->fileCookie = cookie;
3032 
3033 	// send the request
3034 	KernelRequestHandler handler(this, CLOSE_REPLY);
3035 	CloseReply* reply;
3036 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
3037 	if (error != B_OK)
3038 		return error;
3039 	RequestReleaser requestReleaser(port, reply);
3040 
3041 	// process the reply
3042 	if (reply->error != B_OK)
3043 		return reply->error;
3044 	return error;
3045 }
3046 
3047 // _FreeCookie
3048 status_t
3049 Volume::_FreeCookie(fs_vnode node, fs_cookie cookie)
3050 {
3051 	// check capability
3052 	if (!fFileSystem->HasCapability(FS_CAPABILITY_FREE_COOKIE))
3053 		return B_OK;
3054 
3055 	// get a free port
3056 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
3057 	if (!port)
3058 		return B_ERROR;
3059 	PortReleaser _(fFileSystem->GetPortPool(), port);
3060 
3061 	// prepare the request
3062 	RequestAllocator allocator(port->GetPort());
3063 	FreeCookieRequest* request;
3064 	status_t error = AllocateRequest(allocator, &request);
3065 	if (error != B_OK)
3066 		return error;
3067 
3068 	request->volume = fUserlandVolume;
3069 	request->node = node;
3070 	request->fileCookie = cookie;
3071 
3072 	// send the request
3073 	KernelRequestHandler handler(this, FREE_COOKIE_REPLY);
3074 	FreeCookieReply* reply;
3075 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
3076 	if (error != B_OK)
3077 		return error;
3078 	RequestReleaser requestReleaser(port, reply);
3079 
3080 	// process the reply
3081 	if (reply->error != B_OK)
3082 		return reply->error;
3083 	return error;
3084 }
3085 
3086 // _CloseDir
3087 status_t
3088 Volume::_CloseDir(fs_vnode node, fs_vnode cookie)
3089 {
3090 	// check capability
3091 	if (!fFileSystem->HasCapability(FS_CAPABILITY_CLOSE_DIR))
3092 		return B_OK;
3093 
3094 	// get a free port
3095 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
3096 	if (!port)
3097 		return B_ERROR;
3098 	PortReleaser _(fFileSystem->GetPortPool(), port);
3099 
3100 	// prepare the request
3101 	RequestAllocator allocator(port->GetPort());
3102 	CloseDirRequest* request;
3103 	status_t error = AllocateRequest(allocator, &request);
3104 	if (error != B_OK)
3105 		return error;
3106 
3107 	request->volume = fUserlandVolume;
3108 	request->node = node;
3109 	request->dirCookie = cookie;
3110 
3111 	// send the request
3112 	KernelRequestHandler handler(this, CLOSE_DIR_REPLY);
3113 	CloseDirReply* reply;
3114 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
3115 	if (error != B_OK)
3116 		return error;
3117 	RequestReleaser requestReleaser(port, reply);
3118 
3119 	// process the reply
3120 	if (reply->error != B_OK)
3121 		return reply->error;
3122 	return error;
3123 }
3124 
3125 // _FreeDirCookie
3126 status_t
3127 Volume::_FreeDirCookie(fs_vnode node, fs_vnode cookie)
3128 {
3129 	// check capability
3130 	if (!fFileSystem->HasCapability(FS_CAPABILITY_FREE_DIR_COOKIE))
3131 		return B_OK;
3132 
3133 	// get a free port
3134 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
3135 	if (!port)
3136 		return B_ERROR;
3137 	PortReleaser _(fFileSystem->GetPortPool(), port);
3138 
3139 	// prepare the request
3140 	RequestAllocator allocator(port->GetPort());
3141 	FreeDirCookieRequest* request;
3142 	status_t error = AllocateRequest(allocator, &request);
3143 	if (error != B_OK)
3144 		return error;
3145 
3146 	request->volume = fUserlandVolume;
3147 	request->node = node;
3148 	request->dirCookie = cookie;
3149 
3150 	// send the request
3151 	KernelRequestHandler handler(this, FREE_DIR_COOKIE_REPLY);
3152 	FreeDirCookieReply* reply;
3153 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
3154 	if (error != B_OK)
3155 		return error;
3156 	RequestReleaser requestReleaser(port, reply);
3157 
3158 	// process the reply
3159 	if (reply->error != B_OK)
3160 		return reply->error;
3161 	return error;
3162 }
3163 
3164 // _CloseAttrDir
3165 status_t
3166 Volume::_CloseAttrDir(fs_vnode node, fs_cookie cookie)
3167 {
3168 	// check capability
3169 	if (!fFileSystem->HasCapability(FS_CAPABILITY_CLOSE_ATTR_DIR))
3170 		return B_OK;
3171 
3172 	// get a free port
3173 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
3174 	if (!port)
3175 		return B_ERROR;
3176 	PortReleaser _(fFileSystem->GetPortPool(), port);
3177 
3178 	// prepare the request
3179 	RequestAllocator allocator(port->GetPort());
3180 	CloseAttrDirRequest* request;
3181 	status_t error = AllocateRequest(allocator, &request);
3182 	if (error != B_OK)
3183 		return error;
3184 
3185 	request->volume = fUserlandVolume;
3186 	request->node = node;
3187 	request->attrDirCookie = cookie;
3188 
3189 	// send the request
3190 	KernelRequestHandler handler(this, CLOSE_ATTR_DIR_REPLY);
3191 	CloseAttrDirReply* reply;
3192 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
3193 	if (error != B_OK)
3194 		return error;
3195 	RequestReleaser requestReleaser(port, reply);
3196 
3197 	// process the reply
3198 	if (reply->error != B_OK)
3199 		return reply->error;
3200 	return error;
3201 }
3202 
3203 // _FreeAttrDirCookie
3204 status_t
3205 Volume::_FreeAttrDirCookie(fs_vnode node, fs_cookie cookie)
3206 {
3207 	// check capability
3208 	if (!fFileSystem->HasCapability(FS_CAPABILITY_FREE_ATTR_DIR_COOKIE))
3209 		return B_OK;
3210 
3211 	// get a free port
3212 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
3213 	if (!port)
3214 		return B_ERROR;
3215 	PortReleaser _(fFileSystem->GetPortPool(), port);
3216 
3217 	// prepare the request
3218 	RequestAllocator allocator(port->GetPort());
3219 	FreeAttrDirCookieRequest* request;
3220 	status_t error = AllocateRequest(allocator, &request);
3221 	if (error != B_OK)
3222 		return error;
3223 
3224 	request->volume = fUserlandVolume;
3225 	request->node = node;
3226 	request->attrDirCookie = cookie;
3227 
3228 	// send the request
3229 	KernelRequestHandler handler(this, FREE_ATTR_DIR_COOKIE_REPLY);
3230 	FreeAttrDirCookieReply* reply;
3231 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
3232 	if (error != B_OK)
3233 		return error;
3234 	RequestReleaser requestReleaser(port, reply);
3235 
3236 	// process the reply
3237 	if (reply->error != B_OK)
3238 		return reply->error;
3239 	return error;
3240 }
3241 
3242 // _CloseAttr
3243 status_t
3244 Volume::_CloseAttr(fs_vnode node, fs_cookie cookie)
3245 {
3246 	// check capability
3247 	if (!fFileSystem->HasCapability(FS_CAPABILITY_CLOSE_ATTR))
3248 		return B_OK;
3249 
3250 	// get a free port
3251 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
3252 	if (!port)
3253 		return B_ERROR;
3254 	PortReleaser _(fFileSystem->GetPortPool(), port);
3255 
3256 	// prepare the request
3257 	RequestAllocator allocator(port->GetPort());
3258 	CloseAttrRequest* request;
3259 	status_t error = AllocateRequest(allocator, &request);
3260 	if (error != B_OK)
3261 		return error;
3262 
3263 	request->volume = fUserlandVolume;
3264 	request->node = node;
3265 	request->attrCookie = cookie;
3266 
3267 	// send the request
3268 	KernelRequestHandler handler(this, CLOSE_ATTR_REPLY);
3269 	CloseAttrReply* reply;
3270 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
3271 	if (error != B_OK)
3272 		return error;
3273 	RequestReleaser requestReleaser(port, reply);
3274 
3275 	// process the reply
3276 	if (reply->error != B_OK)
3277 		return reply->error;
3278 	return error;
3279 }
3280 
3281 // _FreeAttrCookie
3282 status_t
3283 Volume::_FreeAttrCookie(fs_vnode node, fs_cookie cookie)
3284 {
3285 	// check capability
3286 	if (!fFileSystem->HasCapability(FS_CAPABILITY_FREE_ATTR_COOKIE))
3287 		return B_OK;
3288 
3289 	// get a free port
3290 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
3291 	if (!port)
3292 		return B_ERROR;
3293 	PortReleaser _(fFileSystem->GetPortPool(), port);
3294 
3295 	// prepare the request
3296 	RequestAllocator allocator(port->GetPort());
3297 	FreeAttrCookieRequest* request;
3298 	status_t error = AllocateRequest(allocator, &request);
3299 	if (error != B_OK)
3300 		return error;
3301 
3302 	request->volume = fUserlandVolume;
3303 	request->node = node;
3304 	request->attrCookie = cookie;
3305 
3306 	// send the request
3307 	KernelRequestHandler handler(this, FREE_ATTR_COOKIE_REPLY);
3308 	FreeAttrCookieReply* reply;
3309 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
3310 	if (error != B_OK)
3311 		return error;
3312 	RequestReleaser requestReleaser(port, reply);
3313 
3314 	// process the reply
3315 	if (reply->error != B_OK)
3316 		return reply->error;
3317 	return error;
3318 }
3319 
3320 // _CloseIndexDir
3321 status_t
3322 Volume::_CloseIndexDir(fs_cookie cookie)
3323 {
3324 	// check capability
3325 	if (!fFileSystem->HasCapability(FS_CAPABILITY_CLOSE_INDEX_DIR))
3326 		return B_OK;
3327 
3328 	// get a free port
3329 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
3330 	if (!port)
3331 		return B_ERROR;
3332 	PortReleaser _(fFileSystem->GetPortPool(), port);
3333 
3334 	// prepare the request
3335 	RequestAllocator allocator(port->GetPort());
3336 	CloseIndexDirRequest* request;
3337 	status_t error = AllocateRequest(allocator, &request);
3338 	if (error != B_OK)
3339 		return error;
3340 
3341 	request->volume = fUserlandVolume;
3342 	request->indexDirCookie = cookie;
3343 
3344 	// send the request
3345 	KernelRequestHandler handler(this, CLOSE_INDEX_DIR_REPLY);
3346 	CloseIndexDirReply* reply;
3347 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
3348 	if (error != B_OK)
3349 		return error;
3350 	RequestReleaser requestReleaser(port, reply);
3351 
3352 	// process the reply
3353 	if (reply->error != B_OK)
3354 		return reply->error;
3355 	return error;
3356 }
3357 
3358 // _FreeIndexDirCookie
3359 status_t
3360 Volume::_FreeIndexDirCookie(fs_cookie cookie)
3361 {
3362 	// check capability
3363 	if (!fFileSystem->HasCapability(FS_CAPABILITY_FREE_INDEX_DIR_COOKIE))
3364 		return B_OK;
3365 
3366 	// get a free port
3367 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
3368 	if (!port)
3369 		return B_ERROR;
3370 	PortReleaser _(fFileSystem->GetPortPool(), port);
3371 
3372 	// prepare the request
3373 	RequestAllocator allocator(port->GetPort());
3374 	FreeIndexDirCookieRequest* request;
3375 	status_t error = AllocateRequest(allocator, &request);
3376 	if (error != B_OK)
3377 		return error;
3378 
3379 	request->volume = fUserlandVolume;
3380 	request->indexDirCookie = cookie;
3381 
3382 	// send the request
3383 	KernelRequestHandler handler(this, FREE_INDEX_DIR_COOKIE_REPLY);
3384 	FreeIndexDirCookieReply* reply;
3385 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
3386 	if (error != B_OK)
3387 		return error;
3388 	RequestReleaser requestReleaser(port, reply);
3389 
3390 	// process the reply
3391 	if (reply->error != B_OK)
3392 		return reply->error;
3393 	return error;
3394 }
3395 
3396 // _CloseQuery
3397 status_t
3398 Volume::_CloseQuery(fs_cookie cookie)
3399 {
3400 	// check capability
3401 	if (!fFileSystem->HasCapability(FS_CAPABILITY_CLOSE_QUERY))
3402 		return B_OK;
3403 
3404 	// get a free port
3405 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
3406 	if (!port)
3407 		return B_ERROR;
3408 	PortReleaser _(fFileSystem->GetPortPool(), port);
3409 
3410 	// prepare the request
3411 	RequestAllocator allocator(port->GetPort());
3412 	CloseQueryRequest* request;
3413 	status_t error = AllocateRequest(allocator, &request);
3414 	if (error != B_OK)
3415 		return error;
3416 
3417 	request->volume = fUserlandVolume;
3418 	request->queryCookie = cookie;
3419 
3420 	// send the request
3421 	KernelRequestHandler handler(this, CLOSE_QUERY_REPLY);
3422 	CloseQueryReply* reply;
3423 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
3424 	if (error != B_OK)
3425 		return error;
3426 	RequestReleaser requestReleaser(port, reply);
3427 
3428 	// process the reply
3429 	if (reply->error != B_OK)
3430 		return reply->error;
3431 	return error;
3432 }
3433 
3434 // _FreeQueryCookie
3435 status_t
3436 Volume::_FreeQueryCookie(fs_cookie cookie)
3437 {
3438 	// check capability
3439 	if (!fFileSystem->HasCapability(FS_CAPABILITY_FREE_QUERY_COOKIE))
3440 		return B_OK;
3441 
3442 	// get a free port
3443 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
3444 	if (!port)
3445 		return B_ERROR;
3446 	PortReleaser _(fFileSystem->GetPortPool(), port);
3447 
3448 	// prepare the request
3449 	RequestAllocator allocator(port->GetPort());
3450 	FreeQueryCookieRequest* request;
3451 	status_t error = AllocateRequest(allocator, &request);
3452 	if (error != B_OK)
3453 		return error;
3454 
3455 	request->volume = fUserlandVolume;
3456 	request->queryCookie = cookie;
3457 
3458 	// send the request
3459 	KernelRequestHandler handler(this, FREE_QUERY_COOKIE_REPLY);
3460 	FreeQueryCookieReply* reply;
3461 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
3462 	if (error != B_OK)
3463 		return error;
3464 	RequestReleaser requestReleaser(port, reply);
3465 
3466 	// process the reply
3467 	if (reply->error != B_OK)
3468 		return reply->error;
3469 	return error;
3470 }
3471 
3472 // _SendRequest
3473 status_t
3474 Volume::_SendRequest(RequestPort* port, RequestAllocator* allocator,
3475 	RequestHandler* handler, Request** reply)
3476 {
3477 	if (!fFileSystem->IsUserlandServerThread())
3478 		return port->SendRequest(allocator, handler, reply);
3479 	// Here it gets dangerous: a thread of the userland server team being here
3480 	// calls for trouble. We try receiving the request with a timeout, and
3481 	// close the port -- which will disconnect the whole FS.
3482 	status_t error = port->SendRequest(allocator, handler, reply,
3483 		kUserlandServerlandPortTimeout);
3484 	if (error == B_TIMED_OUT || error == B_WOULD_BLOCK)
3485 		port->Close();
3486 	return error;
3487 }
3488 
3489 // _SendReceiptAck
3490 status_t
3491 Volume::_SendReceiptAck(RequestPort* port)
3492 {
3493 	RequestAllocator allocator(port->GetPort());
3494 	ReceiptAckReply* request;
3495 	status_t error = AllocateRequest(allocator, &request);
3496 	if (error != B_OK)
3497 		return error;
3498 	return port->SendRequest(&allocator);
3499 }
3500 
3501 // _IncrementVNodeCount
3502 void
3503 Volume::_IncrementVNodeCount(ino_t vnid)
3504 {
3505 	if (!fVNodeCountingEnabled)
3506 		return;
3507 	AutoLocker<VNodeCountMap> _(fVNodeCountMap);
3508 	if (!fVNodeCountingEnabled)	// someone may have changed it
3509 		return;
3510 	// get the counter
3511 	int32* count = fVNodeCountMap->Get(vnid);
3512 	if (!count) {
3513 		// vnode not known yet: create and add a new counter
3514 		count = new(nothrow) int32(0);
3515 		if (!count) {
3516 			ERROR(("Volume::_IncrementVNodeCount(): Failed to allocate "
3517 				"counter. Disabling vnode counting.\n"));
3518 			fVNodeCountingEnabled = false;
3519 			return;
3520 		}
3521 		if (fVNodeCountMap->Put(vnid, count) != B_OK) {
3522 			ERROR(("Volume::_IncrementVNodeCount(): Failed to add counter. "
3523 				"Disabling vnode counting.\n"));
3524 			delete count;
3525 			fVNodeCountingEnabled = false;
3526 			return;
3527 		}
3528 	}
3529 	// increment the counter
3530 	(*count)++;
3531 //PRINT(("_IncrementVNodeCount(%Ld): count: %ld, fVNodeCountMap size: %ld\n", vnid, *count, fVNodeCountMap->Size()));
3532 }
3533 
3534 // _DecrementVNodeCount
3535 void
3536 Volume::_DecrementVNodeCount(ino_t vnid)
3537 {
3538 	if (!fVNodeCountingEnabled)
3539 		return;
3540 	AutoLocker<VNodeCountMap> _(fVNodeCountMap);
3541 	if (!fVNodeCountingEnabled)	// someone may have changed it
3542 		return;
3543 	int32* count = fVNodeCountMap->Get(vnid);
3544 	if (!count) {
3545 		// that should never happen
3546 		ERROR(("Volume::_DecrementVNodeCount(): Failed to get counter. "
3547 			"Disabling vnode counting.\n"));
3548 		fVNodeCountingEnabled = false;
3549 		return;
3550 	}
3551 	(*count)--;
3552 //int32 tmpCount = *count;
3553 	if (*count == 0)
3554 		fVNodeCountMap->Remove(vnid);
3555 //PRINT(("_DecrementVNodeCount(%Ld): count: %ld, fVNodeCountMap size: %ld\n", vnid, tmpCount, fVNodeCountMap->Size()));
3556 }
3557 
3558 // _InternalIOCtl
3559 status_t
3560 Volume::_InternalIOCtl(userlandfs_ioctl* buffer, int32 bufferSize)
3561 {
3562 	if (buffer->version != USERLAND_IOCTL_CURRENT_VERSION)
3563 		return B_BAD_VALUE;
3564 	status_t result = B_OK;
3565 	switch (buffer->command) {
3566 		case USERLAND_IOCTL_PUT_ALL_PENDING_VNODES:
3567 			result = _PutAllPendingVNodes();
3568 			break;
3569 		default:
3570 			return B_BAD_VALUE;
3571 	}
3572 	buffer->error = result;
3573 	return B_OK;
3574 }
3575 
3576 // _PutAllPendingVNodes
3577 status_t
3578 Volume::_PutAllPendingVNodes()
3579 {
3580 PRINT(("Volume::_PutAllPendingVNodes()\n"));
3581 	if (!fFileSystem->GetPortPool()->IsDisconnected()) {
3582 		PRINT(("Volume::_PutAllPendingVNodes() failed: still connected\n"));
3583 		return USERLAND_IOCTL_STILL_CONNECTED;
3584 	}
3585 	if (!fVNodeCountingEnabled) {
3586 		PRINT(("Volume::_PutAllPendingVNodes() failed: vnode counting "
3587 			"disabled\n"));
3588 		return USERLAND_IOCTL_VNODE_COUNTING_DISABLED;
3589 	}
3590 	{
3591 		AutoLocker<VNodeCountMap> _(fVNodeCountMap);
3592 		if (!fVNodeCountingEnabled)	{// someone may have changed it
3593 			PRINT(("Volume::_PutAllPendingVNodes() failed: vnode counting "
3594 				"disabled\n"));
3595 			return USERLAND_IOCTL_VNODE_COUNTING_DISABLED;
3596 		}
3597 		// Check whether there are open entities at the moment.
3598 		if (fOpenFiles > 0) {
3599 			PRINT(("Volume::_PutAllPendingVNodes() failed: open files\n"));
3600 			return USERLAND_IOCTL_OPEN_FILES;
3601 		}
3602 		if (fOpenDirectories > 0) {
3603 			PRINT(("Volume::_PutAllPendingVNodes() failed: open dirs\n"));
3604 			return USERLAND_IOCTL_OPEN_DIRECTORIES;
3605 		}
3606 		if (fOpenAttributeDirectories > 0) {
3607 			PRINT(("Volume::_PutAllPendingVNodes() failed: open attr dirs\n"));
3608 			return USERLAND_IOCTL_OPEN_ATTRIBUTE_DIRECTORIES;
3609 		}
3610 		if (fOpenAttributes > 0) {
3611 			PRINT(("Volume::_PutAllPendingVNodes() failed: open attributes\n"));
3612 			return USERLAND_IOCTL_OPEN_ATTRIBUTES;
3613 		}
3614 		if (fOpenIndexDirectories > 0) {
3615 			PRINT(("Volume::_PutAllPendingVNodes() failed: open index dirs\n"));
3616 			return USERLAND_IOCTL_OPEN_INDEX_DIRECTORIES;
3617 		}
3618 		if (fOpenQueries > 0) {
3619 			PRINT(("Volume::_PutAllPendingVNodes() failed: open queries\n"));
3620 			return USERLAND_IOCTL_OPEN_QUERIES;
3621 		}
3622 		// No open entities. Since the port pool is disconnected, no new
3623 		// entities can be opened. Disable node counting and put all pending
3624 		// vnodes.
3625 		fVNodeCountingEnabled = false;
3626 	}
3627 	int32 putVNodeCount = 0;
3628 	for (VNodeCountMap::Iterator it = fVNodeCountMap->GetIterator();
3629 		 it.HasNext();) {
3630 		VNodeCountMap::Entry entry = it.Next();
3631 		int32 count = *entry.value;
3632 		for (int32 i = 0; i < count; i++) {
3633 			PutVNode(entry.key.value);
3634 			putVNodeCount++;
3635 		}
3636 	}
3637 	PRINT(("Volume::_PutAllPendingVNodes() successful: Put %ld vnodes\n",
3638 		putVNodeCount));
3639 	return B_OK;
3640 }
3641 
3642