mirror of
https://github.com/genodelabs/genode.git
synced 2024-12-30 10:38:55 +00:00
New watch handle mechanism for File_system session
File_system clients may now watch files and directories for changes by opening a 'Watch_handle' rather than submitting a 'CONTENT_CHANGED' packet to the server. When a change happens at a node with an open Watch_handle a CONTENT_CHANGED packet will be sent from the server to the client. This serializes registration with other handle operations and separates I/O handle state from notification handle state. Test at run/fs_rom_update. Ref #1934
This commit is contained in:
parent
21b2b7e1ea
commit
4a3fc21ada
@ -5,7 +5,7 @@
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2012-2017 Genode Labs GmbH
|
||||
* Copyright (C) 2012-2018 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.
|
||||
@ -81,6 +81,11 @@ class File_system::Session_client : public Genode::Rpc_client<Session>
|
||||
return call<Rpc_node>(path);
|
||||
}
|
||||
|
||||
Watch_handle watch(Path const &path) override
|
||||
{
|
||||
return call<Rpc_watch>(path);
|
||||
}
|
||||
|
||||
void close(Node_handle node) override
|
||||
{
|
||||
call<Rpc_close>(node);
|
||||
|
@ -5,7 +5,7 @@
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2012-2017 Genode Labs GmbH
|
||||
* Copyright (C) 2012-2018 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.
|
||||
@ -152,6 +152,12 @@ struct File_system::Connection : File_system::Connection_base
|
||||
return _retry([&] () {
|
||||
return Session_client::node(path); });
|
||||
}
|
||||
|
||||
Watch_handle watch(Path const &path) override
|
||||
{
|
||||
return _retry([&] () {
|
||||
return Session_client::watch(path); });
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* _INCLUDE__FILE_SYSTEM_SESSION__CONNECTION_H_ */
|
||||
|
@ -7,7 +7,7 @@
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2012-2017 Genode Labs GmbH
|
||||
* Copyright (C) 2012-2018 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.
|
||||
@ -52,10 +52,19 @@ namespace File_system {
|
||||
};
|
||||
};
|
||||
|
||||
struct Watch : Node
|
||||
{
|
||||
struct Id : Node::Id
|
||||
{
|
||||
explicit Id(unsigned long value) : Node::Id { value } { };
|
||||
};
|
||||
};
|
||||
|
||||
typedef Node::Id Node_handle;
|
||||
typedef File::Id File_handle;
|
||||
typedef Directory::Id Dir_handle;
|
||||
typedef Symlink::Id Symlink_handle;
|
||||
typedef Watch::Id Watch_handle;
|
||||
|
||||
using Genode::size_t;
|
||||
|
||||
@ -337,6 +346,23 @@ struct File_system::Session : public Genode::Session
|
||||
*/
|
||||
virtual Node_handle node(Path const &path) = 0;
|
||||
|
||||
/**
|
||||
* Watch a node for for changes.
|
||||
*
|
||||
* When changes are made to the node at this path a CONTENT_CHANGED
|
||||
* packet will be sent from the server to the client.
|
||||
*
|
||||
* \throw Lookup_failed path lookup failed because one element
|
||||
* of 'path' does not exist
|
||||
* \throw Out_of_ram server cannot allocate metadata
|
||||
* \throw Out_of_caps
|
||||
* \throw Unavailable file-system is static or does not support
|
||||
* notifications
|
||||
*
|
||||
* The returned node handle is used to identify notification packets.
|
||||
*/
|
||||
virtual Watch_handle watch(Path const &path) = 0;
|
||||
|
||||
/**
|
||||
* Close file
|
||||
*
|
||||
@ -421,6 +447,9 @@ struct File_system::Session : public Genode::Session
|
||||
GENODE_RPC_THROW(Rpc_node, Node_handle, node,
|
||||
GENODE_TYPE_LIST(Lookup_failed, Out_of_ram, Out_of_caps),
|
||||
Path const &);
|
||||
GENODE_RPC_THROW(Rpc_watch, Watch_handle, watch,
|
||||
GENODE_TYPE_LIST(Lookup_failed, Out_of_ram, Out_of_caps, Unavailable),
|
||||
Path const &);
|
||||
GENODE_RPC_THROW(Rpc_close, void, close,
|
||||
GENODE_TYPE_LIST(Invalid_handle),
|
||||
Node_handle);
|
||||
@ -444,7 +473,9 @@ struct File_system::Session : public Genode::Session
|
||||
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,
|
||||
GENODE_RPC_INTERFACE(Rpc_tx_cap,
|
||||
Rpc_file, Rpc_symlink, Rpc_dir,
|
||||
Rpc_node, Rpc_watch,
|
||||
Rpc_close, Rpc_status, Rpc_control, Rpc_unlink,
|
||||
Rpc_truncate, Rpc_move);
|
||||
};
|
||||
|
@ -49,6 +49,13 @@ class File_system::Session_rpc_object : public Genode::Rpc_object<Session, Sessi
|
||||
Genode::Capability<Tx> _tx_cap() { return _tx.cap(); }
|
||||
|
||||
Tx::Sink *tx_sink() { return _tx.sink(); }
|
||||
|
||||
/**
|
||||
* Default stub implementation
|
||||
*/
|
||||
Watch_handle watch(Path const &) override {
|
||||
throw Unavailable(); }
|
||||
|
||||
};
|
||||
|
||||
#endif /* _INCLUDE__FILE_SYSTEM_SESSION__SERVER_H_ */
|
||||
|
@ -1,7 +1,3 @@
|
||||
if {[have_spec arm]} {
|
||||
assert_spec arm_v7
|
||||
}
|
||||
|
||||
#
|
||||
# Build
|
||||
#
|
||||
@ -115,6 +111,6 @@ set boot_modules {
|
||||
|
||||
build_boot_image $boot_modules
|
||||
|
||||
append qemu_args " -nographic "
|
||||
append qemu_args " -nographic"
|
||||
|
||||
run_genode_until forever
|
||||
run_genode_until {.*<config iteration="4" />.*} 60
|
||||
|
@ -1,11 +1,12 @@
|
||||
/*
|
||||
* \brief Service that provides files of a file system as ROM sessions
|
||||
* \author Norman Feske
|
||||
* \author Emery Hemingway
|
||||
* \date 2013-01-11
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2013-2017 Genode Labs GmbH
|
||||
* Copyright (C) 2013-2018 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.
|
||||
@ -51,6 +52,7 @@ class Fs_rom::Rom_session_component : public Rpc_object<Rom_session>,
|
||||
private:
|
||||
|
||||
friend class List<Rom_session_component>;
|
||||
friend class Packet_handler;
|
||||
|
||||
Env &_env;
|
||||
|
||||
@ -65,9 +67,14 @@ class Fs_rom::Rom_session_component : public Rpc_object<Rom_session>,
|
||||
Path const _file_path;
|
||||
|
||||
/**
|
||||
* Handle of associated file
|
||||
* Wandering notification handle
|
||||
*/
|
||||
Constructible<File_system::File_handle> _file_handle { };
|
||||
Constructible<File_system::Watch_handle> _watch_handle { };
|
||||
|
||||
/**
|
||||
* Handle of associated file opened during read loop
|
||||
*/
|
||||
File_system::File_handle _file_handle { ~0UL };
|
||||
|
||||
/**
|
||||
* Size of current version of the file
|
||||
@ -79,14 +86,6 @@ class Fs_rom::Rom_session_component : public Rpc_object<Rom_session>,
|
||||
*/
|
||||
File_system::seek_off_t _file_seek = 0;
|
||||
|
||||
/**
|
||||
* Handle of currently watched compound directory
|
||||
*
|
||||
* The compund directory is watched only if the requested file could
|
||||
* not be looked up.
|
||||
*/
|
||||
Constructible<File_system::Dir_handle> _compound_dir_handle { };
|
||||
|
||||
/**
|
||||
* Dataspace exposed as ROM module to the client
|
||||
*/
|
||||
@ -97,11 +96,6 @@ class Fs_rom::Rom_session_component : public Rpc_object<Rom_session>,
|
||||
*/
|
||||
Signal_context_capability _sigh { };
|
||||
|
||||
/*
|
||||
* Exception
|
||||
*/
|
||||
struct Open_compound_dir_failed { };
|
||||
|
||||
/*
|
||||
* Version number used to track the need for ROM update notifications
|
||||
*/
|
||||
@ -110,193 +104,126 @@ class Fs_rom::Rom_session_component : public Rpc_object<Rom_session>,
|
||||
Version _handed_out_version { ~0U };
|
||||
|
||||
/**
|
||||
* Open compound directory of specified file
|
||||
*
|
||||
* \param walk_up If set to true, the function tries to walk up the
|
||||
* hierarchy towards the root and returns the first
|
||||
* existing directory on the way. If set to false, the
|
||||
* function returns the immediate compound directory.
|
||||
* Track if the session file or a directory is being watched
|
||||
*/
|
||||
File_system::Dir_handle _open_compound_dir(File_system::Session &fs,
|
||||
Path const &path,
|
||||
bool walk_up)
|
||||
{
|
||||
using namespace File_system;
|
||||
|
||||
Path dir_path(path.base());
|
||||
|
||||
while (!path.equals("/")) {
|
||||
|
||||
dir_path.strip_last_element();
|
||||
|
||||
try { return fs.dir(dir_path.base(), false); }
|
||||
|
||||
catch (Invalid_handle) { error(_file_path, ": invalid_handle"); }
|
||||
catch (Invalid_name) { error(_file_path, ": invalid_name"); }
|
||||
catch (Lookup_failed) { error(_file_path, ": lookup_failed"); }
|
||||
catch (Permission_denied) { error(_file_path, ": permission_denied"); }
|
||||
catch (Name_too_long) { error(_file_path, ": name_too_long"); }
|
||||
catch (No_space) { error(_file_path, ": no_space"); }
|
||||
|
||||
/*
|
||||
* If the directory could not be opened, walk up the hierarchy
|
||||
* towards the root and try again.
|
||||
*/
|
||||
if (!walk_up) break;
|
||||
}
|
||||
throw Open_compound_dir_failed();
|
||||
}
|
||||
bool _watching_file = false;
|
||||
|
||||
/*
|
||||
* Exception
|
||||
*/
|
||||
struct Open_file_failed { };
|
||||
struct Watch_failed { };
|
||||
|
||||
/**
|
||||
* Open file with specified name at the file system
|
||||
* Watch the session ROM file or some parent directory
|
||||
*/
|
||||
File_system::File_handle _open_file(File_system::Session &fs,
|
||||
Path const &path)
|
||||
void _open_watch_handle()
|
||||
{
|
||||
using namespace File_system;
|
||||
|
||||
try {
|
||||
_close_watch_handle();
|
||||
|
||||
Dir_handle dir = _open_compound_dir(fs, path, false);
|
||||
Path watch_path(_file_path);
|
||||
|
||||
/* track if we can open the file or resort to a parent */
|
||||
bool at_the_file = true;
|
||||
|
||||
try {
|
||||
|
||||
Handle_guard guard(fs, dir);
|
||||
|
||||
/* open file */
|
||||
Path file_name(path.base());
|
||||
file_name.keep_only_last_element();
|
||||
return fs.file(dir, file_name.base() + 1,
|
||||
File_system::READ_ONLY, false);
|
||||
}
|
||||
catch (Invalid_handle) { error(_file_path, ": Invalid_handle"); }
|
||||
catch (Invalid_name) { error(_file_path, ": invalid_name"); }
|
||||
catch (Lookup_failed) { error(_file_path, ": lookup_failed"); }
|
||||
catch (Permission_denied) { error(_file_path, ": Permission_denied"); }
|
||||
catch (...) { error(_file_path, ": unhandled error"); };
|
||||
|
||||
throw Open_file_failed();
|
||||
|
||||
} catch (Open_compound_dir_failed) {
|
||||
throw Open_file_failed();
|
||||
}
|
||||
}
|
||||
|
||||
void _register_for_compound_dir_changes()
|
||||
{
|
||||
using namespace File_system;
|
||||
|
||||
/* forget about the previously watched compound directory */
|
||||
if (_compound_dir_handle.constructed()) {
|
||||
_fs.close(*_compound_dir_handle);
|
||||
_compound_dir_handle.destruct();
|
||||
}
|
||||
|
||||
while (true) {
|
||||
try {
|
||||
_compound_dir_handle.construct(_open_compound_dir(_fs, _file_path, true));
|
||||
|
||||
/* register for changes in compound directory */
|
||||
_fs.tx()->submit_packet(File_system::Packet_descriptor(
|
||||
*_compound_dir_handle,
|
||||
File_system::Packet_descriptor::CONTENT_CHANGED));
|
||||
}
|
||||
catch (Open_compound_dir_failed) {
|
||||
warning("could not track compound dir, giving up"); }
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize '_file_ds' dataspace with file content
|
||||
*/
|
||||
void _update_dataspace()
|
||||
{
|
||||
using namespace File_system;
|
||||
|
||||
/*
|
||||
* On each repeated call of this function, the dataspace is
|
||||
* replaced with a new one that contains the most current file
|
||||
* content. The dataspace is re-allocated if the new version
|
||||
* of the file has become bigger.
|
||||
*/
|
||||
try {
|
||||
File_handle const file_handle = _open_file(_fs, _file_path);
|
||||
File_system::file_size_t const new_file_size =
|
||||
_fs.status(file_handle).size;
|
||||
|
||||
if (_file_ds.size() && (new_file_size > _file_size)) {
|
||||
/* mark as invalid */
|
||||
_file_ds.realloc(&_env.ram(), 0);
|
||||
_file_size = 0;
|
||||
_file_seek = 0;
|
||||
}
|
||||
_fs.close(file_handle);
|
||||
} catch (Open_file_failed) { }
|
||||
|
||||
/* close and then re-open the file */
|
||||
if (_file_handle.constructed()) {
|
||||
_fs.close(*_file_handle);
|
||||
_file_handle.destruct();
|
||||
}
|
||||
|
||||
try {
|
||||
_file_handle.construct(_open_file(_fs, _file_path));
|
||||
} catch (Open_file_failed) { }
|
||||
|
||||
/*
|
||||
* If we got the file, we can stop paying attention to the
|
||||
* compound directory.
|
||||
*/
|
||||
if (_file_handle.constructed() && _compound_dir_handle.constructed()) {
|
||||
_fs.close(*_compound_dir_handle);
|
||||
_compound_dir_handle.destruct();
|
||||
}
|
||||
|
||||
/* register for file changes */
|
||||
if (_file_handle.constructed())
|
||||
_fs.tx()->submit_packet(File_system::Packet_descriptor(
|
||||
*_file_handle, File_system::Packet_descriptor::CONTENT_CHANGED));
|
||||
|
||||
size_t const file_size = _file_handle.constructed()
|
||||
? _fs.status(*_file_handle).size : 0;
|
||||
|
||||
/* allocate new RAM dataspace according to file size */
|
||||
if (file_size > 0) {
|
||||
try {
|
||||
_file_seek = 0;
|
||||
_file_ds.realloc(&_env.ram(), file_size);
|
||||
_file_size = file_size;
|
||||
} catch (...) {
|
||||
error("couldn't allocate memory for file, empty result");
|
||||
_watch_handle.construct(_fs.watch(watch_path.base()));
|
||||
_watching_file = at_the_file;
|
||||
return;
|
||||
}
|
||||
catch (File_system::Lookup_failed) { }
|
||||
catch (File_system::Unavailable) { }
|
||||
|
||||
if (watch_path == "/")
|
||||
throw Watch_failed();
|
||||
watch_path.strip_last_element();
|
||||
|
||||
/* keep looping, but only directories will be opened */
|
||||
at_the_file = false;
|
||||
}
|
||||
} catch (File_system::Out_of_ram) {
|
||||
error("not enough RAM to watch '", watch_path, "'");
|
||||
} catch (File_system::Out_of_caps) {
|
||||
error("not enough caps to watch '", watch_path, "'");
|
||||
}
|
||||
throw Watch_failed();
|
||||
}
|
||||
|
||||
void _close_watch_handle()
|
||||
{
|
||||
if (_watch_handle.constructed()) {
|
||||
_fs.close(*_watch_handle);
|
||||
_watch_handle.destruct();
|
||||
}
|
||||
_watching_file = false;
|
||||
}
|
||||
|
||||
enum { UPDATE_OR_REPLACE = false, UPDATE_ONLY = true };
|
||||
|
||||
/**
|
||||
* Fill dataspace with file content, return true if the
|
||||
* current dataspace is reused.
|
||||
*/
|
||||
bool _read_dataspace(bool update_only)
|
||||
{
|
||||
using namespace File_system;
|
||||
|
||||
Genode::Path<PATH_MAX_LEN> dir_path(_file_path);
|
||||
dir_path.strip_last_element();
|
||||
Genode::Path<PATH_MAX_LEN> file_name(_file_path);
|
||||
file_name.keep_only_last_element();
|
||||
|
||||
Dir_handle parent_handle = _fs.dir(dir_path.base(), false);
|
||||
Handle_guard parent_guard(_fs, parent_handle);
|
||||
|
||||
/* the file handle is opened here... */
|
||||
_file_handle = _fs.file(
|
||||
parent_handle, file_name.base() + 1,
|
||||
File_system::READ_ONLY, false);
|
||||
Handle_guard file_guard(_fs, _file_handle);
|
||||
/* ...but only for the lifetime of this procedure */
|
||||
|
||||
_file_seek = 0;
|
||||
_file_size = _fs.status(_file_handle).size;
|
||||
|
||||
if (_file_size > _file_ds.size()) {
|
||||
/* allocate new RAM dataspace according to file size */
|
||||
if (update_only)
|
||||
return false;
|
||||
|
||||
try {
|
||||
_file_ds.realloc(&_env.ram(), _file_size);
|
||||
} catch (...) {
|
||||
error("failed to allocate memory for ", _file_path);
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
_register_for_compound_dir_changes();
|
||||
return;
|
||||
memset(_file_ds.local_addr<char>(), 0x00, _file_ds.size());
|
||||
}
|
||||
|
||||
/* omit read if file is empty */
|
||||
if (_file_size == 0)
|
||||
return;
|
||||
return false;
|
||||
|
||||
/* read content from file */
|
||||
Tx_source &source = *_fs.tx();
|
||||
while (_file_seek < _file_size) {
|
||||
/* if we cannot submit then process acknowledgements */
|
||||
if (source.ready_to_submit()) {
|
||||
while (!source.ready_to_submit())
|
||||
_env.ep().wait_and_dispatch_one_io_signal();
|
||||
|
||||
size_t chunk_size = min(_file_size - _file_seek,
|
||||
source.bulk_buffer_size() / 2);
|
||||
|
||||
File_system::Packet_descriptor
|
||||
packet(source.alloc_packet(chunk_size),
|
||||
*_file_handle,
|
||||
packet(source.alloc_packet(chunk_size), _file_handle,
|
||||
File_system::Packet_descriptor::READ,
|
||||
chunk_size,
|
||||
_file_seek);
|
||||
chunk_size, _file_seek);
|
||||
|
||||
source.submit_packet(packet);
|
||||
}
|
||||
|
||||
/*
|
||||
* Process the global signal handler until we got a response
|
||||
@ -307,13 +234,46 @@ class Fs_rom::Rom_session_component : public Rpc_object<Rom_session>,
|
||||
while (_file_seek == orig_file_seek)
|
||||
_env.ep().wait_and_dispatch_one_io_signal();
|
||||
}
|
||||
|
||||
_handed_out_version = _curr_version;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool _try_read_dataspace(bool update_only)
|
||||
{
|
||||
using namespace File_system;
|
||||
|
||||
try { _open_watch_handle(); }
|
||||
catch (Watch_failed) { }
|
||||
|
||||
try { return _read_dataspace(update_only); }
|
||||
catch (Lookup_failed) { log(_file_path, " ROM file is missing"); }
|
||||
catch (Invalid_handle) { error(_file_path, ": invalid handle"); }
|
||||
catch (Invalid_name) { error(_file_path, ": invalid name"); }
|
||||
catch (Permission_denied) { error(_file_path, ": permission denied"); }
|
||||
catch (...) { error(_file_path, ": unhandled error"); };
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void _notify_client_about_new_version()
|
||||
{
|
||||
if (_sigh.valid() && _curr_version.value != _handed_out_version.value)
|
||||
using namespace File_system;
|
||||
|
||||
if (_sigh.valid() && _curr_version.value != _handed_out_version.value) {
|
||||
|
||||
/* notify if the file is not empty */
|
||||
try {
|
||||
Node_handle file = _fs.node(_file_path.base());
|
||||
Handle_guard g(_fs, file);
|
||||
_file_size = _fs.status(file).size;
|
||||
}
|
||||
catch (...) { _file_size = 0; }
|
||||
|
||||
if (_file_size > 0)
|
||||
Signal_transmitter(_sigh).submit();
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
@ -328,17 +288,15 @@ class Fs_rom::Rom_session_component : public Rpc_object<Rom_session>,
|
||||
* creation time)
|
||||
*/
|
||||
Rom_session_component(Env &env,
|
||||
File_system::Session &fs, const char *file_path)
|
||||
File_system::Session &fs,
|
||||
const char *file_path)
|
||||
:
|
||||
_env(env), _fs(fs),
|
||||
_file_path(file_path),
|
||||
_file_ds(env.ram(), env.rm(), 0) /* realloc later */
|
||||
{
|
||||
try {
|
||||
_file_handle.construct(_open_file(_fs, _file_path));
|
||||
} catch (Open_file_failed) { }
|
||||
|
||||
_register_for_compound_dir_changes();
|
||||
try { _open_watch_handle(); }
|
||||
catch (Watch_failed) { }
|
||||
}
|
||||
|
||||
/**
|
||||
@ -346,33 +304,45 @@ class Fs_rom::Rom_session_component : public Rpc_object<Rom_session>,
|
||||
*/
|
||||
~Rom_session_component()
|
||||
{
|
||||
/* close re-open the file */
|
||||
if (_file_handle.constructed())
|
||||
_fs.close(*_file_handle);
|
||||
|
||||
if (_compound_dir_handle.constructed())
|
||||
_fs.close(*_compound_dir_handle);
|
||||
_close_watch_handle();
|
||||
}
|
||||
|
||||
using Sessions::Element::next;
|
||||
|
||||
/**
|
||||
* Return dataspace with up-to-date content of file
|
||||
*/
|
||||
Rom_dataspace_capability dataspace()
|
||||
{
|
||||
_update_dataspace();
|
||||
using namespace File_system;
|
||||
|
||||
_try_read_dataspace(UPDATE_OR_REPLACE);
|
||||
|
||||
/* always serve a valid, even empty, dataspace */
|
||||
if (_file_ds.size() < 1) {
|
||||
_file_ds.realloc(&_env.ram(), 1);
|
||||
}
|
||||
|
||||
Dataspace_capability ds = _file_ds.cap();
|
||||
_handed_out_version = _curr_version;
|
||||
return static_cap_cast<Rom_dataspace>(ds);
|
||||
}
|
||||
|
||||
void sigh(Signal_context_capability sigh)
|
||||
{
|
||||
_sigh = sigh;
|
||||
|
||||
if (_sigh.valid()) {
|
||||
try { _open_watch_handle(); }
|
||||
catch (Watch_failed) { }
|
||||
}
|
||||
|
||||
_notify_client_about_new_version();
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the current dataspace content
|
||||
*/
|
||||
bool update() override {
|
||||
return _try_read_dataspace(UPDATE_ONLY); }
|
||||
|
||||
/**
|
||||
* If packet corresponds to this session then process and return true.
|
||||
*
|
||||
@ -383,25 +353,30 @@ class Fs_rom::Rom_session_component : public Rpc_object<Rom_session>,
|
||||
switch (packet.operation()) {
|
||||
|
||||
case File_system::Packet_descriptor::CONTENT_CHANGED:
|
||||
|
||||
_curr_version = Version { _curr_version.value + 1 };
|
||||
|
||||
if ((_file_handle.constructed() && (*_file_handle == packet.handle())) ||
|
||||
(_compound_dir_handle.constructed() && (*_compound_dir_handle == packet.handle())))
|
||||
{
|
||||
_notify_client_about_new_version();
|
||||
return true;
|
||||
}
|
||||
if (!(packet.handle() == *_watch_handle))
|
||||
return false;
|
||||
|
||||
if (!_watching_file) {
|
||||
/* try and get closer to the file */
|
||||
_open_watch_handle();
|
||||
}
|
||||
|
||||
if (_watching_file) {
|
||||
/* notify the client of the change */
|
||||
_curr_version = Version { _curr_version.value + 1 };
|
||||
_notify_client_about_new_version();
|
||||
}
|
||||
return true;
|
||||
|
||||
case File_system::Packet_descriptor::READ: {
|
||||
|
||||
if (!(_file_handle.constructed() && (*_file_handle == packet.handle())))
|
||||
if (!(packet.handle() == _file_handle))
|
||||
return false;
|
||||
|
||||
if (packet.position() > _file_seek || _file_seek >= _file_size) {
|
||||
error("bad packet seek position");
|
||||
_file_ds.realloc(&_env.ram(), 0);
|
||||
_file_seek = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -412,9 +387,14 @@ class Fs_rom::Rom_session_component : public Rpc_object<Rom_session>,
|
||||
return true;
|
||||
}
|
||||
|
||||
default:
|
||||
|
||||
error("discarding strange packet acknowledgement");
|
||||
case File_system::Packet_descriptor::WRITE:
|
||||
warning("discarding strange WRITE acknowledgement");
|
||||
return true;
|
||||
case File_system::Packet_descriptor::SYNC:
|
||||
warning("discarding strange SYNC acknowledgement");
|
||||
return true;
|
||||
case File_system::Packet_descriptor::READ_READY:
|
||||
warning("discarding strange READ_READY acknowledgement");
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
@ -97,11 +97,7 @@ class Ram_fs::Session_component : public File_system::Session_rpc_object
|
||||
break;
|
||||
|
||||
case Packet_descriptor::CONTENT_CHANGED: {
|
||||
open_node.register_notify(*tx_sink());
|
||||
Locked_ptr<Node> node { open_node.node() };
|
||||
if (!node.valid())
|
||||
return;
|
||||
node->notify_listeners();
|
||||
Genode::error("CONTENT_CHANGED packets from clients have no effect");
|
||||
return;
|
||||
}
|
||||
|
||||
@ -365,6 +361,24 @@ class Ram_fs::Session_component : public File_system::Session_rpc_object
|
||||
return open_node->id();
|
||||
}
|
||||
|
||||
Watch_handle watch(Path const &path) override
|
||||
{
|
||||
_assert_valid_path(path.string());
|
||||
|
||||
Node *node = _root.lookup(path.string() + 1);
|
||||
|
||||
Open_node *watcher = new (_alloc)
|
||||
Open_node(node->weak_ptr(), _open_node_registry);
|
||||
|
||||
/*
|
||||
* like other open nodes, just the only
|
||||
* kind registered for notifications
|
||||
*/
|
||||
watcher->register_notify(*tx_sink());
|
||||
|
||||
return Watch_handle { watcher->id().value };
|
||||
}
|
||||
|
||||
void close(Node_handle handle)
|
||||
{
|
||||
auto close_fn = [&] (Open_node &open_node) {
|
||||
|
Loading…
Reference in New Issue
Block a user