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