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

@ -5,6 +5,13 @@
* \date 2013-11-11
*/
/*
* Copyright (C) 2013-2017 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
#ifndef _DIRECTORY_H_
#define _DIRECTORY_H_
@ -19,13 +26,14 @@
#include <lx_util.h>
namespace File_system {
namespace Lx_fs {
using namespace Genode;
using namespace File_system;
class Directory;
}
class File_system::Directory : public Node
class Lx_fs::Directory : public Node
{
private:
@ -72,6 +80,16 @@ class File_system::Directory : public Node
return fd;
}
size_t _num_entries() const
{
unsigned num = 0;
rewinddir(_fd);
while (readdir(_fd)) ++num;
return num;
}
public:
Directory(Allocator &alloc, char const *path, bool create)
@ -90,11 +108,10 @@ class File_system::Directory : public Node
}
/* FIXME returned file node must be locked */
File * file(char const *name, Mode mode, bool create)
File * file(char const *name, Mode mode, bool create) override
{
File *file = new (&_alloc) File(dirfd(_fd), name, mode, create);
file->lock();
return file;
}
@ -105,7 +122,6 @@ class File_system::Directory : public Node
Directory *dir = new (&_alloc) Directory(_alloc, dir_path.base(), create);
dir->lock();
return dir;
}
@ -134,11 +150,10 @@ class File_system::Directory : public Node
else
throw Lookup_failed();
node->lock();
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");
@ -177,20 +192,19 @@ 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;
}
size_t num_entries() const
Status status() override
{
unsigned num = 0;
rewinddir(_fd);
while (readdir(_fd)) ++num;
return num;
Status s;
s.inode = inode();
s.size = _num_entries() * sizeof(File_system::Directory_entry);
s.mode = File_system::Status::MODE_DIRECTORY;
return s;
}
};

View File

