From 0b580628cf82e2b1a496c6ec84b7defcb8598f7d Mon Sep 17 00:00:00 2001 From: Norman Feske Date: Wed, 28 Jun 2017 14:42:45 +0200 Subject: [PATCH] file system: track content via version counter This makes the delivery of CONTENT_CHANGED responses more robust. --- repos/os/include/file_system/listener.h | 50 ++++++++++++++++++------ repos/os/include/file_system/node.h | 11 ++++-- repos/os/include/file_system/open_node.h | 22 +++++++++-- repos/os/src/server/ram_fs/main.cc | 36 +++++++---------- 4 files changed, 80 insertions(+), 39 deletions(-) diff --git a/repos/os/include/file_system/listener.h b/repos/os/include/file_system/listener.h index 8daf013e54..c765e774c9 100644 --- a/repos/os/include/file_system/listener.h +++ b/repos/os/include/file_system/listener.h @@ -26,35 +26,61 @@ namespace File_system { class Listener : public Genode::List::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; } }; diff --git a/repos/os/include/file_system/node.h b/repos/os/include/file_system/node.h index bf2ab687b8..9a4c3390e4 100644 --- a/repos/os/include/file_system/node.h +++ b/repos/os/include/file_system/node.h @@ -28,6 +28,10 @@ namespace File_system { Genode::List _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; } }; } diff --git a/repos/os/include/file_system/open_node.h b/repos/os/include/file_system/open_node.h index efb7bbf953..4a16e3ace5 100644 --- a/repos/os/include/file_system/open_node.h +++ b/repos/os/include/file_system/open_node.h @@ -35,11 +35,19 @@ class File_system::Open_node : public File_system::Node NODE &_node; Genode::Constructible _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 &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_ */ diff --git a/repos/os/src/server/ram_fs/main.cc b/repos/os/src/server/ram_fs/main.cc index 6f1cfc32e1..91432c5bbd 100644 --- a/repos/os/src/server/ram_fs/main.cc +++ b/repos/os/src/server/ram_fs/main.cc @@ -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(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(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();