1/* 2 * Copyright 2007-2009, Ingo Weinhold, ingo_weinhold@gmx.de. 3 * Distributed under the terms of the MIT License. 4 */ 5 6#include "HaikuKernelFileSystem.h" 7 8#include <string.h> 9 10#include <new> 11 12#include <fs_interface.h> 13 14#include <AutoLocker.h> 15 16#include <block_cache.h> 17#include <condition_variable.h> 18#include <file_cache.h> 19 20#include "HaikuKernelIORequest.h" 21#include "HaikuKernelVolume.h" 22 23 24// IORequestHashDefinition 25struct HaikuKernelFileSystem::IORequestHashDefinition { 26 typedef int32 KeyType; 27 typedef HaikuKernelIORequest ValueType; 28 29 size_t HashKey(int32 key) const 30 { return key; } 31 size_t Hash(const HaikuKernelIORequest* value) const 32 { return value->id; } 33 bool Compare(int32 key, const HaikuKernelIORequest* value) const 34 { return value->id == key; } 35 HaikuKernelIORequest*& GetLink(HaikuKernelIORequest* value) const 36 { return value->hashLink; } 37}; 38 39 40// IORequestTable 41struct HaikuKernelFileSystem::IORequestTable 42 : public BOpenHashTable<IORequestHashDefinition> { 43 typedef int32 KeyType; 44 typedef HaikuKernelIORequest ValueType; 45 46 size_t HashKey(int32 key) const 47 { return key; } 48 size_t Hash(const HaikuKernelIORequest* value) const 49 { return value->id; } 50 bool Compare(int32 key, const HaikuKernelIORequest* value) const 51 { return value->id == key; } 52 HaikuKernelIORequest*& GetLink(HaikuKernelIORequest* value) const 53 { return value->hashLink; } 54}; 55 56 57// NodeCapabilitiesHashDefinition 58struct HaikuKernelFileSystem::NodeCapabilitiesHashDefinition { 59 typedef fs_vnode_ops* KeyType; 60 typedef HaikuKernelNode::Capabilities ValueType; 61 62 size_t HashKey(fs_vnode_ops* key) const 63 { return (size_t)(addr_t)key; } 64 size_t Hash(const ValueType* value) const 65 { return HashKey(value->ops); } 66 bool Compare(fs_vnode_ops* key, const ValueType* value) const 67 { return value->ops == key; } 68 ValueType*& GetLink(ValueType* value) const 69 { return value->hashLink; } 70}; 71 72 73// NodeCapabilitiesTable 74struct HaikuKernelFileSystem::NodeCapabilitiesTable 75 : public BOpenHashTable<NodeCapabilitiesHashDefinition> { 76}; 77 78 79// constructor 80HaikuKernelFileSystem::HaikuKernelFileSystem(const char* fsName, 81 file_system_module_info* fsModule) 82 : 83 FileSystem(fsName), 84 fFSModule(fsModule), 85 fIORequests(NULL), 86 fNodeCapabilities(NULL), 87 fLock("HaikuKernelFileSystem") 88{ 89 _InitCapabilities(); 90} 91 92 93// destructor 94HaikuKernelFileSystem::~HaikuKernelFileSystem() 95{ 96 // call the kernel module uninitialization 97 if (fFSModule->info.std_ops) 98 fFSModule->info.std_ops(B_MODULE_UNINIT); 99 100 delete fIORequests; 101 delete fNodeCapabilities; 102 103// TODO: Call the cleanup methods (condition vars, block cache)! 104} 105 106 107// Init 108status_t 109HaikuKernelFileSystem::Init() 110{ 111 status_t error = fLock.InitCheck(); 112 if (error != B_OK) 113 RETURN_ERROR(error); 114 115 // init condition variables 116 condition_variable_init(); 117// TODO: Call the cleanup methods, if something goes wrong! 118 119 // init block cache 120 error = block_cache_init(); 121 if (error != B_OK) 122 RETURN_ERROR(error); 123 124 // init file map 125 error = file_map_init(); 126 if (error != B_OK) 127 RETURN_ERROR(error); 128 129 // create I/O request map 130 fIORequests = new(std::nothrow) IORequestTable; 131 if (fIORequests == NULL) 132 RETURN_ERROR(B_NO_MEMORY); 133 134 error = fIORequests->Init(); 135 if (error != B_OK) 136 RETURN_ERROR(error); 137 138 // create the node capabilites map 139 fNodeCapabilities = new(std::nothrow) NodeCapabilitiesTable; 140 if (fNodeCapabilities == NULL) 141 RETURN_ERROR(B_NO_MEMORY); 142 143 error = fNodeCapabilities->Init(); 144 if (error != B_OK) 145 RETURN_ERROR(error); 146 147 // call the kernel module initialization (if any) 148 if (!fFSModule->info.std_ops) 149 return B_OK; 150 151 error = fFSModule->info.std_ops(B_MODULE_INIT); 152 if (error != B_OK) 153 RETURN_ERROR(error); 154 155 return B_OK; 156} 157 158 159// CreateVolume 160status_t 161HaikuKernelFileSystem::CreateVolume(Volume** _volume, dev_t id) 162{ 163 // check initialization and parameters 164 if (!fFSModule || !_volume) 165 return B_BAD_VALUE; 166 167 // create and init the volume 168 HaikuKernelVolume* volume 169 = new(std::nothrow) HaikuKernelVolume(this, id, fFSModule); 170 if (!volume) 171 return B_NO_MEMORY; 172 173 status_t error = volume->Init(); 174 if (error != B_OK) { 175 delete volume; 176 return error; 177 } 178 179 *_volume = volume; 180 return B_OK; 181} 182 183 184// DeleteVolume 185status_t 186HaikuKernelFileSystem::DeleteVolume(Volume* volume) 187{ 188 if (!volume || !dynamic_cast<HaikuKernelVolume*>(volume)) 189 return B_BAD_VALUE; 190 delete volume; 191 return B_OK; 192} 193 194 195// AddIORequest 196status_t 197HaikuKernelFileSystem::AddIORequest(HaikuKernelIORequest* request) 198{ 199 AutoLocker<Locker> _(fLock); 200 201 // check, if a request with that ID is already in the map 202 if (fIORequests->Lookup(request->id) != NULL) 203 RETURN_ERROR(B_BAD_VALUE); 204 205 fIORequests->Insert(request); 206 return B_OK; 207} 208 209 210// GetIORequest 211HaikuKernelIORequest* 212HaikuKernelFileSystem::GetIORequest(int32 requestID) 213{ 214 AutoLocker<Locker> _(fLock); 215 216 HaikuKernelIORequest* request = fIORequests->Lookup(requestID); 217 if (request != NULL) 218 request->refCount++; 219 220 return request; 221} 222 223 224// PutIORequest 225void 226HaikuKernelFileSystem::PutIORequest(HaikuKernelIORequest* request, 227 int32 refCount) 228{ 229 AutoLocker<Locker> locker(fLock); 230 231 if ((request->refCount -= refCount) <= 0) { 232 fIORequests->Remove(request); 233 locker.Unlock(); 234 delete request; 235 } 236} 237 238 239// GetVNodeCapabilities 240HaikuKernelNode::Capabilities* 241HaikuKernelFileSystem::GetNodeCapabilities(fs_vnode_ops* ops) 242{ 243 AutoLocker<Locker> locker(fLock); 244 245 // check whether the ops are already known 246 HaikuKernelNode::Capabilities* capabilities 247 = fNodeCapabilities->Lookup(ops); 248 if (capabilities != NULL) { 249 capabilities->refCount++; 250 return capabilities; 251 } 252 253 // get the capabilities implied by the ops vector 254 FSVNodeCapabilities nodeCapabilities; 255 _InitNodeCapabilities(ops, nodeCapabilities); 256 257 // create a new object 258 capabilities = new(std::nothrow) HaikuKernelNode::Capabilities(ops, 259 nodeCapabilities); 260 if (capabilities == NULL) 261 return NULL; 262 263 fNodeCapabilities->Insert(capabilities); 264 265 return capabilities; 266} 267 268 269// PutVNodeCapabilities 270void 271HaikuKernelFileSystem::PutNodeCapabilities( 272 HaikuKernelNode::Capabilities* capabilities) 273{ 274 AutoLocker<Locker> locker(fLock); 275 276 if (--capabilities->refCount == 0) { 277 fNodeCapabilities->Remove(capabilities); 278 delete capabilities; 279 } 280} 281 282 283// _InitCapabilities 284void 285HaikuKernelFileSystem::_InitCapabilities() 286{ 287 fCapabilities.ClearAll(); 288 289 // FS interface type 290 fClientFSType = CLIENT_FS_HAIKU_KERNEL; 291 292 // FS operations 293 fCapabilities.Set(FS_CAPABILITY_MOUNT, fFSModule->mount); 294} 295 296 297/*static*/ void 298HaikuKernelFileSystem::_InitNodeCapabilities(fs_vnode_ops* ops, 299 FSVNodeCapabilities& capabilities) 300{ 301 capabilities.ClearAll(); 302 303 // vnode operations 304 capabilities.Set(FS_VNODE_CAPABILITY_LOOKUP, ops->lookup); 305 capabilities.Set(FS_VNODE_CAPABILITY_GET_VNODE_NAME, ops->get_vnode_name); 306 capabilities.Set(FS_VNODE_CAPABILITY_PUT_VNODE, ops->put_vnode); 307 capabilities.Set(FS_VNODE_CAPABILITY_REMOVE_VNODE, ops->remove_vnode); 308 309 // asynchronous I/O 310 capabilities.Set(FS_VNODE_CAPABILITY_IO, ops->io); 311 capabilities.Set(FS_VNODE_CAPABILITY_CANCEL_IO, ops->cancel_io); 312 313 // cache file access 314 capabilities.Set(FS_VNODE_CAPABILITY_GET_FILE_MAP, ops->get_file_map); 315 316 // common operations 317 capabilities.Set(FS_VNODE_CAPABILITY_IOCTL, ops->ioctl); 318 capabilities.Set(FS_VNODE_CAPABILITY_SET_FLAGS, ops->set_flags); 319 capabilities.Set(FS_VNODE_CAPABILITY_SELECT, ops->select); 320 capabilities.Set(FS_VNODE_CAPABILITY_DESELECT, ops->deselect); 321 capabilities.Set(FS_VNODE_CAPABILITY_FSYNC, ops->fsync); 322 323 capabilities.Set(FS_VNODE_CAPABILITY_READ_SYMLINK, ops->read_symlink); 324 capabilities.Set(FS_VNODE_CAPABILITY_CREATE_SYMLINK, ops->create_symlink); 325 326 capabilities.Set(FS_VNODE_CAPABILITY_LINK, ops->link); 327 capabilities.Set(FS_VNODE_CAPABILITY_UNLINK, ops->unlink); 328 capabilities.Set(FS_VNODE_CAPABILITY_RENAME, ops->rename); 329 330 capabilities.Set(FS_VNODE_CAPABILITY_ACCESS, ops->access); 331 capabilities.Set(FS_VNODE_CAPABILITY_READ_STAT, ops->read_stat); 332 capabilities.Set(FS_VNODE_CAPABILITY_WRITE_STAT, ops->write_stat); 333 334 // file operations 335 capabilities.Set(FS_VNODE_CAPABILITY_CREATE, ops->create); 336 capabilities.Set(FS_VNODE_CAPABILITY_OPEN, ops->open); 337 capabilities.Set(FS_VNODE_CAPABILITY_CLOSE, ops->close); 338 capabilities.Set(FS_VNODE_CAPABILITY_FREE_COOKIE, ops->free_cookie); 339 capabilities.Set(FS_VNODE_CAPABILITY_READ, ops->read); 340 capabilities.Set(FS_VNODE_CAPABILITY_WRITE, ops->write); 341 342 // directory operations 343 capabilities.Set(FS_VNODE_CAPABILITY_CREATE_DIR, ops->create_dir); 344 capabilities.Set(FS_VNODE_CAPABILITY_REMOVE_DIR, ops->remove_dir); 345 capabilities.Set(FS_VNODE_CAPABILITY_OPEN_DIR, ops->open_dir); 346 capabilities.Set(FS_VNODE_CAPABILITY_CLOSE_DIR, ops->close_dir); 347 capabilities.Set(FS_VNODE_CAPABILITY_FREE_DIR_COOKIE, ops->free_dir_cookie); 348 capabilities.Set(FS_VNODE_CAPABILITY_READ_DIR, ops->read_dir); 349 capabilities.Set(FS_VNODE_CAPABILITY_REWIND_DIR, ops->rewind_dir); 350 351 // attribute directory operations 352 capabilities.Set(FS_VNODE_CAPABILITY_OPEN_ATTR_DIR, ops->open_attr_dir); 353 capabilities.Set(FS_VNODE_CAPABILITY_CLOSE_ATTR_DIR, ops->close_attr_dir); 354 capabilities.Set(FS_VNODE_CAPABILITY_FREE_ATTR_DIR_COOKIE, 355 ops->free_attr_dir_cookie); 356 capabilities.Set(FS_VNODE_CAPABILITY_READ_ATTR_DIR, ops->read_attr_dir); 357 capabilities.Set(FS_VNODE_CAPABILITY_REWIND_ATTR_DIR, ops->rewind_attr_dir); 358 359 // attribute operations 360 capabilities.Set(FS_VNODE_CAPABILITY_CREATE_ATTR, ops->create_attr); 361 capabilities.Set(FS_VNODE_CAPABILITY_OPEN_ATTR, ops->open_attr); 362 capabilities.Set(FS_VNODE_CAPABILITY_CLOSE_ATTR, ops->close_attr); 363 capabilities.Set(FS_VNODE_CAPABILITY_FREE_ATTR_COOKIE, 364 ops->free_attr_cookie); 365 capabilities.Set(FS_VNODE_CAPABILITY_READ_ATTR, ops->read_attr); 366 capabilities.Set(FS_VNODE_CAPABILITY_WRITE_ATTR, ops->write_attr); 367 368 capabilities.Set(FS_VNODE_CAPABILITY_READ_ATTR_STAT, ops->read_attr_stat); 369 capabilities.Set(FS_VNODE_CAPABILITY_WRITE_ATTR_STAT, 370 ops->write_attr_stat); 371 capabilities.Set(FS_VNODE_CAPABILITY_RENAME_ATTR, ops->rename_attr); 372 capabilities.Set(FS_VNODE_CAPABILITY_REMOVE_ATTR, ops->remove_attr); 373 374 // support for node and FS layers 375 capabilities.Set(FS_VNODE_CAPABILITY_CREATE_SPECIAL_NODE, 376 ops->create_special_node); 377 capabilities.Set(FS_VNODE_CAPABILITY_GET_SUPER_VNODE, ops->get_super_vnode); 378} 379 380 381// #pragma mark - bootstrapping 382 383 384status_t 385userlandfs_create_file_system(const char* fsName, image_id image, 386 FileSystem** _fileSystem) 387{ 388 // get the modules 389 module_info** modules; 390 status_t error = get_image_symbol(image, "modules", B_SYMBOL_TYPE_DATA, 391 (void**)&modules); 392 if (error != B_OK) 393 RETURN_ERROR(error); 394 395 // module name must match "file_systems/<name>/v1" 396 char moduleName[B_PATH_NAME_LENGTH]; 397 snprintf(moduleName, sizeof(moduleName), "file_systems/%s/v1", fsName); 398 399 // find the module 400 file_system_module_info* module = NULL; 401 for (int32 i = 0; modules[i] && modules[i]->name; i++) { 402 if (strcmp(modules[i]->name, moduleName) == 0) { 403 module = (file_system_module_info*)modules[i]; 404 break; 405 } 406 } 407 if (!module) 408 RETURN_ERROR(B_ERROR); 409 410 // create the file system 411 HaikuKernelFileSystem* fileSystem 412 = new(std::nothrow) HaikuKernelFileSystem(fsName, module); 413 if (!fileSystem) 414 RETURN_ERROR(B_NO_MEMORY); 415 416 error = fileSystem->Init(); 417 if (error != B_OK) { 418 delete fileSystem; 419 return error; 420 } 421 422 *_fileSystem = fileSystem; 423 return B_OK; 424} 425