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 */
#include <file_system/open_node.h>
#include <file_system_session/rpc_object.h>
#include <base/attached_rom_dataspace.h>
#include <timer_session/connection.h>
@ -29,6 +28,7 @@
#include <sys/resource.h>
#include "file_system.h"
#include "directory.h"
#include "open_node.h"
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 */
#include <base/component.h>
#include <file_system/open_node.h>
#include <file_system_session/rpc_object.h>
#include <root/component.h>
#include <base/attached_rom_dataspace.h>
@ -25,6 +24,7 @@
/* local includes */
#include <directory.h>
#include <file.h>
#include <open_node.h>
#include <util.h>
/* 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 */
#include <base/heap.h>
#include <file_system/open_node.h>
#include <file_system_session/rpc_object.h>
#include <base/attached_rom_dataspace.h>
#include <os/session_policy.h>
@ -26,6 +25,7 @@
/* local includes */
#include <directory.h>
#include <open_node.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;
NODE &_node;
Genode::Weak_ptr<NODE> _node;
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
@ -44,15 +44,29 @@ class File_system::Open_node : public File_system::Node
*/
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:
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) { }
~Open_node()
{
Genode::Locked_ptr<NODE> node { _node };
if (_listener.constructed()) {
_node.remove_listener(&*_listener);
if (node.valid())
node->remove_listener(&*_listener);
_listener.destruct();
}
@ -60,10 +74,11 @@ class File_system::Open_node : public File_system::Node
* Notify remaining listeners about the changed file
*/
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; }
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)
{
Genode::Locked_ptr<NODE> node { _node };
/*
* If there was already a handler registered for the node,
* remove the old handler.
*/
if (_listener.constructed()) {
_node.remove_listener(&*_listener);
if (node.valid())
node->remove_listener(&*_listener);
_listener.destruct();
}
/*
* Register new handler
*/
if (node.valid()) {
_listener.construct(sink, id(), _version_when_opened);
_node.add_listener(&*_listener);
node->add_listener(&*_listener);
}
}
void mark_as_written() { _was_written = true; }

View File

@ -105,6 +105,7 @@ namespace File_system {
class No_space : Exception { };
class Not_empty : Exception { };
class Permission_denied : Exception { };
class Unavailable : Exception { };
struct Session;
}
@ -288,6 +289,7 @@ struct File_system::Session : public Genode::Session
* \throw Out_of_ram server cannot allocate metadata
* \throw Out_of_caps
* \throw Permission_denied
* \throw Unavailable directory vanished
*/
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_caps
* \throw Permission_denied
* \throw Unavailable directory vanished
*/
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
*
* \throw Invalid_handle node handle is invalid
* \throw Unavailable node vanished
*/
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
*
* \throw Invalid_handle node handle is invalid
* \throw Unavailable node vanished
*/
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
* the backend does not support recursion
* \throw Permission_denied
* \throw Unavailable directory vanished
*/
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 No_space new size exceeds free space
* \throw Permission_denied node modification not allowed
* \throw Unavailable node vanished
*/
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 Lookup_failed 'from' not found
* \throw Permission_denied node modification not allowed
* \throw Unavailable a directory vanished
*/
virtual void move(Dir_handle, Name const &from,
Dir_handle, Name const &to) = 0;
@ -397,13 +405,13 @@ struct File_system::Session : public Genode::Session
GENODE_TYPE_LIST(Invalid_handle, Invalid_name,
Lookup_failed, Node_already_exists,
No_space, Out_of_ram, Out_of_caps,
Permission_denied),
Permission_denied, Unavailable),
Dir_handle, Name const &, Mode, bool);
GENODE_RPC_THROW(Rpc_symlink, Symlink_handle, symlink,
GENODE_TYPE_LIST(Invalid_handle, Invalid_name,
Lookup_failed, Node_already_exists,
No_space, Out_of_ram, Out_of_caps,
Permission_denied),
Permission_denied, Unavailable),
Dir_handle, Name const &, bool);
GENODE_RPC_THROW(Rpc_dir, Dir_handle, dir,
GENODE_TYPE_LIST(Lookup_failed, Name_too_long,
@ -417,23 +425,23 @@ struct File_system::Session : public Genode::Session
GENODE_TYPE_LIST(Invalid_handle),
Node_handle);
GENODE_RPC_THROW(Rpc_status, Status, status,
GENODE_TYPE_LIST(Invalid_handle),
GENODE_TYPE_LIST(Invalid_handle, Unavailable),
Node_handle);
GENODE_RPC_THROW(Rpc_control, void, control,
GENODE_TYPE_LIST(Invalid_handle),
GENODE_TYPE_LIST(Invalid_handle, Unavailable),
Node_handle, Control);
GENODE_RPC_THROW(Rpc_unlink, void, unlink,
GENODE_TYPE_LIST(Invalid_handle, Invalid_name,
Lookup_failed, Not_empty,
Permission_denied),
Permission_denied, Unavailable),
Dir_handle, Name const &);
GENODE_RPC_THROW(Rpc_truncate, void, truncate,
GENODE_TYPE_LIST(Invalid_handle, No_space,
Permission_denied),
Permission_denied, Unavailable),
File_handle, file_size_t);
GENODE_RPC_THROW(Rpc_move, void, move,
GENODE_TYPE_LIST(Invalid_handle, Invalid_name,
Lookup_failed, Permission_denied),
Lookup_failed, Permission_denied, Unavailable),
Dir_handle, Name const &, Dir_handle, Name const &);
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::Not_empty) { return UNLINK_ERR_NOT_EMPTY; }
catch (::File_system::Permission_denied) { return UNLINK_ERR_NO_PERM; }
catch (::File_system::Unavailable) { return UNLINK_ERR_NO_ENTRY; }
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::Out_of_ram) { return OPEN_ERR_OUT_OF_RAM; }
catch (::File_system::Out_of_caps) { return OPEN_ERR_OUT_OF_CAPS; }
catch (::File_system::Unavailable) { return OPEN_ERR_UNACCESSIBLE; }
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_caps) { return OPENLINK_ERR_OUT_OF_CAPS; }
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
@ -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::Permission_denied) { return FTRUNCATE_ERR_NO_PERM; }
catch (::File_system::No_space) { return FTRUNCATE_ERR_NO_SPACE; }
catch (::File_system::Unavailable) { return FTRUNCATE_ERR_NO_PERM; }
return FTRUNCATE_OK;
}

