diff --git a/libports/src/server/ffat_fs/main.cc b/libports/src/server/ffat_fs/main.cc index 7dd5e4236..2034c0cef 100644 --- a/libports/src/server/ffat_fs/main.cc +++ b/libports/src/server/ffat_fs/main.cc @@ -846,7 +846,11 @@ namespace File_system { PERR("f_rename() returned an unexpected error code"); throw Lookup_failed(); } + } + void sigh(Node_handle, Genode::Signal_context_capability) + { + PWRN("File_system::Session::sigh not supported"); } }; diff --git a/os/include/file_system_session/client.h b/os/include/file_system_session/client.h index 9761b3461..c3279a6c6 100644 --- a/os/include/file_system_session/client.h +++ b/os/include/file_system_session/client.h @@ -100,6 +100,10 @@ namespace File_system { call(from_dir, from_name, to_dir, to_name); } + void sigh(Node_handle node, Signal_context_capability sigh) + { + call(node, sigh); + } }; } diff --git a/os/include/file_system_session/connection.h b/os/include/file_system_session/connection.h index 083a4f77f..f9a27d09d 100644 --- a/os/include/file_system_session/connection.h +++ b/os/include/file_system_session/connection.h @@ -35,7 +35,7 @@ namespace File_system { : Genode::Connection( session("ram_quota=%zd, tx_buf_size=%zd, label=\"%s\"", - 3*4096 + tx_buf_size, tx_buf_size, label)), + 4*4096 + tx_buf_size, tx_buf_size, label)), Session_client(cap(), tx_block_alloc) { } }; } diff --git a/os/include/file_system_session/file_system_session.h b/os/include/file_system_session/file_system_session.h index 8f115aa72..6bf0452eb 100644 --- a/os/include/file_system_session/file_system_session.h +++ b/os/include/file_system_session/file_system_session.h @@ -29,6 +29,8 @@ namespace File_system { Node_handle() : value(-1) { } Node_handle(int v) : value(v) { } + + bool valid() const { return value != -1; } }; @@ -273,6 +275,11 @@ namespace File_system { virtual void move(Dir_handle, Name const &from, Dir_handle, Name const &to) = 0; + /** + * Register handler that should be notified on node changes + */ + virtual void sigh(Node_handle, Signal_context_capability sigh) = 0; + /******************* ** RPC interface ** @@ -307,6 +314,9 @@ namespace File_system { GENODE_RPC_THROW(Rpc_move, void, move, GENODE_TYPE_LIST(Permission_denied, Invalid_name, Lookup_failed), Dir_handle, Name const &, Dir_handle, Name const &); + GENODE_RPC_THROW(Rpc_sigh, void, sigh, + GENODE_TYPE_LIST(Invalid_handle), + Node_handle, Signal_context_capability); /* * Manual type-list definition, needed because the RPC interface @@ -324,8 +334,9 @@ namespace File_system { Meta::Type_tuple - > > > > > > > > > > Rpc_functions; + > > > > > > > > > > > Rpc_functions; }; } diff --git a/os/src/server/ram_fs/directory.h b/os/src/server/ram_fs/directory.h index 1e9afea32..5340e0c9d 100644 --- a/os/src/server/ram_fs/directory.h +++ b/os/src/server/ram_fs/directory.h @@ -43,12 +43,16 @@ namespace File_system { */ _entries.insert(node); _num_entries++; + + mark_as_updated(); } void discard_unsynchronized(Node *node) { _entries.remove(node); _num_entries--; + + mark_as_updated(); } Node *lookup_and_lock(char const *path, bool return_parent = false) diff --git a/os/src/server/ram_fs/file.h b/os/src/server/ram_fs/file.h index 81099b37f..a3a6cf3ab 100644 --- a/os/src/server/ram_fs/file.h +++ b/os/src/server/ram_fs/file.h @@ -84,6 +84,8 @@ namespace File_system { * by zero chunks, which do not contribute to 'used_size()'. */ _length = max(_length, seek_offset + len); + + mark_as_updated(); return 0; } @@ -95,6 +97,8 @@ namespace File_system { _chunk.truncate(size); _length = size; + + mark_as_updated(); } }; } diff --git a/os/src/server/ram_fs/main.cc b/os/src/server/ram_fs/main.cc index 65191a574..b5b80bb5e 100644 --- a/os/src/server/ram_fs/main.cc +++ b/os/src/server/ram_fs/main.cc @@ -387,7 +387,27 @@ namespace File_system { from_dir->discard_unsynchronized(node); 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. + */ + to_dir->mark_as_updated(); + to_dir->notify_listeners(); } + + from_dir->mark_as_updated(); + from_dir->notify_listeners(); + + node->mark_as_updated(); + node->notify_listeners(); + } + + void sigh(Node_handle node_handle, Signal_context_capability sigh) + { + _handle_registry.sigh(node_handle, sigh); } }; diff --git a/os/src/server/ram_fs/node.h b/os/src/server/ram_fs/node.h index 0a9df7e35..0e456493e 100644 --- a/os/src/server/ram_fs/node.h +++ b/os/src/server/ram_fs/node.h @@ -10,9 +10,46 @@ /* Genode includes */ #include #include +#include namespace File_system { + class Listener : public List::Element + { + private: + + Lock _lock; + Signal_context_capability _sigh; + bool _marked_as_updated; + + public: + + Listener() : _marked_as_updated(false) { } + + Listener(Signal_context_capability sigh) + : _sigh(sigh), _marked_as_updated(false) { } + + void notify() + { + Lock::Guard guard(_lock); + + if (_marked_as_updated && _sigh.valid()) + Signal_transmitter(_sigh).submit(); + + _marked_as_updated = false; + } + + void mark_as_updated() + { + Lock::Guard guard(_lock); + + _marked_as_updated = true; + } + + bool valid() const { return _sigh.valid(); } + }; + + class Node : public List::Element { public: @@ -25,6 +62,8 @@ namespace File_system { int _ref_count; Name _name; unsigned long const _inode; + List _listeners; + bool _modified; /** * Generate unique inode number @@ -37,9 +76,19 @@ namespace File_system { public: - Node() : _ref_count(0), _inode(_unique_inode()) { _name[0] = 0; } + Node() + : _ref_count(0), _inode(_unique_inode()), _modified(false) + { _name[0] = 0; } - virtual ~Node() { } + virtual ~Node() + { + /* propagate event to listeners */ + mark_as_updated(); + notify_listeners(); + + while (_listeners.first()) + _listeners.remove(_listeners.first()); + } unsigned long inode() const { return _inode; } char const *name() const { return _name; } @@ -55,6 +104,27 @@ namespace File_system { 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; + void add_listener(Listener *listener) + { + _listeners.insert(listener); + } + + void remove_listener(Listener *listener) + { + _listeners.remove(listener); + } + + void notify_listeners() + { + for (Listener *curr = _listeners.first(); curr; curr = curr->next()) + curr->notify(); + } + + void mark_as_updated() + { + for (Listener *curr = _listeners.first(); curr; curr = curr->next()) + curr->mark_as_updated(); + } }; diff --git a/os/src/server/ram_fs/node_handle_registry.h b/os/src/server/ram_fs/node_handle_registry.h index a08c82dc7..a334e423f 100644 --- a/os/src/server/ram_fs/node_handle_registry.h +++ b/os/src/server/ram_fs/node_handle_registry.h @@ -45,6 +45,12 @@ namespace File_system { Node *_nodes[MAX_NODE_HANDLES]; + /** + * Each open node handle can act as a listener to be informed about + * node changes. + */ + Listener _listeners[MAX_NODE_HANDLES]; + /** * Allocate node handle * @@ -90,8 +96,30 @@ namespace File_system { { Lock::Guard guard(_lock); - if (_in_range(handle.value)) - _nodes[handle.value] = 0; + if (!_in_range(handle.value)) + return; + + /* + * Notify listeners about the changed file. + */ + Node *node = dynamic_cast(_nodes[handle.value]); + if (!node) { return; } + + node->lock(); + node->notify_listeners(); + + /* + * De-allocate handle + */ + Listener &listener = _listeners[handle.value]; + + if (listener.valid()) + node->remove_listener(&listener); + + _nodes[handle.value] = 0; + listener = Listener(); + + node->unlock(); } /** @@ -122,11 +150,48 @@ namespace File_system { { Lock::Guard guard(_lock); - if (!_in_range(h1.value) || !_in_range(h2.value)) + if (!_in_range(h1.value) || !_in_range(h2.value)) { + PDBG("refer_to_same_node -> Invalid_handle"); throw Invalid_handle(); + } return _nodes[h1.value] == _nodes[h2.value]; } + + /** + * Register signal handler to be notified of node changes + */ + void sigh(Node_handle handle, Signal_context_capability sigh) + { + Lock::Guard guard(_lock); + + if (!_in_range(handle.value)) + throw Invalid_handle(); + + Node *node = dynamic_cast(_nodes[handle.value]); + if (!node) { + PDBG("Invalid_handle"); + throw Invalid_handle(); + } + + node->lock(); + Node_lock_guard node_lock_guard(*node); + + Listener &listener = _listeners[handle.value]; + + /* + * If there was already a handler registered for the node, + * remove the old handler. + */ + if (listener.valid()) + node->remove_listener(&listener); + + /* + * Register new handler + */ + listener = Listener(sigh); + node->add_listener(&listener); + } }; } diff --git a/os/src/server/tar_fs/main.cc b/os/src/server/tar_fs/main.cc index 9fb868909..65a61f8cc 100644 --- a/os/src/server/tar_fs/main.cc +++ b/os/src/server/tar_fs/main.cc @@ -419,6 +419,11 @@ namespace File_system { throw Permission_denied(); } + + void sigh(Node_handle, Genode::Signal_context_capability) + { + PWRN("File_system::Session::sigh not supported"); + } };