mirror of
https://github.com/genodelabs/genode.git
synced 2025-04-16 07:27:35 +00:00
file system: track content via version counter
This makes the delivery of CONTENT_CHANGED responses more robust.
This commit is contained in:
parent
6a43f3c11a
commit
0b580628cf
@ -26,35 +26,61 @@ namespace File_system {
|
||||
|
||||
class Listener : public Genode::List<Listener>::Element
|
||||
{
|
||||
public:
|
||||
|
||||
struct Version { unsigned value; };
|
||||
|
||||
private:
|
||||
|
||||
Genode::Lock _lock;
|
||||
Sink &_sink;
|
||||
Node_handle _handle;
|
||||
bool _marked_as_updated;
|
||||
Genode::Lock _lock;
|
||||
Sink &_sink;
|
||||
Node_handle const _handle;
|
||||
|
||||
/*
|
||||
* Version at the time when the file was opened
|
||||
*/
|
||||
Version _handed_out_version;
|
||||
|
||||
/*
|
||||
* Version at the time when we issued the most recent notification
|
||||
*/
|
||||
Version _notified_version = _handed_out_version;
|
||||
|
||||
public:
|
||||
|
||||
Listener(Sink &sink, Node_handle handle)
|
||||
: _sink(sink), _handle(handle), _marked_as_updated(false) { }
|
||||
Listener(Sink &sink, Node_handle handle, Version handed_out_version)
|
||||
: _sink(sink), _handle(handle), _handed_out_version(handed_out_version)
|
||||
{ }
|
||||
|
||||
void notify()
|
||||
/*
|
||||
* Called on close of written files, on sync, or on arrival
|
||||
* of a client's CONTENT_CHANGED packet.
|
||||
*/
|
||||
void notify(Version curr_version)
|
||||
{
|
||||
Genode::Lock::Guard guard(_lock);
|
||||
|
||||
if (_marked_as_updated && _sink.ready_to_ack()) {
|
||||
if (curr_version.value == _handed_out_version.value)
|
||||
return;
|
||||
|
||||
if (curr_version.value == _notified_version.value)
|
||||
return;
|
||||
|
||||
if (_sink.ready_to_ack())
|
||||
_sink.acknowledge_packet(Packet_descriptor(
|
||||
_handle, Packet_descriptor::CONTENT_CHANGED));
|
||||
_marked_as_updated = false;
|
||||
}
|
||||
|
||||
_notified_version = curr_version;
|
||||
}
|
||||
|
||||
void mark_as_updated()
|
||||
/*
|
||||
* Called during read
|
||||
*/
|
||||
void handed_out_version(Version version)
|
||||
{
|
||||
Genode::Lock::Guard guard(_lock);
|
||||
|
||||
_marked_as_updated = true;
|
||||
_handed_out_version = version;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -28,6 +28,10 @@ namespace File_system {
|
||||
|
||||
Genode::List<Listener> _listeners;
|
||||
|
||||
typedef Listener::Version Version;
|
||||
|
||||
Version _curr_version { 0 };
|
||||
|
||||
public:
|
||||
|
||||
virtual ~Node_base()
|
||||
@ -53,14 +57,15 @@ namespace File_system {
|
||||
void notify_listeners()
|
||||
{
|
||||
for (Listener *curr = _listeners.first(); curr; curr = curr->next())
|
||||
curr->notify();
|
||||
curr->notify(_curr_version);
|
||||
}
|
||||
|
||||
void mark_as_updated()
|
||||
{
|
||||
for (Listener *curr = _listeners.first(); curr; curr = curr->next())
|
||||
curr->mark_as_updated();
|
||||
_curr_version = Version { _curr_version.value + 1 };
|
||||
}
|
||||
|
||||
Version curr_version() const { return _curr_version; }
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -35,11 +35,19 @@ class File_system::Open_node : public File_system::Node
|
||||
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) { }
|
||||
: _element(*this, id_space), _node(node) { }
|
||||
|
||||
~Open_node()
|
||||
{
|
||||
@ -47,6 +55,12 @@ class File_system::Open_node : public File_system::Node
|
||||
_node.remove_listener(&*_listener);
|
||||
_listener.destruct();
|
||||
}
|
||||
|
||||
/*
|
||||
* Notify remaining listeners about the changed file
|
||||
*/
|
||||
if (_was_written)
|
||||
_node.notify_listeners();
|
||||
}
|
||||
|
||||
NODE &node() { return _node; }
|
||||
@ -71,9 +85,11 @@ class File_system::Open_node : public File_system::Node
|
||||
/*
|
||||
* Register new handler
|
||||
*/
|
||||
_listener.construct(sink, id());
|
||||
_listener.construct(sink, id(), _version_when_opened);
|
||||
_node.add_listener(&*_listener);
|
||||
}
|
||||
|
||||
void mark_as_written() { _was_written = true; }
|
||||
};
|
||||
|
||||
#endif /* _OPEN_NODE_H_ */
|
||||
|
@ -83,6 +83,8 @@ class Ram_fs::Session_component : public File_system::Session_rpc_object
|
||||
case Packet_descriptor::WRITE:
|
||||
if (content && (packet.length() <= packet.size()))
|
||||
res_length = open_node.node().write((char const *)content, length, packet.position());
|
||||
|
||||
open_node.mark_as_written();
|
||||
break;
|
||||
|
||||
case Packet_descriptor::CONTENT_CHANGED:
|
||||
@ -217,9 +219,10 @@ class Ram_fs::Session_component : public File_system::Session_rpc_object
|
||||
|
||||
try {
|
||||
File * const file = new (_alloc)
|
||||
File(_alloc, name.string());
|
||||
File(_alloc, name.string());
|
||||
|
||||
dir.adopt_unsynchronized(file);
|
||||
open_node.mark_as_written();
|
||||
}
|
||||
catch (Allocator::Out_of_memory) { throw No_space(); }
|
||||
}
|
||||
@ -338,19 +341,7 @@ class Ram_fs::Session_component : public File_system::Session_rpc_object
|
||||
void close(Node_handle handle)
|
||||
{
|
||||
auto close_fn = [&] (Open_node &open_node) {
|
||||
|
||||
Node &node = open_node.node();
|
||||
|
||||
/*
|
||||
* Notify listeners about the changed file.
|
||||
*/
|
||||
node.notify_listeners();
|
||||
|
||||
/*
|
||||
* De-allocate handle
|
||||
*/
|
||||
destroy(_alloc, &open_node);
|
||||
};
|
||||
destroy(_alloc, &open_node); };
|
||||
|
||||
try {
|
||||
_open_node_registry.apply<Open_node>(handle, close_fn);
|
||||
@ -362,8 +353,7 @@ 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();
|
||||
};
|
||||
return open_node.node().status(); };
|
||||
|
||||
try {
|
||||
return _open_node_registry.apply<Open_node>(node_handle, status_fn);
|
||||
@ -394,6 +384,7 @@ class Ram_fs::Session_component : public File_system::Session_rpc_object
|
||||
// is still referenced by a node handle
|
||||
|
||||
destroy(_alloc, node);
|
||||
open_node.mark_as_written();
|
||||
};
|
||||
|
||||
try {
|
||||
@ -410,6 +401,7 @@ class Ram_fs::Session_component : public File_system::Session_rpc_object
|
||||
|
||||
auto truncate_fn = [&] (Open_node &open_node) {
|
||||
open_node.node().truncate(size);
|
||||
open_node.mark_as_written();
|
||||
};
|
||||
|
||||
try {
|
||||
@ -448,15 +440,17 @@ class Ram_fs::Session_component : public File_system::Session_rpc_object
|
||||
to_dir.adopt_unsynchronized(node);
|
||||
|
||||
/*
|
||||
* If the file was moved from one directory to another we
|
||||
* need to inform the new directory 'to_dir'. The original
|
||||
* directory 'from_dir' will always get notified (i.e.,
|
||||
* when just the file name was changed) below.
|
||||
*/
|
||||
* If the file was moved from one directory to another we
|
||||
* need to inform the new directory 'to_dir'. The original
|
||||
* directory 'from_dir' will always get notified (i.e.,
|
||||
* when just the file name was changed) below.
|
||||
*/
|
||||
to_dir.mark_as_updated();
|
||||
open_to_dir_node.mark_as_written();
|
||||
to_dir.notify_listeners();
|
||||
|
||||
from_dir.mark_as_updated();
|
||||
open_from_dir_node.mark_as_written();
|
||||
from_dir.notify_listeners();
|
||||
|
||||
node->mark_as_updated();
|
||||
|
Loading…
x
Reference in New Issue
Block a user