* 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: public:
ReadVNodeReply() : ReplyRequest(READ_VNODE_REPLY) {} ReadVNodeReply() : ReplyRequest(READ_VNODE_REPLY) {}
void* node; void* node;
int type; int type;
uint32 flags; uint32 flags;
FSVNodeCapabilities capabilities;
}; };
// WriteVNodeRequest // WriteVNodeRequest
@@ -1604,9 +1605,10 @@ class NewVNodeRequest : public Request {
public: public:
NewVNodeRequest() : Request(NEW_VNODE_REQUEST) {} NewVNodeRequest() : Request(NEW_VNODE_REQUEST) {}
dev_t nsid; dev_t nsid;
ino_t vnid; ino_t vnid;
void* node; void* node;
FSVNodeCapabilities capabilities;
}; };
// NewVNodeReply // NewVNodeReply
@@ -1620,11 +1622,12 @@ class PublishVNodeRequest : public Request {
public: public:
PublishVNodeRequest() : Request(PUBLISH_VNODE_REQUEST) {} PublishVNodeRequest() : Request(PUBLISH_VNODE_REQUEST) {}
dev_t nsid; dev_t nsid;
ino_t vnid; ino_t vnid;
void* node; void* node;
int type; int type;
uint32 flags; uint32 flags;
FSVNodeCapabilities capabilities;
}; };
// PublishVNodeReply // PublishVNodeReply
@@ -3,18 +3,22 @@
* Distributed under the terms of the MIT License. * Distributed under the terms of the MIT License.
*/ */
#include "Volume.h"
#include <util/AutoLock.h>
#include "AutoLocker.h" #include "AutoLocker.h"
#include "Compatibility.h" #include "Compatibility.h"
#include "Debug.h" #include "Debug.h"
#include "FileSystem.h" #include "FileSystem.h"
#include "HashMap.h" #include "HashMap.h"
#include "kernel_interface.h"
#include "KernelRequestHandler.h" #include "KernelRequestHandler.h"
#include "PortReleaser.h" #include "PortReleaser.h"
#include "RequestAllocator.h" #include "RequestAllocator.h"
#include "Requests.h" #include "Requests.h"
#include "Settings.h" #include "Settings.h"
#include "SingleReplyRequestHandler.h" #include "SingleReplyRequestHandler.h"
#include "Volume.h"
// The time after which the notification thread times out at the port and // 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 // restarts the loop. Of interest only when the FS is deleted. It is the
@@ -30,7 +34,6 @@ struct FileSystem::SelectSyncMap
FileSystem::FileSystem() FileSystem::FileSystem()
: :
fVolumes(), fVolumes(),
fVolumeLock(),
fName(), fName(),
fTeam(-1), fTeam(-1),
fNotificationPort(NULL), fNotificationPort(NULL),
@@ -42,6 +45,8 @@ FileSystem::FileSystem()
fInitialized(false), fInitialized(false),
fTerminating(false) fTerminating(false)
{ {
mutex_init(&fVolumeLock, "userlandfs volumes");
mutex_init(&fVNodeOpsLock, "userlandfs vnode ops");
} }
// destructor // destructor
@@ -65,6 +70,18 @@ FileSystem::~FileSystem()
delete fSelectSyncs; delete fSelectSyncs;
} }
delete fSettings; 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 // Init
@@ -83,6 +100,11 @@ FileSystem::Init(const char* name, team_id team, Port::Info* infos, int32 count,
if (!fName.SetTo(name)) if (!fName.SetTo(name))
return B_NO_MEMORY; return B_NO_MEMORY;
// init VNodeOps map
status_t error = fVNodeOps.Init();
if (error != B_OK)
return error;
fTeam = team; fTeam = team;
fCapabilities = capabilities; fCapabilities = capabilities;
@@ -96,7 +118,7 @@ FileSystem::Init(const char* name, team_id team, Port::Info* infos, int32 count,
fNotificationPort = new(nothrow) RequestPort(infos); fNotificationPort = new(nothrow) RequestPort(infos);
if (!fNotificationPort) if (!fNotificationPort)
RETURN_ERROR(B_NO_MEMORY); RETURN_ERROR(B_NO_MEMORY);
status_t error = fNotificationPort->InitCheck(); error = fNotificationPort->InitCheck();
if (error != B_OK) if (error != B_OK)
return error; return error;
@@ -198,18 +220,18 @@ FileSystem::Mount(fs_volume* fsVolume, const char* device, uint32 flags,
return B_NO_MEMORY; return B_NO_MEMORY;
// add volume to the volume list // add volume to the volume list
fVolumeLock.Lock(); MutexLocker locker(fVolumeLock);
status_t error = fVolumes.PushBack(volume); status_t error = fVolumes.PushBack(volume);
fVolumeLock.Unlock(); locker.Unlock();
if (error != B_OK) if (error != B_OK)
return error; return error;
// mount volume // mount volume
error = volume->Mount(device, flags, parameters); error = volume->Mount(device, flags, parameters);
if (error != B_OK) { if (error != B_OK) {
fVolumeLock.Lock(); MutexLocker locker(fVolumeLock);
fVolumes.Remove(volume); fVolumes.Remove(volume);
fVolumeLock.Unlock(); locker.Unlock();
volume->RemoveReference(); volume->RemoveReference();
return error; return error;
} }
@@ -256,16 +278,15 @@ FileSystem::Initialize(const char* deviceName, const char* parameters,
void void
FileSystem::VolumeUnmounted(Volume* volume) FileSystem::VolumeUnmounted(Volume* volume)
{ {
fVolumeLock.Lock(); MutexLocker locker(fVolumeLock);
fVolumes.Remove(volume); fVolumes.Remove(volume);
fVolumeLock.Unlock();
} }
// GetVolume // GetVolume
Volume* Volume*
FileSystem::GetVolume(dev_t id) FileSystem::GetVolume(dev_t id)
{ {
AutoLocker<Locker> _(fVolumeLock); MutexLocker _(fVolumeLock);
for (Vector<Volume*>::Iterator it = fVolumes.Begin(); for (Vector<Volume*>::Iterator it = fVolumes.Begin();
it != fVolumes.End(); it != fVolumes.End();
it++) { it++) {
@@ -318,6 +339,7 @@ FileSystem::RemoveSelectSyncEntry(selectsync* sync)
} }
} }
// KnowsSelectSyncEntry // KnowsSelectSyncEntry
bool bool
FileSystem::KnowsSelectSyncEntry(selectsync* sync) FileSystem::KnowsSelectSyncEntry(selectsync* sync)
@@ -325,6 +347,54 @@ FileSystem::KnowsSelectSyncEntry(selectsync* sync)
return fSelectSyncs->ContainsKey(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 // IsUserlandServerThread
bool bool
FileSystem::IsUserlandServerThread() const FileSystem::IsUserlandServerThread() const
@@ -334,6 +404,108 @@ FileSystem::IsUserlandServerThread() const
return (info.team == fUserlandServerTeam); 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 // _NotificationThreadEntry
int32 int32
FileSystem::_NotificationThreadEntry(void* data) FileSystem::_NotificationThreadEntry(void* data)
@@ -341,6 +513,7 @@ FileSystem::_NotificationThreadEntry(void* data)
return ((FileSystem*)data)->_NotificationThread(); return ((FileSystem*)data)->_NotificationThread();
} }
// _NotificationThread // _NotificationThread
int32 int32
FileSystem::_NotificationThread() FileSystem::_NotificationThread()
@@ -7,6 +7,10 @@
#include <fs_interface.h> #include <fs_interface.h>
#include <util/OpenHashTable.h>
#include <lock.h>
#include "FSCapabilities.h" #include "FSCapabilities.h"
#include "LazyInitializable.h" #include "LazyInitializable.h"
#include "Locker.h" #include "Locker.h"
@@ -20,6 +24,42 @@ struct IOCtlInfo;
class Settings; class Settings;
class Volume; 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 { class FileSystem {
public: public:
FileSystem(); FileSystem();
@@ -52,9 +92,16 @@ public:
void RemoveSelectSyncEntry(selectsync* sync); void RemoveSelectSyncEntry(selectsync* sync);
bool KnowsSelectSyncEntry(selectsync* sync); bool KnowsSelectSyncEntry(selectsync* sync);
VNodeOps* GetVNodeOps(
const FSVNodeCapabilities& capabilities);
void PutVNodeOps(VNodeOps* ops);
bool IsUserlandServerThread() const; bool IsUserlandServerThread() const;
private: private:
void _InitVNodeOpsVector(fs_vnode_ops* ops,
const FSVNodeCapabilities& capabilities);
static int32 _NotificationThreadEntry(void* data); static int32 _NotificationThreadEntry(void* data);
int32 _NotificationThread(); int32 _NotificationThread();
@@ -62,9 +109,12 @@ private:
friend class KernelDebug; friend class KernelDebug;
struct SelectSyncEntry; struct SelectSyncEntry;
struct SelectSyncMap; struct SelectSyncMap;
typedef OpenHashTable<VNodeOpsHashDefinition> VNodeOpsMap;
Vector<Volume*> fVolumes; Vector<Volume*> fVolumes;
Locker fVolumeLock; mutex fVolumeLock;
VNodeOpsMap fVNodeOps;
mutex fVNodeOpsLock;
String fName; String fName;
team_id fTeam; team_id fTeam;
FSCapabilities fCapabilities; FSCapabilities fCapabilities;
@@ -403,8 +403,11 @@ KernelRequestHandler::_HandleRequest(NewVNodeRequest* request)
Volume* volume = NULL; Volume* volume = NULL;
status_t result = _GetVolume(request->nsid, &volume); status_t result = _GetVolume(request->nsid, &volume);
VolumePutter _(volume); VolumePutter _(volume);
if (result == B_OK) if (result == B_OK) {
result = volume->NewVNode(request->vnid, request->node); result = volume->NewVNode(request->vnid, request->node,
request->capabilities);
}
// prepare the reply // prepare the reply
RequestAllocator allocator(fPort->GetPort()); RequestAllocator allocator(fPort->GetPort());
NewVNodeReply* reply; NewVNodeReply* reply;
@@ -412,6 +415,7 @@ KernelRequestHandler::_HandleRequest(NewVNodeRequest* request)
if (error != B_OK) if (error != B_OK)
return error; return error;
reply->error = result; reply->error = result;
// send the reply // send the reply
return fPort->SendRequest(&allocator); return fPort->SendRequest(&allocator);
} }
@@ -426,7 +430,7 @@ KernelRequestHandler::_HandleRequest(PublishVNodeRequest* request)
VolumePutter _(volume); VolumePutter _(volume);
if (result == B_OK) { if (result == B_OK) {
result = volume->PublishVNode(request->vnid, request->node, result = volume->PublishVNode(request->vnid, request->node,
request->type, request->flags); request->type, request->flags, request->capabilities);
} }
// prepare the reply // prepare the reply
@@ -47,22 +47,32 @@ static const bigtime_t kUserlandServerlandPortTimeout = 10000000; // 10s
// VNode // VNode
struct Volume::VNode : HashTableLink<VNode> { struct Volume::VNode : HashTableLink<VNode> {
ino_t id; ino_t id;
void* clientNode; void* clientNode;
void* fileCache; void* fileCache;
int32 useCount; VNodeOps* ops;
bool valid; int32 useCount;
bool valid;
VNode(ino_t id, void* clientNode) VNode(ino_t id, void* clientNode, VNodeOps* ops)
: :
id(id), id(id),
clientNode(clientNode), clientNode(clientNode),
fileCache(NULL), fileCache(NULL),
ops(ops),
useCount(0), useCount(0),
valid(true) 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() ~VNode()
{ {
if (fileCache != NULL) 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 // #pragma mark - client methods
// GetVNode // GetVNode
@@ -342,7 +331,8 @@ PRINT(("acquire_vnode(%ld, %lld)\n", GetID(), vnid));
// NewVNode // NewVNode
status_t 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)); PRINT(("new_vnode(%ld, %lld)\n", GetID(), vnid));
// lookup the node // lookup the node
@@ -353,17 +343,24 @@ PRINT(("new_vnode(%ld, %lld)\n", GetID(), vnid));
RETURN_ERROR(B_BAD_VALUE); RETURN_ERROR(B_BAD_VALUE);
} }
// create the node // get the ops vector for the node
node = new(std::nothrow) VNode(vnid, clientNode); VNodeOps* ops = fFileSystem->GetVNodeOps(capabilities);
if (node == NULL) if (ops == NULL)
RETURN_ERROR(B_NO_MEMORY); 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(); locker.Unlock();
// tell the VFS // 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) { if (error != B_OK) {
delete node; node->Delete(this);
RETURN_ERROR(error); RETURN_ERROR(error);
} }
@@ -376,7 +373,8 @@ PRINT(("new_vnode(%ld, %lld)\n", GetID(), vnid));
// PublishVNode // PublishVNode
status_t 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)); PRINT(("publish_vnode(%ld, %lld, %p)\n", GetID(), vnid, clientNode));
// lookup the node // lookup the node
@@ -386,21 +384,30 @@ PRINT(("publish_vnode(%ld, %lld, %p)\n", GetID(), vnid, clientNode));
if (!nodeKnown) { if (!nodeKnown) {
// The node is not yet known -- create it. // 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); 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(); locker.Unlock();
// tell the VFS // 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); type, flags);
if (error != B_OK) { if (error != B_OK) {
// TODO: We should note whether the node was made known via new_vnode(). If so, // TODO: We should note whether the node was made known via new_vnode(). If so,
// we should remove and delete it here! // we should remove and delete it here!
if (!nodeKnown) if (!nodeKnown)
delete node; node->Delete(this);
RETURN_ERROR(error); RETURN_ERROR(error);
} }
@@ -690,29 +697,33 @@ Volume::Mount(const char* device, uint32 flags, const char* parameters)
// mount // mount
status_t error = _Mount(device, flags, parameters); status_t error = _Mount(device, flags, parameters);
if (error != B_OK)
RETURN_ERROR(error);
if (error == B_OK) { MutexLocker locker(fLock);
MutexLocker locker(fLock); // fetch the root node, so that we can serve Walk() requests on it,
// fetch the root node, so that we can serve Walk() requests on it, // after the connection to the userland server is gone
// after the connection to the userland server is gone fRootNode = fVNodes->Lookup(fRootID);
fRootNode = fVNodes->Lookup(fRootID); if (fRootNode == NULL) {
if (fRootNode == NULL) { // The root node was not added while mounting. That's a serious
// The root node was not added while mounting. That's a serious // problem -- not only because we don't have it, but also because
// problem -- not only because we don't have it, but also because // the VFS requires publish_vnode() to be invoked for the root node.
// the VFS requires publish_vnode() to be invoked for the root node. ERROR(("Volume::Mount(): new_vnode() was not called for root node! "
ERROR(("Volume::Mount(): new_vnode() was not called for root node! " "Unmounting...\n"));
"Unmounting...\n")); locker.Unlock();
locker.Unlock(); Unmount();
Unmount(); return B_ERROR;
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--;
} }
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 // Unmount
@@ -729,7 +740,7 @@ Volume::Unmount()
VNode* node = fVNodes->Clear(true); VNode* node = fVNodes->Clear(true);
while (node != NULL) { while (node != NULL) {
VNode* nextNode = node->fNext; VNode* nextNode = node->fNext;
delete node; node->Delete(this);
node = nextNode; node = nextNode;
} }
delete fVNodes; delete fVNodes;
@@ -937,8 +948,8 @@ Volume::GetVNodeName(void* _node, char* buffer, size_t bufferSize)
// ReadVNode // ReadVNode
status_t status_t
Volume::ReadVNode(ino_t vnid, bool reenter, void** _node, int* type, Volume::ReadVNode(ino_t vnid, bool reenter, void** _node, fs_vnode_ops** _ops,
uint32* flags) int* type, uint32* flags)
{ {
// get a free port // get a free port
RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
@@ -958,7 +969,7 @@ Volume::ReadVNode(ino_t vnid, bool reenter, void** _node, int* type,
request->reenter = reenter; request->reenter = reenter;
// add the uninitialized node to our map // 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) if (vnode == NULL)
RETURN_ERROR(B_NO_MEMORY); RETURN_ERROR(B_NO_MEMORY);
vnode->valid = false; vnode->valid = false;
@@ -983,14 +994,23 @@ Volume::ReadVNode(ino_t vnid, bool reenter, void** _node, int* type,
return reply->error; 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 // everything went fine -- mark the node valid
locker.Lock(); locker.Lock();
vnode->clientNode = reply->node; vnode->clientNode = reply->node;
vnode->ops = ops;
vnode->valid = true; vnode->valid = true;
*_node = vnode; *_node = vnode;
*type = reply->type; *type = reply->type;
*flags = reply->flags; *flags = reply->flags;
*_ops = ops->ops;
return B_OK; return B_OK;
} }
@@ -1021,7 +1041,7 @@ Volume::RemoveVNode(void* _node, bool reenter)
locker.Unlock(); locker.Unlock();
void* clientNode = vnode->clientNode; void* clientNode = vnode->clientNode;
delete vnode; vnode->Delete(this);
// get a free port // get a free port
RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
@@ -3461,6 +3481,60 @@ Volume::RewindQuery(void* cookie)
// #pragma mark - // #pragma mark -
// #pragma mark ----- private implementations ----- // #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 // _Mount
status_t status_t
Volume::_Mount(const char* device, uint32 flags, const char* parameters) Volume::_Mount(const char* device, uint32 flags, const char* parameters)
@@ -3636,7 +3710,7 @@ Volume::_WriteVNode(void* _node, bool reenter)
locker.Unlock(); locker.Unlock();
void* clientNode = vnode->clientNode; void* clientNode = vnode->clientNode;
delete vnode; vnode->Delete(this);
// get a free port // get a free port
RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
@@ -4280,7 +4354,7 @@ Volume::_RemoveInvalidVNode(ino_t vnid)
for (; vnode->useCount > 0; vnode->useCount--) for (; vnode->useCount > 0; vnode->useCount--)
put_vnode(fFSVolume, vnid); put_vnode(fFSVolume, vnid);
delete vnode; vnode->Delete(this);
} }
@@ -38,21 +38,24 @@ public:
fs_volume* fsVolume); fs_volume* fsVolume);
~Volume(); ~Volume();
FileSystem* GetFileSystem() const; inline FileSystem* GetFileSystem() const;
inline dev_t GetID() const; inline dev_t GetID() const;
inline fs_volume_ops* GetVolumeOps() { return &fVolumeOps; }
inline bool HasCapability(int capability) const; inline bool HasCapability(int capability) const;
void* GetUserlandVolume() const; inline void* GetUserlandVolume() const;
ino_t GetRootID() const; inline ino_t GetRootID() const;
// client methods // client methods
status_t GetVNode(ino_t vnid, void** node); status_t GetVNode(ino_t vnid, void** node);
status_t PutVNode(ino_t vnid); status_t PutVNode(ino_t vnid);
status_t AcquireVNode(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, 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 RemoveVNode(ino_t vnid);
status_t UnremoveVNode(ino_t vnid); status_t UnremoveVNode(ino_t vnid);
status_t GetVNodeRemoved(ino_t vnid, bool* removed); status_t GetVNodeRemoved(ino_t vnid, bool* removed);
@@ -88,7 +91,8 @@ public:
status_t GetVNodeName(void* node, char* buffer, status_t GetVNodeName(void* node, char* buffer,
size_t bufferSize); size_t bufferSize);
status_t ReadVNode(ino_t vnid, bool reenter, 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 WriteVNode(void* node, bool reenter);
status_t RemoveVNode(void* node, bool reenter); status_t RemoveVNode(void* node, bool reenter);
@@ -227,6 +231,8 @@ private:
friend class IORequestRemover; friend class IORequestRemover;
private: private:
void _InitVolumeOps();
status_t _Mount(const char* device, uint32 flags, status_t _Mount(const char* device, uint32 flags,
const char* parameters); const char* parameters);
status_t _Unmount(); status_t _Unmount();
@@ -289,6 +295,7 @@ private:
FileSystem* fFileSystem; FileSystem* fFileSystem;
fs_volume* fFSVolume; fs_volume* fFSVolume;
FSVolumeCapabilities fCapabilities; FSVolumeCapabilities fCapabilities;
fs_volume_ops fVolumeOps;
void* fUserlandVolume; void* fUserlandVolume;
ino_t fRootID; ino_t fRootID;
VNode* fRootNode; VNode* fRootNode;
@@ -314,6 +321,15 @@ Volume::GetID() const
} }
// GetFileSystem
inline FileSystem*
Volume::GetFileSystem() const
{
return fFileSystem;
}
// HasCapability
inline bool inline bool
Volume::HasCapability(int capability) const 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 inline bool
Volume::HasVNodeCapability(VNode* vnode, int capability) const 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->private_volume = volume;
fsVolume->ops = &gUserlandFSVolumeOps; fsVolume->ops = volume->GetVolumeOps();
*rootVnodeID = volume->GetRootID(); *rootVnodeID = volume->GetRootID();
PRINT(("userlandfs_mount() done: %p, %lld\n", fsVolume->private_volume, 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, PRINT(("userlandfs_get_vnode(%p, %lld, %p, %d)\n", volume, vnid,
fsNode->private_node, reenter)); fsNode->private_node, reenter));
void* node; 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) { if (error == B_OK) {
fsNode->private_node = node; fsNode->private_node = node;
fsNode->ops = &gUserlandFSVnodeOps; fsNode->ops = ops;
} }
PRINT(("userlandfs_get_vnode() done: (%lx, %p)\n", error, node)); PRINT(("userlandfs_get_vnode() done: (%lx, %p)\n", error, node));
@@ -466,10 +466,11 @@ UserlandRequestHandler::_HandleRequest(ReadVNodeRequest* request)
void* node; void* node;
int type; int type;
uint32 flags; uint32 flags;
FSVNodeCapabilities capabilities;
if (result == B_OK) { if (result == B_OK) {
RequestThreadContext context(volume); RequestThreadContext context(volume);
result = volume->ReadVNode(request->vnid, request->reenter, &node, result = volume->ReadVNode(request->vnid, request->reenter, &node,
&type, &flags); &type, &flags, &capabilities);
} }
// prepare the reply // prepare the reply
@@ -483,6 +484,7 @@ UserlandRequestHandler::_HandleRequest(ReadVNodeRequest* request)
reply->node = node; reply->node = node;
reply->type = type; reply->type = type;
reply->flags = flags; reply->flags = flags;
reply->capabilities = capabilities;
// send the reply // send the reply
return _SendReply(allocator, false); 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" #include "Volume.h"
@@ -169,7 +172,7 @@ Volume::GetVNodeName(void* node, char* buffer, size_t bufferSize)
// ReadVNode // ReadVNode
status_t status_t
Volume::ReadVNode(ino_t vnid, bool reenter, void** node, int* type, Volume::ReadVNode(ino_t vnid, bool reenter, void** node, int* type,
uint32* flags) uint32* flags, FSVNodeCapabilities* _capabilities)
{ {
return B_BAD_VALUE; 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 #ifndef USERLAND_FS_VOLUME_H
#define USERLAND_FS_VOLUME_H #define USERLAND_FS_VOLUME_H
@@ -49,7 +51,8 @@ public:
virtual status_t GetVNodeName(void* node, char* buffer, virtual status_t GetVNodeName(void* node, char* buffer,
size_t bufferSize); size_t bufferSize);
virtual status_t ReadVNode(ino_t vnid, bool reenter, 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 WriteVNode(void* node, bool reenter);
virtual status_t RemoveVNode(void* node, bool reenter); virtual status_t RemoveVNode(void* node, bool reenter);
@@ -4,6 +4,7 @@
#include <new> #include <new>
#include "beos_kernel_emu.h"
#include "BeOSKernelVolume.h" #include "BeOSKernelVolume.h"
#include "fs_cache.h" #include "fs_cache.h"
#include "fs_interface.h" #include "fs_interface.h"
@@ -76,6 +77,8 @@ void
BeOSKernelFileSystem::_InitCapabilities() BeOSKernelFileSystem::_InitCapabilities()
{ {
fCapabilities.ClearAll(); fCapabilities.ClearAll();
fVolumeCapabilities.ClearAll();
fNodeCapabilities.ClearAll();
// FS interface type // FS interface type
fClientFSType = CLIENT_FS_BEOS_KERNEL; 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 // #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" #include "BeOSKernelVolume.h"
@@ -11,6 +14,7 @@
#include "../kernel_emu.h" #include "../kernel_emu.h"
#include "BeOSKernelFileSystem.h"
#include "fs_interface.h" #include "fs_interface.h"
@@ -40,6 +44,14 @@ public:
}; };
// _FileSystem
inline BeOSKernelFileSystem*
BeOSKernelVolume::_FileSystem() const
{
return static_cast<BeOSKernelFileSystem*>(fFileSystem);
}
// constructor // constructor
BeOSKernelVolume::BeOSKernelVolume(FileSystem* fileSystem, dev_t id, BeOSKernelVolume::BeOSKernelVolume(FileSystem* fileSystem, dev_t id,
beos_vnode_ops* fsOps, const FSVolumeCapabilities& capabilities) beos_vnode_ops* fsOps, const FSVolumeCapabilities& capabilities)
@@ -165,7 +177,7 @@ BeOSKernelVolume::GetVNodeType(void* node, int* type)
// ReadVNode // ReadVNode
status_t status_t
BeOSKernelVolume::ReadVNode(ino_t vnid, bool reenter, void** node, int* type, BeOSKernelVolume::ReadVNode(ino_t vnid, bool reenter, void** node, int* type,
uint32* flags) uint32* flags, FSVNodeCapabilities* _capabilities)
{ {
if (!fFSOps->read_vnode) if (!fFSOps->read_vnode)
return B_BAD_VALUE; 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); *type = (st.st_mode & S_IFMT);
*flags = 0; *flags = 0;
_FileSystem()->GetNodeCapabilities(*_capabilities);
return B_OK; 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 #ifndef USERLAND_FS_BEOS_KERNEL_VOLUME_H
#define USERLAND_FS_BEOS_KERNEL_VOLUME_H #define USERLAND_FS_BEOS_KERNEL_VOLUME_H
@@ -9,6 +11,9 @@ struct beos_vnode_ops;
namespace UserlandFS { namespace UserlandFS {
class BeOSKernelFileSystem;
class BeOSKernelVolume : public Volume { class BeOSKernelVolume : public Volume {
public: public:
BeOSKernelVolume(FileSystem* fileSystem, BeOSKernelVolume(FileSystem* fileSystem,
@@ -33,7 +38,8 @@ public:
// the three parameters publish_vnode() is // the three parameters publish_vnode() is
// used. // used.
virtual status_t ReadVNode(ino_t vnid, bool reenter, 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 WriteVNode(void* node, bool reenter);
virtual status_t RemoveVNode(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, status_t _OpenAttr(void* node, const char* name,
uint32 type, int openMode, bool create, uint32 type, int openMode, bool create,
void** cookie); void** cookie);
inline BeOSKernelFileSystem* _FileSystem() const;
private: private:
beos_vnode_ops* fFSOps; beos_vnode_ops* fFSOps;
@@ -1,5 +1,7 @@
// beos_kernel_emu.cpp // beos_kernel_emu.cpp
#include "beos_kernel_emu.h"
#include <stdarg.h> #include <stdarg.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
@@ -145,9 +147,14 @@ put_vnode(nspace_id nsid, ino_t vnid)
int int
new_vnode(nspace_id nsid, ino_t vnid, void *data) 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() // The semantics of new_vnode() has changed. The new publish_vnode()
// should work like the former new_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 // 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" #include "HaikuKernelFileSystem.h"
@@ -37,6 +40,40 @@ struct HaikuKernelFileSystem::IORequestHashDefinition {
// IORequestTable // IORequestTable
struct HaikuKernelFileSystem::IORequestTable struct HaikuKernelFileSystem::IORequestTable
: public OpenHashTable<IORequestHashDefinition> { : 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(), FileSystem(),
fFSModule(fsModule), fFSModule(fsModule),
fIORequests(NULL), fIORequests(NULL),
fNodeCapabilities(NULL),
fLock("HaikuKernelFileSystem") fLock("HaikuKernelFileSystem")
{ {
_InitCapabilities(); _InitCapabilities();
@@ -60,6 +98,7 @@ HaikuKernelFileSystem::~HaikuKernelFileSystem()
fFSModule->info.std_ops(B_MODULE_UNINIT); fFSModule->info.std_ops(B_MODULE_UNINIT);
delete fIORequests; delete fIORequests;
delete fNodeCapabilities;
// TODO: Call the cleanup methods (condition vars, block cache)! // TODO: Call the cleanup methods (condition vars, block cache)!
} }
@@ -91,6 +130,15 @@ HaikuKernelFileSystem::Init()
if (error != B_OK) if (error != B_OK)
RETURN_ERROR(error); 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) // call the kernel module initialization (if any)
if (!fFSModule->info.std_ops) if (!fFSModule->info.std_ops)
return B_OK; 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 // _InitCapabilities
void void
HaikuKernelFileSystem::_InitCapabilities() 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 // #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 #ifndef USERLAND_FS_HAIKU_KERNEL_FILE_SYSTEM_H
#define USERLAND_FS_HAIKU_KERNEL_FILE_SYSTEM_H #define USERLAND_FS_HAIKU_KERNEL_FILE_SYSTEM_H
#include "Locker.h" #include "Locker.h"
#include "HaikuKernelNode.h"
#include "../FileSystem.h" #include "../FileSystem.h"
struct file_system_module_info; struct file_system_module_info;
namespace UserlandFS { namespace UserlandFS {
struct HaikuKernelIORequest; struct HaikuKernelIORequest;
@@ -29,16 +35,27 @@ public:
void PutIORequest(HaikuKernelIORequest* request, void PutIORequest(HaikuKernelIORequest* request,
int32 refCount = 1); int32 refCount = 1);
HaikuKernelNode::Capabilities* GetNodeCapabilities(
fs_vnode_ops* ops);
void PutNodeCapabilities(
HaikuKernelNode::Capabilities*
capabilities);
private: private:
class IORequestHashDefinition; struct IORequestHashDefinition;
class IORequestTable; struct IORequestTable;
struct NodeCapabilitiesHashDefinition;
struct NodeCapabilitiesTable;
private: private:
void _InitCapabilities(); void _InitCapabilities();
static void _InitNodeCapabilities(fs_vnode_ops* ops,
FSVNodeCapabilities& capabilities);
private: private:
file_system_module_info* fFSModule; file_system_module_info* fFSModule;
IORequestTable* fIORequests; IORequestTable* fIORequests;
NodeCapabilitiesTable* fNodeCapabilities;
Locker fLock; Locker fLock;
}; };
@@ -8,8 +8,11 @@
#include <fs_interface.h> #include <fs_interface.h>
#include <SupportDefs.h> #include <SupportDefs.h>
#include <util/OpenHashTable.h>
#include "FSCapabilities.h" #include "FSCapabilities.h"
namespace UserlandFS { namespace UserlandFS {
class HaikuKernelVolume; class HaikuKernelVolume;
@@ -18,14 +21,19 @@ using UserlandFSUtil::FSVNodeCapabilities;
struct HaikuKernelNode : fs_vnode { struct HaikuKernelNode : fs_vnode {
struct Capabilities;
ino_t id; ino_t id;
HaikuKernelVolume* volume; HaikuKernelVolume* volume;
Capabilities* capabilities;
bool published; bool published;
public: public:
inline HaikuKernelNode(HaikuKernelVolume* volume, inline HaikuKernelNode(HaikuKernelVolume* volume,
ino_t vnodeID, void* privateNode, ino_t vnodeID, void* privateNode,
fs_vnode_ops* ops); fs_vnode_ops* ops,
Capabilities* capabilities);
~HaikuKernelNode();
static HaikuKernelNode* GetNode(fs_vnode* node); 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, HaikuKernelNode::HaikuKernelNode(HaikuKernelVolume* volume, ino_t vnodeID,
void* privateNode, fs_vnode_ops* ops) void* privateNode, fs_vnode_ops* ops, Capabilities* capabilities)
: :
id(vnodeID), id(vnodeID),
volume(volume), volume(volume),
capabilities(capabilities),
published(false) published(false)
{ {
this->private_node = privateNode; 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" #include "HaikuKernelVolume.h"
@@ -84,11 +87,20 @@ HaikuKernelVolume::NewVNode(ino_t vnodeID, void* privateNode, fs_vnode_ops* ops,
if (node != NULL) if (node != NULL)
return B_BAD_VALUE; return B_BAD_VALUE;
// create a new node // get node capabilities
node = new(std::nothrow) HaikuKernelNode(this, vnodeID, privateNode, ops); HaikuKernelNode::Capabilities* capabilities
if (node == NULL) = _FileSystem()->GetNodeCapabilities(ops);
if (capabilities == NULL)
return B_NO_MEMORY; 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 // add to map
status_t error = fNodes->Put(vnodeID, node); status_t error = fNodes->Put(vnodeID, node);
if (error != B_OK) { if (error != B_OK) {
@@ -115,11 +127,19 @@ HaikuKernelVolume::PublishVNode(ino_t vnodeID, void* privateNode,
if (node->published) if (node->published)
return B_BAD_VALUE; return B_BAD_VALUE;
} else { } else {
// get node capabilities
HaikuKernelNode::Capabilities* capabilities
= _FileSystem()->GetNodeCapabilities(ops);
if (capabilities == NULL)
return B_NO_MEMORY;
// create a new node // create a new node
node = new(std::nothrow) HaikuKernelNode(this, vnodeID, privateNode, node = new(std::nothrow) HaikuKernelNode(this, vnodeID, privateNode,
ops); ops, capabilities);
if (node == NULL) if (node == NULL) {
_FileSystem()->PutNodeCapabilities(capabilities);
return B_NO_MEMORY; return B_NO_MEMORY;
}
// add to map // add to map
status_t error = fNodes->Put(vnodeID, node); status_t error = fNodes->Put(vnodeID, node);
@@ -271,14 +291,14 @@ HaikuKernelVolume::GetVNodeName(void* _node, char* buffer, size_t bufferSize)
// ReadVNode // ReadVNode
status_t status_t
HaikuKernelVolume::ReadVNode(ino_t vnid, bool reenter, void** _node, int* type, HaikuKernelVolume::ReadVNode(ino_t vnid, bool reenter, void** _node, int* type,
uint32* flags) uint32* flags, FSVNodeCapabilities* _capabilities)
{ {
if (!fVolume.ops->get_vnode) if (!fVolume.ops->get_vnode)
return B_BAD_VALUE; return B_BAD_VALUE;
// create a new wrapper node and add it to the map // create a new wrapper node and add it to the map
HaikuKernelNode* node = new(std::nothrow) HaikuKernelNode(this, vnid, NULL, HaikuKernelNode* node = new(std::nothrow) HaikuKernelNode(this, vnid, NULL,
NULL); NULL, NULL);
if (node == NULL) if (node == NULL)
return B_NO_MEMORY; return B_NO_MEMORY;
ObjectDeleter<HaikuKernelNode> nodeDeleter(node); ObjectDeleter<HaikuKernelNode> nodeDeleter(node);
@@ -301,11 +321,23 @@ HaikuKernelVolume::ReadVNode(ino_t vnid, bool reenter, void** _node, int* type,
return error; 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(); locker.Lock();
node->capabilities = capabilities;
node->published = true; node->published = true;
nodeDeleter.Detach(); nodeDeleter.Detach();
*_node = node; *_node = node;
*_capabilities = capabilities->capabilities;
return B_OK; 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_READ_QUERY, fVolume.ops->read_query);
fCapabilities.Set(FS_VOLUME_CAPABILITY_REWIND_QUERY, fCapabilities.Set(FS_VOLUME_CAPABILITY_REWIND_QUERY,
fVolume.ops->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 #ifndef USERLAND_FS_HAIKU_KERNEL_VOLUME_H
#define 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, virtual status_t GetVNodeName(void* node, char* buffer,
size_t bufferSize); size_t bufferSize);
virtual status_t ReadVNode(ino_t vnid, bool reenter, 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 WriteVNode(void* node, bool reenter);
virtual status_t RemoveVNode(void* node, bool reenter); virtual status_t RemoveVNode(void* node, bool reenter);
@@ -45,6 +45,7 @@ SharedLibrary libuserlandfs_haiku_kernel.so
# UserlandFS server interface # UserlandFS server interface
HaikuKernelFileSystem.cpp HaikuKernelFileSystem.cpp
HaikuKernelNode.cpp
HaikuKernelVolume.cpp HaikuKernelVolume.cpp
: :
@@ -136,7 +136,8 @@ new_vnode(fs_volume *_volume, ino_t vnodeID, void *privateNode,
return error; return error;
// announce the new node // 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) if (error != B_OK)
volume->UndoNewVNode(node); volume->UndoNewVNode(node);
@@ -159,7 +160,7 @@ publish_vnode(fs_volume *_volume, ino_t vnodeID, void *privateNode,
// publish the new node // publish the new node
error = UserlandFS::KernelEmu::publish_vnode(volume->GetID(), vnodeID, node, error = UserlandFS::KernelEmu::publish_vnode(volume->GetID(), vnodeID, node,
type, flags); type, flags, node->capabilities->capabilities);
if (error != B_OK) if (error != B_OK)
volume->UndoPublishVNode(node); volume->UndoPublishVNode(node);
@@ -365,7 +365,8 @@ UserlandFS::KernelEmu::acquire_vnode(dev_t nsid, ino_t vnid)
// new_vnode // new_vnode
status_t 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 // get the request port and the file system
RequestPort* port; RequestPort* port;
@@ -384,6 +385,7 @@ UserlandFS::KernelEmu::new_vnode(dev_t nsid, ino_t vnid, void* data)
request->nsid = nsid; request->nsid = nsid;
request->vnid = vnid; request->vnid = vnid;
request->node = data; request->node = data;
request->capabilities = capabilities;
// send the request // send the request
UserlandRequestHandler handler(fileSystem, NEW_VNODE_REPLY); UserlandRequestHandler handler(fileSystem, NEW_VNODE_REPLY);
@@ -402,7 +404,7 @@ UserlandFS::KernelEmu::new_vnode(dev_t nsid, ino_t vnid, void* data)
// publish_vnode // publish_vnode
status_t 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,
int type, uint32 flags) int type, uint32 flags, const FSVNodeCapabilities& capabilities)
{ {
// get the request port and the file system // get the request port and the file system
RequestPort* port; RequestPort* port;
@@ -423,6 +425,7 @@ UserlandFS::KernelEmu::publish_vnode(dev_t nsid, ino_t vnid, void* data,
request->node = data; request->node = data;
request->type = type; request->type = type;
request->flags = flags; request->flags = flags;
request->capabilities = capabilities;
// send the request // send the request
UserlandRequestHandler handler(fileSystem, PUBLISH_VNODE_REPLY); UserlandRequestHandler handler(fileSystem, PUBLISH_VNODE_REPLY);
@@ -441,7 +444,8 @@ UserlandFS::KernelEmu::publish_vnode(dev_t nsid, ino_t vnid, void* data,
// publish_vnode // publish_vnode
status_t 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 // get the volume
Volume* volume = FileSystem::GetInstance()->VolumeWithID(nsid); Volume* volume = FileSystem::GetInstance()->VolumeWithID(nsid);
@@ -455,7 +459,8 @@ UserlandFS::KernelEmu::publish_vnode(dev_t nsid, ino_t vnid, void* data)
return error; return error;
// publish the node // 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 <OS.h>
#include "FSCapabilities.h"
struct selectsync; struct selectsync;
struct file_io_vec; 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 get_vnode(dev_t nsid, ino_t vnid, void** node);
status_t put_vnode(dev_t nsid, ino_t vnid); status_t put_vnode(dev_t nsid, ino_t vnid);
status_t acquire_vnode(dev_t nsid, ino_t vnodeID); 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, status_t publish_vnode(dev_t nsid, ino_t vnid, void* data, int type,
uint32 flags); uint32 flags, const FSVNodeCapabilities& capabilities);
status_t publish_vnode(dev_t nsid, ino_t vnid, void* data); 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 remove_vnode(dev_t nsid, ino_t vnid);
status_t unremove_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); status_t get_vnode_removed(dev_t nsid, ino_t vnid, bool* removed);