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