ram_fs: throw exception when unlinked node gets accessed

Fixes #2536
This commit is contained in:
Christian Prochaska 2017-09-26 16:35:17 +02:00 committed by Christian Helmuth
parent 30948a4b0d
commit 547cc06976
15 changed files with 561 additions and 81 deletions

View File

@ -13,7 +13,6 @@
*/ */
/* Genode includes */ /* Genode includes */
#include <file_system/open_node.h>
#include <file_system_session/rpc_object.h> #include <file_system_session/rpc_object.h>
#include <base/attached_rom_dataspace.h> #include <base/attached_rom_dataspace.h>
#include <timer_session/connection.h> #include <timer_session/connection.h>
@ -29,6 +28,7 @@
#include <sys/resource.h> #include <sys/resource.h>
#include "file_system.h" #include "file_system.h"
#include "directory.h" #include "directory.h"
#include "open_node.h"
namespace Rump_fs { namespace Rump_fs {

View File

@ -0,0 +1,95 @@
/*
* \brief Representation of an open file system node within the component (deprecated)
* \author Christian Prochaska
* \date 2017-06-09
*/
/*
* Copyright (C) 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 _OPEN_NODE_H_
#define _OPEN_NODE_H_
/* Genode includes */
#include <file_system/listener.h>
#include <file_system_session/file_system_session.h>
namespace File_system {
/*
* \param NODE component-specific node type
*/
template <typename NODE> class Open_node;
}
template <typename NODE>
class File_system::Open_node : public File_system::Node
{
private:
Genode::Id_space<File_system::Node>::Element _element;
NODE &_node;
Genode::Constructible<File_system::Listener> _listener;
Listener::Version const _version_when_opened = _node.curr_version();
/*
* Flag to track whether the underlying file-system node was
* modified via this 'Open_node'. That is, if closing the 'Open_node'
* should notify listeners of the file.
*/
bool _was_written = false;
public:
Open_node(NODE &node, Genode::Id_space<File_system::Node> &id_space)
: _element(*this, id_space), _node(node) { }
~Open_node()
{
if (_listener.constructed()) {
_node.remove_listener(&*_listener);
_listener.destruct();
}
/*
* Notify remaining listeners about the changed file
*/
if (_was_written)
_node.notify_listeners();
}
NODE &node() { return _node; }
File_system::Listener &listener() { return *_listener; }
Genode::Id_space<File_system::Node>::Id id() { return _element.id(); }
/**
* Register packet stream sink to be notified of node changes
*/
void register_notify(File_system::Sink &sink)
{
/*
* If there was already a handler registered for the node,
* remove the old handler.
*/
if (_listener.constructed()) {
_node.remove_listener(&*_listener);
_listener.destruct();
}
/*
* Register new handler
*/
_listener.construct(sink, id(), _version_when_opened);
_node.add_listener(&*_listener);
}
void mark_as_written() { _was_written = true; }
};
#endif /* _OPEN_NODE_H_ */

View File

@ -13,7 +13,6 @@
/* Genode includes */ /* Genode includes */
#include <base/component.h> #include <base/component.h>
#include <file_system/open_node.h>
#include <file_system_session/rpc_object.h> #include <file_system_session/rpc_object.h>
#include <root/component.h> #include <root/component.h>
#include <base/attached_rom_dataspace.h> #include <base/attached_rom_dataspace.h>
@ -25,6 +24,7 @@
/* local includes */ /* local includes */
#include <directory.h> #include <directory.h>
#include <file.h> #include <file.h>
#include <open_node.h>
#include <util.h> #include <util.h>
/* Genode block backend */ /* Genode block backend */

View File

@ -0,0 +1,95 @@
/*
* \brief Representation of an open file system node within the component (deprecated)
* \author Christian Prochaska
* \date 2017-06-09
*/
/*
* Copyright (C) 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 _OPEN_NODE_H_
#define _OPEN_NODE_H_
/* Genode includes */
#include <file_system/listener.h>
#include <file_system_session/file_system_session.h>
namespace File_system {
/*
* \param NODE component-specific node type
*/
template <typename NODE> class Open_node;
}
template <typename NODE>
class File_system::Open_node : public File_system::Node
{
private:
Genode::Id_space<File_system::Node>::Element _element;
NODE &_node;
Genode::Constructible<File_system::Listener> _listener;
Listener::Version const _version_when_opened = _node.curr_version();
/*
* Flag to track whether the underlying file-system node was
* modified via this 'Open_node'. That is, if closing the 'Open_node'
* should notify listeners of the file.
*/
bool _was_written = false;
public:
Open_node(NODE &node, Genode::Id_space<File_system::Node> &id_space)
: _element(*this, id_space), _node(node) { }
~Open_node()
{
if (_listener.constructed()) {
_node.remove_listener(&*_listener);
_listener.destruct();
}
/*
* Notify remaining listeners about the changed file
*/
if (_was_written)
_node.notify_listeners();
}
NODE &node() { return _node; }
File_system::Listener &listener() { return *_listener; }
Genode::Id_space<File_system::Node>::Id id() { return _element.id(); }
/**
* Register packet stream sink to be notified of node changes
*/
void register_notify(File_system::Sink &sink)
{
/*
* If there was already a handler registered for the node,
* remove the old handler.
*/
if (_listener.constructed()) {
_node.remove_listener(&*_listener);
_listener.destruct();
}
/*
* Register new handler
*/
_listener.construct(sink, id(), _version_when_opened);
_node.add_listener(&*_listener);
}
void mark_as_written() { _was_written = true; }
};
#endif /* _OPEN_NODE_H_ */

View File

@ -13,7 +13,6 @@
/* Genode includes */ /* Genode includes */
#include <base/heap.h> #include <base/heap.h>
#include <file_system/open_node.h>
#include <file_system_session/rpc_object.h> #include <file_system_session/rpc_object.h>
#include <base/attached_rom_dataspace.h> #include <base/attached_rom_dataspace.h>
#include <os/session_policy.h> #include <os/session_policy.h>
@ -26,6 +25,7 @@
/* local includes */ /* local includes */
#include <directory.h> #include <directory.h>
#include <open_node.h>
#include <util.h> #include <util.h>

View File

@ -0,0 +1,95 @@
/*
* \brief Representation of an open file system node within the component (deprecated)
* \author Christian Prochaska
* \date 2017-06-09
*/
/*
* Copyright (C) 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 _OPEN_NODE_H_
#define _OPEN_NODE_H_
/* Genode includes */
#include <file_system/listener.h>
#include <file_system_session/file_system_session.h>
namespace File_system {
/*
* \param NODE component-specific node type
*/
template <typename NODE> class Open_node;
}
template <typename NODE>
class File_system::Open_node : public File_system::Node
{
private:
Genode::Id_space<File_system::Node>::Element _element;
NODE &_node;
Genode::Constructible<File_system::Listener> _listener;
Listener::Version const _version_when_opened = _node.curr_version();
/*
* Flag to track whether the underlying file-system node was
* modified via this 'Open_node'. That is, if closing the 'Open_node'
* should notify listeners of the file.
*/
bool _was_written = false;
public:
Open_node(NODE &node, Genode::Id_space<File_system::Node> &id_space)
: _element(*this, id_space), _node(node) { }
~Open_node()
{
if (_listener.constructed()) {
_node.remove_listener(&*_listener);
_listener.destruct();
}
/*
* Notify remaining listeners about the changed file
*/
if (_was_written)
_node.notify_listeners();
}
NODE &node() { return _node; }
File_system::Listener &listener() { return *_listener; }
Genode::Id_space<File_system::Node>::Id id() { return _element.id(); }
/**
* Register packet stream sink to be notified of node changes
*/
void register_notify(File_system::Sink &sink)
{
/*
* If there was already a handler registered for the node,
* remove the old handler.
*/
if (_listener.constructed()) {
_node.remove_listener(&*_listener);
_listener.destruct();
}
/*
* Register new handler
*/
_listener.construct(sink, id(), _version_when_opened);
_node.add_listener(&*_listener);
}
void mark_as_written() { _was_written = true; }
};
#endif /* _OPEN_NODE_H_ */

View File

@ -32,10 +32,10 @@ class File_system::Open_node : public File_system::Node
Genode::Id_space<File_system::Node>::Element _element; Genode::Id_space<File_system::Node>::Element _element;
NODE &_node; Genode::Weak_ptr<NODE> _node;
Genode::Constructible<File_system::Listener> _listener; Genode::Constructible<File_system::Listener> _listener;
Listener::Version const _version_when_opened = _node.curr_version(); Listener::Version const _version_when_opened { _node_version(_node) };
/* /*
* Flag to track whether the underlying file-system node was * Flag to track whether the underlying file-system node was
@ -44,15 +44,29 @@ class File_system::Open_node : public File_system::Node
*/ */
bool _was_written = false; bool _was_written = false;
static Listener::Version const _node_version(Genode::Weak_ptr<NODE> node)
{
Genode::Locked_ptr<NODE> locked_node { node };
if (locked_node.valid())
return locked_node->curr_version();
else
return Listener::Version { 0 };
}
public: public:
Open_node(NODE &node, Genode::Id_space<File_system::Node> &id_space) Open_node(Genode::Weak_ptr<NODE> node,
Genode::Id_space<File_system::Node> &id_space)
: _element(*this, id_space), _node(node) { } : _element(*this, id_space), _node(node) { }
~Open_node() ~Open_node()
{ {
Genode::Locked_ptr<NODE> node { _node };
if (_listener.constructed()) { if (_listener.constructed()) {
_node.remove_listener(&*_listener); if (node.valid())
node->remove_listener(&*_listener);
_listener.destruct(); _listener.destruct();
} }
@ -60,10 +74,11 @@ class File_system::Open_node : public File_system::Node
* Notify remaining listeners about the changed file * Notify remaining listeners about the changed file
*/ */
if (_was_written) if (_was_written)
_node.notify_listeners(); if (node.valid())
node->notify_listeners();
} }
NODE &node() { return _node; } Genode::Weak_ptr<NODE>&node() { return _node; }
File_system::Listener &listener() { return *_listener; } File_system::Listener &listener() { return *_listener; }
Genode::Id_space<File_system::Node>::Id id() { return _element.id(); } Genode::Id_space<File_system::Node>::Id id() { return _element.id(); }
@ -73,20 +88,25 @@ class File_system::Open_node : public File_system::Node
*/ */
void register_notify(File_system::Sink &sink) void register_notify(File_system::Sink &sink)
{ {
Genode::Locked_ptr<NODE> node { _node };
/* /*
* If there was already a handler registered for the node, * If there was already a handler registered for the node,
* remove the old handler. * remove the old handler.
*/ */
if (_listener.constructed()) { if (_listener.constructed()) {
_node.remove_listener(&*_listener); if (node.valid())
node->remove_listener(&*_listener);
_listener.destruct(); _listener.destruct();
} }
/* /*
* Register new handler * Register new handler
*/ */
_listener.construct(sink, id(), _version_when_opened); if (node.valid()) {
_node.add_listener(&*_listener); _listener.construct(sink, id(), _version_when_opened);
node->add_listener(&*_listener);
}
} }
void mark_as_written() { _was_written = true; } void mark_as_written() { _was_written = true; }

View File

@ -105,6 +105,7 @@ namespace File_system {
class No_space : Exception { }; class No_space : Exception { };
class Not_empty : Exception { }; class Not_empty : Exception { };
class Permission_denied : Exception { }; class Permission_denied : Exception { };
class Unavailable : Exception { };
struct Session; struct Session;
} }
@ -288,6 +289,7 @@ struct File_system::Session : public Genode::Session
* \throw Out_of_ram server cannot allocate metadata * \throw Out_of_ram server cannot allocate metadata
* \throw Out_of_caps * \throw Out_of_caps
* \throw Permission_denied * \throw Permission_denied
* \throw Unavailable directory vanished
*/ */
virtual File_handle file(Dir_handle, Name const &name, Mode, bool create) = 0; virtual File_handle file(Dir_handle, Name const &name, Mode, bool create) = 0;
@ -303,6 +305,7 @@ struct File_system::Session : public Genode::Session
* \throw Out_of_ram server cannot allocate metadata * \throw Out_of_ram server cannot allocate metadata
* \throw Out_of_caps * \throw Out_of_caps
* \throw Permission_denied * \throw Permission_denied
* \throw Unavailable directory vanished
*/ */
virtual Symlink_handle symlink(Dir_handle, Name const &name, bool create) = 0; virtual Symlink_handle symlink(Dir_handle, Name const &name, bool create) = 0;
@ -345,6 +348,7 @@ struct File_system::Session : public Genode::Session
* Request information about an open file or directory * Request information about an open file or directory
* *
* \throw Invalid_handle node handle is invalid * \throw Invalid_handle node handle is invalid
* \throw Unavailable node vanished
*/ */
virtual Status status(Node_handle) = 0; virtual Status status(Node_handle) = 0;
@ -352,6 +356,7 @@ struct File_system::Session : public Genode::Session
* Set information about an open file or directory * Set information about an open file or directory
* *
* \throw Invalid_handle node handle is invalid * \throw Invalid_handle node handle is invalid
* \throw Unavailable node vanished
*/ */
virtual void control(Node_handle, Control) = 0; virtual void control(Node_handle, Control) = 0;
@ -364,6 +369,7 @@ struct File_system::Session : public Genode::Session
* \throw Not_empty argument is a non-empty directory and * \throw Not_empty argument is a non-empty directory and
* the backend does not support recursion * the backend does not support recursion
* \throw Permission_denied * \throw Permission_denied
* \throw Unavailable directory vanished
*/ */
virtual void unlink(Dir_handle dir, Name const &name) = 0; virtual void unlink(Dir_handle dir, Name const &name) = 0;
@ -373,6 +379,7 @@ struct File_system::Session : public Genode::Session
* \throw Invalid_handle node handle is invalid * \throw Invalid_handle node handle is invalid
* \throw No_space new size exceeds free space * \throw No_space new size exceeds free space
* \throw Permission_denied node modification not allowed * \throw Permission_denied node modification not allowed
* \throw Unavailable node vanished
*/ */
virtual void truncate(File_handle, file_size_t size) = 0; virtual void truncate(File_handle, file_size_t size) = 0;
@ -383,6 +390,7 @@ struct File_system::Session : public Genode::Session
* \throw Invalid_name 'to' contains invalid characters * \throw Invalid_name 'to' contains invalid characters
* \throw Lookup_failed 'from' not found * \throw Lookup_failed 'from' not found
* \throw Permission_denied node modification not allowed * \throw Permission_denied node modification not allowed
* \throw Unavailable a directory vanished
*/ */
virtual void move(Dir_handle, Name const &from, virtual void move(Dir_handle, Name const &from,
Dir_handle, Name const &to) = 0; Dir_handle, Name const &to) = 0;
@ -397,13 +405,13 @@ struct File_system::Session : public Genode::Session
GENODE_TYPE_LIST(Invalid_handle, Invalid_name, GENODE_TYPE_LIST(Invalid_handle, Invalid_name,
Lookup_failed, Node_already_exists, Lookup_failed, Node_already_exists,
No_space, Out_of_ram, Out_of_caps, No_space, Out_of_ram, Out_of_caps,
Permission_denied), Permission_denied, Unavailable),
Dir_handle, Name const &, Mode, bool); Dir_handle, Name const &, Mode, bool);
GENODE_RPC_THROW(Rpc_symlink, Symlink_handle, symlink, GENODE_RPC_THROW(Rpc_symlink, Symlink_handle, symlink,
GENODE_TYPE_LIST(Invalid_handle, Invalid_name, GENODE_TYPE_LIST(Invalid_handle, Invalid_name,
Lookup_failed, Node_already_exists, Lookup_failed, Node_already_exists,
No_space, Out_of_ram, Out_of_caps, No_space, Out_of_ram, Out_of_caps,
Permission_denied), Permission_denied, Unavailable),
Dir_handle, Name const &, bool); Dir_handle, Name const &, bool);
GENODE_RPC_THROW(Rpc_dir, Dir_handle, dir, GENODE_RPC_THROW(Rpc_dir, Dir_handle, dir,
GENODE_TYPE_LIST(Lookup_failed, Name_too_long, GENODE_TYPE_LIST(Lookup_failed, Name_too_long,
@ -417,23 +425,23 @@ struct File_system::Session : public Genode::Session
GENODE_TYPE_LIST(Invalid_handle), GENODE_TYPE_LIST(Invalid_handle),
Node_handle); Node_handle);
GENODE_RPC_THROW(Rpc_status, Status, status, GENODE_RPC_THROW(Rpc_status, Status, status,
GENODE_TYPE_LIST(Invalid_handle), GENODE_TYPE_LIST(Invalid_handle, Unavailable),
Node_handle); Node_handle);
GENODE_RPC_THROW(Rpc_control, void, control, GENODE_RPC_THROW(Rpc_control, void, control,
GENODE_TYPE_LIST(Invalid_handle), GENODE_TYPE_LIST(Invalid_handle, Unavailable),
Node_handle, Control); Node_handle, Control);
GENODE_RPC_THROW(Rpc_unlink, void, unlink, GENODE_RPC_THROW(Rpc_unlink, void, unlink,
GENODE_TYPE_LIST(Invalid_handle, Invalid_name, GENODE_TYPE_LIST(Invalid_handle, Invalid_name,
Lookup_failed, Not_empty, Lookup_failed, Not_empty,
Permission_denied), Permission_denied, Unavailable),
Dir_handle, Name const &); Dir_handle, Name const &);
GENODE_RPC_THROW(Rpc_truncate, void, truncate, GENODE_RPC_THROW(Rpc_truncate, void, truncate,
GENODE_TYPE_LIST(Invalid_handle, No_space, GENODE_TYPE_LIST(Invalid_handle, No_space,
Permission_denied), Permission_denied, Unavailable),
File_handle, file_size_t); File_handle, file_size_t);
GENODE_RPC_THROW(Rpc_move, void, move, GENODE_RPC_THROW(Rpc_move, void, move,
GENODE_TYPE_LIST(Invalid_handle, Invalid_name, GENODE_TYPE_LIST(Invalid_handle, Invalid_name,
Lookup_failed, Permission_denied), Lookup_failed, Permission_denied, Unavailable),
Dir_handle, Name const &, Dir_handle, Name const &); Dir_handle, Name const &, Dir_handle, Name const &);
GENODE_RPC_INTERFACE(Rpc_tx_cap, Rpc_file, Rpc_symlink, Rpc_dir, Rpc_node, GENODE_RPC_INTERFACE(Rpc_tx_cap, Rpc_file, Rpc_symlink, Rpc_dir, Rpc_node,

View File

@ -638,6 +638,7 @@ class Vfs::Fs_file_system : public File_system
catch (::File_system::Lookup_failed) { return UNLINK_ERR_NO_ENTRY; } catch (::File_system::Lookup_failed) { return UNLINK_ERR_NO_ENTRY; }
catch (::File_system::Not_empty) { return UNLINK_ERR_NOT_EMPTY; } catch (::File_system::Not_empty) { return UNLINK_ERR_NOT_EMPTY; }
catch (::File_system::Permission_denied) { return UNLINK_ERR_NO_PERM; } catch (::File_system::Permission_denied) { return UNLINK_ERR_NO_PERM; }
catch (::File_system::Unavailable) { return UNLINK_ERR_NO_ENTRY; }
return UNLINK_OK; return UNLINK_OK;
} }
@ -765,6 +766,7 @@ class Vfs::Fs_file_system : public File_system
catch (::File_system::No_space) { return OPEN_ERR_NO_SPACE; } catch (::File_system::No_space) { return OPEN_ERR_NO_SPACE; }
catch (::File_system::Out_of_ram) { return OPEN_ERR_OUT_OF_RAM; } catch (::File_system::Out_of_ram) { return OPEN_ERR_OUT_OF_RAM; }
catch (::File_system::Out_of_caps) { return OPEN_ERR_OUT_OF_CAPS; } catch (::File_system::Out_of_caps) { return OPEN_ERR_OUT_OF_CAPS; }
catch (::File_system::Unavailable) { return OPEN_ERR_UNACCESSIBLE; }
return OPEN_OK; return OPEN_OK;
} }
@ -834,6 +836,7 @@ class Vfs::Fs_file_system : public File_system
catch (::File_system::Out_of_ram) { return OPENLINK_ERR_OUT_OF_RAM; } catch (::File_system::Out_of_ram) { return OPENLINK_ERR_OUT_OF_RAM; }
catch (::File_system::Out_of_caps) { return OPENLINK_ERR_OUT_OF_CAPS; } catch (::File_system::Out_of_caps) { return OPENLINK_ERR_OUT_OF_CAPS; }
catch (::File_system::Permission_denied) { return OPENLINK_ERR_PERMISSION_DENIED; } catch (::File_system::Permission_denied) { return OPENLINK_ERR_PERMISSION_DENIED; }
catch (::File_system::Unavailable) { return OPENLINK_ERR_LOOKUP_FAILED; }
} }
void close(Vfs_handle *vfs_handle) override void close(Vfs_handle *vfs_handle) override
@ -940,6 +943,7 @@ class Vfs::Fs_file_system : public File_system
catch (::File_system::Invalid_handle) { return FTRUNCATE_ERR_NO_PERM; } catch (::File_system::Invalid_handle) { return FTRUNCATE_ERR_NO_PERM; }
catch (::File_system::Permission_denied) { return FTRUNCATE_ERR_NO_PERM; } catch (::File_system::Permission_denied) { return FTRUNCATE_ERR_NO_PERM; }
catch (::File_system::No_space) { return FTRUNCATE_ERR_NO_SPACE; } catch (::File_system::No_space) { return FTRUNCATE_ERR_NO_SPACE; }
catch (::File_system::Unavailable) { return FTRUNCATE_ERR_NO_PERM; }
return FTRUNCATE_OK; return FTRUNCATE_OK;
} }

