xref: /haiku/src/add-ons/kernel/file_systems/userlandfs/kernel_add_on/KernelRequestHandler.cpp (revision e81a954787e50e56a7f06f72705b7859b6ab06d1)
1 /*
2  * Copyright 2001-2009, Ingo Weinhold, ingo_weinhold@gmx.de.
3  * Distributed under the terms of the MIT License.
4  */
5 
6 #include "Compatibility.h"
7 #include "Debug.h"
8 #include "FileSystem.h"
9 #include "KernelRequestHandler.h"
10 #include "RequestPort.h"
11 #include "Requests.h"
12 #include "SingleReplyRequestHandler.h"
13 #include "Volume.h"
14 
15 #include <NodeMonitor.h>
16 
17 #include <AutoDeleter.h>
18 
19 
20 // VolumePutter
21 class VolumePutter {
22 public:
23 	VolumePutter(Volume* volume) : fVolume(volume) {}
24 	~VolumePutter()
25 	{
26 		if (fVolume)
27 			fVolume->ReleaseReference();
28 	}
29 
30 private:
31 	Volume	*fVolume;
32 };
33 
34 // constructor
35 KernelRequestHandler::KernelRequestHandler(Volume* volume, uint32 expectedReply)
36 	: RequestHandler(),
37 	  fFileSystem(volume->GetFileSystem()),
38 	  fVolume(volume),
39 	  fExpectedReply(expectedReply)
40 {
41 }
42 
43 // constructor
44 KernelRequestHandler::KernelRequestHandler(FileSystem* fileSystem,
45 	uint32 expectedReply)
46 	: RequestHandler(),
47 	  fFileSystem(fileSystem),
48 	  fVolume(NULL),
49 	  fExpectedReply(expectedReply)
50 {
51 }
52 
53 // destructor
54 KernelRequestHandler::~KernelRequestHandler()
55 {
56 }
57 
58 // HandleRequest
59 status_t
60 KernelRequestHandler::HandleRequest(Request* request)
61 {
62 	if (request->GetType() == fExpectedReply) {
63 		fDone = true;
64 		return B_OK;
65 	}
66 	switch (request->GetType()) {
67 		// notifications
68 		case NOTIFY_LISTENER_REQUEST:
69 			return _HandleRequest((NotifyListenerRequest*)request);
70 		case NOTIFY_SELECT_EVENT_REQUEST:
71 			return _HandleRequest((NotifySelectEventRequest*)request);
72 		case NOTIFY_QUERY_REQUEST:
73 			return _HandleRequest((NotifyQueryRequest*)request);
74 		// vnodes
75 		case GET_VNODE_REQUEST:
76 			return _HandleRequest((GetVNodeRequest*)request);
77 		case PUT_VNODE_REQUEST:
78 			return _HandleRequest((PutVNodeRequest*)request);
79 		case ACQUIRE_VNODE_REQUEST:
80 			return _HandleRequest((AcquireVNodeRequest*)request);
81 		case NEW_VNODE_REQUEST:
82 			return _HandleRequest((NewVNodeRequest*)request);
83 		case PUBLISH_VNODE_REQUEST:
84 			return _HandleRequest((PublishVNodeRequest*)request);
85 		case REMOVE_VNODE_REQUEST:
86 			return _HandleRequest((RemoveVNodeRequest*)request);
87 		case UNREMOVE_VNODE_REQUEST:
88 			return _HandleRequest((UnremoveVNodeRequest*)request);
89 		case GET_VNODE_REMOVED_REQUEST:
90 			return _HandleRequest((GetVNodeRemovedRequest*)request);
91 		// file cache
92 		case FILE_CACHE_CREATE_REQUEST:
93 			return _HandleRequest((FileCacheCreateRequest*)request);
94 		case FILE_CACHE_DELETE_REQUEST:
95 			return _HandleRequest((FileCacheDeleteRequest*)request);
96 		case FILE_CACHE_SET_ENABLED_REQUEST:
97 			return _HandleRequest((FileCacheSetEnabledRequest*)request);
98 		case FILE_CACHE_SET_SIZE_REQUEST:
99 			return _HandleRequest((FileCacheSetSizeRequest*)request);
100 		case FILE_CACHE_SYNC_REQUEST:
101 			return _HandleRequest((FileCacheSyncRequest*)request);
102 		case FILE_CACHE_READ_REQUEST:
103 			return _HandleRequest((FileCacheReadRequest*)request);
104 		case FILE_CACHE_WRITE_REQUEST:
105 			return _HandleRequest((FileCacheWriteRequest*)request);
106 		// I/O
107 		case DO_ITERATIVE_FD_IO_REQUEST:
108 			return _HandleRequest((DoIterativeFDIORequest*)request);
109 		case READ_FROM_IO_REQUEST_REQUEST:
110 			return _HandleRequest((ReadFromIORequestRequest*)request);
111 		case WRITE_TO_IO_REQUEST_REQUEST:
112 			return _HandleRequest((WriteToIORequestRequest*)request);
113 		case NOTIFY_IO_REQUEST_REQUEST:
114 			return _HandleRequest((NotifyIORequestRequest*)request);
115 		// node monitoring
116 		case ADD_NODE_LISTENER_REQUEST:
117 			return _HandleRequest((AddNodeListenerRequest*)request);
118 		case REMOVE_NODE_LISTENER_REQUEST:
119 			return _HandleRequest((RemoveNodeListenerRequest*)request);
120 	}
121 
122 	PRINT(("KernelRequestHandler::HandleRequest(): unexpected request: %"
123 		B_PRIu32 "\n", request->GetType()));
124 	return B_BAD_DATA;
125 }
126 
127 // #pragma mark -
128 // #pragma mark ----- notifications -----
129 
130 // _HandleRequest
131 status_t
132 KernelRequestHandler::_HandleRequest(NotifyListenerRequest* request)
133 {
134 	// check and execute the request
135 	status_t result = B_OK;
136 	if (fVolume && request->device != fVolume->GetID())
137 		result = B_BAD_VALUE;
138 
139 	// get the names
140 	// name
141 	char* name = (char*)request->name.GetData();
142 	int32 nameLen = request->name.GetSize();
143 	if (name && (nameLen <= 0))
144 		name = NULL;
145 	else if (name)
146 		name[nameLen - 1] = '\0';	// NULL-terminate to be safe
147 
148 	// old name
149 	char* oldName = (char*)request->oldName.GetData();
150 	int32 oldNameLen = request->oldName.GetSize();
151 	if (oldName && (oldNameLen <= 0))
152 		oldName = NULL;
153 	else if (oldName)
154 		oldName[oldNameLen - 1] = '\0';	// NULL-terminate to be safe
155 
156 	// check the names
157 	if (result == B_OK) {
158 		switch (request->operation) {
159 			case B_ENTRY_MOVED:
160 				if (!oldName) {
161 					ERROR(("NotifyListenerRequest: NULL oldName for "
162 						"B_ENTRY_MOVED\n"));
163 					result = B_BAD_VALUE;
164 					break;
165 				}
166 				// fall through...
167 			case B_ENTRY_CREATED:
168 			case B_ENTRY_REMOVED:
169 			case B_ATTR_CHANGED:
170 				if (!name) {
171 					ERROR(("NotifyListenerRequest: NULL name for opcode: %"
172 						B_PRId32 "\n", request->operation));
173 					result = B_BAD_VALUE;
174 				}
175 				break;
176 			case B_STAT_CHANGED:
177 				break;
178 		}
179 	}
180 
181 	// execute the request
182 	if (result == B_OK) {
183 		switch (request->operation) {
184 			case B_ENTRY_CREATED:
185 				PRINT(("notify_entry_created(%" B_PRId32 ", %" B_PRId64 ", "
186 					"\"%s\", %" B_PRId64 ")\n", request->device,
187 					request->directory, name, request->node));
188 				result = notify_entry_created(request->device,
189 					request->directory, name, request->node);
190 				break;
191 
192 			case B_ENTRY_REMOVED:
193 				PRINT(("notify_entry_removed(%" B_PRId32 ", %" B_PRId64 ", "
194 					"\"%s\", %" B_PRId64 ")\n", request->device,
195 					request->directory, name, request->node));
196 				result = notify_entry_removed(request->device,
197 					request->directory, name, request->node);
198 				break;
199 
200 			case B_ENTRY_MOVED:
201 				PRINT(("notify_entry_moved(%" B_PRId32 ", %" B_PRId64 ", "
202 					"\"%s\", %" B_PRId64 ", \"%s\", %" B_PRId64 ")\n",
203 					request->device, request->oldDirectory, oldName,
204 					request->directory, name, request->node));
205 				result = notify_entry_moved(request->device,
206 					request->oldDirectory, oldName, request->directory, name,
207 					request->node);
208 				break;
209 
210 			case B_STAT_CHANGED:
211 				PRINT(("notify_stat_changed(%" B_PRId32 ", %" B_PRId64 ", "
212 					"0x%" B_PRIx32 ")\n", request->device, request->node,
213 					request->details));
214 				result = notify_stat_changed(request->device,
215 					request->directory, request->node, request->details);
216 				break;
217 
218 			case B_ATTR_CHANGED:
219 				PRINT(("notify_attribute_changed(%" B_PRId32 ", %" B_PRId64 ", "
220 					"\"%s\", 0x%" B_PRIx32 ")\n", request->device,
221 					request->node, name, (int32)request->details));
222 				result = notify_attribute_changed(request->device,
223 					request->directory, request->node, name,
224 					(int32)request->details);
225 				break;
226 
227 			default:
228 				ERROR(("NotifyQueryRequest: unsupported operation: %" B_PRId32
229 					"\n", request->operation));
230 				result = B_BAD_VALUE;
231 				break;
232 		}
233 	}
234 
235 	// prepare the reply
236 	RequestAllocator allocator(fPort->GetPort());
237 	NotifyListenerReply* reply;
238 	status_t error = AllocateRequest(allocator, &reply);
239 	if (error != B_OK)
240 		return error;
241 
242 	reply->error = result;
243 
244 	// send the reply
245 	return fPort->SendRequest(&allocator);
246 }
247 
248 // _HandleRequest
249 status_t
250 KernelRequestHandler::_HandleRequest(NotifySelectEventRequest* request)
251 {
252 	// check and execute the request
253 	status_t result = B_OK;
254 	if (fFileSystem->KnowsSelectSyncEntry(request->sync)) {
255 		if (request->unspecifiedEvent) {
256 			// old style add-ons can't provide an event argument; we shoot
257 			// all events
258 			notify_select_event(request->sync, B_SELECT_READ);
259 			notify_select_event(request->sync, B_SELECT_WRITE);
260 			notify_select_event(request->sync, B_SELECT_ERROR);
261 		} else {
262 			PRINT(("notify_select_event(%p, %d)\n", request->sync,
263 				(int)request->event));
264 			notify_select_event(request->sync, request->event);
265 		}
266 	} else
267 		result = B_BAD_VALUE;
268 
269 	// prepare the reply
270 	RequestAllocator allocator(fPort->GetPort());
271 	NotifySelectEventReply* reply;
272 	status_t error = AllocateRequest(allocator, &reply);
273 	if (error != B_OK)
274 		return error;
275 
276 	reply->error = result;
277 
278 	// send the reply
279 	return fPort->SendRequest(&allocator);
280 }
281 
282 // _HandleRequest
283 status_t
284 KernelRequestHandler::_HandleRequest(NotifyQueryRequest* request)
285 {
286 	// check and execute the request
287 	status_t result = B_OK;
288 	if (fVolume && request->device != fVolume->GetID())
289 		result = B_BAD_VALUE;
290 
291 	// check the name
292 	char* name = (char*)request->name.GetData();
293 	int32 nameLen = request->name.GetSize();
294 	if (!name || nameLen <= 0) {
295 		ERROR(("NotifyQueryRequest: NULL name!\n"));
296 		result = B_BAD_VALUE;
297 	} else
298 		name[nameLen - 1] = '\0';	// NULL-terminate to be safe
299 
300 	// execute the request
301 	if (result == B_OK) {
302 		switch (request->operation) {
303 			case B_ENTRY_CREATED:
304 				PRINT(("notify_query_entry_created(%" B_PRId32 ", %" B_PRId32
305 					", %" B_PRId32 ", %" B_PRId64 ", \"%s\", %" B_PRId64 ")\n",
306 					request->port, request->token, request->device,
307 					request->directory, name, request->node));
308 				result = notify_query_entry_created(request->port,
309 					request->token, request->device, request->directory, name,
310 					request->node);
311 				break;
312 
313 			case B_ENTRY_REMOVED:
314 				PRINT(("notify_query_entry_removed(%" B_PRId32 ", %" B_PRId32
315 					", %" B_PRId32 ", %" B_PRId64 ", \"%s\", %" B_PRId64 ")\n",
316 					request->port, request->token, request->device,
317 					request->directory, name, request->node));
318 				result = notify_query_entry_removed(request->port,
319 					request->token, request->device, request->directory, name,
320 					request->node);
321 				break;
322 
323 			case B_ENTRY_MOVED:
324 			default:
325 				ERROR(("NotifyQueryRequest: unsupported operation: %" B_PRId32
326 					"\n", request->operation));
327 				result = B_BAD_VALUE;
328 				break;
329 		}
330 	}
331 
332 	// prepare the reply
333 	RequestAllocator allocator(fPort->GetPort());
334 	NotifyQueryReply* reply;
335 	status_t error = AllocateRequest(allocator, &reply);
336 	if (error != B_OK)
337 		return error;
338 
339 	reply->error = result;
340 
341 	// send the reply
342 	return fPort->SendRequest(&allocator);
343 }
344 
345 // #pragma mark -
346 // #pragma mark ----- vnodes -----
347 
348 // _HandleRequest
349 status_t
350 KernelRequestHandler::_HandleRequest(GetVNodeRequest* request)
351 {
352 	// check and execute the request
353 	Volume* volume = NULL;
354 	status_t result = _GetVolume(request->nsid, &volume);
355 	VolumePutter _(volume);
356 	void* node;
357 	if (result == B_OK)
358 		result = volume->GetVNode(request->vnid, &node);
359 	// prepare the reply
360 	RequestAllocator allocator(fPort->GetPort());
361 	GetVNodeReply* reply;
362 	status_t error = AllocateRequest(allocator, &reply);
363 	if (error != B_OK)
364 		return error;
365 	reply->error = result;
366 	reply->node = node;
367 	// send the reply
368 	return fPort->SendRequest(&allocator);
369 }
370 
371 // _HandleRequest
372 status_t
373 KernelRequestHandler::_HandleRequest(PutVNodeRequest* request)
374 {
375 	// check and execute the request
376 	Volume* volume = NULL;
377 	status_t result = _GetVolume(request->nsid, &volume);
378 	VolumePutter _(volume);
379 	if (result == B_OK)
380 		result = volume->PutVNode(request->vnid);
381 	// prepare the reply
382 	RequestAllocator allocator(fPort->GetPort());
383 	PutVNodeReply* reply;
384 	status_t error = AllocateRequest(allocator, &reply);
385 	if (error != B_OK)
386 		return error;
387 	reply->error = result;
388 	// send the reply
389 	return fPort->SendRequest(&allocator);
390 }
391 
392 
393 // _HandleRequest
394 status_t
395 KernelRequestHandler::_HandleRequest(AcquireVNodeRequest* request)
396 {
397 	// check and execute the request
398 	Volume* volume = NULL;
399 	status_t result = _GetVolume(request->nsid, &volume);
400 	VolumePutter _(volume);
401 	if (result == B_OK)
402 		result = volume->AcquireVNode(request->vnid);
403 
404 	// prepare the reply
405 	RequestAllocator allocator(fPort->GetPort());
406 	AcquireVNodeReply* reply;
407 	status_t error = AllocateRequest(allocator, &reply);
408 	if (error != B_OK)
409 		return error;
410 	reply->error = result;
411 
412 	// send the reply
413 	return fPort->SendRequest(&allocator);
414 }
415 
416 
417 // _HandleRequest
418 status_t
419 KernelRequestHandler::_HandleRequest(NewVNodeRequest* request)
420 {
421 	// check and execute the request
422 	Volume* volume = NULL;
423 	status_t result = _GetVolume(request->nsid, &volume);
424 	VolumePutter _(volume);
425 	if (result == B_OK) {
426 		result = volume->NewVNode(request->vnid, request->node,
427 			request->capabilities);
428 	}
429 
430 	// prepare the reply
431 	RequestAllocator allocator(fPort->GetPort());
432 	NewVNodeReply* reply;
433 	status_t error = AllocateRequest(allocator, &reply);
434 	if (error != B_OK)
435 		return error;
436 	reply->error = result;
437 
438 	// send the reply
439 	return fPort->SendRequest(&allocator);
440 }
441 
442 // _HandleRequest
443 status_t
444 KernelRequestHandler::_HandleRequest(PublishVNodeRequest* request)
445 {
446 	// check and execute the request
447 	Volume* volume = NULL;
448 	status_t result = _GetVolume(request->nsid, &volume);
449 	VolumePutter _(volume);
450 	if (result == B_OK) {
451 		result = volume->PublishVNode(request->vnid, request->node,
452 			request->type, request->flags, request->capabilities);
453 	}
454 
455 	// prepare the reply
456 	RequestAllocator allocator(fPort->GetPort());
457 	PublishVNodeReply* reply;
458 	status_t error = AllocateRequest(allocator, &reply);
459 	if (error != B_OK)
460 		return error;
461 
462 	reply->error = result;
463 
464 	// send the reply
465 	return fPort->SendRequest(&allocator);
466 }
467 
468 // _HandleRequest
469 status_t
470 KernelRequestHandler::_HandleRequest(RemoveVNodeRequest* request)
471 {
472 	// check and execute the request
473 	Volume* volume = NULL;
474 	status_t result = _GetVolume(request->nsid, &volume);
475 	VolumePutter _(volume);
476 	if (result == B_OK)
477 		result = volume->RemoveVNode(request->vnid);
478 	// prepare the reply
479 	RequestAllocator allocator(fPort->GetPort());
480 	RemoveVNodeReply* reply;
481 	status_t error = AllocateRequest(allocator, &reply);
482 	if (error != B_OK)
483 		return error;
484 	reply->error = result;
485 	// send the reply
486 	return fPort->SendRequest(&allocator);
487 }
488 
489 // _HandleRequest
490 status_t
491 KernelRequestHandler::_HandleRequest(UnremoveVNodeRequest* request)
492 {
493 	// check and execute the request
494 	Volume* volume = NULL;
495 	status_t result = _GetVolume(request->nsid, &volume);
496 	VolumePutter _(volume);
497 	if (result == B_OK)
498 		result = volume->UnremoveVNode(request->vnid);
499 	// prepare the reply
500 	RequestAllocator allocator(fPort->GetPort());
501 	UnremoveVNodeReply* reply;
502 	status_t error = AllocateRequest(allocator, &reply);
503 	if (error != B_OK)
504 		return error;
505 	reply->error = result;
506 	// send the reply
507 	return fPort->SendRequest(&allocator);
508 }
509 
510 // _HandleRequest
511 status_t
512 KernelRequestHandler::_HandleRequest(GetVNodeRemovedRequest* request)
513 {
514 	// check and execute the request
515 	Volume* volume = NULL;
516 	status_t result = _GetVolume(request->nsid, &volume);
517 	VolumePutter _(volume);
518 	bool removed = false;
519 	if (result == B_OK)
520 		result = volume->GetVNodeRemoved(request->vnid, &removed);
521 
522 	// prepare the reply
523 	RequestAllocator allocator(fPort->GetPort());
524 	GetVNodeRemovedReply* reply;
525 	status_t error = AllocateRequest(allocator, &reply);
526 	if (error != B_OK)
527 		return error;
528 
529 	reply->error = result;
530 	reply->removed = removed;
531 
532 	// send the reply
533 	return fPort->SendRequest(&allocator);
534 }
535 
536 
537 // _HandleRequest
538 status_t
539 KernelRequestHandler::_HandleRequest(FileCacheCreateRequest* request)
540 {
541 	// check and execute the request
542 	Volume* volume = NULL;
543 	status_t result = _GetVolume(request->nsid, &volume);
544 	VolumePutter _(volume);
545 
546 	if (result == B_OK)
547 		result = volume->CreateFileCache(request->vnid, request->size);
548 
549 	// prepare the reply
550 	RequestAllocator allocator(fPort->GetPort());
551 	FileCacheCreateReply* reply;
552 	status_t error = AllocateRequest(allocator, &reply);
553 	if (error != B_OK)
554 		return error;
555 	reply->error = result;
556 
557 	// send the reply
558 	return fPort->SendRequest(&allocator);
559 }
560 
561 
562 // _HandleRequest
563 status_t
564 KernelRequestHandler::_HandleRequest(FileCacheDeleteRequest* request)
565 {
566 	// check and execute the request
567 	Volume* volume = NULL;
568 	status_t result = _GetVolume(request->nsid, &volume);
569 	VolumePutter _(volume);
570 
571 	if (result == B_OK)
572 		result = volume->DeleteFileCache(request->vnid);
573 
574 	// prepare the reply
575 	RequestAllocator allocator(fPort->GetPort());
576 	FileCacheDeleteReply* reply;
577 	status_t error = AllocateRequest(allocator, &reply);
578 	if (error != B_OK)
579 		return error;
580 	reply->error = result;
581 
582 	// send the reply
583 	return fPort->SendRequest(&allocator);
584 }
585 
586 
587 // _HandleRequest
588 status_t
589 KernelRequestHandler::_HandleRequest(FileCacheSetEnabledRequest* request)
590 {
591 	// check and execute the request
592 	Volume* volume = NULL;
593 	status_t result = _GetVolume(request->nsid, &volume);
594 	VolumePutter _(volume);
595 
596 	if (result == B_OK)
597 		result = volume->SetFileCacheEnabled(request->vnid, request->enabled);
598 
599 	// prepare the reply
600 	RequestAllocator allocator(fPort->GetPort());
601 	FileCacheSetEnabledReply* reply;
602 	status_t error = AllocateRequest(allocator, &reply);
603 	if (error != B_OK)
604 		return error;
605 	reply->error = result;
606 
607 	// send the reply
608 	return fPort->SendRequest(&allocator);
609 }
610 
611 
612 // _HandleRequest
613 status_t
614 KernelRequestHandler::_HandleRequest(FileCacheSetSizeRequest* request)
615 {
616 	// check and execute the request
617 	Volume* volume = NULL;
618 	status_t result = _GetVolume(request->nsid, &volume);
619 	VolumePutter _(volume);
620 
621 	if (result == B_OK)
622 		result = volume->SetFileCacheSize(request->vnid, request->size);
623 
624 	// prepare the reply
625 	RequestAllocator allocator(fPort->GetPort());
626 	FileCacheSetSizeReply* reply;
627 	status_t error = AllocateRequest(allocator, &reply);
628 	if (error != B_OK)
629 		return error;
630 	reply->error = result;
631 
632 	// send the reply
633 	return fPort->SendRequest(&allocator);
634 }
635 
636 
637 // _HandleRequest
638 status_t
639 KernelRequestHandler::_HandleRequest(FileCacheSyncRequest* request)
640 {
641 	// check and execute the request
642 	Volume* volume = NULL;
643 	status_t result = _GetVolume(request->nsid, &volume);
644 	VolumePutter _(volume);
645 
646 	if (result == B_OK)
647 		result = volume->SyncFileCache(request->vnid);
648 
649 	// prepare the reply
650 	RequestAllocator allocator(fPort->GetPort());
651 	FileCacheSyncReply* reply;
652 	status_t error = AllocateRequest(allocator, &reply);
653 	if (error != B_OK)
654 		return error;
655 	reply->error = result;
656 
657 	// send the reply
658 	return fPort->SendRequest(&allocator);
659 }
660 
661 
662 // _HandleRequest
663 status_t
664 KernelRequestHandler::_HandleRequest(FileCacheReadRequest* request)
665 {
666 	// check the request
667 	Volume* volume = NULL;
668 	status_t result = _GetVolume(request->nsid, &volume);
669 	VolumePutter _(volume);
670 
671 	size_t size = request->size;
672 
673 	// allocate the reply
674 	RequestAllocator allocator(fPort->GetPort());
675 	FileCacheReadReply* reply;
676 	status_t error = AllocateRequest(allocator, &reply);
677 	if (error != B_OK)
678 		RETURN_ERROR(error);
679 
680 	void* buffer;
681 	if (result == B_OK) {
682 		result = allocator.AllocateAddress(reply->buffer, size, 1, &buffer,
683 			true);
684 	}
685 
686 	// execute the request
687 	if (result == B_OK) {
688 		result = volume->ReadFileCache(request->vnid, request->cookie,
689 			request->pos, buffer, &size);
690 	}
691 
692 	// prepare the reply
693 	reply->error = result;
694 	reply->bytesRead = size;
695 
696 	// send the reply
697 	if (reply->error == B_OK && reply->bytesRead > 0) {
698 		SingleReplyRequestHandler handler(RECEIPT_ACK_REPLY);
699 		return fPort->SendRequest(&allocator, &handler);
700 	}
701 
702 	return fPort->SendRequest(&allocator);
703 }
704 
705 
706 // _HandleRequest
707 status_t
708 KernelRequestHandler::_HandleRequest(FileCacheWriteRequest* request)
709 {
710 	// check and execute the request
711 	Volume* volume = NULL;
712 	status_t result = _GetVolume(request->nsid, &volume);
713 	VolumePutter _(volume);
714 
715 	size_t size = 0;
716 	if (result == B_OK) {
717 		const void* data = request->buffer.GetData();
718 		size = request->size;
719 		if (data != NULL) {
720 			if (size != (size_t)request->buffer.GetSize())
721 				result = B_BAD_DATA;
722 		}
723 
724 		if (result == B_OK) {
725 			result = volume->WriteFileCache(request->vnid, request->cookie,
726 				request->pos, data, &size);
727 		}
728 	}
729 
730 	// prepare the reply
731 	RequestAllocator allocator(fPort->GetPort());
732 	FileCacheWriteReply* reply;
733 	status_t error = AllocateRequest(allocator, &reply);
734 	if (error != B_OK)
735 		return error;
736 	reply->error = result;
737 	reply->bytesWritten = size;
738 
739 	// send the reply
740 	return fPort->SendRequest(&allocator);
741 }
742 
743 
744 // _HandleRequest
745 status_t
746 KernelRequestHandler::_HandleRequest(DoIterativeFDIORequest* request)
747 {
748 	// check and execute the request
749 	Volume* volume = NULL;
750 	status_t result = _GetVolume(request->nsid, &volume);
751 	VolumePutter _(volume);
752 
753 	uint32 vecCount = request->vecCount;
754 	if (result == B_OK && vecCount > DoIterativeFDIORequest::MAX_VECS)
755 		result = B_BAD_VALUE;
756 
757 	if (result == B_OK) {
758 		result = volume->DoIterativeFDIO(request->fd, request->request,
759 			request->cookie, request->vecs, vecCount);
760 	}
761 
762 	// prepare the reply
763 	RequestAllocator allocator(fPort->GetPort());
764 	DoIterativeFDIOReply* reply;
765 	status_t error = AllocateRequest(allocator, &reply);
766 	if (error != B_OK)
767 		return error;
768 	reply->error = result;
769 
770 	// send the reply
771 	return fPort->SendRequest(&allocator);
772 }
773 
774 
775 status_t
776 KernelRequestHandler::_HandleRequest(ReadFromIORequestRequest* request)
777 {
778 	// check the request
779 	Volume* volume = NULL;
780 	status_t result = _GetVolume(request->nsid, &volume);
781 	VolumePutter _(volume);
782 
783 	size_t size = request->size;
784 
785 	// allocate the reply
786 	RequestAllocator allocator(fPort->GetPort());
787 	ReadFromIORequestReply* reply;
788 	status_t error = AllocateRequest(allocator, &reply);
789 	if (error != B_OK)
790 		RETURN_ERROR(error);
791 
792 	void* buffer;
793 	if (result == B_OK) {
794 		result = allocator.AllocateAddress(reply->buffer, size, 1, &buffer,
795 			true);
796 	}
797 
798 	// execute the request
799 	if (result == B_OK)
800 		result = volume->ReadFromIORequest(request->request, buffer, size);
801 
802 	// prepare the reply
803 	reply->error = result;
804 
805 	// send the reply
806 	if (reply->error == B_OK && size > 0) {
807 		SingleReplyRequestHandler handler(RECEIPT_ACK_REPLY);
808 		return fPort->SendRequest(&allocator, &handler);
809 	}
810 
811 	return fPort->SendRequest(&allocator);
812 }
813 
814 
815 status_t
816 KernelRequestHandler::_HandleRequest(WriteToIORequestRequest* request)
817 {
818 	// check and execute the request
819 	Volume* volume = NULL;
820 	status_t result = _GetVolume(request->nsid, &volume);
821 	VolumePutter _(volume);
822 
823 	if (result == B_OK) {
824 		result = volume->WriteToIORequest(request->request,
825 			request->buffer.GetData(), request->buffer.GetSize());
826 	}
827 
828 	// prepare the reply
829 	RequestAllocator allocator(fPort->GetPort());
830 	WriteToIORequestReply* reply;
831 	status_t error = AllocateRequest(allocator, &reply);
832 	if (error != B_OK)
833 		return error;
834 	reply->error = result;
835 
836 	// send the reply
837 	return fPort->SendRequest(&allocator);
838 }
839 
840 
841 // _HandleRequest
842 status_t
843 KernelRequestHandler::_HandleRequest(NotifyIORequestRequest* request)
844 {
845 	// check and execute the request
846 	Volume* volume = NULL;
847 	status_t result = _GetVolume(request->nsid, &volume);
848 	VolumePutter _(volume);
849 
850 	if (result == B_OK)
851 		result = volume->NotifyIORequest(request->request, request->status);
852 
853 	// prepare the reply
854 	RequestAllocator allocator(fPort->GetPort());
855 	NotifyIORequestReply* reply;
856 	status_t error = AllocateRequest(allocator, &reply);
857 	if (error != B_OK)
858 		return error;
859 	reply->error = result;
860 
861 	// send the reply
862 	return fPort->SendRequest(&allocator);
863 }
864 
865 
866 status_t
867 KernelRequestHandler::_HandleRequest(AddNodeListenerRequest* request)
868 {
869 	// check and execute the request
870 	status_t result = fFileSystem->AddNodeListener(request->device,
871 		request->node, request->flags, request->listener);
872 
873 	// prepare the reply
874 	RequestAllocator allocator(fPort->GetPort());
875 	AddNodeListenerReply* reply;
876 	status_t error = AllocateRequest(allocator, &reply);
877 	if (error != B_OK)
878 		return error;
879 
880 	reply->error = result;
881 
882 	// send the reply
883 	return fPort->SendRequest(&allocator);
884 }
885 
886 
887 status_t
888 KernelRequestHandler::_HandleRequest(RemoveNodeListenerRequest* request)
889 {
890 	// check and execute the request
891 	status_t result = fFileSystem->RemoveNodeListener(request->device,
892 		request->node, request->listener);
893 
894 	// prepare the reply
895 	RequestAllocator allocator(fPort->GetPort());
896 	RemoveNodeListenerReply* reply;
897 	status_t error = AllocateRequest(allocator, &reply);
898 	if (error != B_OK)
899 		return error;
900 
901 	reply->error = result;
902 
903 	// send the reply
904 	return fPort->SendRequest(&allocator);
905 }
906 
907 
908 // _GetVolume
909 status_t
910 KernelRequestHandler::_GetVolume(dev_t id, Volume** volume)
911 {
912 	if (fVolume) {
913 		if (fVolume->GetID() != id) {
914 			*volume = NULL;
915 			return B_BAD_VALUE;
916 		}
917 		fVolume->AcquireReference();
918 		*volume = fVolume;
919 		return B_OK;
920 	}
921 	*volume = fFileSystem->GetVolume(id);
922 	return (*volume ? B_OK : B_BAD_VALUE);
923 }
924 
925