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