View File

@ -16,14 +16,13 @@
#include <base/heap.h> #include <base/heap.h>
#include <base/attached_rom_dataspace.h> #include <base/attached_rom_dataspace.h>
#include <root/component.h> #include <root/component.h>
#include <file_system/open_node.h>
#include <file_system_session/rpc_object.h> #include <file_system_session/rpc_object.h>
#include <os/session_policy.h> #include <os/session_policy.h>
#include <util/xml_node.h> #include <util/xml_node.h>
/* local includes */ /* local includes */
#include <directory.h> #include <directory.h>
#include <open_node.h>
namespace Lx_fs { namespace Lx_fs {

View File

@ -0,0 +1,95 @@
/*
* \brief Representation of an open file system node within the component (deprecated)
* \author Christian Prochaska
* \date 2017-06-09
*/
/*
* Copyright (C) 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 _OPEN_NODE_H_
#define _OPEN_NODE_H_
/* Genode includes */
#include <file_system/listener.h>
#include <file_system_session/file_system_session.h>
namespace File_system {
/*
* \param NODE component-specific node type
*/
template <typename NODE> class Open_node;
}
template <typename NODE>
class File_system::Open_node : public File_system::Node
{
private:
Genode::Id_space<File_system::Node>::Element _element;
NODE &_node;
Genode::Constructible<File_system::Listener> _listener;
Listener::Version const _version_when_opened = _node.curr_version();
/*
* Flag to track whether the underlying file-system node was
* modified via this 'Open_node'. That is, if closing the 'Open_node'
* should notify listeners of the file.
*/
bool _was_written = false;
public:
Open_node(NODE &node, Genode::Id_space<File_system::Node> &id_space)
: _element(*this, id_space), _node(node) { }
~Open_node()
{
if (_listener.constructed()) {
_node.remove_listener(&*_listener);
_listener.destruct();
}
/*
* Notify remaining listeners about the changed file
*/
if (_was_written)
_node.notify_listeners();
}
NODE &node() { return _node; }
File_system::Listener &listener() { return *_listener; }
Genode::Id_space<File_system::Node>::Id id() { return _element.id(); }
/**
* Register packet stream sink to be notified of node changes
*/
void register_notify(File_system::Sink &sink)
{
/*
* If there was already a handler registered for the node,
* remove the old handler.
*/
if (_listener.constructed()) {
_node.remove_listener(&*_listener);
_listener.destruct();
}
/*
* Register new handler
*/
_listener.construct(sink, id(), _version_when_opened);
_node.add_listener(&*_listener);
}
void mark_as_written() { _was_written = true; }
};
#endif /* _OPEN_NODE_H_ */

View File

@ -76,30 +76,47 @@ class Ram_fs::Session_component : public File_system::Session_rpc_object
switch (packet.operation()) { switch (packet.operation()) {
case Packet_descriptor::READ: case Packet_descriptor::READ:
if (content && (packet.length() <= packet.size())) if (content && (packet.length() <= packet.size())) {
res_length = open_node.node().read((char *)content, length, packet.position()); Locked_ptr<Node> node { open_node.node() };
if (!node.valid())
break;
res_length = node->read((char *)content, length,
packet.position());
}
break; break;
case Packet_descriptor::WRITE: case Packet_descriptor::WRITE:
if (content && (packet.length() <= packet.size())) if (content && (packet.length() <= packet.size())) {
res_length = open_node.node().write((char const *)content, length, packet.position()); Locked_ptr<Node> node { open_node.node() };
if (!node.valid())
break;
res_length = node->write((char const *)content, length,
packet.position());
}
open_node.mark_as_written(); open_node.mark_as_written();
break; break;
case Packet_descriptor::CONTENT_CHANGED: case Packet_descriptor::CONTENT_CHANGED: {
open_node.register_notify(*tx_sink()); open_node.register_notify(*tx_sink());
open_node.node().notify_listeners(); Locked_ptr<Node> node { open_node.node() };
if (!node.valid())
return;
node->notify_listeners();
return; return;
}
case Packet_descriptor::READ_READY: case Packet_descriptor::READ_READY:
/* not supported */ /* not supported */
break; break;
case Packet_descriptor::SYNC: case Packet_descriptor::SYNC: {
open_node.node().notify_listeners(); Locked_ptr<Node> node { open_node.node() };
if (!node.valid())
break;
node->notify_listeners();
break; break;
} }
}
packet.length(res_length); packet.length(res_length);
packet.succeeded(res_length > 0); packet.succeeded(res_length > 0);
@ -207,7 +224,10 @@ class Ram_fs::Session_component : public File_system::Session_rpc_object
auto file_fn = [&] (Open_node &open_node) { auto file_fn = [&] (Open_node &open_node) {
Node &dir = open_node.node(); Locked_ptr<Node> dir { open_node.node() };
if (!dir.valid())
throw Unavailable();
if (!_writable) if (!_writable)
if (mode != STAT_ONLY && mode != READ_ONLY) if (mode != STAT_ONLY && mode != READ_ONLY)
@ -218,23 +238,23 @@ class Ram_fs::Session_component : public File_system::Session_rpc_object
if (!_writable) if (!_writable)
throw Permission_denied(); throw Permission_denied();
if (dir.has_sub_node_unsynchronized(name.string())) if (dir->has_sub_node_unsynchronized(name.string()))
throw Node_already_exists(); throw Node_already_exists();
try { try {
File * const file = new (_alloc) File * const file = new (_alloc)
File(_alloc, name.string()); File(_alloc, name.string());
dir.adopt_unsynchronized(file); dir->adopt_unsynchronized(file);
open_node.mark_as_written(); open_node.mark_as_written();
} }
catch (Allocator::Out_of_memory) { throw No_space(); } catch (Allocator::Out_of_memory) { throw No_space(); }
} }
File *file = dir.lookup_file(name.string()); File *file = dir->lookup_file(name.string());
Open_node *open_file = Open_node *open_file =
new (_alloc) Open_node(*file, _open_node_registry); new (_alloc) Open_node(file->weak_ptr(), _open_node_registry);
return open_file->id(); return open_file->id();
}; };
@ -255,29 +275,32 @@ class Ram_fs::Session_component : public File_system::Session_rpc_object
auto symlink_fn = [&] (Open_node &open_node) { auto symlink_fn = [&] (Open_node &open_node) {
Node &dir = open_node.node(); Locked_ptr<Node> dir { open_node.node() };
if (!dir.valid())
throw Unavailable();
if (create) { if (create) {
if (!_writable) if (!_writable)
throw Permission_denied(); throw Permission_denied();
if (dir.has_sub_node_unsynchronized(name.string())) if (dir->has_sub_node_unsynchronized(name.string()))
throw Node_already_exists(); throw Node_already_exists();
try { try {
Symlink * const symlink = new (_alloc) Symlink * const symlink = new (_alloc)
Symlink(name.string()); Symlink(name.string());
dir.adopt_unsynchronized(symlink); dir->adopt_unsynchronized(symlink);
} }
catch (Allocator::Out_of_memory) { throw No_space(); } catch (Allocator::Out_of_memory) { throw No_space(); }
} }
Symlink *symlink = dir.lookup_symlink(name.string()); Symlink *symlink = dir->lookup_symlink(name.string());
Open_node *open_symlink = Open_node *open_symlink =
new (_alloc) Open_node(*symlink, _open_node_registry); new (_alloc) Open_node(symlink->weak_ptr(), _open_node_registry);
return open_symlink->id(); return open_symlink->id();
}; };
@ -325,7 +348,7 @@ class Ram_fs::Session_component : public File_system::Session_rpc_object
Directory *dir = _root.lookup_dir(path_str); Directory *dir = _root.lookup_dir(path_str);
Open_node *open_dir = Open_node *open_dir =
new (_alloc) Open_node(*dir, _open_node_registry); new (_alloc) Open_node(dir->weak_ptr(), _open_node_registry);
return Dir_handle { open_dir->id().value }; return Dir_handle { open_dir->id().value };
} }
@ -337,7 +360,7 @@ class Ram_fs::Session_component : public File_system::Session_rpc_object
Node *node = _root.lookup(path.string() + 1); Node *node = _root.lookup(path.string() + 1);
Open_node *open_node = Open_node *open_node =
new (_alloc) Open_node(*node, _open_node_registry); new (_alloc) Open_node(node->weak_ptr(), _open_node_registry);
return open_node->id(); return open_node->id();
} }
@ -345,7 +368,8 @@ class Ram_fs::Session_component : public File_system::Session_rpc_object
void close(Node_handle handle) void close(Node_handle handle)
{ {
auto close_fn = [&] (Open_node &open_node) { auto close_fn = [&] (Open_node &open_node) {
destroy(_alloc, &open_node); }; destroy(_alloc, &open_node);
};
try { try {
_open_node_registry.apply<Open_node>(handle, close_fn); _open_node_registry.apply<Open_node>(handle, close_fn);
@ -357,7 +381,11 @@ class Ram_fs::Session_component : public File_system::Session_rpc_object
Status status(Node_handle node_handle) Status status(Node_handle node_handle)
{ {
auto status_fn = [&] (Open_node &open_node) { auto status_fn = [&] (Open_node &open_node) {
return open_node.node().status(); }; Locked_ptr<Node> node { open_node.node() };
if (!node.valid())
throw Unavailable();
return node->status();
};
try { try {
return _open_node_registry.apply<Open_node>(node_handle, status_fn); return _open_node_registry.apply<Open_node>(node_handle, status_fn);
@ -378,14 +406,14 @@ class Ram_fs::Session_component : public File_system::Session_rpc_object
auto unlink_fn = [&] (Open_node &open_node) { auto unlink_fn = [&] (Open_node &open_node) {
Node &dir = open_node.node(); Locked_ptr<Node> dir { open_node.node() };
Node *node = dir.lookup(name.string()); if (!dir.valid())
throw Unavailable();
dir.discard(node); Node *node = dir->lookup(name.string());
// XXX implement ref counting, do not destroy node that is dir->discard(node);
// is still referenced by a node handle
destroy(_alloc, node); destroy(_alloc, node);
open_node.mark_as_written(); open_node.mark_as_written();
@ -404,7 +432,10 @@ class Ram_fs::Session_component : public File_system::Session_rpc_object
throw Permission_denied(); throw Permission_denied();
auto truncate_fn = [&] (Open_node &open_node) { auto truncate_fn = [&] (Open_node &open_node) {
open_node.node().truncate(size); Locked_ptr<Node> node { open_node.node() };
if (!node.valid())
throw Unavailable();
node->truncate(size);
open_node.mark_as_written(); open_node.mark_as_written();
}; };
@ -431,17 +462,23 @@ class Ram_fs::Session_component : public File_system::Session_rpc_object
auto inner_move_fn = [&] (Open_node &open_to_dir_node) { auto inner_move_fn = [&] (Open_node &open_to_dir_node) {
Node &from_dir = open_from_dir_node.node(); Locked_ptr<Node> from_dir { open_from_dir_node.node() };
Node *node = from_dir.lookup(from_name.string()); if (!from_dir.valid())
throw Unavailable();
Node *node = from_dir->lookup(from_name.string());
node->name(to_name.string()); node->name(to_name.string());
Node &to_dir = open_to_dir_node.node(); if (!(open_to_dir_node.node() == open_from_dir_node.node())) {
if (&to_dir != &from_dir) { Locked_ptr<Node> to_dir { open_to_dir_node.node() };
from_dir.discard(node); if (!to_dir.valid())
to_dir.adopt_unsynchronized(node); throw Unavailable();
from_dir->discard(node);
to_dir->adopt_unsynchronized(node);
/* /*
* If the file was moved from one directory to another we * If the file was moved from one directory to another we
@ -449,13 +486,13 @@ class Ram_fs::Session_component : public File_system::Session_rpc_object
* directory 'from_dir' will always get notified (i.e., * directory 'from_dir' will always get notified (i.e.,
* when just the file name was changed) below. * when just the file name was changed) below.
*/ */
to_dir.mark_as_updated(); to_dir->mark_as_updated();
open_to_dir_node.mark_as_written(); open_to_dir_node.mark_as_written();
to_dir.notify_listeners(); to_dir->notify_listeners();
from_dir.mark_as_updated(); from_dir->mark_as_updated();
open_from_dir_node.mark_as_written(); open_from_dir_node.mark_as_written();
from_dir.notify_listeners(); from_dir->notify_listeners();
node->mark_as_updated(); node->mark_as_updated();
node->notify_listeners(); node->notify_listeners();

View File

@ -29,7 +29,8 @@ namespace Ram_fs {
} }
class Ram_fs::Node : public File_system::Node_base, public List<Node>::Element class Ram_fs::Node : public File_system::Node_base, public Weak_object<Node>,
public List<Node>::Element
{ {
public: public:
@ -56,6 +57,8 @@ class Ram_fs::Node : public File_system::Node_base, public List<Node>::Element
: _ref_count(0), _inode(_unique_inode()) : _ref_count(0), _inode(_unique_inode())
{ _name[0] = 0; } { _name[0] = 0; }
virtual ~Node() { lock_for_destruction(); }
unsigned long inode() const { return _inode; } unsigned long inode() const { return _inode; }
char const *name() const { return _name; } char const *name() const { return _name; }

View File

@ -658,22 +658,36 @@ class Trace_fs::Session_component : public Session_rpc_object
switch (packet.operation()) { switch (packet.operation()) {
case Packet_descriptor::READ: case Packet_descriptor::READ:
if (content && (packet.length() <= packet.size())) if (content && (packet.length() <= packet.size())) {
res_length = open_node.node().read((char *)content, length, packet.position()); Locked_ptr<Node> node { open_node.node() };
if (!node.valid())
break;
res_length = node->read((char *)content, length, packet.position());
}
break; break;
case Packet_descriptor::WRITE: case Packet_descriptor::WRITE:
if (content && (packet.length() <= packet.size())) if (content && (packet.length() <= packet.size())) {
res_length = open_node.node().write((char const *)content, length, packet.position()); Locked_ptr<Node> node { open_node.node() };
if (!node.valid())
break;
res_length = node->write((char const *)content, length, packet.position());
}
break; break;
case Packet_descriptor::CONTENT_CHANGED: case Packet_descriptor::CONTENT_CHANGED: {
open_node.register_notify(*tx_sink()); open_node.register_notify(*tx_sink());
/* notify_listeners may bounce the packet back*/ /* notify_listeners may bounce the packet back*/
open_node.node().notify_listeners(); Locked_ptr<Node> node { open_node.node() };
if (!node.valid())
return;
node->notify_listeners();
/* otherwise defer acknowledgement of this packet */ /* otherwise defer acknowledgement of this packet */
return; return;
}
case Packet_descriptor::READ_READY: case Packet_descriptor::READ_READY:
/* not supported */ /* not supported */
break; break;
@ -824,17 +838,20 @@ class Trace_fs::Session_component : public Session_rpc_object
auto file_fn = [&] (Open_node &open_node) { auto file_fn = [&] (Open_node &open_node) {
Node &dir = open_node.node(); Locked_ptr<Node> dir { open_node.node() };
if (!dir.valid())
throw Invalid_handle();
if (create) if (create)
throw Permission_denied(); throw Permission_denied();
File *file = dynamic_cast<File*>(dir.lookup(name.string())); File *file = dynamic_cast<File*>(dir->lookup(name.string()));
if (!file) if (!file)
throw Invalid_name(); throw Invalid_name();
Open_node *open_file = Open_node *open_file =
new (_md_alloc) Open_node(*file, _open_node_registry); new (_md_alloc) Open_node(file->weak_ptr(), _open_node_registry);
return open_file->id(); return open_file->id();
}; };
@ -871,7 +888,7 @@ class Trace_fs::Session_component : public Session_rpc_object
throw Invalid_name(); throw Invalid_name();
Open_node *open_dir = Open_node *open_dir =
new (_md_alloc) Open_node(*dir, _open_node_registry); new (_md_alloc) Open_node(dir->weak_ptr(), _open_node_registry);
return Dir_handle { open_dir->id().value }; return Dir_handle { open_dir->id().value };
} }
@ -885,7 +902,7 @@ class Trace_fs::Session_component : public Session_rpc_object
Node *node = _root_dir.lookup(path_str + 1); Node *node = _root_dir.lookup(path_str + 1);
Open_node *open_node = Open_node *open_node =
new (_md_alloc) Open_node(*node, _open_node_registry); new (_md_alloc) Open_node(node->weak_ptr(), _open_node_registry);
return open_node->id(); return open_node->id();
} }
@ -894,26 +911,29 @@ class Trace_fs::Session_component : public Session_rpc_object
{ {
auto close_fn = [&] (Open_node &open_node) { auto close_fn = [&] (Open_node &open_node) {
Node &node = open_node.node(); Locked_ptr<Node> node { open_node.node() };
if (!node.valid())
throw Invalid_handle();
/** /**
* Acknowledge the change of the content of files which may be * Acknowledge the change of the content of files which may be
* modified by the user of the file system. * modified by the user of the file system.
*/ */
Changeable_content *changeable = dynamic_cast<Changeable_content*>(&node); Changeable_content *changeable = dynamic_cast<Changeable_content*>(&*node);
if (changeable) { if (changeable) {
if (changeable->changed()) { if (changeable->changed()) {
changeable->acknowledge_change(); changeable->acknowledge_change();
/* let the trace fs perform the provoked actions */ /* let the trace fs perform the provoked actions */
_trace_fs->handle_changed_node(&node); _trace_fs->handle_changed_node(&*node);
} }
} }
/* /*
* Notify listeners about the changed file. * Notify listeners about the changed file.
*/ */
node.notify_listeners(); node->notify_listeners();
/* /*
* De-allocate handle * De-allocate handle
@ -931,7 +951,10 @@ class Trace_fs::Session_component : public Session_rpc_object
Status status(Node_handle node_handle) Status status(Node_handle node_handle)
{ {
auto status_fn = [&] (Open_node &open_node) { auto status_fn = [&] (Open_node &open_node) {
return open_node.node().status(); Locked_ptr<Node> node { open_node.node() };
if (!node.valid())
throw Invalid_handle();
return node->status();
}; };
try { try {
@ -947,7 +970,10 @@ class Trace_fs::Session_component : public Session_rpc_object
void truncate(File_handle handle, file_size_t size) void truncate(File_handle handle, file_size_t size)
{ {
auto truncate_fn = [&] (Open_node &open_node) { auto truncate_fn = [&] (Open_node &open_node) {
open_node.node().truncate(size); Locked_ptr<Node> node { open_node.node() };
if (!node.valid())
throw Invalid_handle();
node->truncate(size);
}; };
try { try {

View File

@ -26,7 +26,8 @@ namespace Trace_fs {
class Node; class Node;
} }
class Trace_fs::Node : public Node_base, public List<Node>::Element class Trace_fs::Node : public Node_base, public Weak_object<Node>,
public List<Node>::Element
{ {
public: public:
@ -52,6 +53,8 @@ class Trace_fs::Node : public Node_base, public List<Node>::Element
: _inode(_unique_inode()) : _inode(_unique_inode())
{ _name[0] = 0; } { _name[0] = 0; }
virtual ~Node() { lock_for_destruction(); }
unsigned long inode() const { return _inode; } unsigned long inode() const { return _inode; }
char const *name() const { return _name; } char const *name() const { return _name; }