@ -5,6 +5,13 @@
* \date 2013-11-11
*/
/*
* Copyright (C) 2013-2017 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
#ifndef _FILE_H_
#define _FILE_H_
@ -13,12 +20,13 @@
#include <lx_util.h>
namespace File_system {
namespace Lx_fs {
using namespace File_system;
class File;
}
class File_system::File : public Node
class Lx_fs::File : public Node
{
private:
@ -74,6 +82,16 @@ class File_system::File : public Node
return fd;
}
file_size_t _length() const
{
struct stat s;
if (fstat(_fd, &s) < 0)
return 0;
return s.st_size;
}
public:
File(int dir,
@ -95,14 +113,14 @@ class File_system::File : public Node
Node::name(basename(path));
}
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 = pread(_fd, dst, len, seek_offset);
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
{
/* should we append? */
if (seek_offset == ~0ULL) {
@ -117,17 +135,16 @@ class File_system::File : public Node
return ret == -1 ? 0 : ret;
}
file_size_t length() const
Status status() override
{
struct stat s;
if (fstat(_fd, &s) < 0)
return 0;
return s.st_size;
Status s;
s.inode = inode();
s.size = _length();
s.mode = File_system::Status::MODE_FILE;
return s;
}
void truncate(file_size_t size)
void truncate(file_size_t size) override
{
if (ftruncate(_fd, size)) /* nothing */;

View File

@ -16,7 +16,7 @@
#include <base/heap.h>
#include <base/attached_rom_dataspace.h>
#include <root/component.h>
#include <file_system/node_handle_registry.h>
#include <file_system/open_node.h>
#include <file_system_session/rpc_object.h>
#include <os/session_policy.h>
#include <util/xml_node.h>
@ -25,22 +25,29 @@
#include <directory.h>
namespace File_system {
namespace Lx_fs {
using namespace File_system;
using File_system::Packet_descriptor;
using File_system::Path;
struct Main;
struct Session_component;
struct Root;
}
class File_system::Session_component : public Session_rpc_object
class Lx_fs::Session_component : public Session_rpc_object
{
private:
Genode::Env &_env;
Allocator &_md_alloc;
Directory &_root;
Node_handle_registry _handle_registry;
bool _writable;
typedef File_system::Open_node<Node> Open_node;
Genode::Env &_env;
Allocator &_md_alloc;
Directory &_root;
Id_space<File_system::Node> _open_node_registry;
bool _writable;
Signal_handler<Session_component> _process_packet_dispatcher;
@ -54,7 +61,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();
@ -66,18 +73,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;
@ -98,13 +105,16 @@ class File_system::Session_component : public Session_rpc_object
/* assume failure by default */
packet.succeeded(false);
try {
Node *node = _handle_registry.lookup_and_lock(packet.handle());
Node_lock_guard guard(node);
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"); }
}
/**
@ -191,23 +201,35 @@ class File_system::Session_component : public Session_rpc_object
if (!valid_name(name.string()))
throw Invalid_name();
Directory *dir = _handle_registry.lookup_and_lock(dir_handle);
Node_lock_guard dir_guard(dir);
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);
if (!_writable)
if (create || (mode != STAT_ONLY && mode != READ_ONLY))
throw Permission_denied();
Node_lock_guard file_guard(file);
return _handle_registry.alloc(file);
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)
{
Genode::error(__func__, " not implemented");
return Symlink_handle();
throw Permission_denied();
}
Dir_handle dir(Path const &path, bool create)
@ -226,8 +248,11 @@ class File_system::Session_component : public Session_rpc_object
throw Name_too_long();
Directory *dir = _root.subdir(path_str, create);
Node_lock_guard guard(dir);
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)
@ -238,43 +263,38 @@ class File_system::Session_component : public Session_rpc_object
Node *node = _root.node(path_str + 1);
Node_lock_guard guard(node);
return _handle_registry.alloc(node);
Open_node *open_node =
new (_md_alloc) Open_node(*node, _open_node_registry);
return open_node->id();
}
void close(Node_handle handle)
{
/* FIXME when to destruct node? */
_handle_registry.free(handle);
auto close_fn = [&] (Open_node &open_node) {
Node &node = open_node.node();
destroy(_md_alloc, &open_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_and_lock(node_handle);
Node_lock_guard guard(node);
auto status_fn = [&] (Open_node &open_node) {
return open_node.node().status();
};
Status s;
s.inode = node->inode();
s.size = 0;
s.mode = 0;
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;
}
Genode::error(__func__, " for symlinks not implemented");
return Status();
}
void control(Node_handle, Control)
@ -292,9 +312,15 @@ class File_system::Session_component : public Session_rpc_object
if (!_writable)
throw Permission_denied();
File *file = _handle_registry.lookup_and_lock(file_handle);
Node_lock_guard file_guard(file);
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, Name const &, Dir_handle, Name const &)
@ -311,7 +337,7 @@ class File_system::Session_component : public Session_rpc_object
};
class File_system::Root : public Root_component<Session_component>
class Lx_fs::Root : public Root_component<Session_component>
{
private:
@ -419,7 +445,7 @@ class File_system::Root : public Root_component<Session_component>
};
struct File_system::Main
struct Lx_fs::Main
{
Genode::Env &env;
@ -434,4 +460,4 @@ struct File_system::Main
};
void Component::construct(Genode::Env &env) { static File_system::Main inst(env); }
void Component::construct(Genode::Env &env) { static Lx_fs::Main inst(env); }

View File

@ -5,43 +5,70 @@
* \date 2013-11-11
*/
/*
* Copyright (C) 2013-2017 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
#ifndef _NODE_H_
#define _NODE_H_
/* Genode includes */
#include <file_system/listener.h>
#include <file_system/node.h>
namespace File_system {
class Node : public Node_base
{
public:
typedef char Name[128];
private:
Name _name;
unsigned long const _inode;
public:
Node(unsigned long inode) : _inode(inode) { _name[0] = 0; }
unsigned long inode() const { return _inode; }
char const *name() const { return _name; }
/**
* Assign name
*/
void name(char const *name) { Genode::strncpy(_name, name, sizeof(_name)); }
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;
};
namespace Lx_fs {
using namespace File_system;
class Node;
class File;
}
class Lx_fs::Node : public File_system::Node_base
{
public:
typedef char Name[128];
private:
Name _name;
unsigned long const _inode;
public:
Node(unsigned long inode) : _inode(inode) { _name[0] = 0; }
unsigned long inode() const { return _inode; }
char const *name() const { return _name; }
/**
* Assign name
*/
void name(char const *name) { Genode::strncpy(_name, name, sizeof(_name)); }
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;
/*
* File functionality
*/
virtual void truncate(file_size_t size)
{
Genode::error(__PRETTY_FUNCTION__, " called on a non-file node");
}
/*
* Directory functionality
*/
virtual File *file(char const *name, Mode mode, bool create)
{
Genode::error(__PRETTY_FUNCTION__, " called on a non-directory node");
return nullptr;
}
};
#endif /* _NODE_H_ */

View File

@ -7,6 +7,13 @@
* FIXME unfinished
*/
/*
* Copyright (C) 2013-2017 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
#ifndef _SYMLINK_H_
#define _SYMLINK_H_
@ -26,18 +33,20 @@ class File_system::Symlink : public Node
char _link_to[MAX_PATH_LEN];
file_size_t _length() const { return strlen(_link_to) + 1; }
public:
Symlink(char const *name) { Node::name(name); }
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
{
size_t count = min(len, sizeof(_link_to) + 1);
Genode::strncpy(dst, _link_to, count);
return count;
}
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 (seek_offset) return 0;
@ -47,7 +56,14 @@ class File_system::Symlink : public Node
return count;
}
file_size_t length() const { return strlen(_link_to) + 1; }
Status status() override
{
Status s;
s.inode = inode();
s.size = _length();
s.mode = File_system::Status::MODE_SYMLINK;
return s;
}
};
#endif /* _SYMLINK_H_ */