Files
haiku-beta6/src/add-ons/kernel/file_systems/userlandfs/server/haiku/HaikuKernelFileSystem.cpp
T
Ingo Weinhold 4649fe05ef * Haiku kernel interface emulation: Retrieve the capabilities for each vnode.
We do some caching using a hash table indexed by the operations vector.
* Pass the vnode capabilities to the kernel module.
* In the kernel tailor the operation vectors for volumes and vnodes passed to
  the VFS according to the respective capabilities. This way those vectors look
  pretty much like those from the client FS. This saves unnecessary calls when
  hooks are not implemented and should also fix compatibility problems in cases
  where not implementing a hook and returning an error don't mean the same to
  the VFS.
* Inlined some of the kernel module Volume class getters.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@29572 a95241bf-73f2-0310-859d-f6bbb57e9c96
2009-03-17 18:51:43 +00:00

420 lines
11 KiB
C++

/*
* Copyright 2007-2009, Ingo Weinhold, [email protected].
* Distributed under the terms of the MIT License.
*/
#include "HaikuKernelFileSystem.h"
#include <string.h>
#include <new>
#include <fs_interface.h>
#include <AutoLocker.h>
#include <block_cache.h>
#include <condition_variable.h>
#include "HaikuKernelIORequest.h"
#include "HaikuKernelVolume.h"
// IORequestHashDefinition
struct HaikuKernelFileSystem::IORequestHashDefinition {
typedef int32 KeyType;
typedef HaikuKernelIORequest ValueType;
size_t HashKey(int32 key) const
{ return key; }
size_t Hash(const HaikuKernelIORequest* value) const
{ return value->id; }
bool Compare(int32 key, const HaikuKernelIORequest* value) const
{ return value->id == key; }
HashTableLink<HaikuKernelIORequest>*
GetLink(HaikuKernelIORequest* value) const
{ return value; }
};
// IORequestTable
struct HaikuKernelFileSystem::IORequestTable
: public OpenHashTable<IORequestHashDefinition> {
typedef int32 KeyType;
typedef HaikuKernelIORequest ValueType;
size_t HashKey(int32 key) const
{ return key; }
size_t Hash(const HaikuKernelIORequest* value) const
{ return value->id; }
bool Compare(int32 key, const HaikuKernelIORequest* value) const
{ return value->id == key; }
HashTableLink<HaikuKernelIORequest>*
GetLink(HaikuKernelIORequest* value) const
{ return value; }
};
// NodeCapabilitiesHashDefinition
struct HaikuKernelFileSystem::NodeCapabilitiesHashDefinition {
typedef fs_vnode_ops* KeyType;
typedef HaikuKernelNode::Capabilities ValueType;
size_t HashKey(fs_vnode_ops* key) const
{ return (size_t)(addr_t)key; }
size_t Hash(const ValueType* value) const
{ return HashKey(value->ops); }
bool Compare(fs_vnode_ops* key, const ValueType* value) const
{ return value->ops == key; }
HashTableLink<ValueType>* GetLink(ValueType* value) const
{ return value; }
};
// NodeCapabilitiesTable
struct HaikuKernelFileSystem::NodeCapabilitiesTable
: public OpenHashTable<NodeCapabilitiesHashDefinition> {
};
// constructor
HaikuKernelFileSystem::HaikuKernelFileSystem(file_system_module_info* fsModule)
:
FileSystem(),
fFSModule(fsModule),
fIORequests(NULL),
fNodeCapabilities(NULL),
fLock("HaikuKernelFileSystem")
{
_InitCapabilities();
}
// destructor
HaikuKernelFileSystem::~HaikuKernelFileSystem()
{
// call the kernel module uninitialization
if (fFSModule->info.std_ops)
fFSModule->info.std_ops(B_MODULE_UNINIT);
delete fIORequests;
delete fNodeCapabilities;
// TODO: Call the cleanup methods (condition vars, block cache)!
}
// Init
status_t
HaikuKernelFileSystem::Init()
{
status_t error = fLock.InitCheck();
if (error != B_OK)
RETURN_ERROR(error);
// init condition variables
condition_variable_init();
// TODO: Call the cleanup methods, if something goes wrong!
// init block cache
error = block_cache_init();
if (error != B_OK)
RETURN_ERROR(error);
// create I/O request map
fIORequests = new(std::nothrow) IORequestTable;
if (fIORequests == NULL)
RETURN_ERROR(B_NO_MEMORY);
error = fIORequests->Init();
if (error != B_OK)
RETURN_ERROR(error);
// create the node capabilites map
fNodeCapabilities = new(std::nothrow) NodeCapabilitiesTable;
if (fNodeCapabilities == NULL)
RETURN_ERROR(B_NO_MEMORY);
error = fNodeCapabilities->Init();
if (error != B_OK)
RETURN_ERROR(error);
// call the kernel module initialization (if any)
if (!fFSModule->info.std_ops)
return B_OK;
error = fFSModule->info.std_ops(B_MODULE_INIT);
if (error != B_OK)
RETURN_ERROR(error);
return B_OK;
}
// CreateVolume
status_t
HaikuKernelFileSystem::CreateVolume(Volume** _volume, dev_t id)
{
// check initialization and parameters
if (!fFSModule || !_volume)
return B_BAD_VALUE;
// create and init the volume
HaikuKernelVolume* volume
= new(std::nothrow) HaikuKernelVolume(this, id, fFSModule);
if (!volume)
return B_NO_MEMORY;
status_t error = volume->Init();
if (error != B_OK) {
delete volume;
return error;
}
*_volume = volume;
return B_OK;
}
// DeleteVolume
status_t
HaikuKernelFileSystem::DeleteVolume(Volume* volume)
{
if (!volume || !dynamic_cast<HaikuKernelVolume*>(volume))
return B_BAD_VALUE;
delete volume;
return B_OK;
}
// AddIORequest
status_t
HaikuKernelFileSystem::AddIORequest(HaikuKernelIORequest* request)
{
AutoLocker<Locker> _(fLock);
// check, if a request with that ID is already in the map
if (fIORequests->Lookup(request->id) != NULL)
RETURN_ERROR(B_BAD_VALUE);
fIORequests->Insert(request);
return B_OK;
}
// GetIORequest
HaikuKernelIORequest*
HaikuKernelFileSystem::GetIORequest(int32 requestID)
{
AutoLocker<Locker> _(fLock);
HaikuKernelIORequest* request = fIORequests->Lookup(requestID);
if (request != NULL)
request->refCount++;
return request;
}
// PutIORequest
void
HaikuKernelFileSystem::PutIORequest(HaikuKernelIORequest* request,
int32 refCount)
{
AutoLocker<Locker> locker(fLock);
if ((request->refCount -= refCount) <= 0) {
fIORequests->Remove(request);
locker.Unlock();
delete request;
}
}
// GetVNodeCapabilities
HaikuKernelNode::Capabilities*
HaikuKernelFileSystem::GetNodeCapabilities(fs_vnode_ops* ops)
{
AutoLocker<Locker> locker(fLock);
// check whether the ops are already known
HaikuKernelNode::Capabilities* capabilities
= fNodeCapabilities->Lookup(ops);
if (capabilities != NULL) {
capabilities->refCount++;
return capabilities;
}
// get the capabilities implied by the ops vector
FSVNodeCapabilities nodeCapabilities;
_InitNodeCapabilities(ops, nodeCapabilities);
// create a new object
capabilities = new(std::nothrow) HaikuKernelNode::Capabilities(ops,
nodeCapabilities);
if (capabilities == NULL)
return NULL;
fNodeCapabilities->Insert(capabilities);
return capabilities;
}
// PutVNodeCapabilities
void
HaikuKernelFileSystem::PutNodeCapabilities(
HaikuKernelNode::Capabilities* capabilities)
{
AutoLocker<Locker> locker(fLock);
if (--capabilities->refCount == 0) {
fNodeCapabilities->Remove(capabilities);
delete capabilities;
}
}
// _InitCapabilities
void
HaikuKernelFileSystem::_InitCapabilities()
{
fCapabilities.ClearAll();
// FS interface type
fClientFSType = CLIENT_FS_HAIKU_KERNEL;
// FS operations
fCapabilities.Set(FS_CAPABILITY_MOUNT, fFSModule->mount);
}
/*static*/ void
HaikuKernelFileSystem::_InitNodeCapabilities(fs_vnode_ops* ops,
FSVNodeCapabilities& capabilities)
{
capabilities.ClearAll();
// vnode operations
capabilities.Set(FS_VNODE_CAPABILITY_LOOKUP, ops->lookup);
capabilities.Set(FS_VNODE_CAPABILITY_GET_VNODE_NAME, ops->get_vnode_name);
capabilities.Set(FS_VNODE_CAPABILITY_PUT_VNODE, ops->put_vnode);
capabilities.Set(FS_VNODE_CAPABILITY_REMOVE_VNODE, ops->remove_vnode);
// asynchronous I/O
capabilities.Set(FS_VNODE_CAPABILITY_IO, ops->io);
capabilities.Set(FS_VNODE_CAPABILITY_CANCEL_IO, ops->cancel_io);
// cache file access
capabilities.Set(FS_VNODE_CAPABILITY_GET_FILE_MAP, ops->get_file_map);
// common operations
capabilities.Set(FS_VNODE_CAPABILITY_IOCTL, ops->ioctl);
capabilities.Set(FS_VNODE_CAPABILITY_SET_FLAGS, ops->set_flags);
capabilities.Set(FS_VNODE_CAPABILITY_SELECT, ops->select);
capabilities.Set(FS_VNODE_CAPABILITY_DESELECT, ops->deselect);
capabilities.Set(FS_VNODE_CAPABILITY_FSYNC, ops->fsync);
capabilities.Set(FS_VNODE_CAPABILITY_READ_SYMLINK, ops->read_symlink);
capabilities.Set(FS_VNODE_CAPABILITY_CREATE_SYMLINK, ops->create_symlink);
capabilities.Set(FS_VNODE_CAPABILITY_LINK, ops->link);
capabilities.Set(FS_VNODE_CAPABILITY_UNLINK, ops->unlink);
capabilities.Set(FS_VNODE_CAPABILITY_RENAME, ops->rename);
capabilities.Set(FS_VNODE_CAPABILITY_ACCESS, ops->access);
capabilities.Set(FS_VNODE_CAPABILITY_READ_STAT, ops->read_stat);
capabilities.Set(FS_VNODE_CAPABILITY_WRITE_STAT, ops->write_stat);
// file operations
capabilities.Set(FS_VNODE_CAPABILITY_CREATE, ops->create);
capabilities.Set(FS_VNODE_CAPABILITY_OPEN, ops->open);
capabilities.Set(FS_VNODE_CAPABILITY_CLOSE, ops->close);
capabilities.Set(FS_VNODE_CAPABILITY_FREE_COOKIE, ops->free_cookie);
capabilities.Set(FS_VNODE_CAPABILITY_READ, ops->read);
capabilities.Set(FS_VNODE_CAPABILITY_WRITE, ops->write);
// directory operations
capabilities.Set(FS_VNODE_CAPABILITY_CREATE_DIR, ops->create_dir);
capabilities.Set(FS_VNODE_CAPABILITY_REMOVE_DIR, ops->remove_dir);
capabilities.Set(FS_VNODE_CAPABILITY_OPEN_DIR, ops->open_dir);
capabilities.Set(FS_VNODE_CAPABILITY_CLOSE_DIR, ops->close_dir);
capabilities.Set(FS_VNODE_CAPABILITY_FREE_DIR_COOKIE, ops->free_dir_cookie);
capabilities.Set(FS_VNODE_CAPABILITY_READ_DIR, ops->read_dir);
capabilities.Set(FS_VNODE_CAPABILITY_REWIND_DIR, ops->rewind_dir);
// attribute directory operations
capabilities.Set(FS_VNODE_CAPABILITY_OPEN_ATTR_DIR, ops->open_attr_dir);
capabilities.Set(FS_VNODE_CAPABILITY_CLOSE_ATTR_DIR, ops->close_attr_dir);
capabilities.Set(FS_VNODE_CAPABILITY_FREE_ATTR_DIR_COOKIE,
ops->free_attr_dir_cookie);
capabilities.Set(FS_VNODE_CAPABILITY_READ_ATTR_DIR, ops->read_attr_dir);
capabilities.Set(FS_VNODE_CAPABILITY_REWIND_ATTR_DIR, ops->rewind_attr_dir);
// attribute operations
capabilities.Set(FS_VNODE_CAPABILITY_CREATE_ATTR, ops->create_attr);
capabilities.Set(FS_VNODE_CAPABILITY_OPEN_ATTR, ops->open_attr);
capabilities.Set(FS_VNODE_CAPABILITY_CLOSE_ATTR, ops->close_attr);
capabilities.Set(FS_VNODE_CAPABILITY_FREE_ATTR_COOKIE,
ops->free_attr_cookie);
capabilities.Set(FS_VNODE_CAPABILITY_READ_ATTR, ops->read_attr);
capabilities.Set(FS_VNODE_CAPABILITY_WRITE_ATTR, ops->write_attr);
capabilities.Set(FS_VNODE_CAPABILITY_READ_ATTR_STAT, ops->read_attr_stat);
capabilities.Set(FS_VNODE_CAPABILITY_WRITE_ATTR_STAT,
ops->write_attr_stat);
capabilities.Set(FS_VNODE_CAPABILITY_RENAME_ATTR, ops->rename_attr);
capabilities.Set(FS_VNODE_CAPABILITY_REMOVE_ATTR, ops->remove_attr);
// support for node and FS layers
capabilities.Set(FS_VNODE_CAPABILITY_CREATE_SPECIAL_NODE,
ops->create_special_node);
capabilities.Set(FS_VNODE_CAPABILITY_GET_SUPER_VNODE, ops->get_super_vnode);
}
// #pragma mark - bootstrapping
status_t
userlandfs_create_file_system(const char* fsName, image_id image,
FileSystem** _fileSystem)
{
// get the modules
module_info** modules;
status_t error = get_image_symbol(image, "modules", B_SYMBOL_TYPE_DATA,
(void**)&modules);
if (error != B_OK)
RETURN_ERROR(error);
// module name must match "file_systems/<name>/v1"
char moduleName[B_PATH_NAME_LENGTH];
snprintf(moduleName, sizeof(moduleName), "file_systems/%s/v1", fsName);
// find the module
file_system_module_info* module = NULL;
for (int32 i = 0; modules[i]->name; i++) {
if (strcmp(modules[i]->name, moduleName) == 0) {
module = (file_system_module_info*)modules[i];
break;
}
}
if (!module)
RETURN_ERROR(B_ERROR);
// create the file system
HaikuKernelFileSystem* fileSystem
= new(std::nothrow) HaikuKernelFileSystem(module);
if (!fileSystem)
RETURN_ERROR(B_NO_MEMORY);
error = fileSystem->Init();
if (error != B_OK) {
delete fileSystem;
return error;
}
*_fileSystem = fileSystem;
return B_OK;
}