diff --git a/headers/private/userlandfs/private/Requests.h b/headers/private/userlandfs/private/Requests.h index 265cd5940b..e474570a26 100644 --- a/headers/private/userlandfs/private/Requests.h +++ b/headers/private/userlandfs/private/Requests.h @@ -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 diff --git a/src/add-ons/kernel/file_systems/userlandfs/kernel_add_on/FileSystem.cpp b/src/add-ons/kernel/file_systems/userlandfs/kernel_add_on/FileSystem.cpp index da994d3a97..7edc5f7d7e 100644 --- a/src/add-ons/kernel/file_systems/userlandfs/kernel_add_on/FileSystem.cpp +++ b/src/add-ons/kernel/file_systems/userlandfs/kernel_add_on/FileSystem.cpp @@ -3,18 +3,22 @@ * Distributed under the terms of the MIT License. */ +#include "Volume.h" + +#include + #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 _(fVolumeLock); + MutexLocker _(fVolumeLock); for (Vector::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() diff --git a/src/add-ons/kernel/file_systems/userlandfs/kernel_add_on/FileSystem.h b/src/add-ons/kernel/file_systems/userlandfs/kernel_add_on/FileSystem.h index 716ce750e7..78260a4f8f 100644 --- a/src/add-ons/kernel/file_systems/userlandfs/kernel_add_on/FileSystem.h +++ b/src/add-ons/kernel/file_systems/userlandfs/kernel_add_on/FileSystem.h @@ -7,6 +7,10 @@ #include +#include + +#include + #include "FSCapabilities.h" #include "LazyInitializable.h" #include "Locker.h" @@ -20,6 +24,42 @@ struct IOCtlInfo; class Settings; class Volume; + +struct VNodeOps : HashTableLink { + 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* 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 VNodeOpsMap; Vector fVolumes; - Locker fVolumeLock; + mutex fVolumeLock; + VNodeOpsMap fVNodeOps; + mutex fVNodeOpsLock; String fName; team_id fTeam; FSCapabilities fCapabilities; diff --git a/src/add-ons/kernel/file_systems/userlandfs/kernel_add_on/KernelRequestHandler.cpp b/src/add-ons/kernel/file_systems/userlandfs/kernel_add_on/KernelRequestHandler.cpp index 69446d7e60..c3f20330d2 100644 --- a/src/add-ons/kernel/file_systems/userlandfs/kernel_add_on/KernelRequestHandler.cpp +++ b/src/add-ons/kernel/file_systems/userlandfs/kernel_add_on/KernelRequestHandler.cpp @@ -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 diff --git a/src/add-ons/kernel/file_systems/userlandfs/kernel_add_on/Volume.cpp b/src/add-ons/kernel/file_systems/userlandfs/kernel_add_on/Volume.cpp index b8e77749d2..c60572742a 100644 --- a/src/add-ons/kernel/file_systems/userlandfs/kernel_add_on/Volume.cpp +++ b/src/add-ons/kernel/file_systems/userlandfs/kernel_add_on/Volume.cpp @@ -47,22 +47,32 @@ static const bigtime_t kUserlandServerlandPortTimeout = 10000000; // 10s // VNode struct Volume::VNode : HashTableLink { - 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); } diff --git a/src/add-ons/kernel/file_systems/userlandfs/kernel_add_on/Volume.h b/src/add-ons/kernel/file_systems/userlandfs/kernel_add_on/Volume.h index 2bccfb8a4a..172d8f8a4d 100644 --- a/src/add-ons/kernel/file_systems/userlandfs/kernel_add_on/Volume.h +++ b/src/add-ons/kernel/file_systems/userlandfs/kernel_add_on/Volume.h @@ -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 { diff --git a/src/add-ons/kernel/file_systems/userlandfs/kernel_add_on/kernel_interface.cpp b/src/add-ons/kernel/file_systems/userlandfs/kernel_add_on/kernel_interface.cpp index f6d3859a2b..46b72a1043 100644 --- a/src/add-ons/kernel/file_systems/userlandfs/kernel_add_on/kernel_interface.cpp +++ b/src/add-ons/kernel/file_systems/userlandfs/kernel_add_on/kernel_interface.cpp @@ -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)); diff --git a/src/add-ons/kernel/file_systems/userlandfs/server/UserlandRequestHandler.cpp b/src/add-ons/kernel/file_systems/userlandfs/server/UserlandRequestHandler.cpp index f9f95d39a4..2d6cddb39b 100644 --- a/src/add-ons/kernel/file_systems/userlandfs/server/UserlandRequestHandler.cpp +++ b/src/add-ons/kernel/file_systems/userlandfs/server/UserlandRequestHandler.cpp @@ -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); diff --git a/src/add-ons/kernel/file_systems/userlandfs/server/Volume.cpp b/src/add-ons/kernel/file_systems/userlandfs/server/Volume.cpp index d9e46de1b8..e393e38d0b 100644 --- a/src/add-ons/kernel/file_systems/userlandfs/server/Volume.cpp +++ b/src/add-ons/kernel/file_systems/userlandfs/server/Volume.cpp @@ -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; } diff --git a/src/add-ons/kernel/file_systems/userlandfs/server/Volume.h b/src/add-ons/kernel/file_systems/userlandfs/server/Volume.h index 3d45ca5383..c921bed631 100644 --- a/src/add-ons/kernel/file_systems/userlandfs/server/Volume.h +++ b/src/add-ons/kernel/file_systems/userlandfs/server/Volume.h @@ -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); diff --git a/src/add-ons/kernel/file_systems/userlandfs/server/beos/BeOSKernelFileSystem.cpp b/src/add-ons/kernel/file_systems/userlandfs/server/beos/BeOSKernelFileSystem.cpp index 99afa5da01..3e28be308d 100644 --- a/src/add-ons/kernel/file_systems/userlandfs/server/beos/BeOSKernelFileSystem.cpp +++ b/src/add-ons/kernel/file_systems/userlandfs/server/beos/BeOSKernelFileSystem.cpp @@ -4,6 +4,7 @@ #include +#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(FileSystem::GetInstance()); + fileSystem->GetNodeCapabilities(capabilities); +} + + // #pragma mark - bootstrapping diff --git a/src/add-ons/kernel/file_systems/userlandfs/server/beos/BeOSKernelVolume.cpp b/src/add-ons/kernel/file_systems/userlandfs/server/beos/BeOSKernelVolume.cpp index c51d10a3c5..65d5790e1c 100644 --- a/src/add-ons/kernel/file_systems/userlandfs/server/beos/BeOSKernelVolume.cpp +++ b/src/add-ons/kernel/file_systems/userlandfs/server/beos/BeOSKernelVolume.cpp @@ -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(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; } diff --git a/src/add-ons/kernel/file_systems/userlandfs/server/beos/BeOSKernelVolume.h b/src/add-ons/kernel/file_systems/userlandfs/server/beos/BeOSKernelVolume.h index 03cae80aae..caf9b7ed58 100644 --- a/src/add-ons/kernel/file_systems/userlandfs/server/beos/BeOSKernelVolume.h +++ b/src/add-ons/kernel/file_systems/userlandfs/server/beos/BeOSKernelVolume.h @@ -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; diff --git a/src/add-ons/kernel/file_systems/userlandfs/server/beos/beos_kernel_emu.cpp b/src/add-ons/kernel/file_systems/userlandfs/server/beos/beos_kernel_emu.cpp index f649cc6b59..52cf42da49 100644 --- a/src/add-ons/kernel/file_systems/userlandfs/server/beos/beos_kernel_emu.cpp +++ b/src/add-ons/kernel/file_systems/userlandfs/server/beos/beos_kernel_emu.cpp @@ -1,5 +1,7 @@ // beos_kernel_emu.cpp +#include "beos_kernel_emu.h" + #include #include #include @@ -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 diff --git a/src/add-ons/kernel/file_systems/userlandfs/server/haiku/HaikuKernelFileSystem.cpp b/src/add-ons/kernel/file_systems/userlandfs/server/haiku/HaikuKernelFileSystem.cpp index 1765034f72..1d11494536 100644 --- a/src/add-ons/kernel/file_systems/userlandfs/server/haiku/HaikuKernelFileSystem.cpp +++ b/src/add-ons/kernel/file_systems/userlandfs/server/haiku/HaikuKernelFileSystem.cpp @@ -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 { + 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* + 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* GetLink(ValueType* value) const + { return value; } +}; + + +// NodeCapabilitiesTable +struct HaikuKernelFileSystem::NodeCapabilitiesTable + : public OpenHashTable { }; @@ -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(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(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 diff --git a/src/add-ons/kernel/file_systems/userlandfs/server/haiku/HaikuKernelFileSystem.h b/src/add-ons/kernel/file_systems/userlandfs/server/haiku/HaikuKernelFileSystem.h index d74bfde55a..fbe2a0bf6d 100644 --- a/src/add-ons/kernel/file_systems/userlandfs/server/haiku/HaikuKernelFileSystem.h +++ b/src/add-ons/kernel/file_systems/userlandfs/server/haiku/HaikuKernelFileSystem.h @@ -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; }; diff --git a/src/add-ons/kernel/file_systems/userlandfs/server/haiku/HaikuKernelNode.h b/src/add-ons/kernel/file_systems/userlandfs/server/haiku/HaikuKernelNode.h index e1163cc72a..1ec0b081be 100644 --- a/src/add-ons/kernel/file_systems/userlandfs/server/haiku/HaikuKernelNode.h +++ b/src/add-ons/kernel/file_systems/userlandfs/server/haiku/HaikuKernelNode.h @@ -8,8 +8,11 @@ #include #include +#include + #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 { + 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; diff --git a/src/add-ons/kernel/file_systems/userlandfs/server/haiku/HaikuKernelVolume.cpp b/src/add-ons/kernel/file_systems/userlandfs/server/haiku/HaikuKernelVolume.cpp index 533f20db47..0e9fba420f 100644 --- a/src/add-ons/kernel/file_systems/userlandfs/server/haiku/HaikuKernelVolume.cpp +++ b/src/add-ons/kernel/file_systems/userlandfs/server/haiku/HaikuKernelVolume.cpp @@ -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 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 } diff --git a/src/add-ons/kernel/file_systems/userlandfs/server/haiku/HaikuKernelVolume.h b/src/add-ons/kernel/file_systems/userlandfs/server/haiku/HaikuKernelVolume.h index d5216ed8f4..01c3bcd51e 100644 --- a/src/add-ons/kernel/file_systems/userlandfs/server/haiku/HaikuKernelVolume.h +++ b/src/add-ons/kernel/file_systems/userlandfs/server/haiku/HaikuKernelVolume.h @@ -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); diff --git a/src/add-ons/kernel/file_systems/userlandfs/server/haiku/Jamfile b/src/add-ons/kernel/file_systems/userlandfs/server/haiku/Jamfile index cc80a492ce..a8eedcfb26 100644 --- a/src/add-ons/kernel/file_systems/userlandfs/server/haiku/Jamfile +++ b/src/add-ons/kernel/file_systems/userlandfs/server/haiku/Jamfile @@ -45,6 +45,7 @@ SharedLibrary libuserlandfs_haiku_kernel.so # UserlandFS server interface HaikuKernelFileSystem.cpp + HaikuKernelNode.cpp HaikuKernelVolume.cpp : diff --git a/src/add-ons/kernel/file_systems/userlandfs/server/haiku/haiku_kernel_emu.cpp b/src/add-ons/kernel/file_systems/userlandfs/server/haiku/haiku_kernel_emu.cpp index 340210017c..95bafac871 100644 --- a/src/add-ons/kernel/file_systems/userlandfs/server/haiku/haiku_kernel_emu.cpp +++ b/src/add-ons/kernel/file_systems/userlandfs/server/haiku/haiku_kernel_emu.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); diff --git a/src/add-ons/kernel/file_systems/userlandfs/server/kernel_emu.cpp b/src/add-ons/kernel/file_systems/userlandfs/server/kernel_emu.cpp index 3d00fe75d5..dcc9fa18a1 100644 --- a/src/add-ons/kernel/file_systems/userlandfs/server/kernel_emu.cpp +++ b/src/add-ons/kernel/file_systems/userlandfs/server/kernel_emu.cpp @@ -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); } diff --git a/src/add-ons/kernel/file_systems/userlandfs/server/kernel_emu.h b/src/add-ons/kernel/file_systems/userlandfs/server/kernel_emu.h index 0ad5ab3047..52c26a71ad 100644 --- a/src/add-ons/kernel/file_systems/userlandfs/server/kernel_emu.h +++ b/src/add-ons/kernel/file_systems/userlandfs/server/kernel_emu.h @@ -4,6 +4,9 @@ #include +#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);