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	}
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
131status_t
132KernelRequestHandler::_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
249status_t
250KernelRequestHandler::_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
283status_t
284KernelRequestHandler::_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
349status_t
350KernelRequestHandler::_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
372status_t
373KernelRequestHandler::_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
394status_t
395KernelRequestHandler::_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
418status_t
419KernelRequestHandler::_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
443status_t
444KernelRequestHandler::_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
469status_t
470KernelRequestHandler::_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
490status_t
491KernelRequestHandler::_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
511status_t
512KernelRequestHandler::_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
538status_t
539KernelRequestHandler::_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
563status_t
564KernelRequestHandler::_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
588status_t
589KernelRequestHandler::_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
613status_t
614KernelRequestHandler::_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
638status_t
639KernelRequestHandler::_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
663status_t
664KernelRequestHandler::_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
707status_t
708KernelRequestHandler::_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
745status_t
746KernelRequestHandler::_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
775status_t
776KernelRequestHandler::_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
815status_t
816KernelRequestHandler::_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
842status_t
843KernelRequestHandler::_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
866status_t
867KernelRequestHandler::_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
887status_t
888KernelRequestHandler::_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
909status_t
910KernelRequestHandler::_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