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