* 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
This commit is contained in:
Ingo Weinhold
2009-03-17 18:51:43 +00:00
parent fabcaf1c0a
commit 4649fe05ef
23 changed files with 794 additions and 216 deletions
+14 -11
View File
@@ -509,9 +509,10 @@ class ReadVNodeReply : public ReplyRequest {
public:
ReadVNodeReply() : ReplyRequest(READ_VNODE_REPLY) {}
void* node;
int type;
uint32 flags;
void* node;
int type;
uint32 flags;
FSVNodeCapabilities capabilities;
};
// WriteVNodeRequest
@@ -1604,9 +1605,10 @@ class NewVNodeRequest : public Request {
public:
NewVNodeRequest() : Request(NEW_VNODE_REQUEST) {}
dev_t nsid;
ino_t vnid;
void* node;
dev_t nsid;
ino_t vnid;
void* node;
FSVNodeCapabilities capabilities;
};
// NewVNodeReply
@@ -1620,11 +1622,12 @@ class PublishVNodeRequest : public Request {
public:
PublishVNodeRequest() : Request(PUBLISH_VNODE_REQUEST) {}
dev_t nsid;
ino_t vnid;
void* node;
int type;
uint32 flags;
dev_t nsid;
ino_t vnid;
void* node;
int type;
uint32 flags;
FSVNodeCapabilities capabilities;
};
// PublishVNodeReply
@@ -3,18 +3,22 @@
* Distributed under the terms of the MIT License.
*/
#include "Volume.h"
#include <util/AutoLock.h>
#include "AutoLocker.h"
#include "Compatibility.h"
#include "Debug.h"
#include "FileSystem.h"
#include "HashMap.h"
#include "kernel_interface.h"
#include "KernelRequestHandler.h"
#include "PortReleaser.h"
#include "RequestAllocator.h"
#include "Requests.h"
#include "Settings.h"
#include "SingleReplyRequestHandler.h"
#include "Volume.h"
// The time after which the notification thread times out at the port and
// restarts the loop. Of interest only when the FS is deleted. It is the
@@ -30,7 +34,6 @@ struct FileSystem::SelectSyncMap
FileSystem::FileSystem()
:
fVolumes(),
fVolumeLock(),
fName(),
fTeam(-1),
fNotificationPort(NULL),
@@ -42,6 +45,8 @@ FileSystem::FileSystem()
fInitialized(false),
fTerminating(false)
{
mutex_init(&fVolumeLock, "userlandfs volumes");
mutex_init(&fVNodeOpsLock, "userlandfs vnode ops");
}
// destructor
@@ -65,6 +70,18 @@ FileSystem::~FileSystem()
delete fSelectSyncs;
}
delete fSettings;
// delete vnode ops vectors -- there shouldn't be any left, though
VNodeOps* ops = fVNodeOps.Clear();
int32 count = 0;
while (ops != NULL) {
count++;
VNodeOps* next = ops->fNext;
free(ops);
ops = next;
}
if (count > 0)
WARN(("Deleted %ld vnode ops vectors!\n", count));
}
// Init
@@ -83,6 +100,11 @@ FileSystem::Init(const char* name, team_id team, Port::Info* infos, int32 count,
if (!fName.SetTo(name))
return B_NO_MEMORY;
// init VNodeOps map
status_t error = fVNodeOps.Init();
if (error != B_OK)
return error;
fTeam = team;
fCapabilities = capabilities;
@@ -96,7 +118,7 @@ FileSystem::Init(const char* name, team_id team, Port::Info* infos, int32 count,
fNotificationPort = new(nothrow) RequestPort(infos);
if (!fNotificationPort)
RETURN_ERROR(B_NO_MEMORY);
status_t error = fNotificationPort->InitCheck();
error = fNotificationPort->InitCheck();
if (error != B_OK)
return error;
@@ -198,18 +220,18 @@ FileSystem::Mount(fs_volume* fsVolume, const char* device, uint32 flags,
return B_NO_MEMORY;
// add volume to the volume list
fVolumeLock.Lock();
MutexLocker locker(fVolumeLock);
status_t error = fVolumes.PushBack(volume);
fVolumeLock.Unlock();
locker.Unlock();
if (error != B_OK)
return error;
// mount volume
error = volume->Mount(device, flags, parameters);
if (error != B_OK) {
fVolumeLock.Lock();
MutexLocker locker(fVolumeLock);
fVolumes.Remove(volume);
fVolumeLock.Unlock();
locker.Unlock();
volume->RemoveReference();
return error;
}
@@ -256,16 +278,15 @@ FileSystem::Initialize(const char* deviceName, const char* parameters,
void
FileSystem::VolumeUnmounted(Volume* volume)
{
fVolumeLock.Lock();
MutexLocker locker(fVolumeLock);
fVolumes.Remove(volume);
fVolumeLock.Unlock();
}
// GetVolume
Volume*
FileSystem::GetVolume(dev_t id)
{
AutoLocker<Locker> _(fVolumeLock);
MutexLocker _(fVolumeLock);
for (Vector<Volume*>::Iterator it = fVolumes.Begin();
it != fVolumes.End();
it++) {
@@ -318,6 +339,7 @@ FileSystem::RemoveSelectSyncEntry(selectsync* sync)
}
}
// KnowsSelectSyncEntry
bool
FileSystem::KnowsSelectSyncEntry(selectsync* sync)
@@ -325,6 +347,54 @@ FileSystem::KnowsSelectSyncEntry(selectsync* sync)
return fSelectSyncs->ContainsKey(sync);
}
// GetVNodeOps
VNodeOps*
FileSystem::GetVNodeOps(const FSVNodeCapabilities& capabilities)
{
MutexLocker locker(fVNodeOpsLock);
// do we already have ops for those capabilities
VNodeOps* ops = fVNodeOps.Lookup(capabilities);
if (ops != NULL) {
ops->refCount++;
return ops;
}
// no, create a new object
fs_vnode_ops* opsVector = new(std::nothrow) fs_vnode_ops;
if (opsVector == NULL)
return NULL;
// set the operations
_InitVNodeOpsVector(opsVector, capabilities);
// create the VNodeOps object
ops = new(std::nothrow) VNodeOps(capabilities, opsVector);
if (ops == NULL) {
delete opsVector;
return NULL;
}
fVNodeOps.Insert(ops);
return ops;
}
// PutVNodeOps
void
FileSystem::PutVNodeOps(VNodeOps* ops)
{
MutexLocker locker(fVNodeOpsLock);
if (--ops->refCount == 0) {
fVNodeOps.Remove(ops);
delete ops;
}
}
// IsUserlandServerThread
bool
FileSystem::IsUserlandServerThread() const
@@ -334,6 +404,108 @@ FileSystem::IsUserlandServerThread() const
return (info.team == fUserlandServerTeam);
}
// _InitVNodeOpsVector
void
FileSystem::_InitVNodeOpsVector(fs_vnode_ops* ops,
const FSVNodeCapabilities& capabilities)
{
memcpy(ops, &gUserlandFSVnodeOps, sizeof(fs_vnode_ops));
#undef CLEAR_UNSUPPORTED
#define CLEAR_UNSUPPORTED(capability, op) \
if (!capabilities.Get(capability)) \
ops->op = NULL
// vnode operations
// FS_VNODE_CAPABILITY_LOOKUP: lookup
// FS_VNODE_CAPABILITY_GET_VNODE_NAME: get_vnode_name
// emulated in userland
// FS_VNODE_CAPABILITY_PUT_VNODE: put_vnode
// FS_VNODE_CAPABILITY_REMOVE_VNODE: remove_vnode
// needed by Volume to clean up
// asynchronous I/O
CLEAR_UNSUPPORTED(FS_VNODE_CAPABILITY_IO, io);
CLEAR_UNSUPPORTED(FS_VNODE_CAPABILITY_CANCEL_IO, cancel_io);
// cache file access
ops->get_file_map = NULL; // never used
// common operations
// FS_VNODE_CAPABILITY_IOCTL: ioctl
// needed by Volume
CLEAR_UNSUPPORTED(FS_VNODE_CAPABILITY_SET_FLAGS, set_flags);
CLEAR_UNSUPPORTED(FS_VNODE_CAPABILITY_SELECT, select);
CLEAR_UNSUPPORTED(FS_VNODE_CAPABILITY_DESELECT, deselect);
CLEAR_UNSUPPORTED(FS_VNODE_CAPABILITY_FSYNC, fsync);
CLEAR_UNSUPPORTED(FS_VNODE_CAPABILITY_READ_SYMLINK, read_symlink);
CLEAR_UNSUPPORTED(FS_VNODE_CAPABILITY_CREATE_SYMLINK, create_symlink);
CLEAR_UNSUPPORTED(FS_VNODE_CAPABILITY_LINK, link);
CLEAR_UNSUPPORTED(FS_VNODE_CAPABILITY_UNLINK, unlink);
CLEAR_UNSUPPORTED(FS_VNODE_CAPABILITY_RENAME, rename);
CLEAR_UNSUPPORTED(FS_VNODE_CAPABILITY_ACCESS, access);
// FS_VNODE_CAPABILITY_READ_STAT: read_stat
// needed by Volume
CLEAR_UNSUPPORTED(FS_VNODE_CAPABILITY_WRITE_STAT, write_stat);
// file operations
CLEAR_UNSUPPORTED(FS_VNODE_CAPABILITY_CREATE, create);
CLEAR_UNSUPPORTED(FS_VNODE_CAPABILITY_OPEN, open);
// FS_VNODE_CAPABILITY_CLOSE: close
// needed by Volume
// FS_VNODE_CAPABILITY_FREE_COOKIE: free_cookie
// needed by Volume
CLEAR_UNSUPPORTED(FS_VNODE_CAPABILITY_READ, read);
CLEAR_UNSUPPORTED(FS_VNODE_CAPABILITY_WRITE, write);
// directory operations
CLEAR_UNSUPPORTED(FS_VNODE_CAPABILITY_CREATE_DIR, create_dir);
CLEAR_UNSUPPORTED(FS_VNODE_CAPABILITY_REMOVE_DIR, remove_dir);
CLEAR_UNSUPPORTED(FS_VNODE_CAPABILITY_OPEN_DIR, open_dir);
// FS_VNODE_CAPABILITY_CLOSE_DIR: close_dir
// needed by Volume
// FS_VNODE_CAPABILITY_FREE_DIR_COOKIE: free_dir_cookie
// needed by Volume
CLEAR_UNSUPPORTED(FS_VNODE_CAPABILITY_READ_DIR, read_dir);
CLEAR_UNSUPPORTED(FS_VNODE_CAPABILITY_REWIND_DIR, rewind_dir);
// attribute directory operations
CLEAR_UNSUPPORTED(FS_VNODE_CAPABILITY_OPEN_ATTR_DIR, open_attr_dir);
// FS_VNODE_CAPABILITY_CLOSE_ATTR_DIR: close_attr_dir
// needed by Volume
// FS_VNODE_CAPABILITY_FREE_ATTR_DIR_COOKIE: free_attr_dir_cookie
// needed by Volume
CLEAR_UNSUPPORTED(FS_VNODE_CAPABILITY_READ_ATTR_DIR, read_attr_dir);
CLEAR_UNSUPPORTED(FS_VNODE_CAPABILITY_REWIND_ATTR_DIR, rewind_attr_dir);
// attribute operations
CLEAR_UNSUPPORTED(FS_VNODE_CAPABILITY_CREATE_ATTR, create_attr);
CLEAR_UNSUPPORTED(FS_VNODE_CAPABILITY_OPEN_ATTR, open_attr);
// FS_VNODE_CAPABILITY_CLOSE_ATTR: close_attr
// needed by Volume
// FS_VNODE_CAPABILITY_FREE_ATTR_COOKIE: free_attr_cookie
// needed by Volume
CLEAR_UNSUPPORTED(FS_VNODE_CAPABILITY_READ_ATTR, read_attr);
CLEAR_UNSUPPORTED(FS_VNODE_CAPABILITY_WRITE_ATTR, write_attr);
CLEAR_UNSUPPORTED(FS_VNODE_CAPABILITY_READ_ATTR_STAT, read_attr_stat);
CLEAR_UNSUPPORTED(FS_VNODE_CAPABILITY_WRITE_ATTR_STAT, write_attr_stat);
CLEAR_UNSUPPORTED(FS_VNODE_CAPABILITY_RENAME_ATTR, rename_attr);
CLEAR_UNSUPPORTED(FS_VNODE_CAPABILITY_REMOVE_ATTR, remove_attr);
// support for node and FS layers
CLEAR_UNSUPPORTED(FS_VNODE_CAPABILITY_CREATE_SPECIAL_NODE,
create_special_node);
CLEAR_UNSUPPORTED(FS_VNODE_CAPABILITY_GET_SUPER_VNODE, get_super_vnode);
#undef CLEAR_UNSUPPORTED
}
// _NotificationThreadEntry
int32
FileSystem::_NotificationThreadEntry(void* data)
@@ -341,6 +513,7 @@ FileSystem::_NotificationThreadEntry(void* data)
return ((FileSystem*)data)->_NotificationThread();
}
// _NotificationThread
int32
FileSystem::_NotificationThread()
@@ -7,6 +7,10 @@
#include <fs_interface.h>
#include <util/OpenHashTable.h>
#include <lock.h>
#include "FSCapabilities.h"
#include "LazyInitializable.h"
#include "Locker.h"
@@ -20,6 +24,42 @@ struct IOCtlInfo;
class Settings;
class Volume;
struct VNodeOps : HashTableLink<VNodeOps> {
int32 refCount;
FSVNodeCapabilities capabilities;
fs_vnode_ops* ops;
VNodeOps(const FSVNodeCapabilities& capabilities, fs_vnode_ops* ops)
:
refCount(1),
capabilities(capabilities),
ops(ops)
{
}
~VNodeOps()
{
delete ops;
}
};
struct VNodeOpsHashDefinition {
typedef FSVNodeCapabilities KeyType;
typedef VNodeOps ValueType;
size_t HashKey(const FSVNodeCapabilities& key) const
{ return key.GetHashCode(); }
size_t Hash(const VNodeOps* value) const
{ return HashKey(value->capabilities); }
bool Compare(const FSVNodeCapabilities& key, const VNodeOps* value) const
{ return value->capabilities == key; }
HashTableLink<VNodeOps>* GetLink(VNodeOps* value) const
{ return value; }
};
class FileSystem {
public:
FileSystem();
@@ -52,9 +92,16 @@ public:
void RemoveSelectSyncEntry(selectsync* sync);
bool KnowsSelectSyncEntry(selectsync* sync);
VNodeOps* GetVNodeOps(
const FSVNodeCapabilities& capabilities);
void PutVNodeOps(VNodeOps* ops);
bool IsUserlandServerThread() const;
private:
void _InitVNodeOpsVector(fs_vnode_ops* ops,
const FSVNodeCapabilities& capabilities);
static int32 _NotificationThreadEntry(void* data);
int32 _NotificationThread();
@@ -62,9 +109,12 @@ private:
friend class KernelDebug;
struct SelectSyncEntry;
struct SelectSyncMap;
typedef OpenHashTable<VNodeOpsHashDefinition> VNodeOpsMap;
Vector<Volume*> fVolumes;
Locker fVolumeLock;
mutex fVolumeLock;
VNodeOpsMap fVNodeOps;
mutex fVNodeOpsLock;
String fName;
team_id fTeam;
FSCapabilities fCapabilities;
@@ -403,8 +403,11 @@ KernelRequestHandler::_HandleRequest(NewVNodeRequest* request)
Volume* volume = NULL;
status_t result = _GetVolume(request->nsid, &volume);
VolumePutter _(volume);
if (result == B_OK)
result = volume->NewVNode(request->vnid, request->node);
if (result == B_OK) {
result = volume->NewVNode(request->vnid, request->node,
request->capabilities);
}
// prepare the reply
RequestAllocator allocator(fPort->GetPort());
NewVNodeReply* reply;
@@ -412,6 +415,7 @@ KernelRequestHandler::_HandleRequest(NewVNodeRequest* request)
if (error != B_OK)
return error;
reply->error = result;
// send the reply
return fPort->SendRequest(&allocator);
}
@@ -426,7 +430,7 @@ KernelRequestHandler::_HandleRequest(PublishVNodeRequest* request)
VolumePutter _(volume);
if (result == B_OK) {
result = volume->PublishVNode(request->vnid, request->node,
request->type, request->flags);
request->type, request->flags, request->capabilities);
}
// prepare the reply
@@ -47,22 +47,32 @@ static const bigtime_t kUserlandServerlandPortTimeout = 10000000; // 10s
// VNode
struct Volume::VNode : HashTableLink<VNode> {
ino_t id;
void* clientNode;
void* fileCache;
int32 useCount;
bool valid;
ino_t id;
void* clientNode;
void* fileCache;
VNodeOps* ops;
int32 useCount;
bool valid;
VNode(ino_t id, void* clientNode)
VNode(ino_t id, void* clientNode, VNodeOps* ops)
:
id(id),
clientNode(clientNode),
fileCache(NULL),
ops(ops),
useCount(0),
valid(true)
{
}
void Delete(Volume* volume)
{
if (ops != NULL)
volume->GetFileSystem()->PutVNodeOps(ops);
delete this;
}
protected: // should be private, but gcc 2.95.3 issues a warning
~VNode()
{
if (fileCache != NULL)
@@ -278,27 +288,6 @@ Volume::~Volume()
}
// GetFileSystem
FileSystem*
Volume::GetFileSystem() const
{
return fFileSystem;
}
// GetUserlandVolume
void*
Volume::GetUserlandVolume() const
{
return fUserlandVolume;
}
// GetRootID
ino_t
Volume::GetRootID() const
{
return fRootID;
}
// #pragma mark - client methods
// GetVNode
@@ -342,7 +331,8 @@ PRINT(("acquire_vnode(%ld, %lld)\n", GetID(), vnid));
// NewVNode
status_t
Volume::NewVNode(ino_t vnid, void* clientNode)
Volume::NewVNode(ino_t vnid, void* clientNode,
const FSVNodeCapabilities& capabilities)
{
PRINT(("new_vnode(%ld, %lld)\n", GetID(), vnid));
// lookup the node
@@ -353,17 +343,24 @@ PRINT(("new_vnode(%ld, %lld)\n", GetID(), vnid));
RETURN_ERROR(B_BAD_VALUE);
}
// create the node
node = new(std::nothrow) VNode(vnid, clientNode);
if (node == NULL)
// get the ops vector for the node
VNodeOps* ops = fFileSystem->GetVNodeOps(capabilities);
if (ops == NULL)
RETURN_ERROR(B_NO_MEMORY);
// create the node
node = new(std::nothrow) VNode(vnid, clientNode, ops);
if (node == NULL) {
fFileSystem->PutVNodeOps(ops);
RETURN_ERROR(B_NO_MEMORY);
}
locker.Unlock();
// tell the VFS
status_t error = new_vnode(fFSVolume, vnid, node, &gUserlandFSVnodeOps);
status_t error = new_vnode(fFSVolume, vnid, node, node->ops->ops);
if (error != B_OK) {
delete node;
node->Delete(this);
RETURN_ERROR(error);
}
@@ -376,7 +373,8 @@ PRINT(("new_vnode(%ld, %lld)\n", GetID(), vnid));
// PublishVNode
status_t
Volume::PublishVNode(ino_t vnid, void* clientNode, int type, uint32 flags)
Volume::PublishVNode(ino_t vnid, void* clientNode, int type, uint32 flags,
const FSVNodeCapabilities& capabilities)
{
PRINT(("publish_vnode(%ld, %lld, %p)\n", GetID(), vnid, clientNode));
// lookup the node
@@ -386,21 +384,30 @@ PRINT(("publish_vnode(%ld, %lld, %p)\n", GetID(), vnid, clientNode));
if (!nodeKnown) {
// The node is not yet known -- create it.
node = new(std::nothrow) VNode(vnid, clientNode);
if (node == NULL)
// get the ops vector for the node
VNodeOps* ops = fFileSystem->GetVNodeOps(capabilities);
if (ops == NULL)
RETURN_ERROR(B_NO_MEMORY);
// create the node
node = new(std::nothrow) VNode(vnid, clientNode, ops);
if (node == NULL) {
fFileSystem->PutVNodeOps(ops);
RETURN_ERROR(B_NO_MEMORY);
}
}
locker.Unlock();
// tell the VFS
status_t error = publish_vnode(fFSVolume, vnid, node, &gUserlandFSVnodeOps,
status_t error = publish_vnode(fFSVolume, vnid, node, node->ops->ops,
type, flags);
if (error != B_OK) {
// TODO: We should note whether the node was made known via new_vnode(). If so,
// we should remove and delete it here!
if (!nodeKnown)
delete node;
node->Delete(this);
RETURN_ERROR(error);
}
@@ -690,29 +697,33 @@ Volume::Mount(const char* device, uint32 flags, const char* parameters)
// mount
status_t error = _Mount(device, flags, parameters);
if (error != B_OK)
RETURN_ERROR(error);
if (error == B_OK) {
MutexLocker locker(fLock);
// fetch the root node, so that we can serve Walk() requests on it,
// after the connection to the userland server is gone
fRootNode = fVNodes->Lookup(fRootID);
if (fRootNode == NULL) {
// The root node was not added while mounting. That's a serious
// problem -- not only because we don't have it, but also because
// the VFS requires publish_vnode() to be invoked for the root node.
ERROR(("Volume::Mount(): new_vnode() was not called for root node! "
"Unmounting...\n"));
locker.Unlock();
Unmount();
return B_ERROR;
}
// Decrement the root node use count. The publish_vnode() the client FS
// did will be balanced by the VFS.
if (fVNodeCountingEnabled)
fRootNode->useCount--;
MutexLocker locker(fLock);
// fetch the root node, so that we can serve Walk() requests on it,
// after the connection to the userland server is gone
fRootNode = fVNodes->Lookup(fRootID);
if (fRootNode == NULL) {
// The root node was not added while mounting. That's a serious
// problem -- not only because we don't have it, but also because
// the VFS requires publish_vnode() to be invoked for the root node.
ERROR(("Volume::Mount(): new_vnode() was not called for root node! "
"Unmounting...\n"));
locker.Unlock();
Unmount();
return B_ERROR;
}
return error;
// Decrement the root node use count. The publish_vnode() the client FS
// did will be balanced by the VFS.
if (fVNodeCountingEnabled)
fRootNode->useCount--;
// init the volume ops vector we'll give the VFS
_InitVolumeOps();
return B_OK;
}
// Unmount
@@ -729,7 +740,7 @@ Volume::Unmount()
VNode* node = fVNodes->Clear(true);
while (node != NULL) {
VNode* nextNode = node->fNext;
delete node;
node->Delete(this);
node = nextNode;
}
delete fVNodes;
@@ -937,8 +948,8 @@ Volume::GetVNodeName(void* _node, char* buffer, size_t bufferSize)
// ReadVNode
status_t
Volume::ReadVNode(ino_t vnid, bool reenter, void** _node, int* type,
uint32* flags)
Volume::ReadVNode(ino_t vnid, bool reenter, void** _node, fs_vnode_ops** _ops,
int* type, uint32* flags)
{
// get a free port
RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
@@ -958,7 +969,7 @@ Volume::ReadVNode(ino_t vnid, bool reenter, void** _node, int* type,
request->reenter = reenter;
// add the uninitialized node to our map
VNode* vnode = new(std::nothrow) VNode(vnid, NULL);
VNode* vnode = new(std::nothrow) VNode(vnid, NULL, NULL);
if (vnode == NULL)
RETURN_ERROR(B_NO_MEMORY);
vnode->valid = false;
@@ -983,14 +994,23 @@ Volume::ReadVNode(ino_t vnid, bool reenter, void** _node, int* type,
return reply->error;
}
// get the ops vector for the node
VNodeOps* ops = fFileSystem->GetVNodeOps(reply->capabilities);
if (ops == NULL) {
_RemoveInvalidVNode(vnid);
RETURN_ERROR(B_NO_MEMORY);
}
// everything went fine -- mark the node valid
locker.Lock();
vnode->clientNode = reply->node;
vnode->ops = ops;
vnode->valid = true;
*_node = vnode;
*type = reply->type;
*flags = reply->flags;
*_ops = ops->ops;
return B_OK;
}
@@ -1021,7 +1041,7 @@ Volume::RemoveVNode(void* _node, bool reenter)
locker.Unlock();
void* clientNode = vnode->clientNode;
delete vnode;
vnode->Delete(this);
// get a free port
RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
@@ -3461,6 +3481,60 @@ Volume::RewindQuery(void* cookie)
// #pragma mark -
// #pragma mark ----- private implementations -----
// _InitVolumeOps
void
Volume::_InitVolumeOps()
{
memcpy(&fVolumeOps, &gUserlandFSVolumeOps, sizeof(fs_volume_ops));
#undef CLEAR_UNSUPPORTED
#define CLEAR_UNSUPPORTED(capability, op) \
if (!fCapabilities.Get(capability)) \
fVolumeOps.op = NULL
// FS operations
// FS_VOLUME_CAPABILITY_UNMOUNT: unmount
// always needed
// FS_VOLUME_CAPABILITY_READ_FS_INFO: read_fs_info
// always needed
CLEAR_UNSUPPORTED(FS_VOLUME_CAPABILITY_WRITE_FS_INFO, write_fs_info);
CLEAR_UNSUPPORTED(FS_VOLUME_CAPABILITY_SYNC, sync);
// vnode operations
// FS_VOLUME_CAPABILITY_GET_VNODE: get_vnode
// always needed
// index directory & index operations
CLEAR_UNSUPPORTED(FS_VOLUME_CAPABILITY_OPEN_INDEX_DIR, open_index_dir);
// FS_VOLUME_CAPABILITY_CLOSE_INDEX_DIR: close_index_dir
// always needed
// FS_VOLUME_CAPABILITY_FREE_INDEX_DIR_COOKIE: free_index_dir_cookie
// always needed
CLEAR_UNSUPPORTED(FS_VOLUME_CAPABILITY_READ_INDEX_DIR, read_index_dir);
CLEAR_UNSUPPORTED(FS_VOLUME_CAPABILITY_REWIND_INDEX_DIR, rewind_index_dir);
CLEAR_UNSUPPORTED(FS_VOLUME_CAPABILITY_CREATE_INDEX, create_index);
CLEAR_UNSUPPORTED(FS_VOLUME_CAPABILITY_REMOVE_INDEX, remove_index);
CLEAR_UNSUPPORTED(FS_VOLUME_CAPABILITY_READ_INDEX_STAT, read_index_stat);
// query operations
CLEAR_UNSUPPORTED(FS_VOLUME_CAPABILITY_OPEN_QUERY, open_query);
// FS_VOLUME_CAPABILITY_CLOSE_QUERY: close_query
// always needed
// FS_VOLUME_CAPABILITY_FREE_QUERY_COOKIE: free_query_cookie
// always needed
CLEAR_UNSUPPORTED(FS_VOLUME_CAPABILITY_READ_QUERY, read_query);
CLEAR_UNSUPPORTED(FS_VOLUME_CAPABILITY_REWIND_QUERY, rewind_query);
#undef CLEAR_UNSUPPORTED
}
// #pragma mark -
// _Mount
status_t
Volume::_Mount(const char* device, uint32 flags, const char* parameters)
@@ -3636,7 +3710,7 @@ Volume::_WriteVNode(void* _node, bool reenter)
locker.Unlock();
void* clientNode = vnode->clientNode;
delete vnode;
vnode->Delete(this);
// get a free port
RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
@@ -4280,7 +4354,7 @@ Volume::_RemoveInvalidVNode(ino_t vnid)
for (; vnode->useCount > 0; vnode->useCount--)
put_vnode(fFSVolume, vnid);
delete vnode;
vnode->Delete(this);
}
@@ -38,21 +38,24 @@ public:
fs_volume* fsVolume);
~Volume();
FileSystem* GetFileSystem() const;
inline FileSystem* GetFileSystem() const;
inline dev_t GetID() const;
inline fs_volume_ops* GetVolumeOps() { return &fVolumeOps; }
inline bool HasCapability(int capability) const;
void* GetUserlandVolume() const;
ino_t GetRootID() const;
inline void* GetUserlandVolume() const;
inline ino_t GetRootID() const;
// client methods
status_t GetVNode(ino_t vnid, void** node);
status_t PutVNode(ino_t vnid);
status_t AcquireVNode(ino_t vnid);
status_t NewVNode(ino_t vnid, void* node);
status_t NewVNode(ino_t vnid, void* node,
const FSVNodeCapabilities& capabilities);
status_t PublishVNode(ino_t vnid, void* node,
int type, uint32 flags);
int type, uint32 flags,
const FSVNodeCapabilities& capabilities);
status_t RemoveVNode(ino_t vnid);
status_t UnremoveVNode(ino_t vnid);
status_t GetVNodeRemoved(ino_t vnid, bool* removed);
@@ -88,7 +91,8 @@ public:
status_t GetVNodeName(void* node, char* buffer,
size_t bufferSize);
status_t ReadVNode(ino_t vnid, bool reenter,
void** node, int* type, uint32* flags);
void** node, fs_vnode_ops** _ops, int* type,
uint32* flags);
status_t WriteVNode(void* node, bool reenter);
status_t RemoveVNode(void* node, bool reenter);
@@ -227,6 +231,8 @@ private:
friend class IORequestRemover;
private:
void _InitVolumeOps();
status_t _Mount(const char* device, uint32 flags,
const char* parameters);
status_t _Unmount();
@@ -289,6 +295,7 @@ private:
FileSystem* fFileSystem;
fs_volume* fFSVolume;
FSVolumeCapabilities fCapabilities;
fs_volume_ops fVolumeOps;
void* fUserlandVolume;
ino_t fRootID;
VNode* fRootNode;
@@ -314,6 +321,15 @@ Volume::GetID() const
}
// GetFileSystem
inline FileSystem*
Volume::GetFileSystem() const
{
return fFileSystem;
}
// HasCapability
inline bool
Volume::HasCapability(int capability) const
{
@@ -321,6 +337,22 @@ Volume::HasCapability(int capability) const
}
// GetUserlandVolume
inline void*
Volume::GetUserlandVolume() const
{
return fUserlandVolume;
}
// GetRootID
inline ino_t
Volume::GetRootID() const
{
return fRootID;
}
inline bool
Volume::HasVNodeCapability(VNode* vnode, int capability) const
{
@@ -105,7 +105,7 @@ userlandfs_mount(fs_volume* fsVolume, const char* device, uint32 flags,
}
fsVolume->private_volume = volume;
fsVolume->ops = &gUserlandFSVolumeOps;
fsVolume->ops = volume->GetVolumeOps();
*rootVnodeID = volume->GetRootID();
PRINT(("userlandfs_mount() done: %p, %lld\n", fsVolume->private_volume,
@@ -207,10 +207,12 @@ userlandfs_get_vnode(fs_volume* fsVolume, ino_t vnid, fs_vnode* fsNode,
PRINT(("userlandfs_get_vnode(%p, %lld, %p, %d)\n", volume, vnid,
fsNode->private_node, reenter));
void* node;
status_t error = volume->ReadVNode(vnid, reenter, &node, _type, _flags);
fs_vnode_ops* ops;
status_t error = volume->ReadVNode(vnid, reenter, &node, &ops, _type,
_flags);
if (error == B_OK) {
fsNode->private_node = node;
fsNode->ops = &gUserlandFSVnodeOps;
fsNode->ops = ops;
}
PRINT(("userlandfs_get_vnode() done: (%lx, %p)\n", error, node));
@@ -466,10 +466,11 @@ UserlandRequestHandler::_HandleRequest(ReadVNodeRequest* request)
void* node;
int type;
uint32 flags;
FSVNodeCapabilities capabilities;
if (result == B_OK) {
RequestThreadContext context(volume);
result = volume->ReadVNode(request->vnid, request->reenter, &node,
&type, &flags);
&type, &flags, &capabilities);
}
// prepare the reply
@@ -483,6 +484,7 @@ UserlandRequestHandler::_HandleRequest(ReadVNodeRequest* request)
reply->node = node;
reply->type = type;
reply->flags = flags;
reply->capabilities = capabilities;
// send the reply
return _SendReply(allocator, false);
@@ -1,4 +1,7 @@
// Volume.cpp
/*
* Copyright 2001-2009, Ingo Weinhold, ingo_weinhold@gmx.de.
* Distributed under the terms of the MIT License.
*/
#include "Volume.h"
@@ -169,7 +172,7 @@ Volume::GetVNodeName(void* node, char* buffer, size_t bufferSize)
// ReadVNode
status_t
Volume::ReadVNode(ino_t vnid, bool reenter, void** node, int* type,
uint32* flags)
uint32* flags, FSVNodeCapabilities* _capabilities)
{
return B_BAD_VALUE;
}
@@ -1,5 +1,7 @@
// Volume.h
/*
* Copyright 2001-2009, Ingo Weinhold, ingo_weinhold@gmx.de.
* Distributed under the terms of the MIT License.
*/
#ifndef USERLAND_FS_VOLUME_H
#define USERLAND_FS_VOLUME_H
@@ -49,7 +51,8 @@ public:
virtual status_t GetVNodeName(void* node, char* buffer,
size_t bufferSize);
virtual status_t ReadVNode(ino_t vnid, bool reenter,
void** node, int* type, uint32* flags);
void** node, int* type, uint32* flags,
FSVNodeCapabilities* _capabilities);
virtual status_t WriteVNode(void* node, bool reenter);
virtual status_t RemoveVNode(void* node, bool reenter);
@@ -4,6 +4,7 @@
#include <new>
#include "beos_kernel_emu.h"
#include "BeOSKernelVolume.h"
#include "fs_cache.h"
#include "fs_interface.h"
@@ -76,6 +77,8 @@ void
BeOSKernelFileSystem::_InitCapabilities()
{
fCapabilities.ClearAll();
fVolumeCapabilities.ClearAll();
fNodeCapabilities.ClearAll();
// FS interface type
fClientFSType = CLIENT_FS_BEOS_KERNEL;
@@ -207,6 +210,21 @@ BeOSKernelFileSystem::_InitCapabilities()
}
// #pragma mark -
// get_beos_file_system_node_capabilities
//
// Service function for beos_kernel_emu.cpp. Declared in beos_kernel_emu.h.
void
get_beos_file_system_node_capabilities(FSVNodeCapabilities& capabilities)
{
BeOSKernelFileSystem* fileSystem
= static_cast<BeOSKernelFileSystem*>(FileSystem::GetInstance());
fileSystem->GetNodeCapabilities(capabilities);
}
// #pragma mark - bootstrapping
@@ -1,4 +1,7 @@
// BeOSKernelVolume.cpp
/*
* Copyright 2001-2009, Ingo Weinhold, ingo_weinhold@gmx.de.
* Distributed under the terms of the MIT License.
*/
#include "BeOSKernelVolume.h"
@@ -11,6 +14,7 @@
#include "../kernel_emu.h"
#include "BeOSKernelFileSystem.h"
#include "fs_interface.h"
@@ -40,6 +44,14 @@ public:
};
// _FileSystem
inline BeOSKernelFileSystem*
BeOSKernelVolume::_FileSystem() const
{
return static_cast<BeOSKernelFileSystem*>(fFileSystem);
}
// constructor
BeOSKernelVolume::BeOSKernelVolume(FileSystem* fileSystem, dev_t id,
beos_vnode_ops* fsOps, const FSVolumeCapabilities& capabilities)
@@ -165,7 +177,7 @@ BeOSKernelVolume::GetVNodeType(void* node, int* type)
// ReadVNode
status_t
BeOSKernelVolume::ReadVNode(ino_t vnid, bool reenter, void** node, int* type,
uint32* flags)
uint32* flags, FSVNodeCapabilities* _capabilities)
{
if (!fFSOps->read_vnode)
return B_BAD_VALUE;
@@ -186,6 +198,7 @@ BeOSKernelVolume::ReadVNode(ino_t vnid, bool reenter, void** node, int* type,
*type = (st.st_mode & S_IFMT);
*flags = 0;
_FileSystem()->GetNodeCapabilities(*_capabilities);
return B_OK;
}
@@ -1,5 +1,7 @@
// BeOSKernelVolume.h
/*
* Copyright 2001-2009, Ingo Weinhold, ingo_weinhold@gmx.de.
* Distributed under the terms of the MIT License.
*/
#ifndef USERLAND_FS_BEOS_KERNEL_VOLUME_H
#define USERLAND_FS_BEOS_KERNEL_VOLUME_H
@@ -9,6 +11,9 @@ struct beos_vnode_ops;
namespace UserlandFS {
class BeOSKernelFileSystem;
class BeOSKernelVolume : public Volume {
public:
BeOSKernelVolume(FileSystem* fileSystem,
@@ -33,7 +38,8 @@ public:
// the three parameters publish_vnode() is
// used.
virtual status_t ReadVNode(ino_t vnid, bool reenter,
void** node, int* type, uint32* flags);
void** node, int* type, uint32* flags,
FSVNodeCapabilities* _capabilities);
virtual status_t WriteVNode(void* node, bool reenter);
virtual status_t RemoveVNode(void* node, bool reenter);
@@ -154,6 +160,7 @@ private:
status_t _OpenAttr(void* node, const char* name,
uint32 type, int openMode, bool create,
void** cookie);
inline BeOSKernelFileSystem* _FileSystem() const;
private:
beos_vnode_ops* fFSOps;
@@ -1,5 +1,7 @@
// beos_kernel_emu.cpp
#include "beos_kernel_emu.h"
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
@@ -145,9 +147,14 @@ put_vnode(nspace_id nsid, ino_t vnid)
int
new_vnode(nspace_id nsid, ino_t vnid, void *data)
{
// get the node capabilities
FSVNodeCapabilities capabilities;
get_beos_file_system_node_capabilities(capabilities);
// The semantics of new_vnode() has changed. The new publish_vnode()
// should work like the former new_vnode().
return UserlandFS::KernelEmu::publish_vnode(nsid, vnid, data);
return UserlandFS::KernelEmu::publish_vnode(nsid, vnid, data,
capabilities);
}
// remove_vnode
@@ -1,4 +1,7 @@
// HaikuKernelFileSystem.cpp
/*
* Copyright 2007-2009, Ingo Weinhold, ingo_weinhold@gmx.de.
* Distributed under the terms of the MIT License.
*/
#include "HaikuKernelFileSystem.h"
@@ -37,6 +40,40 @@ struct HaikuKernelFileSystem::IORequestHashDefinition {
// 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> {
};
@@ -46,6 +83,7 @@ HaikuKernelFileSystem::HaikuKernelFileSystem(file_system_module_info* fsModule)
FileSystem(),
fFSModule(fsModule),
fIORequests(NULL),
fNodeCapabilities(NULL),
fLock("HaikuKernelFileSystem")
{
_InitCapabilities();
@@ -60,6 +98,7 @@ HaikuKernelFileSystem::~HaikuKernelFileSystem()
fFSModule->info.std_ops(B_MODULE_UNINIT);
delete fIORequests;
delete fNodeCapabilities;
// TODO: Call the cleanup methods (condition vars, block cache)!
}
@@ -91,6 +130,15 @@ HaikuKernelFileSystem::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;
@@ -183,6 +231,50 @@ HaikuKernelFileSystem::PutIORequest(HaikuKernelIORequest* 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()
@@ -197,6 +289,90 @@ HaikuKernelFileSystem::_InitCapabilities()
}
/*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
@@ -1,14 +1,20 @@
// HaikuKernelFileSystem.h
/*
* Copyright 2007-2009, Ingo Weinhold, ingo_weinhold@gmx.de.
* Distributed under the terms of the MIT License.
*/
#ifndef USERLAND_FS_HAIKU_KERNEL_FILE_SYSTEM_H
#define USERLAND_FS_HAIKU_KERNEL_FILE_SYSTEM_H
#include "Locker.h"
#include "HaikuKernelNode.h"
#include "../FileSystem.h"
struct file_system_module_info;
namespace UserlandFS {
struct HaikuKernelIORequest;
@@ -29,16 +35,27 @@ public:
void PutIORequest(HaikuKernelIORequest* request,
int32 refCount = 1);
HaikuKernelNode::Capabilities* GetNodeCapabilities(
fs_vnode_ops* ops);
void PutNodeCapabilities(
HaikuKernelNode::Capabilities*
capabilities);
private:
class IORequestHashDefinition;
class IORequestTable;
struct IORequestHashDefinition;
struct IORequestTable;
struct NodeCapabilitiesHashDefinition;
struct NodeCapabilitiesTable;
private:
void _InitCapabilities();
static void _InitNodeCapabilities(fs_vnode_ops* ops,
FSVNodeCapabilities& capabilities);
private:
file_system_module_info* fFSModule;
IORequestTable* fIORequests;
NodeCapabilitiesTable* fNodeCapabilities;
Locker fLock;
};
@@ -8,8 +8,11 @@
#include <fs_interface.h>
#include <SupportDefs.h>
#include <util/OpenHashTable.h>
#include "FSCapabilities.h"
namespace UserlandFS {
class HaikuKernelVolume;
@@ -18,14 +21,19 @@ using UserlandFSUtil::FSVNodeCapabilities;
struct HaikuKernelNode : fs_vnode {
struct Capabilities;
ino_t id;
HaikuKernelVolume* volume;
Capabilities* capabilities;
bool published;
public:
inline HaikuKernelNode(HaikuKernelVolume* volume,
ino_t vnodeID, void* privateNode,
fs_vnode_ops* ops);
fs_vnode_ops* ops,
Capabilities* capabilities);
~HaikuKernelNode();
static HaikuKernelNode* GetNode(fs_vnode* node);
@@ -33,11 +41,27 @@ public:
};
struct HaikuKernelNode::Capabilities : HashTableLink<Capabilities> {
int32 refCount;
fs_vnode_ops* ops;
FSVNodeCapabilities capabilities;
Capabilities(fs_vnode_ops* ops, FSVNodeCapabilities capabilities)
:
refCount(1),
ops(ops),
capabilities(capabilities)
{
}
};
HaikuKernelNode::HaikuKernelNode(HaikuKernelVolume* volume, ino_t vnodeID,
void* privateNode, fs_vnode_ops* ops)
void* privateNode, fs_vnode_ops* ops, Capabilities* capabilities)
:
id(vnodeID),
volume(volume),
capabilities(capabilities),
published(false)
{
this->private_node = privateNode;
@@ -1,4 +1,7 @@
// HaikuKernelVolume.cpp
/*
* Copyright 2007-2009, Ingo Weinhold, ingo_weinhold@gmx.de.
* Distributed under the terms of the MIT License.
*/
#include "HaikuKernelVolume.h"
@@ -84,11 +87,20 @@ HaikuKernelVolume::NewVNode(ino_t vnodeID, void* privateNode, fs_vnode_ops* ops,
if (node != NULL)
return B_BAD_VALUE;
// create a new node
node = new(std::nothrow) HaikuKernelNode(this, vnodeID, privateNode, ops);
if (node == NULL)
// get node capabilities
HaikuKernelNode::Capabilities* capabilities
= _FileSystem()->GetNodeCapabilities(ops);
if (capabilities == NULL)
return B_NO_MEMORY;
// create a new node
node = new(std::nothrow) HaikuKernelNode(this, vnodeID, privateNode, ops,
capabilities);
if (node == NULL) {
_FileSystem()->PutNodeCapabilities(capabilities);
return B_NO_MEMORY;
}
// add to map
status_t error = fNodes->Put(vnodeID, node);
if (error != B_OK) {
@@ -115,11 +127,19 @@ HaikuKernelVolume::PublishVNode(ino_t vnodeID, void* privateNode,
if (node->published)
return B_BAD_VALUE;
} else {
// get node capabilities
HaikuKernelNode::Capabilities* capabilities
= _FileSystem()->GetNodeCapabilities(ops);
if (capabilities == NULL)
return B_NO_MEMORY;
// create a new node
node = new(std::nothrow) HaikuKernelNode(this, vnodeID, privateNode,
ops);
if (node == NULL)
ops, capabilities);
if (node == NULL) {
_FileSystem()->PutNodeCapabilities(capabilities);
return B_NO_MEMORY;
}
// add to map
status_t error = fNodes->Put(vnodeID, node);
@@ -271,14 +291,14 @@ HaikuKernelVolume::GetVNodeName(void* _node, char* buffer, size_t bufferSize)
// ReadVNode
status_t
HaikuKernelVolume::ReadVNode(ino_t vnid, bool reenter, void** _node, int* type,
uint32* flags)
uint32* flags, FSVNodeCapabilities* _capabilities)
{
if (!fVolume.ops->get_vnode)
return B_BAD_VALUE;
// create a new wrapper node and add it to the map
HaikuKernelNode* node = new(std::nothrow) HaikuKernelNode(this, vnid, NULL,
NULL);
NULL, NULL);
if (node == NULL)
return B_NO_MEMORY;
ObjectDeleter<HaikuKernelNode> nodeDeleter(node);
@@ -301,11 +321,23 @@ HaikuKernelVolume::ReadVNode(ino_t vnid, bool reenter, void** _node, int* type,
return error;
}
// get node capabilities
HaikuKernelNode::Capabilities* capabilities
= _FileSystem()->GetNodeCapabilities(node->ops);
if (capabilities == NULL) {
node->ops->put_vnode(&fVolume, node, reenter);
locker.Lock();
fNodes->Remove(vnid);
return B_NO_MEMORY;
}
locker.Lock();
node->capabilities = capabilities;
node->published = true;
nodeDeleter.Detach();
*_node = node;
*_capabilities = capabilities->capabilities;
return B_OK;
}
@@ -1166,81 +1198,4 @@ HaikuKernelVolume::_InitCapabilities()
fCapabilities.Set(FS_VOLUME_CAPABILITY_READ_QUERY, fVolume.ops->read_query);
fCapabilities.Set(FS_VOLUME_CAPABILITY_REWIND_QUERY,
fVolume.ops->rewind_query);
#if 0
// vnode operations
fCapabilities.Set(FS_VNODE_CAPABILITY_LOOKUP, fFSModule->lookup);
fCapabilities.Set(FS_VNODE_CAPABILITY_GET_VNODE_NAME, fFSModule->get_vnode_name);
fCapabilities.Set(FS_VNODE_CAPABILITY_GET_VNODE, fFSModule->get_vnode);
fCapabilities.Set(FS_VNODE_CAPABILITY_PUT_VNODE, fFSModule->put_vnode);
fCapabilities.Set(FS_VNODE_CAPABILITY_REMOVE_VNODE, fFSModule->remove_vnode);
// VM file access
fCapabilities.Set(FS_VNODE_CAPABILITY_CAN_PAGE, fFSModule->can_page);
fCapabilities.Set(FS_VNODE_CAPABILITY_READ_PAGES, fFSModule->read_pages);
fCapabilities.Set(FS_VNODE_CAPABILITY_WRITE_PAGES, fFSModule->write_pages);
// cache file access
fCapabilities.Set(FS_VNODE_CAPABILITY_GET_FILE_MAP, fFSModule->get_file_map);
// common operations
fCapabilities.Set(FS_VNODE_CAPABILITY_IOCTL, fFSModule->ioctl);
fCapabilities.Set(FS_VNODE_CAPABILITY_SET_FLAGS, fFSModule->set_flags);
fCapabilities.Set(FS_VNODE_CAPABILITY_SELECT, fFSModule->select);
fCapabilities.Set(FS_VNODE_CAPABILITY_DESELECT, fFSModule->deselect);
fCapabilities.Set(FS_VNODE_CAPABILITY_FSYNC, fFSModule->fsync);
fCapabilities.Set(FS_VNODE_CAPABILITY_READ_SYMLINK, fFSModule->read_symlink);
fCapabilities.Set(FS_VNODE_CAPABILITY_CREATE_SYMLINK, fFSModule->create_symlink);
fCapabilities.Set(FS_VNODE_CAPABILITY_LINK, fFSModule->link);
fCapabilities.Set(FS_VNODE_CAPABILITY_UNLINK, fFSModule->unlink);
fCapabilities.Set(FS_VNODE_CAPABILITY_RENAME, fFSModule->rename);
fCapabilities.Set(FS_VNODE_CAPABILITY_ACCESS, fFSModule->access);
fCapabilities.Set(FS_VNODE_CAPABILITY_READ_STAT, fFSModule->read_stat);
fCapabilities.Set(FS_VNODE_CAPABILITY_WRITE_STAT, fFSModule->write_stat);
// file operations
fCapabilities.Set(FS_VNODE_CAPABILITY_CREATE, fFSModule->create);
fCapabilities.Set(FS_VNODE_CAPABILITY_OPEN, fFSModule->open);
fCapabilities.Set(FS_VNODE_CAPABILITY_CLOSE, fFSModule->close);
fCapabilities.Set(FS_VNODE_CAPABILITY_FREE_COOKIE, fFSModule->free_cookie);
fCapabilities.Set(FS_VNODE_CAPABILITY_READ, fFSModule->read);
fCapabilities.Set(FS_VNODE_CAPABILITY_WRITE, fFSModule->write);
// directory operations
fCapabilities.Set(FS_VNODE_CAPABILITY_CREATE_DIR, fFSModule->create_dir);
fCapabilities.Set(FS_VNODE_CAPABILITY_REMOVE_DIR, fFSModule->remove_dir);
fCapabilities.Set(FS_VNODE_CAPABILITY_OPEN_DIR, fFSModule->open_dir);
fCapabilities.Set(FS_VNODE_CAPABILITY_CLOSE_DIR, fFSModule->close_dir);
fCapabilities.Set(FS_VNODE_CAPABILITY_FREE_DIR_COOKIE, fFSModule->free_dir_cookie);
fCapabilities.Set(FS_VNODE_CAPABILITY_READ_DIR, fFSModule->read_dir);
fCapabilities.Set(FS_VNODE_CAPABILITY_REWIND_DIR, fFSModule->rewind_dir);
// attribute directory operations
fCapabilities.Set(FS_VNODE_CAPABILITY_OPEN_ATTR_DIR, fFSModule->open_attr_dir);
fCapabilities.Set(FS_VNODE_CAPABILITY_CLOSE_ATTR_DIR, fFSModule->close_attr_dir);
fCapabilities.Set(FS_VNODE_CAPABILITY_FREE_ATTR_DIR_COOKIE,
fFSModule->free_attr_dir_cookie);
fCapabilities.Set(FS_VNODE_CAPABILITY_READ_ATTR_DIR, fFSModule->read_attr_dir);
fCapabilities.Set(FS_VNODE_CAPABILITY_REWIND_ATTR_DIR, fFSModule->rewind_attr_dir);
// attribute operations
fCapabilities.Set(FS_VNODE_CAPABILITY_CREATE_ATTR, fFSModule->create_attr);
fCapabilities.Set(FS_VNODE_CAPABILITY_OPEN_ATTR, fFSModule->open_attr);
fCapabilities.Set(FS_VNODE_CAPABILITY_CLOSE_ATTR, fFSModule->close_attr);
fCapabilities.Set(FS_VNODE_CAPABILITY_FREE_ATTR_COOKIE,
fFSModule->free_attr_cookie);
fCapabilities.Set(FS_VNODE_CAPABILITY_READ_ATTR, fFSModule->read_attr);
fCapabilities.Set(FS_VNODE_CAPABILITY_WRITE_ATTR, fFSModule->write_attr);
fCapabilities.Set(FS_VNODE_CAPABILITY_READ_ATTR_STAT, fFSModule->read_attr_stat);
fCapabilities.Set(FS_VNODE_CAPABILITY_WRITE_ATTR_STAT,
fFSModule->write_attr_stat);
fCapabilities.Set(FS_VNODE_CAPABILITY_RENAME_ATTR, fFSModule->rename_attr);
fCapabilities.Set(FS_VNODE_CAPABILITY_REMOVE_ATTR, fFSModule->remove_attr);
#endif
}
@@ -1,5 +1,7 @@
// HaikuKernelVolume.h
/*
* Copyright 2007-2009, Ingo Weinhold, ingo_weinhold@gmx.de.
* Distributed under the terms of the MIT License.
*/
#ifndef USERLAND_FS_HAIKU_KERNEL_VOLUME_H
#define USERLAND_FS_HAIKU_KERNEL_VOLUME_H
@@ -56,7 +58,8 @@ public:
virtual status_t GetVNodeName(void* node, char* buffer,
size_t bufferSize);
virtual status_t ReadVNode(ino_t vnid, bool reenter,
void** node, int* type, uint32* flags);
void** node, int* type, uint32* flags,
FSVNodeCapabilities* _capabilities);
virtual status_t WriteVNode(void* node, bool reenter);
virtual status_t RemoveVNode(void* node, bool reenter);
@@ -45,6 +45,7 @@ SharedLibrary libuserlandfs_haiku_kernel.so
# UserlandFS server interface
HaikuKernelFileSystem.cpp
HaikuKernelNode.cpp
HaikuKernelVolume.cpp
:
@@ -136,7 +136,8 @@ new_vnode(fs_volume *_volume, ino_t vnodeID, void *privateNode,
return error;
// announce the new node
error = UserlandFS::KernelEmu::new_vnode(volume->GetID(), vnodeID, node);
error = UserlandFS::KernelEmu::new_vnode(volume->GetID(), vnodeID, node,
node->capabilities->capabilities);
if (error != B_OK)
volume->UndoNewVNode(node);
@@ -159,7 +160,7 @@ publish_vnode(fs_volume *_volume, ino_t vnodeID, void *privateNode,
// publish the new node
error = UserlandFS::KernelEmu::publish_vnode(volume->GetID(), vnodeID, node,
type, flags);
type, flags, node->capabilities->capabilities);
if (error != B_OK)
volume->UndoPublishVNode(node);
@@ -365,7 +365,8 @@ UserlandFS::KernelEmu::acquire_vnode(dev_t nsid, ino_t vnid)
// new_vnode
status_t
UserlandFS::KernelEmu::new_vnode(dev_t nsid, ino_t vnid, void* data)
UserlandFS::KernelEmu::new_vnode(dev_t nsid, ino_t vnid, void* data,
const FSVNodeCapabilities& capabilities)
{
// get the request port and the file system
RequestPort* port;
@@ -384,6 +385,7 @@ UserlandFS::KernelEmu::new_vnode(dev_t nsid, ino_t vnid, void* data)
request->nsid = nsid;
request->vnid = vnid;
request->node = data;
request->capabilities = capabilities;
// send the request
UserlandRequestHandler handler(fileSystem, NEW_VNODE_REPLY);
@@ -402,7 +404,7 @@ UserlandFS::KernelEmu::new_vnode(dev_t nsid, ino_t vnid, void* data)
// publish_vnode
status_t
UserlandFS::KernelEmu::publish_vnode(dev_t nsid, ino_t vnid, void* data,
int type, uint32 flags)
int type, uint32 flags, const FSVNodeCapabilities& capabilities)
{
// get the request port and the file system
RequestPort* port;
@@ -423,6 +425,7 @@ UserlandFS::KernelEmu::publish_vnode(dev_t nsid, ino_t vnid, void* data,
request->node = data;
request->type = type;
request->flags = flags;
request->capabilities = capabilities;
// send the request
UserlandRequestHandler handler(fileSystem, PUBLISH_VNODE_REPLY);
@@ -441,7 +444,8 @@ UserlandFS::KernelEmu::publish_vnode(dev_t nsid, ino_t vnid, void* data,
// publish_vnode
status_t
UserlandFS::KernelEmu::publish_vnode(dev_t nsid, ino_t vnid, void* data)
UserlandFS::KernelEmu::publish_vnode(dev_t nsid, ino_t vnid, void* data,
const FSVNodeCapabilities& capabilities)
{
// get the volume
Volume* volume = FileSystem::GetInstance()->VolumeWithID(nsid);
@@ -455,7 +459,8 @@ UserlandFS::KernelEmu::publish_vnode(dev_t nsid, ino_t vnid, void* data)
return error;
// publish the node
return UserlandFS::KernelEmu::publish_vnode(nsid, vnid, data, type, 0);
return UserlandFS::KernelEmu::publish_vnode(nsid, vnid, data, type, 0,
capabilities);
}
@@ -4,6 +4,9 @@
#include <OS.h>
#include "FSCapabilities.h"
struct selectsync;
struct file_io_vec;
@@ -24,10 +27,12 @@ status_t notify_query(port_id port, int32 token, int32 operation,
status_t get_vnode(dev_t nsid, ino_t vnid, void** node);
status_t put_vnode(dev_t nsid, ino_t vnid);
status_t acquire_vnode(dev_t nsid, ino_t vnodeID);
status_t new_vnode(dev_t nsid, ino_t vnid, void* data);
status_t new_vnode(dev_t nsid, ino_t vnid, void* data,
const FSVNodeCapabilities& capabilities);
status_t publish_vnode(dev_t nsid, ino_t vnid, void* data, int type,
uint32 flags);
status_t publish_vnode(dev_t nsid, ino_t vnid, void* data);
uint32 flags, const FSVNodeCapabilities& capabilities);
status_t publish_vnode(dev_t nsid, ino_t vnid, void* data,
const FSVNodeCapabilities& capabilities);
status_t remove_vnode(dev_t nsid, ino_t vnid);
status_t unremove_vnode(dev_t nsid, ino_t vnid);
status_t get_vnode_removed(dev_t nsid, ino_t vnid, bool* removed);