xref: /haiku/src/add-ons/kernel/file_systems/userlandfs/server/haiku/haiku_kernel_emu.cpp (revision 6f7fc2204ba9aa1329eb27461240b026c7a813ed)
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 
41 cpu_ent gCPU[1];
42 
43 
44 int32
smp_get_current_cpu(void)45 smp_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
58 status_t
notify_entry_created(dev_t device,ino_t directory,const char * name,ino_t node)59 notify_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
71 status_t
notify_entry_removed(dev_t device,ino_t directory,const char * name,ino_t node)72 notify_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
84 status_t
notify_entry_moved(dev_t device,ino_t fromDirectory,const char * fromName,ino_t toDirectory,const char * toName,ino_t node)85 notify_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
98 status_t
notify_stat_changed(dev_t device,ino_t directory,ino_t node,uint32 statFields)99 notify_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
108 status_t
notify_attribute_changed(dev_t device,ino_t directory,ino_t node,const char * attribute,int32 cause)109 notify_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
121 status_t
notify_select_event(selectsync * sync,uint8 event)122 notify_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
129 status_t
notify_query_entry_created(port_id port,int32 token,dev_t device,ino_t directory,const char * name,ino_t node)130 notify_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
142 status_t
notify_query_entry_removed(port_id port,int32 token,dev_t device,ino_t directory,const char * name,ino_t node)143 notify_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
158 status_t
new_vnode(fs_volume * _volume,ino_t vnodeID,void * privateNode,fs_vnode_ops * ops)159 new_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
181 status_t
publish_vnode(fs_volume * _volume,ino_t vnodeID,void * privateNode,fs_vnode_ops * ops,int type,uint32 flags)182 publish_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
205 status_t
get_vnode(fs_volume * _volume,ino_t vnodeID,void ** privateNode)206 get_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
225 status_t
put_vnode(fs_volume * _volume,ino_t vnodeID)226 put_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
235 status_t
acquire_vnode(fs_volume * _volume,ino_t vnodeID)236 acquire_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
245 status_t
remove_vnode(fs_volume * _volume,ino_t vnodeID)246 remove_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
255 status_t
unremove_vnode(fs_volume * _volume,ino_t vnodeID)256 unremove_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
265 status_t
get_vnode_removed(fs_volume * _volume,ino_t vnodeID,bool * removed)266 get_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
276 fs_volume*
volume_for_vnode(fs_vnode * vnode)277 volume_for_vnode(fs_vnode *vnode)
278 {
279 	return HaikuKernelNode::GetNode(vnode)->GetVolume()->GetFSVolume();
280 }
281 
282 
283 // read_file_io_vec_pages
284 status_t
read_file_io_vec_pages(int fd,const struct file_io_vec * fileVecs,size_t fileVecCount,const struct iovec * vecs,size_t vecCount,uint32 * _vecIndex,size_t * _vecOffset,size_t * _bytes)285 read_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
295 status_t
write_file_io_vec_pages(int fd,const struct file_io_vec * fileVecs,size_t fileVecCount,const struct iovec * vecs,size_t vecCount,uint32 * _vecIndex,size_t * _vecOffset,size_t * _bytes)296 write_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
306 status_t
do_fd_io(int fd,io_request * request)307 do_fd_io(int fd, io_request *request)
308 {
309 	// TODO: Implement!
310 	return B_UNSUPPORTED;
311 }
312 
313 
314 // do_iterative_fd_io
315 status_t
do_iterative_fd_io(int fd,io_request * _request,iterative_io_get_vecs getVecs,iterative_io_finished finished,void * _cookie)316 do_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 
356 bool
io_request_is_write(const io_request * request)357 io_request_is_write(const io_request* request)
358 {
359 	return ((HaikuKernelIORequest*)request)->isWrite;
360 }
361 
362 
363 bool
io_request_is_vip(const io_request * request)364 io_request_is_vip(const io_request* request)
365 {
366 	return ((HaikuKernelIORequest*)request)->isVIP;
367 }
368 
369 
370 off_t
io_request_offset(const io_request * request)371 io_request_offset(const io_request* request)
372 {
373 	return ((HaikuKernelIORequest*)request)->offset;
374 }
375 
376 
377 off_t
io_request_length(const io_request * request)378 io_request_length(const io_request* request)
379 {
380 	return ((HaikuKernelIORequest*)request)->length;
381 }
382 
383 
384 status_t
read_from_io_request(io_request * _request,void * buffer,size_t size)385 read_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 
395 status_t
write_to_io_request(io_request * _request,const void * buffer,size_t size)396 write_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 
406 void
notify_io_request(io_request * _request,status_t status)407 notify_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 
420 status_t
add_node_listener(dev_t device,ino_t node,uint32 flags,NotificationListener & listener)421 add_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 
429 status_t
remove_node_listener(dev_t device,ino_t node,NotificationListener & listener)430 remove_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
440 status_t
get_default_partition_content_name(partition_id partitionID,const char * fileSystemName,char * buffer,size_t bufferSize)441 get_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
451 status_t
scan_partition(partition_id partitionID)452 scan_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
460 bool
update_disk_device_job_progress(disk_job_id jobID,float progress)461 update_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 
471 status_t
vfs_get_file_map(struct vnode * vnode,off_t offset,size_t size,struct file_io_vec * vecs,size_t * _count)472 vfs_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 
481 status_t
vfs_lookup_vnode(dev_t mountID,ino_t vnodeID,struct vnode ** _vnode)482 vfs_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