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
21class VolumePutter {
22public:
23	VolumePutter(Volume* volume) : fVolume(volume) {}
24	~VolumePutter()
25	{
26		if (fVolume)
27			fVolume->ReleaseReference();
28	}
29
30private:
31	Volume	*fVolume;
32};
33
34// constructor
35KernelRequestHandler::KernelRequestHandler(Volume* volume, uint32 expectedReply)
36	: RequestHandler(),
37	  fFileSystem(volume->GetFileSystem()),
38	  fVolume(volume),
39	  fExpectedReply(expectedReply)
40{
41}
42
43// constructor
44KernelRequestHandler::KernelRequestHandler(FileSystem* fileSystem,
45	uint32 expectedReply)
46	: RequestHandler(),
47	  fFileSystem(fileSystem),
48	  fVolume(NULL),
49	  fExpectedReply(expectedReply)
50{
51}
52
53// destructor
54KernelRequestHandler::~KernelRequestHandler()
55{
56}
57
58// HandleRequest
59status_t
60KernelRequestHandler::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	}
121PRINT(("KernelRequestHandler::HandleRequest(): unexpected request: %lu\n",
122request->GetType()));
123	return B_BAD_DATA;
124}
125
126// #pragma mark -
127// #pragma mark ----- notifications -----
128
129// _HandleRequest
130status_t
131KernelRequestHandler::_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
243status_t
244KernelRequestHandler::_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
277status_t
278KernelRequestHandler::_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
341status_t
342KernelRequestHandler::_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
364status_t
365KernelRequestHandler::_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
386status_t
387KernelRequestHandler::_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
410status_t
411KernelRequestHandler::_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
435status_t
436KernelRequestHandler::_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
461status_t
462KernelRequestHandler::_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
482status_t
483KernelRequestHandler::_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
503status_t
504KernelRequestHandler::_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
530status_t
531KernelRequestHandler::_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
555status_t
556KernelRequestHandler::_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
580status_t
581KernelRequestHandler::_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
605status_t
606KernelRequestHandler::_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
630status_t
631KernelRequestHandler::_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
655status_t
656KernelRequestHandler::_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
699status_t
700KernelRequestHandler::_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
737status_t
738KernelRequestHandler::_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
767status_t
768KernelRequestHandler::_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
807status_t
808KernelRequestHandler::_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
834status_t
835KernelRequestHandler::_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
858status_t
859KernelRequestHandler::_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
879status_t
880KernelRequestHandler::_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
901status_t
902KernelRequestHandler::_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