View File

@ -16,14 +16,13 @@
#include <base/heap.h>
#include <base/attached_rom_dataspace.h>
#include <root/component.h>
#include <file_system/open_node.h>
#include <file_system_session/rpc_object.h>
#include <os/session_policy.h>
#include <util/xml_node.h>
/* local includes */
#include <directory.h>
#include <open_node.h>
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,29 +76,46 @@ class Ram_fs::Session_component : public File_system::Session_rpc_object
switch (packet.operation()) {
case Packet_descriptor::READ:
if (content && (packet.length() <= packet.size()))
res_length = open_node.node().read((char *)content, length, packet.position());
if (content && (packet.length() <= packet.size())) {
Locked_ptr<Node> node { open_node.node() };
if (!node.valid())
break;
res_length = node->read((char *)content, length,
packet.position());
}
break;
case Packet_descriptor::WRITE:
if (content && (packet.length() <= packet.size()))
res_length = open_node.node().write((char const *)content, length, packet.position());
if (content && (packet.length() <= packet.size())) {
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();
break;
case Packet_descriptor::CONTENT_CHANGED:
case Packet_descriptor::CONTENT_CHANGED: {
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;
}
case Packet_descriptor::READ_READY:
/* not supported */
break;
case Packet_descriptor::SYNC:
open_node.node().notify_listeners();
case Packet_descriptor::SYNC: {
Locked_ptr<Node> node { open_node.node() };
if (!node.valid())
break;
node->notify_listeners();
break;
}
}
packet.length(res_length);
@ -207,7 +224,10 @@ class Ram_fs::Session_component : public File_system::Session_rpc_object
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 (mode != STAT_ONLY && mode != READ_ONLY)
@ -218,23 +238,23 @@ class Ram_fs::Session_component : public File_system::Session_rpc_object
if (!_writable)
throw Permission_denied();
if (dir.has_sub_node_unsynchronized(name.string()))
if (dir->has_sub_node_unsynchronized(name.string()))
throw Node_already_exists();
try {
File * const file = new (_alloc)
File(_alloc, name.string());
dir.adopt_unsynchronized(file);
dir->adopt_unsynchronized(file);
open_node.mark_as_written();
}
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 =
new (_alloc) Open_node(*file, _open_node_registry);
new (_alloc) Open_node(file->weak_ptr(), _open_node_registry);
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) {
Node &dir = open_node.node();
Locked_ptr<Node> dir { open_node.node() };
if (!dir.valid())
throw Unavailable();
if (create) {
if (!_writable)
throw Permission_denied();
if (dir.has_sub_node_unsynchronized(name.string()))
if (dir->has_sub_node_unsynchronized(name.string()))
throw Node_already_exists();
try {
Symlink * const symlink = new (_alloc)
Symlink(name.string());
dir.adopt_unsynchronized(symlink);
dir->adopt_unsynchronized(symlink);
}
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 =
new (_alloc) Open_node(*symlink, _open_node_registry);
new (_alloc) Open_node(symlink->weak_ptr(), _open_node_registry);
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);
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 };
}
@ -337,7 +360,7 @@ class Ram_fs::Session_component : public File_system::Session_rpc_object
Node *node = _root.lookup(path.string() + 1);
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();
}
@ -345,7 +368,8 @@ class Ram_fs::Session_component : public File_system::Session_rpc_object
void close(Node_handle handle)
{
auto close_fn = [&] (Open_node &open_node) {
destroy(_alloc, &open_node); };
destroy(_alloc, &open_node);
};
try {
_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)
{
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 {
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) {
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
// is still referenced by a node handle
dir->discard(node);
destroy(_alloc, node);
open_node.mark_as_written();
@ -404,7 +432,10 @@ class Ram_fs::Session_component : public File_system::Session_rpc_object
throw Permission_denied();
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();
};
@ -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) {
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 &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);
to_dir.adopt_unsynchronized(node);
if (!to_dir.valid())
throw Unavailable();
from_dir->discard(node);
to_dir->adopt_unsynchronized(node);
/*
* 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.,
* 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();
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();
from_dir.notify_listeners();
from_dir->notify_listeners();
node->mark_as_updated();
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:
@ -56,6 +57,8 @@ class Ram_fs::Node : public File_system::Node_base, public List<Node>::Element
: _ref_count(0), _inode(_unique_inode())
{ _name[0] = 0; }
virtual ~Node() { lock_for_destruction(); }
unsigned long inode() const { return _inode; }
char const *name() const { return _name; }

View File

@ -658,21 +658,35 @@ class Trace_fs::Session_component : public Session_rpc_object
switch (packet.operation()) {
case Packet_descriptor::READ:
if (content && (packet.length() <= packet.size()))
res_length = open_node.node().read((char *)content, length, packet.position());
if (content && (packet.length() <= packet.size())) {
Locked_ptr<Node> node { open_node.node() };
if (!node.valid())
break;
res_length = node->read((char *)content, length, packet.position());
}
break;
case Packet_descriptor::WRITE:
if (content && (packet.length() <= packet.size()))
res_length = open_node.node().write((char const *)content, length, packet.position());
if (content && (packet.length() <= packet.size())) {
Locked_ptr<Node> node { open_node.node() };
if (!node.valid())
break;
res_length = node->write((char const *)content, length, packet.position());
}
break;
case Packet_descriptor::CONTENT_CHANGED:
case Packet_descriptor::CONTENT_CHANGED: {
open_node.register_notify(*tx_sink());
/* 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 */
return;
}
case Packet_descriptor::READ_READY:
/* not supported */
@ -824,17 +838,20 @@ class Trace_fs::Session_component : public Session_rpc_object
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)
throw Permission_denied();
File *file = dynamic_cast<File*>(dir.lookup(name.string()));
File *file = dynamic_cast<File*>(dir->lookup(name.string()));
if (!file)
throw Invalid_name();
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();
};
@ -871,7 +888,7 @@ class Trace_fs::Session_component : public Session_rpc_object
throw Invalid_name();
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 };
}
@ -885,7 +902,7 @@ class Trace_fs::Session_component : public Session_rpc_object
Node *node = _root_dir.lookup(path_str + 1);
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();
}
@ -894,26 +911,29 @@ class Trace_fs::Session_component : public Session_rpc_object
{
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
* 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->changed()) {
changeable->acknowledge_change();
/* 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.
*/
node.notify_listeners();
node->notify_listeners();
/*
* De-allocate handle
@ -931,7 +951,10 @@ class Trace_fs::Session_component : public Session_rpc_object
Status status(Node_handle node_handle)
{
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 {
@ -947,7 +970,10 @@ class Trace_fs::Session_component : public Session_rpc_object
void truncate(File_handle handle, file_size_t size)
{
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 {

View File

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