file system: use Id_space instead of Node_handle_registry

Fixes #2436
This commit is contained in:
Christian Prochaska
2017-06-20 14:23:22 +02:00
committed by Christian Helmuth
parent 0d1be4abe2
commit 6a43f3c11a
44 changed files with 3623 additions and 3100 deletions

View File

@@ -26,11 +26,11 @@
#include "file.h"
#include "symlink.h"
namespace File_system {
namespace Rump_fs {
class Directory;
}
class File_system::Directory : public Node
class Rump_fs::Directory : public Node
{
private:
@@ -106,14 +106,14 @@ class File_system::Directory : public Node
rump_sys_close(_fd);
}
int fd() const { return _fd; }
int fd() const override { return _fd; }
File * file(char const *name, Mode mode, bool create)
File * file(char const *name, Mode mode, bool create) override
{
return new (&_alloc) File(_fd, name, mode, create);
}
Symlink * symlink(char const *name, bool create)
Symlink * symlink(char const *name, bool create) override
{
return new (&_alloc) Symlink(_path.base(), name, create);
}
@@ -148,7 +148,7 @@ class File_system::Directory : public Node
return node;
}
size_t read(char *dst, size_t len, seek_off_t seek_offset)
size_t read(char *dst, size_t len, seek_off_t seek_offset) override
{
if (len < sizeof(Directory_entry)) {
Genode::error("read buffer too small for directory entry");
@@ -222,12 +222,22 @@ class File_system::Directory : public Node
return sizeof(Directory_entry);
}
size_t write(char const *src, size_t len, seek_off_t seek_offset)
size_t write(char const *src, size_t len, seek_off_t seek_offset) override
{
/* writing to directory nodes is not supported */
return 0;
}
Status status() override
{
Status s;
s.inode = inode();
s.size = num_entries() * sizeof (Directory_entry);
s.mode = File_system::Status::MODE_DIRECTORY;
return s;
}
size_t num_entries() const
{
int bytes = 0;
@@ -247,7 +257,7 @@ class File_system::Directory : public Node
return count;
}
void unlink(char const *path)
void unlink(char const *path) override
{
Path node_path(path, _path.base());

View File

@@ -21,11 +21,11 @@
#include "node.h"
namespace File_system {
namespace Rump_fs {
class File;
}
class File_system::File : public Node
class Rump_fs::File : public Node
{
private:
@@ -114,7 +114,7 @@ class File_system::File : public Node
virtual ~File() { rump_sys_close(_fd); }
size_t read(char *dst, size_t len, seek_off_t seek_offset)
size_t read(char *dst, size_t len, seek_off_t seek_offset) override
{
ssize_t ret;
@@ -127,7 +127,7 @@ class File_system::File : public Node
return ret == -1 ? 0 : ret;
}
size_t write(char const *src, size_t len, seek_off_t seek_offset)
size_t write(char const *src, size_t len, seek_off_t seek_offset) override
{
ssize_t ret;
@@ -140,6 +140,17 @@ class File_system::File : public Node
return ret == -1 ? 0 : ret;
}
virtual Status status() override
{
Status s;
s.inode = inode();
s.size = length();
s.mode = File_system::Status::MODE_FILE;
return s;
}
file_size_t length() const
{
struct stat s;
@@ -150,7 +161,7 @@ class File_system::File : public Node
return s.st_size;
}
void truncate(file_size_t size)
void truncate(file_size_t size) override
{
rump_sys_ftruncate(_fd, size);

View File

@@ -13,7 +13,7 @@
*/
/* Genode includes */
#include <file_system/node_handle_registry.h>
#include <file_system/open_node.h>
#include <file_system_session/rpc_object.h>
#include <base/attached_rom_dataspace.h>
#include <timer_session/connection.h>
@@ -30,20 +30,26 @@
#include "file_system.h"
#include "directory.h"
namespace File_system {
namespace Rump_fs {
using File_system::Packet_descriptor;
using File_system::Path;
struct Main;
struct Root;
struct Session_component;
}
class File_system::Session_component : public Session_rpc_object
class Rump_fs::Session_component : public Session_rpc_object
{
private:
Allocator &_md_alloc;
Directory &_root;
Node_handle_registry _handle_registry;
bool _writable;
typedef File_system::Open_node<Node> Open_node;
Allocator &_md_alloc;
Directory &_root;
Id_space<File_system::Node> _open_node_registry;
bool _writable;
Signal_handler<Session_component> _process_packet_handler;
@@ -57,7 +63,7 @@ class File_system::Session_component : public Session_rpc_object
*
* \return true on success, false on failure
*/
void _process_packet_op(Packet_descriptor &packet, Node &node)
void _process_packet_op(Packet_descriptor &packet, Open_node &open_node)
{
void * const content = tx_sink()->packet_content(packet);
size_t const length = packet.length();
@@ -69,18 +75,18 @@ class File_system::Session_component : public Session_rpc_object
case Packet_descriptor::READ:
if (content && (packet.length() <= packet.size()))
res_length = node.read((char *)content, length, packet.position());
res_length = open_node.node().read((char *)content, length, packet.position());
break;
case Packet_descriptor::WRITE:
if (content && (packet.length() <= packet.size()))
res_length = node.write((char const *)content, length, packet.position());
res_length = open_node.node().write((char const *)content, length, packet.position());
break;
case Packet_descriptor::CONTENT_CHANGED:
_handle_registry.register_notify(*tx_sink(), packet.handle());
open_node.register_notify(*tx_sink());
/* notify_listeners may bounce the packet back*/
node.notify_listeners();
open_node.node().notify_listeners();
/* otherwise defer acknowledgement of this packet */
return;
@@ -101,12 +107,16 @@ class File_system::Session_component : public Session_rpc_object
/* assume failure by default */
packet.succeeded(false);
try {
Node *node = _handle_registry.lookup(packet.handle());
auto process_packet_fn = [&] (Open_node &open_node) {
_process_packet_op(packet, open_node);
};
_process_packet_op(packet, *node);
try {
_open_node_registry.apply<Open_node>(packet.handle(), process_packet_fn);
} catch (Id_space<File_system::Node>::Unknown_id const &) {
Genode::error("Invalid_handle");
tx_sink()->acknowledge_packet(packet);
}
catch (Invalid_handle) { Genode::error("Invalid_handle"); }
}
/**
@@ -189,14 +199,29 @@ class File_system::Session_component : public Session_rpc_object
if (!valid_name(name.string()))
throw Invalid_name();
Directory *dir = _handle_registry.lookup(dir_handle);
auto file_fn = [&] (Open_node &open_node) {
if (!_writable)
if (create || (mode != STAT_ONLY && mode != READ_ONLY))
throw Permission_denied();
Node &dir = open_node.node();
File *file = dir->file(name.string(), mode, create);
return _handle_registry.alloc(file);
if (!_writable)
if (create || (mode != STAT_ONLY && mode != READ_ONLY))
throw Permission_denied();
File *file = dir.file(name.string(), mode, create);
Open_node *open_file =
new (_md_alloc) Open_node(*file, _open_node_registry);
return open_file->id();
};
try {
return File_handle {
_open_node_registry.apply<Open_node>(dir_handle, file_fn).value
};
} catch (Id_space<File_system::Node>::Unknown_id const &) {
throw Invalid_handle();
}
}
Symlink_handle symlink(Dir_handle dir_handle, Name const &name, bool create)
@@ -207,13 +232,28 @@ class File_system::Session_component : public Session_rpc_object
if (!valid_name(name.string()))
throw Invalid_name();
Directory *dir = _handle_registry.lookup(dir_handle);
auto symlink_fn = [&] (Open_node &open_node) {
if (create && !_writable)
throw Permission_denied();
Node &dir = open_node.node();
Symlink *link = dir->symlink(name.string(), create);
return _handle_registry.alloc(link);
if (create && !_writable)
throw Permission_denied();
Symlink *link = dir.symlink(name.string(), create);
Open_node *open_symlink =
new (_md_alloc) Open_node(*link, _open_node_registry);
return open_symlink->id();
};
try {
return Symlink_handle {
_open_node_registry.apply<Open_node>(dir_handle, symlink_fn).value
};
} catch (Id_space<File_system::Node>::Unknown_id const &) {
throw Invalid_handle();
}
}
Dir_handle dir(Path const &path, bool create)
@@ -231,7 +271,11 @@ class File_system::Session_component : public Session_rpc_object
throw Name_too_long();
Directory *dir = _root.subdir(path_str, create);
return _handle_registry.alloc(dir);
Open_node *open_dir =
new (_md_alloc) Open_node(*dir, _open_node_registry);
return Dir_handle { open_dir->id().value };
}
Node_handle node(Path const &path)
@@ -240,55 +284,39 @@ class File_system::Session_component : public Session_rpc_object
_assert_valid_path(path_str);
Node *node = _root.node(path_str + 1);
Node_handle h = _handle_registry.alloc(node);
return h;
Open_node *open_node =
new (_md_alloc) Open_node(*node, _open_node_registry);
return open_node->id();
}
void close(Node_handle handle)
{
Node *node = 0;
try {
node = _handle_registry.lookup(handle);
} catch (Invalid_handle) { return; }
auto close_fn = [&] (Open_node &open_node) {
Node &node = open_node.node();
destroy(_md_alloc, &open_node);
destroy(_md_alloc, &node);
};
_handle_registry.free(handle);
/* destruct node */
if (node)
destroy(&_md_alloc, node);
try {
_open_node_registry.apply<Open_node>(handle, close_fn);
} catch (Id_space<File_system::Node>::Unknown_id const &) {
throw Invalid_handle();
}
}
Status status(Node_handle node_handle)
{
Node *node = _handle_registry.lookup(node_handle);
Status s;
s.inode = node->inode();
s.size = 0;
s.mode = 0;
auto status_fn = [&] (Open_node &open_node) {
return open_node.node().status();
};
File *file = dynamic_cast<File *>(node);
if (file) {
s.size = file->length();
s.mode = File_system::Status::MODE_FILE;
return s;
try {
return _open_node_registry.apply<Open_node>(node_handle, status_fn);
} catch (Id_space<File_system::Node>::Unknown_id const &) {
throw Invalid_handle();
}
Directory *dir = dynamic_cast<Directory *>(node);
if (dir) {
s.size = dir->num_entries()*sizeof(Directory_entry);
s.mode = File_system::Status::MODE_DIRECTORY;
return s;
}
Symlink *link = dynamic_cast<Symlink *>(node);
if (link) {
s.size = link->length();
s.mode = File_system::Status::MODE_SYMLINK;
return s;
}
return Status();
}
void control(Node_handle, Control) override { }
@@ -301,8 +329,16 @@ class File_system::Session_component : public Session_rpc_object
if (!_writable)
throw Permission_denied();
Directory *dir = _handle_registry.lookup(dir_handle);
dir->unlink(name.string());
auto unlink_fn = [&] (Open_node &open_node) {
Node &dir = open_node.node();
dir.unlink(name.string());
};
try {
_open_node_registry.apply<Open_node>(dir_handle, unlink_fn);
} catch (Id_space<File_system::Node>::Unknown_id const &) {
throw Invalid_handle();
}
}
void truncate(File_handle file_handle, file_size_t size)
@@ -310,8 +346,15 @@ class File_system::Session_component : public Session_rpc_object
if (!_writable)
throw Permission_denied();
File *file = _handle_registry.lookup(file_handle);
file->truncate(size);
auto truncate_fn = [&] (Open_node &open_node) {
open_node.node().truncate(size);
};
try {
_open_node_registry.apply<Open_node>(file_handle, truncate_fn);
} catch (Id_space<File_system::Node>::Unknown_id const &) {
throw Invalid_handle();
}
}
void move(Dir_handle from_dir_handle, Name const &from_name,
@@ -320,41 +363,59 @@ class File_system::Session_component : public Session_rpc_object
if (!_writable)
throw Permission_denied();
char const *from_str = from_name.string();
char const *to_str = to_name.string();
auto move_fn = [&] (Open_node &open_from_dir_node) {
if (!(valid_name(from_str) && valid_name(to_str)))
throw Lookup_failed();
auto inner_move_fn = [&] (Open_node &open_to_dir_node) {
Directory *from_dir = _handle_registry.lookup(from_dir_handle);
Directory *to_dir = _handle_registry.lookup( to_dir_handle);
Node &from_dir = open_from_dir_node.node();
Node &to_dir = open_to_dir_node.node();
if (rump_sys_renameat(from_dir->fd(), from_str,
to_dir->fd(), to_str) == 0) {
from_dir->mark_as_updated();
from_dir->notify_listeners();
if (!_handle_registry.refer_to_same_node(from_dir_handle,
to_dir_handle)) {
to_dir->mark_as_updated();
to_dir->notify_listeners();
char const *from_str = from_name.string();
char const *to_str = to_name.string();
if (!(valid_name(from_str) && valid_name(to_str)))
throw Lookup_failed();
if (rump_sys_renameat(from_dir.fd(), from_str,
to_dir.fd(), to_str) == 0) {
from_dir.mark_as_updated();
from_dir.notify_listeners();
if (&from_dir != &to_dir) {
to_dir.mark_as_updated();
to_dir.notify_listeners();
}
return;
}
switch (errno) {
case ENOTEMPTY: throw Node_already_exists();
case ENOENT: throw Lookup_failed();
}
Genode::warning("renameat produced unhandled error ", errno, ", ", from_str, " -> ", to_str);
throw Permission_denied();
};
try {
_open_node_registry.apply<Open_node>(to_dir_handle, inner_move_fn);
} catch (Id_space<File_system::Node>::Unknown_id const &) {
throw Invalid_handle();
}
};
return;
try {
_open_node_registry.apply<Open_node>(from_dir_handle, move_fn);
} catch (Id_space<File_system::Node>::Unknown_id const &) {
throw Invalid_handle();
}
switch (errno) {
case ENOTEMPTY: throw Node_already_exists();
case ENOENT: throw Lookup_failed();
}
Genode::warning("renameat produced unhandled error ", errno, ", ", from_str, " -> ", to_str);
throw Permission_denied();
}
void sync(Node_handle) override { rump_sys_sync(); }
};
class File_system::Root : public Root_component<Session_component>
class Rump_fs::Root : public Root_component<Session_component>
{
private:
@@ -453,7 +514,7 @@ class File_system::Root : public Root_component<Session_component>
};
struct File_system::Main
struct Rump_fs::Main
{
Genode::Env &env;
@@ -516,5 +577,5 @@ void Component::construct(Genode::Env &env)
/* XXX execute constructors of global statics (uses shared objects) */
env.exec_static_constructors();
static File_system::Main inst(env);
static Rump_fs::Main inst(env);
}

View File

@@ -18,16 +18,20 @@
/* Genode includes */
#include <file_system/node.h>
#include <util/list.h>
#include <base/signal.h>
namespace File_system {
namespace Rump_fs {
using namespace File_system;
using namespace Genode;
using Genode::size_t;
class Node;
class File;
class Directory;
class Symlink;
}
class File_system::Node : public Node_base, public List<Node>::Element
class Rump_fs::Node : public Node_base
{
public:
@@ -52,6 +56,41 @@ class File_system::Node : public Node_base, public List<Node>::Element
virtual size_t read(char *dst, size_t len, seek_off_t) = 0;
virtual size_t write(char const *src, size_t len, seek_off_t) = 0;
virtual Status status() = 0;
/*
* Directory functionality
*/
virtual int fd() const
{
Genode::error(__PRETTY_FUNCTION__, " called on a non-directory node");
return -1;
}
virtual File *file(char const *name, Mode mode, bool create)
{
Genode::error(__PRETTY_FUNCTION__, " called on a non-directory node");
return nullptr;
}
virtual Symlink *symlink(char const *name, bool create)
{
Genode::error(__PRETTY_FUNCTION__, " called on a non-directory node");
return nullptr;
}
virtual void unlink(char const *path)
{
Genode::error(__PRETTY_FUNCTION__, " called on a non-directory node");
}
/*
* File functionality
*/
virtual void truncate(file_size_t size)
{
Genode::error(__PRETTY_FUNCTION__, " called on a non-file node");
}
};
#endif /* _NODE_H_ */

View File

@@ -20,11 +20,11 @@
#include "node.h"
namespace File_system {
namespace Rump_fs {
class Symlink;
}
class File_system::Symlink : public Node
class Rump_fs::Symlink : public Node
{
private:
@@ -47,7 +47,7 @@ class File_system::Symlink : public Node
Node::name(basename(path));
}
size_t write(char const *src, size_t len, seek_off_t seek_offset)
size_t write(char const *src, size_t len, seek_off_t seek_offset) override
{
/* Ideal symlink operations are atomic. */
if (!_create || seek_offset)
@@ -60,12 +60,22 @@ class File_system::Symlink : public Node
return ret == -1 ? 0 : ret;
}
size_t read(char *dst, size_t len, seek_off_t seek_offset)
size_t read(char *dst, size_t len, seek_off_t seek_offset) override
{
int ret = rump_sys_readlink(_path.base(), dst, len);
return ret == -1 ? 0 : ret;
}
Status status() override
{
Status s;
s.inode = inode();
s.size = length();
s.mode = File_system::Status::MODE_SYMLINK;
return s;
}
file_size_t length()
{
char link_to[MAX_PATH_LEN];