mirror of
https://github.com/genodelabs/genode.git
synced 2024-12-25 16:31:06 +00:00
Introduce notifications to file-system interface
This patch extends the file-system interface with the ability to monitor changes of files or directories. The new 'File_system::sigh' function can be used to install a signal handler for an open node. The 'ram_fs' server has been enhanced to support the new interface. So any file or directory changes can now be observed by 'ram_fs' clients. Fixes #607
This commit is contained in:
parent
7318c5d7d4
commit
fca8994584
@ -846,7 +846,11 @@ namespace File_system {
|
|||||||
PERR("f_rename() returned an unexpected error code");
|
PERR("f_rename() returned an unexpected error code");
|
||||||
throw Lookup_failed();
|
throw Lookup_failed();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void sigh(Node_handle, Genode::Signal_context_capability)
|
||||||
|
{
|
||||||
|
PWRN("File_system::Session::sigh not supported");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -100,6 +100,10 @@ namespace File_system {
|
|||||||
call<Rpc_move>(from_dir, from_name, to_dir, to_name);
|
call<Rpc_move>(from_dir, from_name, to_dir, to_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void sigh(Node_handle node, Signal_context_capability sigh)
|
||||||
|
{
|
||||||
|
call<Rpc_sigh>(node, sigh);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -35,7 +35,7 @@ namespace File_system {
|
|||||||
:
|
:
|
||||||
Genode::Connection<Session>(
|
Genode::Connection<Session>(
|
||||||
session("ram_quota=%zd, tx_buf_size=%zd, label=\"%s\"",
|
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) { }
|
Session_client(cap(), tx_block_alloc) { }
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -29,6 +29,8 @@ namespace File_system {
|
|||||||
|
|
||||||
Node_handle() : value(-1) { }
|
Node_handle() : value(-1) { }
|
||||||
Node_handle(int v) : value(v) { }
|
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,
|
virtual void move(Dir_handle, Name const &from,
|
||||||
Dir_handle, Name const &to) = 0;
|
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 **
|
** RPC interface **
|
||||||
@ -307,6 +314,9 @@ namespace File_system {
|
|||||||
GENODE_RPC_THROW(Rpc_move, void, move,
|
GENODE_RPC_THROW(Rpc_move, void, move,
|
||||||
GENODE_TYPE_LIST(Permission_denied, Invalid_name, Lookup_failed),
|
GENODE_TYPE_LIST(Permission_denied, Invalid_name, Lookup_failed),
|
||||||
Dir_handle, Name const &, Dir_handle, Name const &);
|
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
|
* Manual type-list definition, needed because the RPC interface
|
||||||
@ -324,8 +334,9 @@ namespace File_system {
|
|||||||
Meta::Type_tuple<Rpc_unlink,
|
Meta::Type_tuple<Rpc_unlink,
|
||||||
Meta::Type_tuple<Rpc_truncate,
|
Meta::Type_tuple<Rpc_truncate,
|
||||||
Meta::Type_tuple<Rpc_move,
|
Meta::Type_tuple<Rpc_move,
|
||||||
|
Meta::Type_tuple<Rpc_sigh,
|
||||||
Meta::Empty>
|
Meta::Empty>
|
||||||
> > > > > > > > > > Rpc_functions;
|
> > > > > > > > > > > Rpc_functions;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -43,12 +43,16 @@ namespace File_system {
|
|||||||
*/
|
*/
|
||||||
_entries.insert(node);
|
_entries.insert(node);
|
||||||
_num_entries++;
|
_num_entries++;
|
||||||
|
|
||||||
|
mark_as_updated();
|
||||||
}
|
}
|
||||||
|
|
||||||
void discard_unsynchronized(Node *node)
|
void discard_unsynchronized(Node *node)
|
||||||
{
|
{
|
||||||
_entries.remove(node);
|
_entries.remove(node);
|
||||||
_num_entries--;
|
_num_entries--;
|
||||||
|
|
||||||
|
mark_as_updated();
|
||||||
}
|
}
|
||||||
|
|
||||||
Node *lookup_and_lock(char const *path, bool return_parent = false)
|
Node *lookup_and_lock(char const *path, bool return_parent = false)
|
||||||
|
@ -84,6 +84,8 @@ namespace File_system {
|
|||||||
* by zero chunks, which do not contribute to 'used_size()'.
|
* by zero chunks, which do not contribute to 'used_size()'.
|
||||||
*/
|
*/
|
||||||
_length = max(_length, seek_offset + len);
|
_length = max(_length, seek_offset + len);
|
||||||
|
|
||||||
|
mark_as_updated();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -95,6 +97,8 @@ namespace File_system {
|
|||||||
_chunk.truncate(size);
|
_chunk.truncate(size);
|
||||||
|
|
||||||
_length = size;
|
_length = size;
|
||||||
|
|
||||||
|
mark_as_updated();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -387,7 +387,27 @@ namespace File_system {
|
|||||||
|
|
||||||
from_dir->discard_unsynchronized(node);
|
from_dir->discard_unsynchronized(node);
|
||||||
to_dir->adopt_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);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -10,9 +10,46 @@
|
|||||||
/* Genode includes */
|
/* Genode includes */
|
||||||
#include <util/list.h>
|
#include <util/list.h>
|
||||||
#include <base/lock.h>
|
#include <base/lock.h>
|
||||||
|
#include <base/signal.h>
|
||||||
|
|
||||||
namespace File_system {
|
namespace File_system {
|
||||||
|
|
||||||
|
class Listener : public List<Listener>::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<Node>::Element
|
class Node : public List<Node>::Element
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@ -25,6 +62,8 @@ namespace File_system {
|
|||||||
int _ref_count;
|
int _ref_count;
|
||||||
Name _name;
|
Name _name;
|
||||||
unsigned long const _inode;
|
unsigned long const _inode;
|
||||||
|
List<Listener> _listeners;
|
||||||
|
bool _modified;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generate unique inode number
|
* Generate unique inode number
|
||||||
@ -37,9 +76,19 @@ namespace File_system {
|
|||||||
|
|
||||||
public:
|
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; }
|
unsigned long inode() const { return _inode; }
|
||||||
char const *name() const { return _name; }
|
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 read(char *dst, size_t len, seek_off_t) = 0;
|
||||||
virtual size_t write(char const *src, 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();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -45,6 +45,12 @@ namespace File_system {
|
|||||||
|
|
||||||
Node *_nodes[MAX_NODE_HANDLES];
|
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
|
* Allocate node handle
|
||||||
*
|
*
|
||||||
@ -90,8 +96,30 @@ namespace File_system {
|
|||||||
{
|
{
|
||||||
Lock::Guard guard(_lock);
|
Lock::Guard guard(_lock);
|
||||||
|
|
||||||
if (_in_range(handle.value))
|
if (!_in_range(handle.value))
|
||||||
|
return;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Notify listeners about the changed file.
|
||||||
|
*/
|
||||||
|
Node *node = dynamic_cast<Node *>(_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;
|
_nodes[handle.value] = 0;
|
||||||
|
listener = Listener();
|
||||||
|
|
||||||
|
node->unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -122,11 +150,48 @@ namespace File_system {
|
|||||||
{
|
{
|
||||||
Lock::Guard guard(_lock);
|
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();
|
throw Invalid_handle();
|
||||||
|
}
|
||||||
|
|
||||||
return _nodes[h1.value] == _nodes[h2.value];
|
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<Node *>(_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);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -419,6 +419,11 @@ namespace File_system {
|
|||||||
|
|
||||||
throw Permission_denied();
|
throw Permission_denied();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void sigh(Node_handle, Genode::Signal_context_capability)
|
||||||
|
{
|
||||||
|
PWRN("File_system::Session::sigh not supported");
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user