1/*
2 * Copyright 2009-2010, Ingo Weinhold, ingo_weinhold@gmx.de.
3 * Distributed under the terms of the MIT License.
4 */
5
6#include <stdarg.h>
7#include <stdio.h>
8#include <stdlib.h>
9
10#include <disk_device_manager.h>
11#include <fs_cache.h>
12#include <fs_interface.h>
13#include <io_requests.h>
14#include <KernelExport.h>
15#include <NodeMonitor.h>
16
17#include <fs/node_monitor.h>
18
19#include "Debug.h"
20
21#include "../FileSystem.h"
22#include "../IORequestInfo.h"
23#include "../kernel_emu.h"
24#include "../RequestThread.h"
25
26#include "HaikuKernelIORequest.h"
27#include "HaikuKernelNode.h"
28#include "HaikuKernelVolume.h"
29#include "vfs.h"
30
31
32// When GCC 2 compiles inline functions in debug mode, it doesn't throw away
33// the generated non-inlined functions, if they aren't used. So we have to
34// provide the dependencies referenced by inline functions in private kernel
35// headers.
36#if __GNUC__ == 2
37
38#include <cpu.h>
39#include <smp.h>
40
41cpu_ent gCPU[1];
42
43
44int32
45smp_get_current_cpu(void)
46{
47	return 0;
48}
49
50
51#endif	// __GNUC__ == 2
52
53
54// #pragma mark - Notifications
55
56
57// notify_entry_created
58status_t
59notify_entry_created(dev_t device, ino_t directory, const char *name,
60	ino_t node)
61{
62	if (!name)
63		return B_BAD_VALUE;
64
65	return UserlandFS::KernelEmu::notify_listener(B_ENTRY_CREATED, 0, device, 0,
66		directory, node, NULL, name);
67}
68
69
70// notify_entry_removed
71status_t
72notify_entry_removed(dev_t device, ino_t directory, const char *name,
73	ino_t node)
74{
75	if (!name)
76		return B_BAD_VALUE;
77
78	return UserlandFS::KernelEmu::notify_listener(B_ENTRY_REMOVED, 0, device, 0,
79		directory, node, NULL, name);
80}
81
82
83// notify_entry_moved
84status_t
85notify_entry_moved(dev_t device, ino_t fromDirectory,
86	const char *fromName, ino_t toDirectory, const char *toName,
87	ino_t node)
88{
89	if (!fromName || !toName)
90		return B_BAD_VALUE;
91
92	return UserlandFS::KernelEmu::notify_listener(B_ENTRY_MOVED, 0, device,
93		fromDirectory, toDirectory, node, fromName, toName);
94}
95
96
97// notify_stat_changed
98status_t
99notify_stat_changed(dev_t device, ino_t directory, ino_t node,
100	uint32 statFields)
101{
102	return UserlandFS::KernelEmu::notify_listener(B_STAT_CHANGED, statFields,
103		device, 0, directory, node, NULL, NULL);
104}
105
106
107// notify_attribute_changed
108status_t
109notify_attribute_changed(dev_t device, ino_t directory, ino_t node,
110	const char *attribute, int32 cause)
111{
112	if (!attribute)
113		return B_BAD_VALUE;
114
115	return UserlandFS::KernelEmu::notify_listener(B_ATTR_CHANGED, cause,
116		device, 0, directory, node, NULL, attribute);
117}
118
119
120// notify_select_event
121status_t
122notify_select_event(selectsync *sync, uint8 event)
123{
124	return UserlandFS::KernelEmu::notify_select_event(sync, event, false);
125}
126
127
128// notify_query_entry_created
129status_t
130notify_query_entry_created(port_id port, int32 token, dev_t device,
131	ino_t directory, const char *name, ino_t node)
132{
133	if (!name)
134		return B_BAD_VALUE;
135
136	return UserlandFS::KernelEmu::notify_query(port, token, B_ENTRY_CREATED,
137		device, directory, name, node);
138}
139
140
141// notify_query_entry_removed
142status_t
143notify_query_entry_removed(port_id port, int32 token, dev_t device,
144	ino_t directory, const char *name, ino_t node)
145{
146	if (!name)
147		return B_BAD_VALUE;
148
149	return UserlandFS::KernelEmu::notify_query(port, token, B_ENTRY_REMOVED,
150		device, directory, name, node);
151}
152
153
154// #pragma mark - VNodes
155
156
157// new_vnode
158status_t
159new_vnode(fs_volume *_volume, ino_t vnodeID, void *privateNode,
160	fs_vnode_ops *ops)
161{
162	HaikuKernelVolume* volume = HaikuKernelVolume::GetVolume(_volume);
163
164	// translate to a wrapper node
165	HaikuKernelNode* node;
166	status_t error = volume->NewVNode(vnodeID, privateNode, ops, &node);
167	if (error != B_OK)
168		return error;
169
170	// announce the new node
171	error = UserlandFS::KernelEmu::new_vnode(volume->GetID(), vnodeID, node,
172		node->capabilities->capabilities);
173	if (error != B_OK)
174		volume->UndoNewVNode(node);
175
176	return error;
177}
178
179
180// publish_vnode
181status_t
182publish_vnode(fs_volume *_volume, ino_t vnodeID, void *privateNode,
183	fs_vnode_ops *ops, int type, uint32 flags)
184{
185	HaikuKernelVolume* volume = HaikuKernelVolume::GetVolume(_volume);
186
187	// translate to a wrapper node
188	HaikuKernelNode* node;
189	status_t error = volume->PublishVNode(vnodeID, privateNode, ops, type,
190		flags, &node);
191	if (error != B_OK)
192		return error;
193
194	// publish the new node
195	error = UserlandFS::KernelEmu::publish_vnode(volume->GetID(), vnodeID, node,
196		type, flags, node->capabilities->capabilities);
197	if (error != B_OK)
198		volume->UndoPublishVNode(node);
199
200	return error;
201}
202
203
204// get_vnode
205status_t
206get_vnode(fs_volume *_volume, ino_t vnodeID, void **privateNode)
207{
208	HaikuKernelVolume* volume = HaikuKernelVolume::GetVolume(_volume);
209
210	// get the node
211	void* foundNode;
212	status_t error = UserlandFS::KernelEmu::get_vnode(volume->GetID(), vnodeID,
213		&foundNode);
214	if (error != B_OK)
215		return error;
216
217	if (privateNode != NULL)
218		*privateNode = ((HaikuKernelNode*)foundNode)->private_node;
219
220	return B_OK;
221}
222
223
224// put_vnode
225status_t
226put_vnode(fs_volume *_volume, ino_t vnodeID)
227{
228	HaikuKernelVolume* volume = HaikuKernelVolume::GetVolume(_volume);
229
230	return UserlandFS::KernelEmu::put_vnode(volume->GetID(), vnodeID);
231}
232
233
234// acquire_vnode
235status_t
236acquire_vnode(fs_volume *_volume, ino_t vnodeID)
237{
238	HaikuKernelVolume* volume = HaikuKernelVolume::GetVolume(_volume);
239
240	return UserlandFS::KernelEmu::acquire_vnode(volume->GetID(), vnodeID);
241}
242
243
244// remove_vnode
245status_t
246remove_vnode(fs_volume *_volume, ino_t vnodeID)
247{
248	HaikuKernelVolume* volume = HaikuKernelVolume::GetVolume(_volume);
249
250	return UserlandFS::KernelEmu::remove_vnode(volume->GetID(), vnodeID);
251}
252
253
254// unremove_vnode
255status_t
256unremove_vnode(fs_volume *_volume, ino_t vnodeID)
257{
258	HaikuKernelVolume* volume = HaikuKernelVolume::GetVolume(_volume);
259
260	return UserlandFS::KernelEmu::unremove_vnode(volume->GetID(), vnodeID);
261}
262
263
264// get_vnode_removed
265status_t
266get_vnode_removed(fs_volume *_volume, ino_t vnodeID, bool* removed)
267{
268	HaikuKernelVolume* volume = HaikuKernelVolume::GetVolume(_volume);
269
270	return UserlandFS::KernelEmu::get_vnode_removed(volume->GetID(), vnodeID,
271		removed);
272}
273
274
275// volume_for_vnode
276fs_volume*
277volume_for_vnode(fs_vnode *vnode)
278{
279	return HaikuKernelNode::GetNode(vnode)->GetVolume()->GetFSVolume();
280}
281
282
283// read_file_io_vec_pages
284status_t
285read_file_io_vec_pages(int fd, const struct file_io_vec *fileVecs,
286	size_t fileVecCount, const struct iovec *vecs, size_t vecCount,
287	uint32 *_vecIndex, size_t *_vecOffset, size_t *_bytes)
288{
289	// TODO: Implement!
290	return B_UNSUPPORTED;
291}
292
293
294// write_file_io_vec_pages
295status_t
296write_file_io_vec_pages(int fd, const struct file_io_vec *fileVecs,
297	size_t fileVecCount, const struct iovec *vecs, size_t vecCount,
298	uint32 *_vecIndex, size_t *_vecOffset, size_t *_bytes)
299{
300	// TODO: Implement!
301	return B_UNSUPPORTED;
302}
303
304
305// do_fd_io
306status_t
307do_fd_io(int fd, io_request *request)
308{
309	// TODO: Implement!
310	return B_UNSUPPORTED;
311}
312
313
314// do_iterative_fd_io
315status_t
316do_iterative_fd_io(int fd, io_request *_request, iterative_io_get_vecs getVecs,
317	iterative_io_finished finished, void *_cookie)
318{
319	HaikuKernelIORequest* request = (HaikuKernelIORequest*)_request;
320
321	// get the first vecs already -- this saves a guaranteed trip back from
322	// kernel to userland
323	file_io_vec fileVecs[DoIterativeFDIORequest::MAX_VECS];
324	size_t fileVecCount = DoIterativeFDIORequest::MAX_VECS;
325	status_t error = getVecs(_cookie, _request, request->offset,
326		request->length, fileVecs, &fileVecCount);
327	if (error != B_OK && error != B_BUFFER_OVERFLOW)
328		return error;
329
330	// create a cookie
331	HaikuKernelIterativeFDIOCookie* cookie
332		= new(std::nothrow) HaikuKernelIterativeFDIOCookie(fd, request, getVecs,
333			finished, _cookie);
334	if (cookie == NULL) {
335		finished(_cookie, _request, B_NO_MEMORY, false, 0);
336		return B_NO_MEMORY;
337	}
338
339	// send the request
340// TODO: Up to this point we should call the finished hook on error!
341	error = UserlandFS::KernelEmu::do_iterative_fd_io(
342		request->volume->GetID(), fd, request->id, cookie, fileVecs,
343		fileVecCount);
344	if (error != B_OK) {
345		delete cookie;
346		return error;
347	}
348
349	return B_OK;
350}
351
352
353// #pragma mark - I/O requests
354
355
356bool
357io_request_is_write(const io_request* request)
358{
359	return ((HaikuKernelIORequest*)request)->isWrite;
360}
361
362
363bool
364io_request_is_vip(const io_request* request)
365{
366	return ((HaikuKernelIORequest*)request)->isVIP;
367}
368
369
370off_t
371io_request_offset(const io_request* request)
372{
373	return ((HaikuKernelIORequest*)request)->offset;
374}
375
376
377off_t
378io_request_length(const io_request* request)
379{
380	return ((HaikuKernelIORequest*)request)->length;
381}
382
383
384status_t
385read_from_io_request(io_request* _request, void* buffer, size_t size)
386{
387	HaikuKernelIORequest* request = (HaikuKernelIORequest*)_request;
388
389	// send the request
390	return UserlandFS::KernelEmu::read_from_io_request(request->volume->GetID(),
391		request->id, buffer, size);
392}
393
394
395status_t
396write_to_io_request(io_request* _request, const void* buffer, size_t size)
397{
398	HaikuKernelIORequest* request = (HaikuKernelIORequest*)_request;
399
400	// send the request
401	return UserlandFS::KernelEmu::write_to_io_request(request->volume->GetID(),
402		request->id, buffer, size);
403}
404
405
406void
407notify_io_request(io_request* _request, status_t status)
408{
409	HaikuKernelIORequest* request = (HaikuKernelIORequest*)_request;
410
411	// send the request
412	UserlandFS::KernelEmu::notify_io_request(request->volume->GetID(),
413		request->id, status);
414}
415
416
417// #pragma mark - node monitoring
418
419
420status_t
421add_node_listener(dev_t device, ino_t node, uint32 flags,
422	NotificationListener& listener)
423{
424	return UserlandFS::KernelEmu::add_node_listener(device, node, flags,
425		&listener);
426}
427
428
429status_t
430remove_node_listener(dev_t device, ino_t node, NotificationListener& listener)
431{
432	return UserlandFS::KernelEmu::remove_node_listener(device, node, &listener);
433}
434
435
436// #pragma mark - Disk Device Manager
437
438
439// get_default_partition_content_name
440status_t
441get_default_partition_content_name(partition_id partitionID,
442	const char* fileSystemName, char* buffer, size_t bufferSize)
443{
444	// TODO: Improve!
445	snprintf(buffer, bufferSize, "%s Volume", fileSystemName);
446	return B_OK;
447}
448
449
450// scan_partition
451status_t
452scan_partition(partition_id partitionID)
453{
454	// Only needed when we decide to add disk system support.
455	return B_OK;
456}
457
458
459// update_disk_device_job_progress
460bool
461update_disk_device_job_progress(disk_job_id jobID, float progress)
462{
463	// Only needed when we decide to add disk system support.
464	return true;
465}
466
467
468// #pragma mark - VFS private
469
470
471status_t
472vfs_get_file_map(struct vnode *vnode, off_t offset, size_t size,
473	struct file_io_vec *vecs, size_t *_count)
474{
475	HaikuKernelNode* node = (HaikuKernelNode*)vnode;
476
477	return node->volume->GetFileMap(node, offset, size, vecs, _count);
478}
479
480
481status_t
482vfs_lookup_vnode(dev_t mountID, ino_t vnodeID, struct vnode **_vnode)
483{
484	// get the volume
485	HaikuKernelVolume* volume = dynamic_cast<HaikuKernelVolume*>(
486		FileSystem::GetInstance()->VolumeWithID(mountID));
487	if (volume == NULL)
488		return B_BAD_VALUE;
489
490	// get the node
491	HaikuKernelNode* node = volume->NodeWithID(vnodeID);
492	if (node == NULL)
493		return B_BAD_VALUE;
494
495	*_vnode = (struct vnode*)node;
496
497	return B_OK;
498}
499