xref: /haiku/src/add-ons/kernel/file_systems/userlandfs/kernel_add_on/Volume.cpp (revision 80d75f15dfa48ebea421c6b2c19a5296cc63d7eb)
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, ref, 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->ref = ref;
761 	request->sync = sync;
762 
763 	// add a selectsync entry
764 	error = fFileSystem->AddSelectSyncEntry(sync);
765 	if (error != B_OK)
766 		return error;
767 
768 	// send the request
769 	KernelRequestHandler handler(this, SELECT_REPLY);
770 	SelectReply* reply;
771 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
772 	if (error != B_OK) {
773 		fFileSystem->RemoveSelectSyncEntry(sync);
774 		return error;
775 	}
776 	RequestReleaser requestReleaser(port, reply);
777 
778 	// process the reply
779 	if (reply->error != B_OK) {
780 		fFileSystem->RemoveSelectSyncEntry(sync);
781 		return reply->error;
782 	}
783 	return error;
784 }
785 
786 // Deselect
787 status_t
788 Volume::Deselect(fs_vnode node, fs_cookie cookie, uint8 event, selectsync* sync)
789 {
790 	// check capability
791 	if (!fFileSystem->HasCapability(FS_CAPABILITY_DESELECT))
792 		return B_OK;
793 
794 	struct SyncRemover {
795 		SyncRemover(FileSystem* fs, selectsync* sync)
796 			: fs(fs), sync(sync) {}
797 		~SyncRemover() { fs->RemoveSelectSyncEntry(sync); }
798 
799 		FileSystem*	fs;
800 		selectsync*	sync;
801 	} syncRemover(fFileSystem, sync);
802 
803 	// get a free port
804 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
805 	if (!port)
806 		return B_ERROR;
807 	PortReleaser _(fFileSystem->GetPortPool(), port);
808 
809 	// prepare the request
810 	RequestAllocator allocator(port->GetPort());
811 	DeselectRequest* request;
812 	status_t error = AllocateRequest(allocator, &request);
813 	if (error != B_OK)
814 		return error;
815 
816 	request->volume = fUserlandVolume;
817 	request->node = node;
818 	request->fileCookie = cookie;
819 	request->event = event;
820 	request->sync = sync;
821 
822 	// send the request
823 	KernelRequestHandler handler(this, DESELECT_REPLY);
824 	DeselectReply* reply;
825 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
826 	if (error != B_OK)
827 		return error;
828 	RequestReleaser requestReleaser(port, reply);
829 
830 	// process the reply
831 	if (reply->error != B_OK)
832 		return reply->error;
833 	return error;
834 }
835 
836 // FSync
837 status_t
838 Volume::FSync(fs_vnode node)
839 {
840 	// check capability
841 	if (!fFileSystem->HasCapability(FS_CAPABILITY_FSYNC))
842 		return B_BAD_VALUE;
843 
844 	// get a free port
845 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
846 	if (!port)
847 		return B_ERROR;
848 	PortReleaser _(fFileSystem->GetPortPool(), port);
849 
850 	// prepare the request
851 	RequestAllocator allocator(port->GetPort());
852 	FSyncRequest* request;
853 	status_t error = AllocateRequest(allocator, &request);
854 	if (error != B_OK)
855 		return error;
856 
857 	request->volume = fUserlandVolume;
858 	request->node = node;
859 
860 	// send the request
861 	KernelRequestHandler handler(this, FSYNC_REPLY);
862 	FSyncReply* reply;
863 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
864 	if (error != B_OK)
865 		return error;
866 	RequestReleaser requestReleaser(port, reply);
867 
868 	// process the reply
869 	if (reply->error != B_OK)
870 		return reply->error;
871 	return error;
872 }
873 
874 // ReadSymlink
875 status_t
876 Volume::ReadSymlink(fs_vnode node, char* buffer, size_t bufferSize,
877 	size_t* bytesRead)
878 {
879 	*bytesRead = 0;
880 
881 	// check capability
882 	if (!fFileSystem->HasCapability(FS_CAPABILITY_READ_SYMLINK))
883 		return B_BAD_VALUE;
884 
885 	// get a free port
886 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
887 	if (!port)
888 		return B_ERROR;
889 	PortReleaser _(fFileSystem->GetPortPool(), port);
890 
891 	// prepare the request
892 	RequestAllocator allocator(port->GetPort());
893 	ReadSymlinkRequest* request;
894 	status_t error = AllocateRequest(allocator, &request);
895 	if (error != B_OK)
896 		return error;
897 
898 	request->volume = fUserlandVolume;
899 	request->node = node;
900 	request->size = bufferSize;
901 
902 	// send the request
903 	KernelRequestHandler handler(this, READ_SYMLINK_REPLY);
904 	ReadSymlinkReply* reply;
905 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
906 	if (error != B_OK)
907 		return error;
908 	RequestReleaser requestReleaser(port, reply);
909 
910 	// process the reply
911 	if (reply->error != B_OK)
912 		return reply->error;
913 	void* readBuffer = reply->buffer.GetData();
914 	if (reply->bytesRead > (uint32)reply->buffer.GetSize()
915 		|| reply->bytesRead > bufferSize) {
916 		return B_BAD_DATA;
917 	}
918 	if (reply->bytesRead > 0)
919 		memcpy(buffer, readBuffer, reply->bytesRead);
920 	*bytesRead = reply->bytesRead;
921 	_SendReceiptAck(port);
922 	return error;
923 }
924 
925 // CreateSymlink
926 status_t
927 Volume::CreateSymlink(fs_vnode dir, const char* name, const char* target,
928 	int mode)
929 {
930 	// check capability
931 	if (!fFileSystem->HasCapability(FS_CAPABILITY_CREATE_SYMLINK))
932 		return B_BAD_VALUE;
933 
934 	// get a free port
935 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
936 	if (!port)
937 		return B_ERROR;
938 	PortReleaser _(fFileSystem->GetPortPool(), port);
939 
940 	// prepare the request
941 	RequestAllocator allocator(port->GetPort());
942 	CreateSymlinkRequest* request;
943 	status_t error = AllocateRequest(allocator, &request);
944 	if (error != B_OK)
945 		return error;
946 
947 	request->volume = fUserlandVolume;
948 	request->node = dir;
949 	error = allocator.AllocateString(request->name, name);
950 	if (error == B_OK)
951 		error = allocator.AllocateString(request->target, target);
952 	if (error != B_OK)
953 		return error;
954 	request->mode = mode;
955 
956 	// send the request
957 	KernelRequestHandler handler(this, CREATE_SYMLINK_REPLY);
958 	CreateSymlinkReply* reply;
959 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
960 	if (error != B_OK)
961 		return error;
962 	RequestReleaser requestReleaser(port, reply);
963 
964 	// process the reply
965 	if (reply->error != B_OK)
966 		return reply->error;
967 	return error;
968 }
969 
970 // Link
971 status_t
972 Volume::Link(fs_vnode dir, const char* name, fs_vnode node)
973 {
974 	// check capability
975 	if (!fFileSystem->HasCapability(FS_CAPABILITY_LINK))
976 		return B_BAD_VALUE;
977 
978 	// get a free port
979 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
980 	if (!port)
981 		return B_ERROR;
982 	PortReleaser _(fFileSystem->GetPortPool(), port);
983 
984 	// prepare the request
985 	RequestAllocator allocator(port->GetPort());
986 	LinkRequest* request;
987 	status_t error = AllocateRequest(allocator, &request);
988 	if (error != B_OK)
989 		return error;
990 
991 	request->volume = fUserlandVolume;
992 	request->node = dir;
993 	error = allocator.AllocateString(request->name, name);
994 	request->target = node;
995 	if (error != B_OK)
996 		return error;
997 
998 	// send the request
999 	KernelRequestHandler handler(this, LINK_REPLY);
1000 	LinkReply* reply;
1001 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
1002 	if (error != B_OK)
1003 		return error;
1004 	RequestReleaser requestReleaser(port, reply);
1005 
1006 	// process the reply
1007 	if (reply->error != B_OK)
1008 		return reply->error;
1009 	return error;
1010 }
1011 
1012 // Unlink
1013 status_t
1014 Volume::Unlink(fs_vnode dir, const char* name)
1015 {
1016 	// check capability
1017 	if (!fFileSystem->HasCapability(FS_CAPABILITY_UNLINK))
1018 		return B_BAD_VALUE;
1019 
1020 	// get a free port
1021 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
1022 	if (!port)
1023 		return B_ERROR;
1024 	PortReleaser _(fFileSystem->GetPortPool(), port);
1025 
1026 	// prepare the request
1027 	RequestAllocator allocator(port->GetPort());
1028 	UnlinkRequest* request;
1029 	status_t error = AllocateRequest(allocator, &request);
1030 	if (error != B_OK)
1031 		return error;
1032 
1033 	request->volume = fUserlandVolume;
1034 	request->node = dir;
1035 	error = allocator.AllocateString(request->name, name);
1036 	if (error != B_OK)
1037 		return error;
1038 
1039 	// send the request
1040 	KernelRequestHandler handler(this, UNLINK_REPLY);
1041 	UnlinkReply* reply;
1042 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
1043 	if (error != B_OK)
1044 		return error;
1045 	RequestReleaser requestReleaser(port, reply);
1046 
1047 	// process the reply
1048 	if (reply->error != B_OK)
1049 		return reply->error;
1050 	return error;
1051 }
1052 
1053 // Rename
1054 status_t
1055 Volume::Rename(fs_vnode oldDir, const char* oldName, fs_vnode newDir,
1056 	const char* newName)
1057 {
1058 	// check capability
1059 	if (!fFileSystem->HasCapability(FS_CAPABILITY_RENAME))
1060 		return B_BAD_VALUE;
1061 
1062 	// get a free port
1063 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
1064 	if (!port)
1065 		return B_ERROR;
1066 	PortReleaser _(fFileSystem->GetPortPool(), port);
1067 
1068 	// prepare the request
1069 	RequestAllocator allocator(port->GetPort());
1070 	RenameRequest* request;
1071 	status_t error = AllocateRequest(allocator, &request);
1072 	if (error != B_OK)
1073 		return error;
1074 
1075 	request->volume = fUserlandVolume;
1076 	request->oldDir = oldDir;
1077 	request->newDir = newDir;
1078 	error = allocator.AllocateString(request->oldName, oldName);
1079 	if (error == B_OK)
1080 		error = allocator.AllocateString(request->newName, newName);
1081 	if (error != B_OK)
1082 		return error;
1083 
1084 	// send the request
1085 	KernelRequestHandler handler(this, RENAME_REPLY);
1086 	RenameReply* reply;
1087 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
1088 	if (error != B_OK)
1089 		return error;
1090 	RequestReleaser requestReleaser(port, reply);
1091 
1092 	// process the reply
1093 	if (reply->error != B_OK)
1094 		return reply->error;
1095 	return error;
1096 }
1097 
1098 // Access
1099 status_t
1100 Volume::Access(fs_vnode node, int mode)
1101 {
1102 	// check capability
1103 	if (!fFileSystem->HasCapability(FS_CAPABILITY_ACCESS))
1104 		return B_OK;
1105 
1106 	// get a free port
1107 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
1108 	if (!port)
1109 		return B_ERROR;
1110 	PortReleaser _(fFileSystem->GetPortPool(), port);
1111 
1112 	// prepare the request
1113 	RequestAllocator allocator(port->GetPort());
1114 	AccessRequest* request;
1115 	status_t error = AllocateRequest(allocator, &request);
1116 	if (error != B_OK)
1117 		return error;
1118 
1119 	request->volume = fUserlandVolume;
1120 	request->node = node;
1121 	request->mode = mode;
1122 
1123 	// send the request
1124 	KernelRequestHandler handler(this, ACCESS_REPLY);
1125 	AccessReply* reply;
1126 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
1127 	if (error != B_OK)
1128 		return error;
1129 	RequestReleaser requestReleaser(port, reply);
1130 
1131 	// process the reply
1132 	if (reply->error != B_OK)
1133 		return reply->error;
1134 	return error;
1135 }
1136 
1137 // ReadStat
1138 status_t
1139 Volume::ReadStat(fs_vnode node, struct stat* st)
1140 {
1141 	// When the connection to the userland server is lost, we serve
1142 	// read_stat(fRootNode) requests manually to allow clean unmounting.
1143 	status_t error = _ReadStat(node, st);
1144 	if (error != B_OK && fFileSystem->GetPortPool()->IsDisconnected()
1145 		&& node == fRootNode) {
1146 		WARN(("Volume::ReadStat(): connection lost, emulating stat for the "
1147 			"root node\n"));
1148 
1149 		st->st_dev = fID;
1150 		st->st_ino = fRootID;
1151 		st->st_mode = ACCESSPERMS;
1152 		st->st_nlink = 1;
1153 		st->st_uid = 0;
1154 		st->st_gid = 0;
1155 		st->st_size = 512;
1156 		st->st_blksize = 512;
1157 		st->st_atime = 0;
1158 		st->st_mtime = 0;
1159 		st->st_ctime = 0;
1160 		st->st_crtime = 0;
1161 
1162 		error = B_OK;
1163 	}
1164 	return error;
1165 }
1166 
1167 // WriteStat
1168 status_t
1169 Volume::WriteStat(fs_vnode node, const struct stat* st, uint32 mask)
1170 {
1171 	// check capability
1172 	if (!fFileSystem->HasCapability(FS_CAPABILITY_WRITE_STAT))
1173 		return B_BAD_VALUE;
1174 
1175 	// get a free port
1176 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
1177 	if (!port)
1178 		return B_ERROR;
1179 	PortReleaser _(fFileSystem->GetPortPool(), port);
1180 
1181 	// prepare the request
1182 	RequestAllocator allocator(port->GetPort());
1183 	WriteStatRequest* request;
1184 	status_t error = AllocateRequest(allocator, &request);
1185 	if (error != B_OK)
1186 		return error;
1187 
1188 	request->volume = fUserlandVolume;
1189 	request->node = node;
1190 	request->st = *st;
1191 	request->mask = mask;
1192 
1193 	// send the request
1194 	KernelRequestHandler handler(this, WRITE_STAT_REPLY);
1195 	WriteStatReply* reply;
1196 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
1197 	if (error != B_OK)
1198 		return error;
1199 	RequestReleaser requestReleaser(port, reply);
1200 
1201 	// process the reply
1202 	if (reply->error != B_OK)
1203 		return reply->error;
1204 	return error;
1205 }
1206 
1207 
1208 // #pragma mark - files
1209 
1210 // Create
1211 status_t
1212 Volume::Create(fs_vnode dir, const char* name, int openMode, int mode,
1213 	void** cookie, ino_t* vnid)
1214 {
1215 	// check capability
1216 	if (!fFileSystem->HasCapability(FS_CAPABILITY_CREATE))
1217 		return B_BAD_VALUE;
1218 
1219 	// get a free port
1220 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
1221 	if (!port)
1222 		return B_ERROR;
1223 	PortReleaser _(fFileSystem->GetPortPool(), port);
1224 	AutoIncrementer incrementer(&fOpenFiles);
1225 
1226 	// prepare the request
1227 	RequestAllocator allocator(port->GetPort());
1228 	CreateRequest* request;
1229 	status_t error = AllocateRequest(allocator, &request);
1230 	if (error != B_OK)
1231 		return error;
1232 
1233 	request->volume = fUserlandVolume;
1234 	request->node = dir;
1235 	error = allocator.AllocateString(request->name, name);
1236 	request->openMode = openMode;
1237 	request->mode = mode;
1238 	if (error != B_OK)
1239 		return error;
1240 
1241 	// send the request
1242 	KernelRequestHandler handler(this, CREATE_REPLY);
1243 	CreateReply* reply;
1244 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
1245 	if (error != B_OK)
1246 		return error;
1247 	RequestReleaser requestReleaser(port, reply);
1248 
1249 	// process the reply
1250 	if (reply->error != B_OK)
1251 		return reply->error;
1252 	incrementer.Keep();
1253 	*vnid = reply->vnid;
1254 	*cookie = reply->fileCookie;
1255 	// The VFS will balance the new_vnode() call for the FS.
1256 	if (error == B_OK)
1257 		_DecrementVNodeCount(*vnid);
1258 	return error;
1259 }
1260 
1261 // Open
1262 status_t
1263 Volume::Open(fs_vnode node, int openMode, fs_cookie* cookie)
1264 {
1265 	// check capability
1266 	if (!fFileSystem->HasCapability(FS_CAPABILITY_OPEN))
1267 		return B_BAD_VALUE;
1268 
1269 	// get a free port
1270 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
1271 	if (!port)
1272 		return B_ERROR;
1273 	PortReleaser _(fFileSystem->GetPortPool(), port);
1274 	AutoIncrementer incrementer(&fOpenFiles);
1275 
1276 	// prepare the request
1277 	RequestAllocator allocator(port->GetPort());
1278 	OpenRequest* request;
1279 	status_t error = AllocateRequest(allocator, &request);
1280 	if (error != B_OK)
1281 		return error;
1282 	request->volume = fUserlandVolume;
1283 	request->node = node;
1284 	request->openMode = openMode;
1285 
1286 	// send the request
1287 	KernelRequestHandler handler(this, OPEN_REPLY);
1288 	OpenReply* reply;
1289 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
1290 	if (error != B_OK)
1291 		return error;
1292 	RequestReleaser requestReleaser(port, reply);
1293 
1294 	// process the reply
1295 	if (reply->error != B_OK)
1296 		return reply->error;
1297 	incrementer.Keep();
1298 	*cookie = reply->fileCookie;
1299 	return error;
1300 }
1301 
1302 // Close
1303 status_t
1304 Volume::Close(fs_vnode node, fs_cookie cookie)
1305 {
1306 	status_t error = _Close(node, cookie);
1307 	if (error != B_OK && fFileSystem->GetPortPool()->IsDisconnected()) {
1308 		// This isn't really necessary, as the return value is irrelevant to
1309 		// the VFS. OBOS ignores it completely. The fsshell returns it to the
1310 		// userland, but considers the node closed anyway.
1311 		WARN(("Volume::Close(): connection lost, forcing close\n"));
1312 		return B_OK;
1313 	}
1314 	return error;
1315 }
1316 
1317 // FreeCookie
1318 status_t
1319 Volume::FreeCookie(fs_vnode node, fs_cookie cookie)
1320 {
1321 	status_t error = _FreeCookie(node, cookie);
1322 	bool disconnected = false;
1323 	if (error != B_OK && fFileSystem->GetPortPool()->IsDisconnected()) {
1324 		// This isn't really necessary, as the return value is irrelevant to
1325 		// the VFS. It's completely ignored by OBOS as well as by the fsshell.
1326 		WARN(("Volume::FreeCookie(): connection lost, forcing free cookie\n"));
1327 		error = B_OK;
1328 		disconnected = true;
1329 	}
1330 
1331 	int32 openFiles = atomic_add(&fOpenFiles, -1);
1332 	if (openFiles <= 1 && disconnected)
1333 		_PutAllPendingVNodes();
1334 	return error;
1335 }
1336 
1337 // Read
1338 status_t
1339 Volume::Read(fs_vnode node, fs_cookie cookie, off_t pos, void* buffer,
1340 	size_t bufferSize, size_t* bytesRead)
1341 {
1342 	*bytesRead = 0;
1343 
1344 	// check capability
1345 	if (!fFileSystem->HasCapability(FS_CAPABILITY_READ))
1346 		return B_BAD_VALUE;
1347 
1348 	// get a free port
1349 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
1350 	if (!port)
1351 		return B_ERROR;
1352 	PortReleaser _(fFileSystem->GetPortPool(), port);
1353 
1354 	// prepare the request
1355 	RequestAllocator allocator(port->GetPort());
1356 	ReadRequest* request;
1357 	status_t error = AllocateRequest(allocator, &request);
1358 	if (error != B_OK)
1359 		return error;
1360 
1361 	request->volume = fUserlandVolume;
1362 	request->node = node;
1363 	request->fileCookie = cookie;
1364 	request->pos = pos;
1365 	request->size = bufferSize;
1366 
1367 	// send the request
1368 	KernelRequestHandler handler(this, READ_REPLY);
1369 	ReadReply* reply;
1370 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
1371 	if (error != B_OK)
1372 		return error;
1373 	RequestReleaser requestReleaser(port, reply);
1374 
1375 	// process the reply
1376 	if (reply->error != B_OK)
1377 		return reply->error;
1378 	void* readBuffer = reply->buffer.GetData();
1379 	if (reply->bytesRead > (uint32)reply->buffer.GetSize()
1380 		|| reply->bytesRead > bufferSize) {
1381 		return B_BAD_DATA;
1382 	}
1383 	if (reply->bytesRead > 0)
1384 		memcpy(buffer, readBuffer, reply->bytesRead);
1385 	*bytesRead = reply->bytesRead;
1386 	_SendReceiptAck(port);
1387 	return error;
1388 }
1389 
1390 // Write
1391 status_t
1392 Volume::Write(fs_vnode node, fs_cookie cookie, off_t pos, const void* buffer,
1393 	size_t size, size_t* bytesWritten)
1394 {
1395 	*bytesWritten = 0;
1396 
1397 	// check capability
1398 	if (!fFileSystem->HasCapability(FS_CAPABILITY_WRITE))
1399 		return B_BAD_VALUE;
1400 
1401 	// get a free port
1402 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
1403 	if (!port)
1404 		return B_ERROR;
1405 	PortReleaser _(fFileSystem->GetPortPool(), port);
1406 
1407 	// prepare the request
1408 	RequestAllocator allocator(port->GetPort());
1409 	WriteRequest* request;
1410 	status_t error = AllocateRequest(allocator, &request);
1411 	if (error != B_OK)
1412 		return error;
1413 
1414 	request->volume = fUserlandVolume;
1415 	request->node = node;
1416 	request->fileCookie = cookie;
1417 	request->pos = pos;
1418 	error = allocator.AllocateData(request->buffer, buffer, size, 1);
1419 	if (error != B_OK)
1420 		return error;
1421 
1422 	// send the request
1423 	KernelRequestHandler handler(this, WRITE_REPLY);
1424 	WriteReply* reply;
1425 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
1426 	if (error != B_OK)
1427 		return error;
1428 	RequestReleaser requestReleaser(port, reply);
1429 
1430 	// process the reply
1431 	if (reply->error != B_OK)
1432 		return reply->error;
1433 	*bytesWritten = reply->bytesWritten;
1434 	return error;
1435 }
1436 
1437 
1438 // #pragma mark - directories
1439 
1440 // CreateDir
1441 status_t
1442 Volume::CreateDir(fs_vnode dir, const char* name, int mode, ino_t *newDir)
1443 {
1444 	// check capability
1445 	if (!fFileSystem->HasCapability(FS_CAPABILITY_CREATE_DIR))
1446 		return B_BAD_VALUE;
1447 
1448 	// get a free port
1449 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
1450 	if (!port)
1451 		return B_ERROR;
1452 	PortReleaser _(fFileSystem->GetPortPool(), port);
1453 
1454 	// prepare the request
1455 	RequestAllocator allocator(port->GetPort());
1456 	CreateDirRequest* request;
1457 	status_t error = AllocateRequest(allocator, &request);
1458 	if (error != B_OK)
1459 		return error;
1460 
1461 	request->volume = fUserlandVolume;
1462 	request->node = dir;
1463 	error = allocator.AllocateString(request->name, name);
1464 	request->mode = mode;
1465 	if (error != B_OK)
1466 		return error;
1467 
1468 	// send the request
1469 	KernelRequestHandler handler(this, CREATE_DIR_REPLY);
1470 	CreateDirReply* reply;
1471 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
1472 	if (error != B_OK)
1473 		return error;
1474 	RequestReleaser requestReleaser(port, reply);
1475 
1476 	// process the reply
1477 	if (reply->error != B_OK)
1478 		return reply->error;
1479 	*newDir = reply->newDir;
1480 	return error;
1481 }
1482 
1483 // RemoveDir
1484 status_t
1485 Volume::RemoveDir(fs_vnode dir, const char* name)
1486 {
1487 	// check capability
1488 	if (!fFileSystem->HasCapability(FS_CAPABILITY_REMOVE_DIR))
1489 		return B_BAD_VALUE;
1490 
1491 	// get a free port
1492 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
1493 	if (!port)
1494 		return B_ERROR;
1495 	PortReleaser _(fFileSystem->GetPortPool(), port);
1496 
1497 	// prepare the request
1498 	RequestAllocator allocator(port->GetPort());
1499 	RemoveDirRequest* request;
1500 	status_t error = AllocateRequest(allocator, &request);
1501 	if (error != B_OK)
1502 		return error;
1503 
1504 	request->volume = fUserlandVolume;
1505 	request->node = dir;
1506 	error = allocator.AllocateString(request->name, name);
1507 	if (error != B_OK)
1508 		return error;
1509 
1510 	// send the request
1511 	KernelRequestHandler handler(this, REMOVE_DIR_REPLY);
1512 	RemoveDirReply* reply;
1513 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
1514 	if (error != B_OK)
1515 		return error;
1516 	RequestReleaser requestReleaser(port, reply);
1517 
1518 	// process the reply
1519 	if (reply->error != B_OK)
1520 		return reply->error;
1521 	return error;
1522 }
1523 
1524 // OpenDir
1525 status_t
1526 Volume::OpenDir(fs_vnode node, fs_cookie* cookie)
1527 {
1528 	// check capability
1529 	if (!fFileSystem->HasCapability(FS_CAPABILITY_OPEN_DIR))
1530 		return B_BAD_VALUE;
1531 
1532 	// get a free port
1533 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
1534 	if (!port)
1535 		return B_ERROR;
1536 	PortReleaser _(fFileSystem->GetPortPool(), port);
1537 	AutoIncrementer incrementer(&fOpenDirectories);
1538 
1539 	// prepare the request
1540 	RequestAllocator allocator(port->GetPort());
1541 	OpenDirRequest* request;
1542 	status_t error = AllocateRequest(allocator, &request);
1543 	if (error != B_OK)
1544 		return error;
1545 
1546 	request->volume = fUserlandVolume;
1547 	request->node = node;
1548 
1549 	// send the request
1550 	KernelRequestHandler handler(this, OPEN_DIR_REPLY);
1551 	OpenDirReply* reply;
1552 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
1553 	if (error != B_OK)
1554 		return error;
1555 	RequestReleaser requestReleaser(port, reply);
1556 
1557 	// process the reply
1558 	if (reply->error != B_OK)
1559 		return reply->error;
1560 	incrementer.Keep();
1561 	*cookie = reply->dirCookie;
1562 	return error;
1563 }
1564 
1565 // CloseDir
1566 status_t
1567 Volume::CloseDir(fs_vnode node, fs_vnode cookie)
1568 {
1569 	status_t error = _CloseDir(node, cookie);
1570 	if (error != B_OK && fFileSystem->GetPortPool()->IsDisconnected()) {
1571 		// This isn't really necessary, as the return value is irrelevant to
1572 		// the VFS. OBOS ignores it completely. The fsshell returns it to the
1573 		// userland, but considers the node closed anyway.
1574 		WARN(("Volume::CloseDir(): connection lost, forcing close dir\n"));
1575 		return B_OK;
1576 	}
1577 	return error;
1578 }
1579 
1580 // FreeDirCookie
1581 status_t
1582 Volume::FreeDirCookie(void* node, void* cookie)
1583 {
1584 	status_t error = _FreeDirCookie(node, cookie);
1585 	bool disconnected = false;
1586 	if (error != B_OK && fFileSystem->GetPortPool()->IsDisconnected()) {
1587 		// This isn't really necessary, as the return value is irrelevant to
1588 		// the VFS. It's completely ignored by OBOS as well as by the fsshell.
1589 		WARN(("Volume::FreeDirCookie(): connection lost, forcing free dir "
1590 			"cookie\n"));
1591 		error = B_OK;
1592 		disconnected = true;
1593 	}
1594 	int32 openDirs = atomic_add(&fOpenDirectories, -1);
1595 	if (openDirs <= 1 && disconnected)
1596 		_PutAllPendingVNodes();
1597 	return error;
1598 }
1599 
1600 // ReadDir
1601 status_t
1602 Volume::ReadDir(fs_vnode node, fs_vnode cookie, void* buffer, size_t bufferSize,
1603 	uint32 count, uint32* countRead)
1604 {
1605 	*countRead = 0;
1606 
1607 	// check capability
1608 	if (!fFileSystem->HasCapability(FS_CAPABILITY_READ_DIR))
1609 		return B_BAD_VALUE;
1610 
1611 	// get a free port
1612 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
1613 	if (!port)
1614 		return B_ERROR;
1615 	PortReleaser _(fFileSystem->GetPortPool(), port);
1616 
1617 	// prepare the request
1618 	RequestAllocator allocator(port->GetPort());
1619 	ReadDirRequest* request;
1620 	status_t error = AllocateRequest(allocator, &request);
1621 	if (error != B_OK)
1622 		return error;
1623 
1624 	request->volume = fUserlandVolume;
1625 	request->node = node;
1626 	request->dirCookie = cookie;
1627 	request->bufferSize = bufferSize;
1628 	request->count = count;
1629 
1630 	// send the request
1631 	KernelRequestHandler handler(this, READ_DIR_REPLY);
1632 	ReadDirReply* reply;
1633 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
1634 	if (error != B_OK)
1635 		return error;
1636 	RequestReleaser requestReleaser(port, reply);
1637 
1638 	// process the reply
1639 	if (reply->error != B_OK)
1640 		return reply->error;
1641 	if (reply->count < 0 || reply->count > count)
1642 		return B_BAD_DATA;
1643 	if ((int32)bufferSize < reply->buffer.GetSize())
1644 		return B_BAD_DATA;
1645 PRINT(("Volume::ReadDir(): buffer returned: %ld bytes\n",
1646 reply->buffer.GetSize()));
1647 
1648 	*countRead = reply->count;
1649 	if (*countRead > 0) {
1650 		// copy the buffer -- limit the number of bytes to copy
1651 		uint32 maxBytes = *countRead
1652 			* (sizeof(struct dirent) + B_FILE_NAME_LENGTH);
1653 		uint32 copyBytes = reply->buffer.GetSize();
1654 		if (copyBytes > maxBytes)
1655 			copyBytes = maxBytes;
1656 		memcpy(buffer, reply->buffer.GetData(), copyBytes);
1657 	}
1658 	_SendReceiptAck(port);
1659 	return error;
1660 }
1661 
1662 // RewindDir
1663 status_t
1664 Volume::RewindDir(fs_vnode node, fs_vnode cookie)
1665 {
1666 	// check capability
1667 	if (!fFileSystem->HasCapability(FS_CAPABILITY_REWIND_DIR))
1668 		return B_BAD_VALUE;
1669 
1670 	// get a free port
1671 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
1672 	if (!port)
1673 		return B_ERROR;
1674 	PortReleaser _(fFileSystem->GetPortPool(), port);
1675 
1676 	// prepare the request
1677 	RequestAllocator allocator(port->GetPort());
1678 	RewindDirRequest* request;
1679 	status_t error = AllocateRequest(allocator, &request);
1680 	if (error != B_OK)
1681 		return error;
1682 
1683 	request->volume = fUserlandVolume;
1684 	request->node = node;
1685 	request->dirCookie = cookie;
1686 
1687 	// send the request
1688 	KernelRequestHandler handler(this, REWIND_DIR_REPLY);
1689 	RewindDirReply* reply;
1690 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
1691 	if (error != B_OK)
1692 		return error;
1693 	RequestReleaser requestReleaser(port, reply);
1694 
1695 	// process the reply
1696 	if (reply->error != B_OK)
1697 		return reply->error;
1698 	return error;
1699 }
1700 
1701 
1702 // #pragma mark - attribute directories
1703 
1704 
1705 // OpenAttrDir
1706 status_t
1707 Volume::OpenAttrDir(fs_vnode node, fs_cookie *cookie)
1708 {
1709 	// check capability
1710 	if (!fFileSystem->HasCapability(FS_CAPABILITY_OPEN_ATTR_DIR))
1711 		return B_BAD_VALUE;
1712 
1713 	// get a free port
1714 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
1715 	if (!port)
1716 		return B_ERROR;
1717 	PortReleaser _(fFileSystem->GetPortPool(), port);
1718 	AutoIncrementer incrementer(&fOpenAttributeDirectories);
1719 
1720 	// prepare the request
1721 	RequestAllocator allocator(port->GetPort());
1722 	OpenAttrDirRequest* request;
1723 	status_t error = AllocateRequest(allocator, &request);
1724 	if (error != B_OK)
1725 		return error;
1726 
1727 	request->volume = fUserlandVolume;
1728 	request->node = node;
1729 
1730 	// send the request
1731 	KernelRequestHandler handler(this, OPEN_ATTR_DIR_REPLY);
1732 	OpenAttrDirReply* reply;
1733 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
1734 	if (error != B_OK)
1735 		return error;
1736 	RequestReleaser requestReleaser(port, reply);
1737 
1738 	// process the reply
1739 	if (reply->error != B_OK)
1740 		return reply->error;
1741 	incrementer.Keep();
1742 	*cookie = reply->attrDirCookie;
1743 	return error;
1744 }
1745 
1746 // CloseAttrDir
1747 status_t
1748 Volume::CloseAttrDir(fs_vnode node, fs_cookie cookie)
1749 {
1750 	status_t error = _CloseAttrDir(node, cookie);
1751 	if (error != B_OK && fFileSystem->GetPortPool()->IsDisconnected()) {
1752 		// This isn't really necessary, as the return value is irrelevant to
1753 		// the VFS. OBOS ignores it completely. The fsshell returns it to the
1754 		// userland, but considers the node closed anyway.
1755 		WARN(("Volume::CloseAttrDir(): connection lost, forcing close attr "
1756 			"dir\n"));
1757 		return B_OK;
1758 	}
1759 	return error;
1760 }
1761 
1762 // FreeAttrDirCookie
1763 status_t
1764 Volume::FreeAttrDirCookie(void* node, void* cookie)
1765 {
1766 	status_t error = _FreeAttrDirCookie(node, cookie);
1767 	bool disconnected = false;
1768 	if (error != B_OK && fFileSystem->GetPortPool()->IsDisconnected()) {
1769 		// This isn't really necessary, as the return value is irrelevant to
1770 		// the VFS. It's completely ignored by OBOS as well as by the fsshell.
1771 		WARN(("Volume::FreeAttrDirCookie(): connection lost, forcing free attr "
1772 			"dir cookie\n"));
1773 		error = B_OK;
1774 		disconnected = true;
1775 	}
1776 
1777 	int32 openAttrDirs = atomic_add(&fOpenAttributeDirectories, -1);
1778 	if (openAttrDirs <= 1 && disconnected)
1779 		_PutAllPendingVNodes();
1780 	return error;
1781 }
1782 
1783 // ReadAttrDir
1784 status_t
1785 Volume::ReadAttrDir(fs_vnode node, fs_cookie cookie, void* buffer,
1786 	size_t bufferSize, uint32 count, uint32* countRead)
1787 {
1788 	// check capability
1789 	if (!fFileSystem->HasCapability(FS_CAPABILITY_READ_ATTR_DIR))
1790 		return B_BAD_VALUE;
1791 
1792 	*countRead = 0;
1793 	// get a free port
1794 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
1795 	if (!port)
1796 		return B_ERROR;
1797 	PortReleaser _(fFileSystem->GetPortPool(), port);
1798 
1799 	// prepare the request
1800 	RequestAllocator allocator(port->GetPort());
1801 	ReadAttrDirRequest* request;
1802 	status_t error = AllocateRequest(allocator, &request);
1803 	if (error != B_OK)
1804 		return error;
1805 
1806 	request->volume = fUserlandVolume;
1807 	request->node = node;
1808 	request->attrDirCookie = cookie;
1809 	request->bufferSize = bufferSize;
1810 	request->count = count;
1811 
1812 	// send the request
1813 	KernelRequestHandler handler(this, READ_ATTR_DIR_REPLY);
1814 	ReadAttrDirReply* reply;
1815 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
1816 	if (error != B_OK)
1817 		return error;
1818 	RequestReleaser requestReleaser(port, reply);
1819 
1820 	// process the reply
1821 	if (reply->error != B_OK)
1822 		return reply->error;
1823 	if (reply->count < 0 || reply->count > count)
1824 		return B_BAD_DATA;
1825 	if ((int32)bufferSize < reply->buffer.GetSize())
1826 		return B_BAD_DATA;
1827 
1828 	*countRead = reply->count;
1829 	if (*countRead > 0) {
1830 		// copy the buffer -- limit the number of bytes to copy
1831 		uint32 maxBytes = *countRead
1832 			* (sizeof(struct dirent) + B_ATTR_NAME_LENGTH);
1833 		uint32 copyBytes = reply->buffer.GetSize();
1834 		if (copyBytes > maxBytes)
1835 			copyBytes = maxBytes;
1836 		memcpy(buffer, reply->buffer.GetData(), copyBytes);
1837 	}
1838 	_SendReceiptAck(port);
1839 	return error;
1840 }
1841 
1842 // RewindAttrDir
1843 status_t
1844 Volume::RewindAttrDir(fs_vnode node, fs_cookie cookie)
1845 {
1846 	// check capability
1847 	if (!fFileSystem->HasCapability(FS_CAPABILITY_REWIND_ATTR_DIR))
1848 		return B_BAD_VALUE;
1849 
1850 	// get a free port
1851 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
1852 	if (!port)
1853 		return B_ERROR;
1854 	PortReleaser _(fFileSystem->GetPortPool(), port);
1855 
1856 	// prepare the request
1857 	RequestAllocator allocator(port->GetPort());
1858 	RewindAttrDirRequest* request;
1859 	status_t error = AllocateRequest(allocator, &request);
1860 	if (error != B_OK)
1861 		return error;
1862 
1863 	request->volume = fUserlandVolume;
1864 	request->node = node;
1865 	request->attrDirCookie = cookie;
1866 
1867 	// send the request
1868 	KernelRequestHandler handler(this, REWIND_ATTR_DIR_REPLY);
1869 	RewindAttrDirReply* reply;
1870 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
1871 	if (error != B_OK)
1872 		return error;
1873 	RequestReleaser requestReleaser(port, reply);
1874 
1875 	// process the reply
1876 	if (reply->error != B_OK)
1877 		return reply->error;
1878 	return error;
1879 }
1880 
1881 
1882 // #pragma mark - attributes
1883 
1884 // CreateAttr
1885 status_t
1886 Volume::CreateAttr(fs_vnode node, const char* name, uint32 type, int openMode,
1887 	fs_cookie* cookie)
1888 {
1889 	// check capability
1890 	if (!fFileSystem->HasCapability(FS_CAPABILITY_CREATE_ATTR))
1891 		return B_BAD_VALUE;
1892 
1893 	// get a free port
1894 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
1895 	if (!port)
1896 		return B_ERROR;
1897 	PortReleaser _(fFileSystem->GetPortPool(), port);
1898 	AutoIncrementer incrementer(&fOpenAttributes);
1899 
1900 	// prepare the request
1901 	RequestAllocator allocator(port->GetPort());
1902 	CreateAttrRequest* request;
1903 	status_t error = AllocateRequest(allocator, &request);
1904 	if (error != B_OK)
1905 		return error;
1906 
1907 	request->volume = fUserlandVolume;
1908 	request->node = node;
1909 	error = allocator.AllocateString(request->name, name);
1910 	request->type = type;
1911 	request->openMode = openMode;
1912 	if (error != B_OK)
1913 		return error;
1914 
1915 	// send the request
1916 	KernelRequestHandler handler(this, CREATE_ATTR_REPLY);
1917 	CreateAttrReply* reply;
1918 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
1919 	if (error != B_OK)
1920 		return error;
1921 	RequestReleaser requestReleaser(port, reply);
1922 
1923 	// process the reply
1924 	if (reply->error != B_OK)
1925 		return reply->error;
1926 	incrementer.Keep();
1927 	*cookie = reply->attrCookie;
1928 	return error;
1929 }
1930 
1931 // OpenAttr
1932 status_t
1933 Volume::OpenAttr(fs_vnode node, const char* name, int openMode,
1934 	fs_cookie* cookie)
1935 {
1936 	// check capability
1937 	if (!fFileSystem->HasCapability(FS_CAPABILITY_OPEN_ATTR))
1938 		return B_BAD_VALUE;
1939 
1940 	// get a free port
1941 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
1942 	if (!port)
1943 		return B_ERROR;
1944 	PortReleaser _(fFileSystem->GetPortPool(), port);
1945 	AutoIncrementer incrementer(&fOpenAttributes);
1946 
1947 	// prepare the request
1948 	RequestAllocator allocator(port->GetPort());
1949 	OpenAttrRequest* request;
1950 	status_t error = AllocateRequest(allocator, &request);
1951 	if (error != B_OK)
1952 		return error;
1953 
1954 	request->volume = fUserlandVolume;
1955 	request->node = node;
1956 	error = allocator.AllocateString(request->name, name);
1957 	request->openMode = openMode;
1958 	if (error != B_OK)
1959 		return error;
1960 
1961 	// send the request
1962 	KernelRequestHandler handler(this, OPEN_ATTR_REPLY);
1963 	OpenAttrReply* reply;
1964 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
1965 	if (error != B_OK)
1966 		return error;
1967 	RequestReleaser requestReleaser(port, reply);
1968 
1969 	// process the reply
1970 	if (reply->error != B_OK)
1971 		return reply->error;
1972 	incrementer.Keep();
1973 	*cookie = reply->attrCookie;
1974 	return error;
1975 }
1976 
1977 // CloseAttr
1978 status_t
1979 Volume::CloseAttr(fs_vnode node, fs_cookie cookie)
1980 {
1981 	status_t error = _CloseAttr(node, cookie);
1982 	if (error != B_OK && fFileSystem->GetPortPool()->IsDisconnected()) {
1983 		// This isn't really necessary, as the return value is irrelevant to
1984 		// the VFS. OBOS ignores it completely. The fsshell returns it to the
1985 		// userland, but considers the node closed anyway.
1986 		WARN(("Volume::CloseAttr(): connection lost, forcing close attr\n"));
1987 		return B_OK;
1988 	}
1989 	return error;
1990 }
1991 
1992 // FreeAttrCookie
1993 status_t
1994 Volume::FreeAttrCookie(fs_vnode node, fs_cookie cookie)
1995 {
1996 	status_t error = _FreeAttrCookie(node, cookie);
1997 	bool disconnected = false;
1998 	if (error != B_OK && fFileSystem->GetPortPool()->IsDisconnected()) {
1999 		// This isn't really necessary, as the return value is irrelevant to
2000 		// the VFS. It's completely ignored by OBOS as well as by the fsshell.
2001 		WARN(("Volume::FreeAttrCookie(): connection lost, forcing free attr "
2002 			"cookie\n"));
2003 		error = B_OK;
2004 		disconnected = true;
2005 	}
2006 
2007 	int32 openAttributes = atomic_add(&fOpenAttributes, -1);
2008 	if (openAttributes <= 1 && disconnected)
2009 		_PutAllPendingVNodes();
2010 	return error;
2011 }
2012 
2013 // ReadAttr
2014 status_t
2015 Volume::ReadAttr(fs_vnode node, fs_cookie cookie, off_t pos,
2016 	void* buffer, size_t bufferSize, size_t* bytesRead)
2017 {
2018 	*bytesRead = 0;
2019 
2020 	// check capability
2021 	if (!fFileSystem->HasCapability(FS_CAPABILITY_READ_ATTR))
2022 		return B_BAD_VALUE;
2023 
2024 	// get a free port
2025 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
2026 	if (!port)
2027 		return B_ERROR;
2028 	PortReleaser _(fFileSystem->GetPortPool(), port);
2029 
2030 	// prepare the request
2031 	RequestAllocator allocator(port->GetPort());
2032 	ReadAttrRequest* request;
2033 	status_t error = AllocateRequest(allocator, &request);
2034 	if (error != B_OK)
2035 		return error;
2036 
2037 	request->volume = fUserlandVolume;
2038 	request->node = node;
2039 	request->attrCookie = cookie;
2040 	request->pos = pos;
2041 	request->size = bufferSize;
2042 
2043 	// send the request
2044 	KernelRequestHandler handler(this, READ_ATTR_REPLY);
2045 	ReadAttrReply* reply;
2046 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
2047 	if (error != B_OK)
2048 		return error;
2049 	RequestReleaser requestReleaser(port, reply);
2050 
2051 	// process the reply
2052 	if (reply->error != B_OK)
2053 		return reply->error;
2054 	void* readBuffer = reply->buffer.GetData();
2055 	if (reply->bytesRead > (uint32)reply->buffer.GetSize()
2056 		|| reply->bytesRead > bufferSize) {
2057 		return B_BAD_DATA;
2058 	}
2059 	if (reply->bytesRead > 0)
2060 		memcpy(buffer, readBuffer, reply->bytesRead);
2061 	*bytesRead = reply->bytesRead;
2062 	_SendReceiptAck(port);
2063 	return error;
2064 }
2065 
2066 // WriteAttr
2067 status_t
2068 Volume::WriteAttr(fs_vnode node, fs_cookie cookie, off_t pos,
2069 	const void* buffer, size_t bufferSize, size_t* bytesWritten)
2070 {
2071 	*bytesWritten = 0;
2072 
2073 	// check capability
2074 	if (!fFileSystem->HasCapability(FS_CAPABILITY_WRITE_ATTR))
2075 		return B_BAD_VALUE;
2076 
2077 	// get a free port
2078 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
2079 	if (!port)
2080 		return B_ERROR;
2081 	PortReleaser _(fFileSystem->GetPortPool(), port);
2082 
2083 	// prepare the request
2084 	RequestAllocator allocator(port->GetPort());
2085 	WriteAttrRequest* request;
2086 	status_t error = AllocateRequest(allocator, &request);
2087 	if (error != B_OK)
2088 		return error;
2089 
2090 	request->volume = fUserlandVolume;
2091 	request->node = node;
2092 	request->attrCookie = cookie;
2093 	request->pos = pos;
2094 	error = allocator.AllocateData(request->buffer, buffer, bufferSize, 1);
2095 	if (error != B_OK)
2096 		return error;
2097 
2098 	// send the request
2099 	KernelRequestHandler handler(this, WRITE_ATTR_REPLY);
2100 	WriteAttrReply* reply;
2101 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
2102 	if (error != B_OK)
2103 		return error;
2104 	RequestReleaser requestReleaser(port, reply);
2105 
2106 	// process the reply
2107 	if (reply->error != B_OK)
2108 		return reply->error;
2109 	*bytesWritten = reply->bytesWritten;
2110 	return error;
2111 }
2112 
2113 // ReadAttrStat
2114 status_t
2115 Volume::ReadAttrStat(fs_vnode node, fs_cookie cookie, struct stat *st)
2116 {
2117 	// check capability
2118 	if (!fFileSystem->HasCapability(FS_CAPABILITY_READ_ATTR_STAT))
2119 		return B_BAD_VALUE;
2120 
2121 	// get a free port
2122 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
2123 	if (!port)
2124 		return B_ERROR;
2125 	PortReleaser _(fFileSystem->GetPortPool(), port);
2126 
2127 	// prepare the request
2128 	RequestAllocator allocator(port->GetPort());
2129 	ReadAttrStatRequest* request;
2130 	status_t error = AllocateRequest(allocator, &request);
2131 	if (error != B_OK)
2132 		return error;
2133 
2134 	request->volume = fUserlandVolume;
2135 	request->node = node;
2136 	request->attrCookie = cookie;
2137 
2138 	// send the request
2139 	KernelRequestHandler handler(this, READ_ATTR_STAT_REPLY);
2140 	ReadAttrStatReply* reply;
2141 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
2142 	if (error != B_OK)
2143 		return error;
2144 	RequestReleaser requestReleaser(port, reply);
2145 
2146 	// process the reply
2147 	if (reply->error != B_OK)
2148 		return reply->error;
2149 	*st = reply->st;
2150 	return error;
2151 }
2152 
2153 // WriteAttrStat
2154 status_t
2155 Volume::WriteAttrStat(fs_vnode node, fs_cookie cookie, const struct stat *st,
2156 	int statMask)
2157 {
2158 	// check capability
2159 	if (!fFileSystem->HasCapability(FS_CAPABILITY_WRITE_ATTR_STAT))
2160 		return B_BAD_VALUE;
2161 
2162 	// get a free port
2163 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
2164 	if (!port)
2165 		return B_ERROR;
2166 	PortReleaser _(fFileSystem->GetPortPool(), port);
2167 
2168 	// prepare the request
2169 	RequestAllocator allocator(port->GetPort());
2170 	WriteAttrStatRequest* request;
2171 	status_t error = AllocateRequest(allocator, &request);
2172 	if (error != B_OK)
2173 		return error;
2174 
2175 	request->volume = fUserlandVolume;
2176 	request->node = node;
2177 	request->attrCookie = cookie;
2178 	request->st = *st;
2179 	request->mask = statMask;
2180 
2181 	// send the request
2182 	KernelRequestHandler handler(this, WRITE_ATTR_STAT_REPLY);
2183 	WriteAttrStatReply* reply;
2184 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
2185 	if (error != B_OK)
2186 		return error;
2187 	RequestReleaser requestReleaser(port, reply);
2188 
2189 	// process the reply
2190 	if (reply->error != B_OK)
2191 		return reply->error;
2192 	return error;
2193 }
2194 
2195 // RenameAttr
2196 status_t
2197 Volume::RenameAttr(fs_vnode oldNode, const char* oldName, fs_vnode newNode,
2198 	const char* newName)
2199 {
2200 	// check capability
2201 	if (!fFileSystem->HasCapability(FS_CAPABILITY_RENAME_ATTR))
2202 		return B_BAD_VALUE;
2203 
2204 	// get a free port
2205 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
2206 	if (!port)
2207 		return B_ERROR;
2208 	PortReleaser _(fFileSystem->GetPortPool(), port);
2209 
2210 	// prepare the request
2211 	RequestAllocator allocator(port->GetPort());
2212 	RenameAttrRequest* request;
2213 	status_t error = AllocateRequest(allocator, &request);
2214 	if (error != B_OK)
2215 		return error;
2216 
2217 	request->volume = fUserlandVolume;
2218 	request->oldNode = oldNode;
2219 	request->newNode = newNode;
2220 	error = allocator.AllocateString(request->oldName, oldName);
2221 	if (error == B_OK)
2222 		error = allocator.AllocateString(request->newName, newName);
2223 	if (error != B_OK)
2224 		return error;
2225 
2226 	// send the request
2227 	KernelRequestHandler handler(this, RENAME_ATTR_REPLY);
2228 	RenameAttrReply* reply;
2229 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
2230 	if (error != B_OK)
2231 		return error;
2232 	RequestReleaser requestReleaser(port, reply);
2233 
2234 	// process the reply
2235 	if (reply->error != B_OK)
2236 		return reply->error;
2237 	return error;
2238 }
2239 
2240 // RemoveAttr
2241 status_t
2242 Volume::RemoveAttr(fs_vnode node, const char* name)
2243 {
2244 	// check capability
2245 	if (!fFileSystem->HasCapability(FS_CAPABILITY_REMOVE_ATTR))
2246 		return B_BAD_VALUE;
2247 
2248 	// get a free port
2249 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
2250 	if (!port)
2251 		return B_ERROR;
2252 	PortReleaser _(fFileSystem->GetPortPool(), port);
2253 
2254 	// prepare the request
2255 	RequestAllocator allocator(port->GetPort());
2256 	RemoveAttrRequest* request;
2257 	status_t error = AllocateRequest(allocator, &request);
2258 	if (error != B_OK)
2259 		return error;
2260 
2261 	request->volume = fUserlandVolume;
2262 	request->node = node;
2263 	error = allocator.AllocateString(request->name, name);
2264 	if (error != B_OK)
2265 		return error;
2266 
2267 	// send the request
2268 	KernelRequestHandler handler(this, REMOVE_ATTR_REPLY);
2269 	RemoveAttrReply* reply;
2270 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
2271 	if (error != B_OK)
2272 		return error;
2273 	RequestReleaser requestReleaser(port, reply);
2274 
2275 	// process the reply
2276 	if (reply->error != B_OK)
2277 		return reply->error;
2278 	return error;
2279 }
2280 
2281 
2282 // #pragma mark - indices
2283 
2284 
2285 // OpenIndexDir
2286 status_t
2287 Volume::OpenIndexDir(fs_cookie *cookie)
2288 {
2289 	// check capability
2290 	if (!fFileSystem->HasCapability(FS_CAPABILITY_OPEN_INDEX_DIR))
2291 		return B_BAD_VALUE;
2292 
2293 	// get a free port
2294 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
2295 	if (!port)
2296 		return B_ERROR;
2297 	PortReleaser _(fFileSystem->GetPortPool(), port);
2298 	AutoIncrementer incrementer(&fOpenIndexDirectories);
2299 
2300 	// prepare the request
2301 	RequestAllocator allocator(port->GetPort());
2302 	OpenIndexDirRequest* request;
2303 	status_t error = AllocateRequest(allocator, &request);
2304 	if (error != B_OK)
2305 		return error;
2306 
2307 	request->volume = fUserlandVolume;
2308 
2309 	// send the request
2310 	KernelRequestHandler handler(this, OPEN_INDEX_DIR_REPLY);
2311 	OpenIndexDirReply* reply;
2312 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
2313 	if (error != B_OK)
2314 		return error;
2315 	RequestReleaser requestReleaser(port, reply);
2316 
2317 	// process the reply
2318 	if (reply->error != B_OK)
2319 		return reply->error;
2320 	incrementer.Keep();
2321 	*cookie = reply->indexDirCookie;
2322 	return error;
2323 }
2324 
2325 // CloseIndexDir
2326 status_t
2327 Volume::CloseIndexDir(fs_cookie cookie)
2328 {
2329 	status_t error = _CloseIndexDir(cookie);
2330 	if (error != B_OK && fFileSystem->GetPortPool()->IsDisconnected()) {
2331 		// This isn't really necessary, as the return value is irrelevant to
2332 		// the VFS. OBOS ignores it completely. The fsshell returns it to the
2333 		// userland, but considers the node closed anyway.
2334 		WARN(("Volume::CloseIndexDir(): connection lost, forcing close "
2335 			"index dir\n"));
2336 		return B_OK;
2337 	}
2338 	return error;
2339 }
2340 
2341 // FreeIndexDirCookie
2342 status_t
2343 Volume::FreeIndexDirCookie(fs_cookie cookie)
2344 {
2345 	status_t error = _FreeIndexDirCookie(cookie);
2346 	bool disconnected = false;
2347 	if (error != B_OK && fFileSystem->GetPortPool()->IsDisconnected()) {
2348 		// This isn't really necessary, as the return value is irrelevant to
2349 		// the VFS. It's completely ignored by OBOS as well as by the fsshell.
2350 		WARN(("Volume::FreeIndexDirCookie(): connection lost, forcing free "
2351 			"index dir cookie\n"));
2352 		error = B_OK;
2353 		disconnected = true;
2354 	}
2355 
2356 	int32 openIndexDirs = atomic_add(&fOpenIndexDirectories, -1);
2357 	if (openIndexDirs <= 1 && disconnected)
2358 		_PutAllPendingVNodes();
2359 	return error;
2360 }
2361 
2362 // ReadIndexDir
2363 status_t
2364 Volume::ReadIndexDir(fs_cookie cookie, void* buffer, size_t bufferSize,
2365 	uint32 count, uint32* countRead)
2366 {
2367 	*countRead = 0;
2368 
2369 	// check capability
2370 	if (!fFileSystem->HasCapability(FS_CAPABILITY_READ_INDEX_DIR))
2371 		return B_BAD_VALUE;
2372 
2373 	// get a free port
2374 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
2375 	if (!port)
2376 		return B_ERROR;
2377 	PortReleaser _(fFileSystem->GetPortPool(), port);
2378 
2379 	// prepare the request
2380 	RequestAllocator allocator(port->GetPort());
2381 	ReadIndexDirRequest* request;
2382 	status_t error = AllocateRequest(allocator, &request);
2383 	if (error != B_OK)
2384 		return error;
2385 
2386 	request->volume = fUserlandVolume;
2387 	request->indexDirCookie = cookie;
2388 	request->bufferSize = bufferSize;
2389 	request->count = count;
2390 
2391 	// send the request
2392 	KernelRequestHandler handler(this, READ_INDEX_DIR_REPLY);
2393 	ReadIndexDirReply* reply;
2394 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
2395 	if (error != B_OK)
2396 		return error;
2397 	RequestReleaser requestReleaser(port, reply);
2398 
2399 	// process the reply
2400 	if (reply->error != B_OK)
2401 		return reply->error;
2402 	if (reply->count < 0 || reply->count > count)
2403 		return B_BAD_DATA;
2404 	if ((int32)bufferSize < reply->buffer.GetSize())
2405 		return B_BAD_DATA;
2406 
2407 	*countRead = reply->count;
2408 	if (*countRead > 0) {
2409 		// copy the buffer -- limit the number of bytes to copy
2410 		uint32 maxBytes = *countRead
2411 			* (sizeof(struct dirent) + B_FILE_NAME_LENGTH);
2412 		uint32 copyBytes = reply->buffer.GetSize();
2413 		if (copyBytes > maxBytes)
2414 			copyBytes = maxBytes;
2415 		memcpy(buffer, reply->buffer.GetData(), copyBytes);
2416 	}
2417 	_SendReceiptAck(port);
2418 	return error;
2419 }
2420 
2421 // RewindIndexDir
2422 status_t
2423 Volume::RewindIndexDir(fs_cookie cookie)
2424 {
2425 	// check capability
2426 	if (!fFileSystem->HasCapability(FS_CAPABILITY_REWIND_INDEX_DIR))
2427 		return B_BAD_VALUE;
2428 
2429 	// get a free port
2430 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
2431 	if (!port)
2432 		return B_ERROR;
2433 	PortReleaser _(fFileSystem->GetPortPool(), port);
2434 
2435 	// prepare the request
2436 	RequestAllocator allocator(port->GetPort());
2437 	RewindIndexDirRequest* request;
2438 	status_t error = AllocateRequest(allocator, &request);
2439 	if (error != B_OK)
2440 		return error;
2441 
2442 	request->volume = fUserlandVolume;
2443 	request->indexDirCookie = cookie;
2444 
2445 	// send the request
2446 	KernelRequestHandler handler(this, REWIND_INDEX_DIR_REPLY);
2447 	RewindIndexDirReply* reply;
2448 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
2449 	if (error != B_OK)
2450 		return error;
2451 	RequestReleaser requestReleaser(port, reply);
2452 
2453 	// process the reply
2454 	if (reply->error != B_OK)
2455 		return reply->error;
2456 	return error;
2457 }
2458 
2459 // CreateIndex
2460 status_t
2461 Volume::CreateIndex(const char* name, uint32 type, uint32 flags)
2462 {
2463 	// check capability
2464 	if (!fFileSystem->HasCapability(FS_CAPABILITY_CREATE_INDEX))
2465 		return B_BAD_VALUE;
2466 
2467 	// get a free port
2468 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
2469 	if (!port)
2470 		return B_ERROR;
2471 	PortReleaser _(fFileSystem->GetPortPool(), port);
2472 
2473 	// prepare the request
2474 	RequestAllocator allocator(port->GetPort());
2475 	CreateIndexRequest* request;
2476 	status_t error = AllocateRequest(allocator, &request);
2477 	if (error != B_OK)
2478 		return error;
2479 
2480 	request->volume = fUserlandVolume;
2481 	error = allocator.AllocateString(request->name, name);
2482 	request->type = type;
2483 	request->flags = flags;
2484 	if (error != B_OK)
2485 		return error;
2486 
2487 	// send the request
2488 	KernelRequestHandler handler(this, CREATE_INDEX_REPLY);
2489 	CreateIndexReply* reply;
2490 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
2491 	if (error != B_OK)
2492 		return error;
2493 	RequestReleaser requestReleaser(port, reply);
2494 
2495 	// process the reply
2496 	if (reply->error != B_OK)
2497 		return reply->error;
2498 	return error;
2499 }
2500 
2501 // RemoveIndex
2502 status_t
2503 Volume::RemoveIndex(const char* name)
2504 {
2505 	// check capability
2506 	if (!fFileSystem->HasCapability(FS_CAPABILITY_REMOVE_INDEX))
2507 		return B_BAD_VALUE;
2508 
2509 	// get a free port
2510 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
2511 	if (!port)
2512 		return B_ERROR;
2513 	PortReleaser _(fFileSystem->GetPortPool(), port);
2514 
2515 	// prepare the request
2516 	RequestAllocator allocator(port->GetPort());
2517 	RemoveIndexRequest* request;
2518 	status_t error = AllocateRequest(allocator, &request);
2519 	if (error != B_OK)
2520 		return error;
2521 
2522 	request->volume = fUserlandVolume;
2523 	error = allocator.AllocateString(request->name, name);
2524 	if (error != B_OK)
2525 		return error;
2526 
2527 	// send the request
2528 	KernelRequestHandler handler(this, REMOVE_INDEX_REPLY);
2529 	RemoveIndexReply* reply;
2530 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
2531 	if (error != B_OK)
2532 		return error;
2533 	RequestReleaser requestReleaser(port, reply);
2534 
2535 	// process the reply
2536 	if (reply->error != B_OK)
2537 		return reply->error;
2538 	return error;
2539 }
2540 
2541 // ReadIndexStat
2542 status_t
2543 Volume::ReadIndexStat(const char* name, struct stat *st)
2544 {
2545 	// check capability
2546 	if (!fFileSystem->HasCapability(FS_CAPABILITY_READ_INDEX_STAT))
2547 		return B_BAD_VALUE;
2548 
2549 	// get a free port
2550 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
2551 	if (!port)
2552 		return B_ERROR;
2553 	PortReleaser _(fFileSystem->GetPortPool(), port);
2554 
2555 	// prepare the request
2556 	RequestAllocator allocator(port->GetPort());
2557 	ReadIndexStatRequest* request;
2558 	status_t error = AllocateRequest(allocator, &request);
2559 	if (error != B_OK)
2560 		return error;
2561 
2562 	request->volume = fUserlandVolume;
2563 	error = allocator.AllocateString(request->name, name);
2564 	if (error != B_OK)
2565 		return error;
2566 
2567 	// send the request
2568 	KernelRequestHandler handler(this, READ_INDEX_STAT_REPLY);
2569 	ReadIndexStatReply* reply;
2570 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
2571 	if (error != B_OK)
2572 		return error;
2573 	RequestReleaser requestReleaser(port, reply);
2574 
2575 	// process the reply
2576 	if (reply->error != B_OK)
2577 		return reply->error;
2578 	*st = reply->st;
2579 	return error;
2580 }
2581 
2582 
2583 // #pragma mark - queries
2584 
2585 
2586 // OpenQuery
2587 status_t
2588 Volume::OpenQuery(const char* queryString, uint32 flags, port_id targetPort,
2589 	uint32 token, fs_cookie *cookie)
2590 {
2591 	// check capability
2592 	if (!fFileSystem->HasCapability(FS_CAPABILITY_OPEN_QUERY))
2593 		return B_BAD_VALUE;
2594 
2595 	// get a free port
2596 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
2597 	if (!port)
2598 		return B_ERROR;
2599 	PortReleaser _(fFileSystem->GetPortPool(), port);
2600 	AutoIncrementer incrementer(&fOpenQueries);
2601 
2602 	// prepare the request
2603 	RequestAllocator allocator(port->GetPort());
2604 	OpenQueryRequest* request;
2605 	status_t error = AllocateRequest(allocator, &request);
2606 	if (error != B_OK)
2607 		return error;
2608 
2609 	request->volume = fUserlandVolume;
2610 	error = allocator.AllocateString(request->queryString, queryString);
2611 	if (error != B_OK)
2612 		return error;
2613 	request->flags = flags;
2614 	request->port = targetPort;
2615 	request->token = token;
2616 
2617 	// send the request
2618 	KernelRequestHandler handler(this, OPEN_QUERY_REPLY);
2619 	OpenQueryReply* reply;
2620 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
2621 	if (error != B_OK)
2622 		return error;
2623 	RequestReleaser requestReleaser(port, reply);
2624 
2625 	// process the reply
2626 	if (reply->error != B_OK)
2627 		return reply->error;
2628 	incrementer.Keep();
2629 	*cookie = reply->queryCookie;
2630 	return error;
2631 }
2632 
2633 // CloseQuery
2634 status_t
2635 Volume::CloseQuery(fs_cookie cookie)
2636 {
2637 	status_t error = _CloseQuery(cookie);
2638 	if (error != B_OK && fFileSystem->GetPortPool()->IsDisconnected()) {
2639 		// This isn't really necessary, as the return value is irrelevant to
2640 		// the VFS. OBOS ignores it completely. The fsshell returns it to the
2641 		// userland, but considers the node closed anyway.
2642 		WARN(("Volume::CloseQuery(): connection lost, forcing close query\n"));
2643 		return B_OK;
2644 	}
2645 	return error;
2646 }
2647 
2648 // FreeQueryCookie
2649 status_t
2650 Volume::FreeQueryCookie(fs_cookie cookie)
2651 {
2652 	status_t error = _FreeQueryCookie(cookie);
2653 	bool disconnected = false;
2654 	if (error != B_OK && fFileSystem->GetPortPool()->IsDisconnected()) {
2655 		// This isn't really necessary, as the return value is irrelevant to
2656 		// the VFS. It's completely ignored by OBOS as well as by the fsshell.
2657 		WARN(("Volume::FreeQueryCookie(): connection lost, forcing free "
2658 			"query cookie\n"));
2659 		error = B_OK;
2660 		disconnected = true;
2661 	}
2662 
2663 	int32 openQueries = atomic_add(&fOpenQueries, -1);
2664 	if (openQueries <= 1 && disconnected)
2665 		_PutAllPendingVNodes();
2666 	return error;
2667 }
2668 
2669 // ReadQuery
2670 status_t
2671 Volume::ReadQuery(fs_cookie cookie, void* buffer, size_t bufferSize,
2672 	uint32 count, uint32* countRead)
2673 {
2674 	*countRead = 0;
2675 
2676 	// check capability
2677 	if (!fFileSystem->HasCapability(FS_CAPABILITY_READ_QUERY))
2678 		return B_BAD_VALUE;
2679 
2680 	// get a free port
2681 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
2682 	if (!port)
2683 		return B_ERROR;
2684 	PortReleaser _(fFileSystem->GetPortPool(), port);
2685 
2686 	// prepare the request
2687 	RequestAllocator allocator(port->GetPort());
2688 	ReadQueryRequest* request;
2689 	status_t error = AllocateRequest(allocator, &request);
2690 	if (error != B_OK)
2691 		return error;
2692 
2693 	request->volume = fUserlandVolume;
2694 	request->queryCookie = cookie;
2695 	request->bufferSize = bufferSize;
2696 	request->count = count;
2697 
2698 	// send the request
2699 	KernelRequestHandler handler(this, READ_QUERY_REPLY);
2700 	ReadQueryReply* reply;
2701 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
2702 	if (error != B_OK)
2703 		return error;
2704 	RequestReleaser requestReleaser(port, reply);
2705 
2706 	// process the reply
2707 	if (reply->error != B_OK)
2708 		return reply->error;
2709 	if (reply->count < 0 || reply->count > count)
2710 		return B_BAD_DATA;
2711 	if ((int32)bufferSize < reply->buffer.GetSize())
2712 		return B_BAD_DATA;
2713 
2714 	*countRead = reply->count;
2715 	if (*countRead > 0) {
2716 		// copy the buffer -- limit the number of bytes to copy
2717 		uint32 maxBytes = *countRead
2718 			* (sizeof(struct dirent) + B_FILE_NAME_LENGTH);
2719 		uint32 copyBytes = reply->buffer.GetSize();
2720 		if (copyBytes > maxBytes)
2721 			copyBytes = maxBytes;
2722 		memcpy(buffer, reply->buffer.GetData(), copyBytes);
2723 	}
2724 	_SendReceiptAck(port);
2725 	return error;
2726 }
2727 
2728 // RewindQuery
2729 status_t
2730 Volume::RewindQuery(fs_cookie cookie)
2731 {
2732 	// check capability
2733 	if (!fFileSystem->HasCapability(FS_CAPABILITY_REWIND_QUERY))
2734 		return B_BAD_VALUE;
2735 
2736 	// get a free port
2737 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
2738 	if (!port)
2739 		return B_ERROR;
2740 	PortReleaser _(fFileSystem->GetPortPool(), port);
2741 
2742 	// prepare the request
2743 	RequestAllocator allocator(port->GetPort());
2744 	RewindQueryRequest* request;
2745 	status_t error = AllocateRequest(allocator, &request);
2746 	if (error != B_OK)
2747 		return error;
2748 
2749 	request->volume = fUserlandVolume;
2750 	request->queryCookie = cookie;
2751 
2752 	// send the request
2753 	KernelRequestHandler handler(this, REWIND_QUERY_REPLY);
2754 	RewindQueryReply* reply;
2755 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
2756 	if (error != B_OK)
2757 		return error;
2758 	RequestReleaser requestReleaser(port, reply);
2759 
2760 	// process the reply
2761 	if (reply->error != B_OK)
2762 		return reply->error;
2763 	return error;
2764 }
2765 
2766 // #pragma mark -
2767 // #pragma mark ----- private implementations -----
2768 
2769 // _Mount
2770 status_t
2771 Volume::_Mount(const char* device, uint32 flags, const char* parameters)
2772 {
2773 	// get a free port
2774 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
2775 	if (!port)
2776 		return B_ERROR;
2777 	PortReleaser _(fFileSystem->GetPortPool(), port);
2778 
2779 	// get the current working directory
2780 	char cwd[B_PATH_NAME_LENGTH];
2781 	if (!getcwd(cwd, sizeof(cwd)))
2782 		return errno;
2783 
2784 	// prepare the request
2785 	RequestAllocator allocator(port->GetPort());
2786 	MountVolumeRequest* request;
2787 	status_t error = AllocateRequest(allocator, &request);
2788 	if (error != B_OK)
2789 		return error;
2790 
2791 	request->nsid = fID;
2792 	error = allocator.AllocateString(request->cwd, cwd);
2793 	if (error == B_OK)
2794 		error = allocator.AllocateString(request->device, device);
2795 	request->flags = flags;
2796 	if (error == B_OK)
2797 		error = allocator.AllocateString(request->parameters, parameters);
2798 	if (error != B_OK)
2799 		return error;
2800 
2801 	// send the request
2802 	KernelRequestHandler handler(this, MOUNT_VOLUME_REPLY);
2803 	MountVolumeReply* reply;
2804 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
2805 	if (error != B_OK)
2806 		return error;
2807 	RequestReleaser requestReleaser(port, reply);
2808 
2809 	// process the reply
2810 	if (reply->error != B_OK)
2811 		return reply->error;
2812 	fRootID = reply->rootID;
2813 	fUserlandVolume = reply->volume;
2814 
2815 	// enable vnode counting
2816 	fVNodeCountMap = new(nothrow) VNodeCountMap;
2817 	if (fVNodeCountMap)
2818 		fVNodeCountingEnabled = true;
2819 	else
2820 		ERROR(("Failed to allocate vnode count map."));
2821 	return error;
2822 }
2823 
2824 // _Unmount
2825 status_t
2826 Volume::_Unmount()
2827 {
2828 	// get a free port
2829 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
2830 	if (!port)
2831 		return B_ERROR;
2832 	PortReleaser _(fFileSystem->GetPortPool(), port);
2833 
2834 	// prepare the request
2835 	RequestAllocator allocator(port->GetPort());
2836 	UnmountVolumeRequest* request;
2837 	status_t error = AllocateRequest(allocator, &request);
2838 	if (error != B_OK)
2839 		return error;
2840 
2841 	request->volume = fUserlandVolume;
2842 
2843 	// send the request
2844 	KernelRequestHandler handler(this, UNMOUNT_VOLUME_REPLY);
2845 	UnmountVolumeReply* reply;
2846 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
2847 	if (error != B_OK)
2848 		return error;
2849 	RequestReleaser requestReleaser(port, reply);
2850 
2851 	// process the reply
2852 	if (reply->error != B_OK)
2853 		return reply->error;
2854 	return error;
2855 }
2856 
2857 // _ReadFSInfo
2858 status_t
2859 Volume::_ReadFSInfo(fs_info* info)
2860 {
2861 	// check capability
2862 	if (!fFileSystem->HasCapability(FS_CAPABILITY_READ_FS_INFO))
2863 		return B_BAD_VALUE;
2864 
2865 	// get a free port
2866 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
2867 	if (!port)
2868 		return B_ERROR;
2869 	PortReleaser _(fFileSystem->GetPortPool(), port);
2870 
2871 	// prepare the request
2872 	RequestAllocator allocator(port->GetPort());
2873 	ReadFSInfoRequest* request;
2874 	status_t error = AllocateRequest(allocator, &request);
2875 	if (error != B_OK)
2876 		return error;
2877 
2878 	request->volume = fUserlandVolume;
2879 
2880 	// send the request
2881 	KernelRequestHandler handler(this, READ_FS_INFO_REPLY);
2882 	ReadFSInfoReply* reply;
2883 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
2884 	if (error != B_OK)
2885 		return error;
2886 	RequestReleaser requestReleaser(port, reply);
2887 
2888 	// process the reply
2889 	if (reply->error != B_OK)
2890 		return reply->error;
2891 	*info = reply->info;
2892 	return error;
2893 }
2894 
2895 // _Lookup
2896 status_t
2897 Volume::_Lookup(fs_vnode dir, const char* entryName, ino_t* vnid, int* type)
2898 {
2899 	// get a free port
2900 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
2901 	if (!port)
2902 		return B_ERROR;
2903 	PortReleaser _(fFileSystem->GetPortPool(), port);
2904 
2905 	// prepare the request
2906 	RequestAllocator allocator(port->GetPort());
2907 	LookupRequest* request;
2908 	status_t error = AllocateRequest(allocator, &request);
2909 	if (error != B_OK)
2910 		return error;
2911 	request->volume = fUserlandVolume;
2912 	request->node = dir;
2913 	error = allocator.AllocateString(request->entryName, entryName);
2914 	if (error != B_OK)
2915 		return error;
2916 
2917 	// send the request
2918 	KernelRequestHandler handler(this, LOOKUP_REPLY);
2919 	LookupReply* reply;
2920 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
2921 	if (error != B_OK)
2922 		return error;
2923 	RequestReleaser requestReleaser(port, reply);
2924 
2925 	// process the reply
2926 	if (reply->error != B_OK)
2927 		return reply->error;
2928 	*vnid = reply->vnid;
2929 	*type = reply->type;
2930 
2931 	// The VFS will balance the get_vnode() call for the FS.
2932 	_DecrementVNodeCount(*vnid);
2933 	return error;
2934 }
2935 
2936 // _WriteVNode
2937 status_t
2938 Volume::_WriteVNode(fs_vnode node, bool reenter)
2939 {
2940 	// get a free port
2941 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
2942 	if (!port)
2943 		return B_ERROR;
2944 	PortReleaser _(fFileSystem->GetPortPool(), port);
2945 
2946 	// prepare the request
2947 	RequestAllocator allocator(port->GetPort());
2948 	WriteVNodeRequest* request;
2949 	status_t error = AllocateRequest(allocator, &request);
2950 	if (error != B_OK)
2951 		return error;
2952 	request->volume = fUserlandVolume;
2953 	request->node = node;
2954 	request->reenter = reenter;
2955 
2956 	// send the request
2957 	KernelRequestHandler handler(this, WRITE_VNODE_REPLY);
2958 	WriteVNodeReply* reply;
2959 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
2960 	if (error != B_OK)
2961 		return error;
2962 	RequestReleaser requestReleaser(port, reply);
2963 
2964 	// process the reply
2965 	if (reply->error != B_OK)
2966 		return reply->error;
2967 	return error;
2968 }
2969 
2970 // _ReadStat
2971 status_t
2972 Volume::_ReadStat(fs_vnode node, struct stat* st)
2973 {
2974 	// check capability
2975 	if (!fFileSystem->HasCapability(FS_CAPABILITY_READ_STAT))
2976 		return B_BAD_VALUE;
2977 
2978 	// get a free port
2979 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
2980 	if (!port)
2981 		return B_ERROR;
2982 	PortReleaser _(fFileSystem->GetPortPool(), port);
2983 
2984 	// prepare the request
2985 	RequestAllocator allocator(port->GetPort());
2986 	ReadStatRequest* request;
2987 	status_t error = AllocateRequest(allocator, &request);
2988 	if (error != B_OK)
2989 		return error;
2990 
2991 	request->volume = fUserlandVolume;
2992 	request->node = node;
2993 
2994 	// send the request
2995 	KernelRequestHandler handler(this, READ_STAT_REPLY);
2996 	ReadStatReply* reply;
2997 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
2998 	if (error != B_OK)
2999 		return error;
3000 	RequestReleaser requestReleaser(port, reply);
3001 
3002 	// process the reply
3003 	if (reply->error != B_OK)
3004 		return reply->error;
3005 	*st = reply->st;
3006 	return error;
3007 }
3008 
3009 // _Close
3010 status_t
3011 Volume::_Close(fs_vnode node, fs_cookie cookie)
3012 {
3013 	// check capability
3014 	if (!fFileSystem->HasCapability(FS_CAPABILITY_CLOSE))
3015 		return B_OK;
3016 
3017 	// get a free port
3018 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
3019 	if (!port)
3020 		return B_ERROR;
3021 	PortReleaser _(fFileSystem->GetPortPool(), port);
3022 
3023 	// prepare the request
3024 	RequestAllocator allocator(port->GetPort());
3025 	CloseRequest* request;
3026 	status_t error = AllocateRequest(allocator, &request);
3027 	if (error != B_OK)
3028 		return error;
3029 
3030 	request->volume = fUserlandVolume;
3031 	request->node = node;
3032 	request->fileCookie = cookie;
3033 
3034 	// send the request
3035 	KernelRequestHandler handler(this, CLOSE_REPLY);
3036 	CloseReply* reply;
3037 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
3038 	if (error != B_OK)
3039 		return error;
3040 	RequestReleaser requestReleaser(port, reply);
3041 
3042 	// process the reply
3043 	if (reply->error != B_OK)
3044 		return reply->error;
3045 	return error;
3046 }
3047 
3048 // _FreeCookie
3049 status_t
3050 Volume::_FreeCookie(fs_vnode node, fs_cookie cookie)
3051 {
3052 	// check capability
3053 	if (!fFileSystem->HasCapability(FS_CAPABILITY_FREE_COOKIE))
3054 		return B_OK;
3055 
3056 	// get a free port
3057 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
3058 	if (!port)
3059 		return B_ERROR;
3060 	PortReleaser _(fFileSystem->GetPortPool(), port);
3061 
3062 	// prepare the request
3063 	RequestAllocator allocator(port->GetPort());
3064 	FreeCookieRequest* request;
3065 	status_t error = AllocateRequest(allocator, &request);
3066 	if (error != B_OK)
3067 		return error;
3068 
3069 	request->volume = fUserlandVolume;
3070 	request->node = node;
3071 	request->fileCookie = cookie;
3072 
3073 	// send the request
3074 	KernelRequestHandler handler(this, FREE_COOKIE_REPLY);
3075 	FreeCookieReply* reply;
3076 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
3077 	if (error != B_OK)
3078 		return error;
3079 	RequestReleaser requestReleaser(port, reply);
3080 
3081 	// process the reply
3082 	if (reply->error != B_OK)
3083 		return reply->error;
3084 	return error;
3085 }
3086 
3087 // _CloseDir
3088 status_t
3089 Volume::_CloseDir(fs_vnode node, fs_vnode cookie)
3090 {
3091 	// check capability
3092 	if (!fFileSystem->HasCapability(FS_CAPABILITY_CLOSE_DIR))
3093 		return B_OK;
3094 
3095 	// get a free port
3096 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
3097 	if (!port)
3098 		return B_ERROR;
3099 	PortReleaser _(fFileSystem->GetPortPool(), port);
3100 
3101 	// prepare the request
3102 	RequestAllocator allocator(port->GetPort());
3103 	CloseDirRequest* request;
3104 	status_t error = AllocateRequest(allocator, &request);
3105 	if (error != B_OK)
3106 		return error;
3107 
3108 	request->volume = fUserlandVolume;
3109 	request->node = node;
3110 	request->dirCookie = cookie;
3111 
3112 	// send the request
3113 	KernelRequestHandler handler(this, CLOSE_DIR_REPLY);
3114 	CloseDirReply* reply;
3115 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
3116 	if (error != B_OK)
3117 		return error;
3118 	RequestReleaser requestReleaser(port, reply);
3119 
3120 	// process the reply
3121 	if (reply->error != B_OK)
3122 		return reply->error;
3123 	return error;
3124 }
3125 
3126 // _FreeDirCookie
3127 status_t
3128 Volume::_FreeDirCookie(fs_vnode node, fs_vnode cookie)
3129 {
3130 	// check capability
3131 	if (!fFileSystem->HasCapability(FS_CAPABILITY_FREE_DIR_COOKIE))
3132 		return B_OK;
3133 
3134 	// get a free port
3135 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
3136 	if (!port)
3137 		return B_ERROR;
3138 	PortReleaser _(fFileSystem->GetPortPool(), port);
3139 
3140 	// prepare the request
3141 	RequestAllocator allocator(port->GetPort());
3142 	FreeDirCookieRequest* request;
3143 	status_t error = AllocateRequest(allocator, &request);
3144 	if (error != B_OK)
3145 		return error;
3146 
3147 	request->volume = fUserlandVolume;
3148 	request->node = node;
3149 	request->dirCookie = cookie;
3150 
3151 	// send the request
3152 	KernelRequestHandler handler(this, FREE_DIR_COOKIE_REPLY);
3153 	FreeDirCookieReply* reply;
3154 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
3155 	if (error != B_OK)
3156 		return error;
3157 	RequestReleaser requestReleaser(port, reply);
3158 
3159 	// process the reply
3160 	if (reply->error != B_OK)
3161 		return reply->error;
3162 	return error;
3163 }
3164 
3165 // _CloseAttrDir
3166 status_t
3167 Volume::_CloseAttrDir(fs_vnode node, fs_cookie cookie)
3168 {
3169 	// check capability
3170 	if (!fFileSystem->HasCapability(FS_CAPABILITY_CLOSE_ATTR_DIR))
3171 		return B_OK;
3172 
3173 	// get a free port
3174 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
3175 	if (!port)
3176 		return B_ERROR;
3177 	PortReleaser _(fFileSystem->GetPortPool(), port);
3178 
3179 	// prepare the request
3180 	RequestAllocator allocator(port->GetPort());
3181 	CloseAttrDirRequest* request;
3182 	status_t error = AllocateRequest(allocator, &request);
3183 	if (error != B_OK)
3184 		return error;
3185 
3186 	request->volume = fUserlandVolume;
3187 	request->node = node;
3188 	request->attrDirCookie = cookie;
3189 
3190 	// send the request
3191 	KernelRequestHandler handler(this, CLOSE_ATTR_DIR_REPLY);
3192 	CloseAttrDirReply* reply;
3193 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
3194 	if (error != B_OK)
3195 		return error;
3196 	RequestReleaser requestReleaser(port, reply);
3197 
3198 	// process the reply
3199 	if (reply->error != B_OK)
3200 		return reply->error;
3201 	return error;
3202 }
3203 
3204 // _FreeAttrDirCookie
3205 status_t
3206 Volume::_FreeAttrDirCookie(fs_vnode node, fs_cookie cookie)
3207 {
3208 	// check capability
3209 	if (!fFileSystem->HasCapability(FS_CAPABILITY_FREE_ATTR_DIR_COOKIE))
3210 		return B_OK;
3211 
3212 	// get a free port
3213 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
3214 	if (!port)
3215 		return B_ERROR;
3216 	PortReleaser _(fFileSystem->GetPortPool(), port);
3217 
3218 	// prepare the request
3219 	RequestAllocator allocator(port->GetPort());
3220 	FreeAttrDirCookieRequest* request;
3221 	status_t error = AllocateRequest(allocator, &request);
3222 	if (error != B_OK)
3223 		return error;
3224 
3225 	request->volume = fUserlandVolume;
3226 	request->node = node;
3227 	request->attrDirCookie = cookie;
3228 
3229 	// send the request
3230 	KernelRequestHandler handler(this, FREE_ATTR_DIR_COOKIE_REPLY);
3231 	FreeAttrDirCookieReply* reply;
3232 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
3233 	if (error != B_OK)
3234 		return error;
3235 	RequestReleaser requestReleaser(port, reply);
3236 
3237 	// process the reply
3238 	if (reply->error != B_OK)
3239 		return reply->error;
3240 	return error;
3241 }
3242 
3243 // _CloseAttr
3244 status_t
3245 Volume::_CloseAttr(fs_vnode node, fs_cookie cookie)
3246 {
3247 	// check capability
3248 	if (!fFileSystem->HasCapability(FS_CAPABILITY_CLOSE_ATTR))
3249 		return B_OK;
3250 
3251 	// get a free port
3252 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
3253 	if (!port)
3254 		return B_ERROR;
3255 	PortReleaser _(fFileSystem->GetPortPool(), port);
3256 
3257 	// prepare the request
3258 	RequestAllocator allocator(port->GetPort());
3259 	CloseAttrRequest* request;
3260 	status_t error = AllocateRequest(allocator, &request);
3261 	if (error != B_OK)
3262 		return error;
3263 
3264 	request->volume = fUserlandVolume;
3265 	request->node = node;
3266 	request->attrCookie = cookie;
3267 
3268 	// send the request
3269 	KernelRequestHandler handler(this, CLOSE_ATTR_REPLY);
3270 	CloseAttrReply* reply;
3271 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
3272 	if (error != B_OK)
3273 		return error;
3274 	RequestReleaser requestReleaser(port, reply);
3275 
3276 	// process the reply
3277 	if (reply->error != B_OK)
3278 		return reply->error;
3279 	return error;
3280 }
3281 
3282 // _FreeAttrCookie
3283 status_t
3284 Volume::_FreeAttrCookie(fs_vnode node, fs_cookie cookie)
3285 {
3286 	// check capability
3287 	if (!fFileSystem->HasCapability(FS_CAPABILITY_FREE_ATTR_COOKIE))
3288 		return B_OK;
3289 
3290 	// get a free port
3291 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
3292 	if (!port)
3293 		return B_ERROR;
3294 	PortReleaser _(fFileSystem->GetPortPool(), port);
3295 
3296 	// prepare the request
3297 	RequestAllocator allocator(port->GetPort());
3298 	FreeAttrCookieRequest* request;
3299 	status_t error = AllocateRequest(allocator, &request);
3300 	if (error != B_OK)
3301 		return error;
3302 
3303 	request->volume = fUserlandVolume;
3304 	request->node = node;
3305 	request->attrCookie = cookie;
3306 
3307 	// send the request
3308 	KernelRequestHandler handler(this, FREE_ATTR_COOKIE_REPLY);
3309 	FreeAttrCookieReply* reply;
3310 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
3311 	if (error != B_OK)
3312 		return error;
3313 	RequestReleaser requestReleaser(port, reply);
3314 
3315 	// process the reply
3316 	if (reply->error != B_OK)
3317 		return reply->error;
3318 	return error;
3319 }
3320 
3321 // _CloseIndexDir
3322 status_t
3323 Volume::_CloseIndexDir(fs_cookie cookie)
3324 {
3325 	// check capability
3326 	if (!fFileSystem->HasCapability(FS_CAPABILITY_CLOSE_INDEX_DIR))
3327 		return B_OK;
3328 
3329 	// get a free port
3330 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
3331 	if (!port)
3332 		return B_ERROR;
3333 	PortReleaser _(fFileSystem->GetPortPool(), port);
3334 
3335 	// prepare the request
3336 	RequestAllocator allocator(port->GetPort());
3337 	CloseIndexDirRequest* request;
3338 	status_t error = AllocateRequest(allocator, &request);
3339 	if (error != B_OK)
3340 		return error;
3341 
3342 	request->volume = fUserlandVolume;
3343 	request->indexDirCookie = cookie;
3344 
3345 	// send the request
3346 	KernelRequestHandler handler(this, CLOSE_INDEX_DIR_REPLY);
3347 	CloseIndexDirReply* reply;
3348 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
3349 	if (error != B_OK)
3350 		return error;
3351 	RequestReleaser requestReleaser(port, reply);
3352 
3353 	// process the reply
3354 	if (reply->error != B_OK)
3355 		return reply->error;
3356 	return error;
3357 }
3358 
3359 // _FreeIndexDirCookie
3360 status_t
3361 Volume::_FreeIndexDirCookie(fs_cookie cookie)
3362 {
3363 	// check capability
3364 	if (!fFileSystem->HasCapability(FS_CAPABILITY_FREE_INDEX_DIR_COOKIE))
3365 		return B_OK;
3366 
3367 	// get a free port
3368 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
3369 	if (!port)
3370 		return B_ERROR;
3371 	PortReleaser _(fFileSystem->GetPortPool(), port);
3372 
3373 	// prepare the request
3374 	RequestAllocator allocator(port->GetPort());
3375 	FreeIndexDirCookieRequest* request;
3376 	status_t error = AllocateRequest(allocator, &request);
3377 	if (error != B_OK)
3378 		return error;
3379 
3380 	request->volume = fUserlandVolume;
3381 	request->indexDirCookie = cookie;
3382 
3383 	// send the request
3384 	KernelRequestHandler handler(this, FREE_INDEX_DIR_COOKIE_REPLY);
3385 	FreeIndexDirCookieReply* reply;
3386 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
3387 	if (error != B_OK)
3388 		return error;
3389 	RequestReleaser requestReleaser(port, reply);
3390 
3391 	// process the reply
3392 	if (reply->error != B_OK)
3393 		return reply->error;
3394 	return error;
3395 }
3396 
3397 // _CloseQuery
3398 status_t
3399 Volume::_CloseQuery(fs_cookie cookie)
3400 {
3401 	// check capability
3402 	if (!fFileSystem->HasCapability(FS_CAPABILITY_CLOSE_QUERY))
3403 		return B_OK;
3404 
3405 	// get a free port
3406 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
3407 	if (!port)
3408 		return B_ERROR;
3409 	PortReleaser _(fFileSystem->GetPortPool(), port);
3410 
3411 	// prepare the request
3412 	RequestAllocator allocator(port->GetPort());
3413 	CloseQueryRequest* request;
3414 	status_t error = AllocateRequest(allocator, &request);
3415 	if (error != B_OK)
3416 		return error;
3417 
3418 	request->volume = fUserlandVolume;
3419 	request->queryCookie = cookie;
3420 
3421 	// send the request
3422 	KernelRequestHandler handler(this, CLOSE_QUERY_REPLY);
3423 	CloseQueryReply* reply;
3424 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
3425 	if (error != B_OK)
3426 		return error;
3427 	RequestReleaser requestReleaser(port, reply);
3428 
3429 	// process the reply
3430 	if (reply->error != B_OK)
3431 		return reply->error;
3432 	return error;
3433 }
3434 
3435 // _FreeQueryCookie
3436 status_t
3437 Volume::_FreeQueryCookie(fs_cookie cookie)
3438 {
3439 	// check capability
3440 	if (!fFileSystem->HasCapability(FS_CAPABILITY_FREE_QUERY_COOKIE))
3441 		return B_OK;
3442 
3443 	// get a free port
3444 	RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
3445 	if (!port)
3446 		return B_ERROR;
3447 	PortReleaser _(fFileSystem->GetPortPool(), port);
3448 
3449 	// prepare the request
3450 	RequestAllocator allocator(port->GetPort());
3451 	FreeQueryCookieRequest* request;
3452 	status_t error = AllocateRequest(allocator, &request);
3453 	if (error != B_OK)
3454 		return error;
3455 
3456 	request->volume = fUserlandVolume;
3457 	request->queryCookie = cookie;
3458 
3459 	// send the request
3460 	KernelRequestHandler handler(this, FREE_QUERY_COOKIE_REPLY);
3461 	FreeQueryCookieReply* reply;
3462 	error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
3463 	if (error != B_OK)
3464 		return error;
3465 	RequestReleaser requestReleaser(port, reply);
3466 
3467 	// process the reply
3468 	if (reply->error != B_OK)
3469 		return reply->error;
3470 	return error;
3471 }
3472 
3473 // _SendRequest
3474 status_t
3475 Volume::_SendRequest(RequestPort* port, RequestAllocator* allocator,
3476 	RequestHandler* handler, Request** reply)
3477 {
3478 	if (!fFileSystem->IsUserlandServerThread())
3479 		return port->SendRequest(allocator, handler, reply);
3480 	// Here it gets dangerous: a thread of the userland server team being here
3481 	// calls for trouble. We try receiving the request with a timeout, and
3482 	// close the port -- which will disconnect the whole FS.
3483 	status_t error = port->SendRequest(allocator, handler, reply,
3484 		kUserlandServerlandPortTimeout);
3485 	if (error == B_TIMED_OUT || error == B_WOULD_BLOCK)
3486 		port->Close();
3487 	return error;
3488 }
3489 
3490 // _SendReceiptAck
3491 status_t
3492 Volume::_SendReceiptAck(RequestPort* port)
3493 {
3494 	RequestAllocator allocator(port->GetPort());
3495 	ReceiptAckReply* request;
3496 	status_t error = AllocateRequest(allocator, &request);
3497 	if (error != B_OK)
3498 		return error;
3499 	return port->SendRequest(&allocator);
3500 }
3501 
3502 // _IncrementVNodeCount
3503 void
3504 Volume::_IncrementVNodeCount(ino_t vnid)
3505 {
3506 	if (!fVNodeCountingEnabled)
3507 		return;
3508 	AutoLocker<VNodeCountMap> _(fVNodeCountMap);
3509 	if (!fVNodeCountingEnabled)	// someone may have changed it
3510 		return;
3511 	// get the counter
3512 	int32* count = fVNodeCountMap->Get(vnid);
3513 	if (!count) {
3514 		// vnode not known yet: create and add a new counter
3515 		count = new(nothrow) int32(0);
3516 		if (!count) {
3517 			ERROR(("Volume::_IncrementVNodeCount(): Failed to allocate "
3518 				"counter. Disabling vnode counting.\n"));
3519 			fVNodeCountingEnabled = false;
3520 			return;
3521 		}
3522 		if (fVNodeCountMap->Put(vnid, count) != B_OK) {
3523 			ERROR(("Volume::_IncrementVNodeCount(): Failed to add counter. "
3524 				"Disabling vnode counting.\n"));
3525 			delete count;
3526 			fVNodeCountingEnabled = false;
3527 			return;
3528 		}
3529 	}
3530 	// increment the counter
3531 	(*count)++;
3532 //PRINT(("_IncrementVNodeCount(%Ld): count: %ld, fVNodeCountMap size: %ld\n", vnid, *count, fVNodeCountMap->Size()));
3533 }
3534 
3535 // _DecrementVNodeCount
3536 void
3537 Volume::_DecrementVNodeCount(ino_t vnid)
3538 {
3539 	if (!fVNodeCountingEnabled)
3540 		return;
3541 	AutoLocker<VNodeCountMap> _(fVNodeCountMap);
3542 	if (!fVNodeCountingEnabled)	// someone may have changed it
3543 		return;
3544 	int32* count = fVNodeCountMap->Get(vnid);
3545 	if (!count) {
3546 		// that should never happen
3547 		ERROR(("Volume::_DecrementVNodeCount(): Failed to get counter. "
3548 			"Disabling vnode counting.\n"));
3549 		fVNodeCountingEnabled = false;
3550 		return;
3551 	}
3552 	(*count)--;
3553 //int32 tmpCount = *count;
3554 	if (*count == 0)
3555 		fVNodeCountMap->Remove(vnid);
3556 //PRINT(("_DecrementVNodeCount(%Ld): count: %ld, fVNodeCountMap size: %ld\n", vnid, tmpCount, fVNodeCountMap->Size()));
3557 }
3558 
3559 // _InternalIOCtl
3560 status_t
3561 Volume::_InternalIOCtl(userlandfs_ioctl* buffer, int32 bufferSize)
3562 {
3563 	if (buffer->version != USERLAND_IOCTL_CURRENT_VERSION)
3564 		return B_BAD_VALUE;
3565 	status_t result = B_OK;
3566 	switch (buffer->command) {
3567 		case USERLAND_IOCTL_PUT_ALL_PENDING_VNODES:
3568 			result = _PutAllPendingVNodes();
3569 			break;
3570 		default:
3571 			return B_BAD_VALUE;
3572 	}
3573 	buffer->error = result;
3574 	return B_OK;
3575 }
3576 
3577 // _PutAllPendingVNodes
3578 status_t
3579 Volume::_PutAllPendingVNodes()
3580 {
3581 PRINT(("Volume::_PutAllPendingVNodes()\n"));
3582 	if (!fFileSystem->GetPortPool()->IsDisconnected()) {
3583 		PRINT(("Volume::_PutAllPendingVNodes() failed: still connected\n"));
3584 		return USERLAND_IOCTL_STILL_CONNECTED;
3585 	}
3586 	if (!fVNodeCountingEnabled) {
3587 		PRINT(("Volume::_PutAllPendingVNodes() failed: vnode counting "
3588 			"disabled\n"));
3589 		return USERLAND_IOCTL_VNODE_COUNTING_DISABLED;
3590 	}
3591 	{
3592 		AutoLocker<VNodeCountMap> _(fVNodeCountMap);
3593 		if (!fVNodeCountingEnabled)	{// someone may have changed it
3594 			PRINT(("Volume::_PutAllPendingVNodes() failed: vnode counting "
3595 				"disabled\n"));
3596 			return USERLAND_IOCTL_VNODE_COUNTING_DISABLED;
3597 		}
3598 		// Check whether there are open entities at the moment.
3599 		if (fOpenFiles > 0) {
3600 			PRINT(("Volume::_PutAllPendingVNodes() failed: open files\n"));
3601 			return USERLAND_IOCTL_OPEN_FILES;
3602 		}
3603 		if (fOpenDirectories > 0) {
3604 			PRINT(("Volume::_PutAllPendingVNodes() failed: open dirs\n"));
3605 			return USERLAND_IOCTL_OPEN_DIRECTORIES;
3606 		}
3607 		if (fOpenAttributeDirectories > 0) {
3608 			PRINT(("Volume::_PutAllPendingVNodes() failed: open attr dirs\n"));
3609 			return USERLAND_IOCTL_OPEN_ATTRIBUTE_DIRECTORIES;
3610 		}
3611 		if (fOpenAttributes > 0) {
3612 			PRINT(("Volume::_PutAllPendingVNodes() failed: open attributes\n"));
3613 			return USERLAND_IOCTL_OPEN_ATTRIBUTES;
3614 		}
3615 		if (fOpenIndexDirectories > 0) {
3616 			PRINT(("Volume::_PutAllPendingVNodes() failed: open index dirs\n"));
3617 			return USERLAND_IOCTL_OPEN_INDEX_DIRECTORIES;
3618 		}
3619 		if (fOpenQueries > 0) {
3620 			PRINT(("Volume::_PutAllPendingVNodes() failed: open queries\n"));
3621 			return USERLAND_IOCTL_OPEN_QUERIES;
3622 		}
3623 		// No open entities. Since the port pool is disconnected, no new
3624 		// entities can be opened. Disable node counting and put all pending
3625 		// vnodes.
3626 		fVNodeCountingEnabled = false;
3627 	}
3628 	int32 putVNodeCount = 0;
3629 	for (VNodeCountMap::Iterator it = fVNodeCountMap->GetIterator();
3630 		 it.HasNext();) {
3631 		VNodeCountMap::Entry entry = it.Next();
3632 		int32 count = *entry.value;
3633 		for (int32 i = 0; i < count; i++) {
3634 			PutVNode(entry.key.value);
3635 			putVNodeCount++;
3636 		}
3637 	}
3638 	PRINT(("Volume::_PutAllPendingVNodes() successful: Put %ld vnodes\n",
3639 		putVNodeCount));
3640 	return B_OK;
3641 }
3642 
3643