vfs/lwip: deferred wakeup of NIC server

This patch fosters the batching of network packets transferred by the
lwIP stack over the NIC connection. It replaces the eager submission of
the packet-stream's data-flow signals by explicit wakeup notifications.

The commit also increases the NIC session's buffer size from 128 to 1024
packets.

Issue #4697
This commit is contained in:
Norman Feske 2022-12-03 18:50:25 +01:00 committed by Christian Helmuth
parent 60175631df
commit 8a9974b6f9
20 changed files with 163 additions and 123 deletions

View File

@ -307,13 +307,12 @@ class Main
}
}
_blk.tx()->wakeup();
_vfs_env.io().commit();
}
public:
Main(Env &env)
:
_env { env }
Main(Env &env) : _env { env }
{
if (_blk_ratio == 0) {
error("backend block size not supported");

View File

@ -219,6 +219,8 @@ class Main
}
break;
}
_vfs_env.io().commit();
}
Io_response_handler _io_response_handler { _io_handler };

View File

@ -2526,6 +2526,7 @@ class Main
_execute_cbe(progress);
}
}
_vfs_env.io().commit();
}
public:

View File

@ -188,20 +188,7 @@ struct Fs_query::Main : Vfs::Watch_response_handler
Signal_transmitter(_config_handler).submit();
}
struct Vfs_env : Vfs::Env
{
Main &_main;
Vfs_env(Main &main) : _main(main) { }
Genode::Env &env() override { return _main._env; }
Allocator &alloc() override { return _main._heap; }
Vfs::File_system &root_dir() override { return _main._root_dir_fs; }
} _vfs_env { *this };
Vfs::Dir_file_system _root_dir_fs {
_vfs_env, _config.xml().sub_node("vfs"), _fs_factory };
Vfs::Simple_env _vfs_env { _env, _heap, _config.xml().sub_node("vfs") };
Directory _root_dir { _vfs_env };
@ -229,7 +216,7 @@ struct Fs_query::Main : Vfs::Watch_response_handler
Xml_node const config = _config.xml();
_root_dir_fs.apply_config(config.sub_node("vfs"));
_vfs_env.root_dir().apply_config(config.sub_node("vfs"));
_dirs.for_each([&] (Registered<Watched_directory> &dir) {
destroy(_heap, &dir); });

View File

@ -35,20 +35,7 @@ struct Fs_tool::Main
Vfs::Global_file_system_factory _fs_factory { _heap };
struct Vfs_env : Vfs::Env
{
Main &_main;
Vfs_env(Main &main) : _main(main) { }
Genode::Env &env() override { return _main._env; }
Allocator &alloc() override { return _main._heap; }
Vfs::File_system &root_dir() override { return _main._root_dir_fs; }
} _vfs_env { *this };
Vfs::Dir_file_system _root_dir_fs {
_vfs_env, _config.xml().sub_node("vfs"), _fs_factory };
Vfs::Simple_env _vfs_env { _env, _heap, _config.xml().sub_node("vfs") };
Directory _root_dir { _vfs_env };
@ -71,7 +58,7 @@ struct Fs_tool::Main
_verbose = config.attribute_value("verbose", false);
_root_dir_fs.apply_config(config.sub_node("vfs"));
_vfs_env.root_dir().apply_config(config.sub_node("vfs"));
config.for_each_sub_node([&] (Xml_node operation) {

View File

@ -96,20 +96,7 @@ struct Menu_view::Main
Heap _heap { _env.ram(), _env.rm() };
struct Vfs_env : Vfs::Env
{
Genode::Env &_env;
Allocator &_alloc;
Vfs::File_system &_vfs;
Vfs_env(Genode::Env &env, Allocator &alloc, Vfs::File_system &vfs)
: _env(env), _alloc(alloc), _vfs(vfs) { }
Genode::Env &env() override { return _env; }
Allocator &alloc() override { return _alloc; }
Vfs::File_system &root_dir() override { return _vfs; }
} _vfs_env;
Vfs::Env &_vfs_env;
Directory _root_dir { _vfs_env };
Directory _fonts_dir { _root_dir, "fonts" };
@ -211,9 +198,9 @@ struct Menu_view::Main
*/
unsigned _frame_cnt = 0;
Main(Env &env, Vfs::File_system &libc_vfs)
Main(Env &env, Vfs::Env &libc_vfs_env)
:
_env(env), _vfs_env(_env, _heap, libc_vfs)
_env(env), _vfs_env(libc_vfs_env)
{
_dialog_rom.sigh(_dialog_update_handler);
_config.sigh(_config_handler);
@ -470,6 +457,6 @@ extern "C" void _sigprocmask() { }
void Libc::Component::construct(Libc::Env &env)
{
static Menu_view::Main main(env, env.vfs());
static Menu_view::Main main(env, env.vfs_env());
}

View File

@ -35,10 +35,10 @@ class Vfs_replay
Vfs_replay(const Vfs_replay&) = delete;
Vfs_replay& operator=(const Vfs_replay&) = delete;
Env &_env;
Vfs::File_system &_vfs;
Vfs::Env::Io &_io;
Vfs::Vfs_handle *_vfs_handle;
Attached_ram_dataspace _write_buffer;
@ -421,6 +421,8 @@ class Vfs_replay
if (_finished) {
_env.parent().exit(failed ? 1 : 0);
}
_io.commit();
}
struct Io_response_handler : Vfs::Io_response_handler
@ -441,11 +443,12 @@ class Vfs_replay
public:
Vfs_replay(Vfs::File_system &vfs, Env &env,
Vfs_replay(Env &env, Vfs::File_system &vfs, Vfs::Env::Io &io,
Xml_node const & config)
:
_env { env },
_vfs { vfs },
_io { io },
_vfs_handle { nullptr },
_write_buffer { _env.ram(), _env.rm(),
config.attribute_value("write_buffer_size", 1u << 20) },
@ -513,7 +516,7 @@ struct Main : private Genode::Entrypoint::Io_progress_handler
Genode::Signal_handler<Main> _reactivate_handler {
_env.ep(), *this, &Main::handle_io_progress };
Vfs_replay _replay { _vfs_env.root_dir(), _env, _config_rom.xml() };
Vfs_replay _replay { _env, _vfs_env.root_dir(), _vfs_env.io(), _config_rom.xml() };
Main(Genode::Env &env) : _env { env }
{

View File

@ -28,7 +28,7 @@
namespace Libc { class Env; }
namespace Vfs { struct File_system; }
namespace Vfs { struct Env; }
/**
* Interface to be provided by the component implementation
@ -49,9 +49,9 @@ class Libc::Env : public Genode::Env
func(_config_xml()); }
/**
* Virtual File System configured for this component
* Virtual file system configured for this component
*/
virtual Vfs::File_system &vfs() = 0;
virtual Vfs::Env &vfs_env() = 0;
/**
* Libc configuration for this component

View File

@ -67,16 +67,15 @@ class Libc::Env_implementation : public Libc::Env, public Config_accessor
Env_implementation(Genode::Env &env, Genode::Allocator &alloc)
: _env(env), _vfs_env(_env, alloc, _vfs_config()) { }
Vfs::Env &vfs_env() { return _vfs_env; }
Vfs::File_system &vfs() { return _vfs_env.root_dir(); }
/*************************
** Libc::Env interface **
*************************/
Vfs::File_system &vfs() override {
return _vfs_env.root_dir(); }
Vfs::Env &vfs_env() override {
return _vfs_env; }
Xml_node libc_config() override {
return _libc_config(); }

View File

@ -703,7 +703,7 @@ struct Libc::Kernel final : Vfs::Io_response_handler,
void wakeup_remote_peers()
{
_libc_env.vfs_env().deferred_wakeups().trigger();
_libc_env.vfs_env().io().commit();
}
};

View File

@ -161,7 +161,7 @@ class Libc::Vfs_plugin final : public Plugin
Xml_node config)
:
_alloc(alloc),
_root_fs(env.vfs()),
_root_fs(env.vfs_env().root_dir()),
_response_handler(handler),
_update_mtime(update_mtime),
_current_real_time(current_real_time),

View File

@ -75,14 +75,25 @@ extern "C" {
class Lwip::Nic_netif
{
public:
struct Wakeup_scheduler : Genode::Noncopyable, Genode::Interface
{
virtual void schedule_nic_server_wakeup() = 0;
};
private:
Genode::Entrypoint &_ep;
Wakeup_scheduler &_wakeup_scheduler;
enum {
PACKET_SIZE = Nic::Packet_allocator::DEFAULT_PACKET_SIZE,
BUF_SIZE = 128 * PACKET_SIZE,
BUF_SIZE = 1024*PACKET_SIZE,
};
Genode::Tslab<Nic_netif_pbuf, 128*sizeof(Nic_netif_pbuf)> _pbuf_alloc;
Genode::Tslab<Nic_netif_pbuf, 1024*sizeof(Nic_netif_pbuf)> _pbuf_alloc;
Nic::Packet_allocator _nic_tx_alloc;
Nic::Connection _nic;
@ -103,11 +114,17 @@ class Lwip::Nic_netif
void free_pbuf(Nic_netif_pbuf &pbuf)
{
if (!_nic.rx()->ready_to_ack()) {
Genode::error("Nic rx acknowledgement queue congested, blocking to free pbuf");
bool msg_once = true;
while (!_nic.rx()->ready_to_ack()) {
if (msg_once)
Genode::error("Nic rx acknowledgement queue congested, blocking to free pbuf");
msg_once = false;
_ep.wait_and_dispatch_one_io_signal();
}
_nic.rx()->acknowledge_packet(pbuf.packet);
_nic.rx()->try_ack_packet(pbuf.packet);
_wakeup_scheduler.schedule_nic_server_wakeup();
destroy(_pbuf_alloc, &pbuf);
}
@ -144,9 +161,12 @@ class Lwip::Nic_netif
{
auto &rx = *_nic.rx();
bool progress = false;
while (rx.packet_avail() && rx.ready_to_ack()) {
Nic::Packet_descriptor packet = rx.get_packet();
Nic::Packet_descriptor packet = rx.try_get_packet();
progress = true;
Nic_netif_pbuf *nic_pbuf = new (_pbuf_alloc)
Nic_netif_pbuf(*this, packet);
@ -165,6 +185,9 @@ class Lwip::Nic_netif
pbuf_free(p);
}
}
if (progress)
_wakeup_scheduler.schedule_nic_server_wakeup();
}
/**
@ -174,12 +197,19 @@ class Lwip::Nic_netif
{
auto &tx = *_nic.tx();
bool progress = false;
/* flush acknowledgements */
while (tx.ack_avail())
tx.release_packet(tx.get_acked_packet());
while (tx.ack_avail()) {
tx.release_packet(tx.try_get_acked_packet());
progress = true;
}
/* notify subclass to resume pending transmissions */
status_callback();
if (progress)
_wakeup_scheduler.schedule_nic_server_wakeup();
}
void configure(Genode::Xml_node const &config)
@ -240,8 +270,11 @@ class Lwip::Nic_netif
Nic_netif(Genode::Env &env,
Genode::Allocator &alloc,
Genode::Xml_node config)
Genode::Xml_node config,
Wakeup_scheduler &wakeup_scheduler)
:
_ep(env.ep()),
_wakeup_scheduler(wakeup_scheduler),
_pbuf_alloc(alloc), _nic_tx_alloc(&alloc),
_nic(env, &_nic_tx_alloc,
BUF_SIZE, BUF_SIZE,
@ -365,7 +398,8 @@ class Lwip::Nic_netif
dst += q->len;
}
tx.submit_packet(packet);
tx.try_submit_packet(packet);
_wakeup_scheduler.schedule_nic_server_wakeup();
LINK_STATS_INC(link.xmit);
return ERR_OK;
}
@ -375,6 +409,15 @@ class Lwip::Nic_netif
return netif_is_up(&_netif) &&
!ip_addr_isany(&_netif.ip_addr);
}
/**
* Trigger submission of deferred packet-stream signals
*/
void wakeup_nic_server()
{
_nic.rx()->wakeup();
_nic.tx()->wakeup();
}
};

View File

@ -1713,8 +1713,12 @@ class Lwip::File_system final : public Vfs::File_system, public Lwip::Directory
/**
* LwIP connection to Nic service
*/
struct Vfs_netif : Lwip::Nic_netif
struct Vfs_netif : Lwip::Nic_netif,
private Vfs::Remote_io,
private Lwip::Nic_netif::Wakeup_scheduler
{
Remote_io::Peer _peer;
Tcp_proto_dir tcp_dir;
Udp_proto_dir udp_dir;
@ -1725,10 +1729,11 @@ class Lwip::File_system final : public Vfs::File_system, public Lwip::Directory
Handle_queue blocked_handles { };
Vfs_netif(Vfs::Env &vfs_env,
Genode::Xml_node config)
: Lwip::Nic_netif(vfs_env.env(), vfs_env.alloc(), config),
tcp_dir(vfs_env), udp_dir(vfs_env)
Vfs_netif(Vfs::Env &vfs_env, Genode::Xml_node config)
:
Lwip::Nic_netif(vfs_env.env(), vfs_env.alloc(), config, *this),
_peer(vfs_env.deferred_wakeups(), *this),
tcp_dir(vfs_env), udp_dir(vfs_env)
{ }
~Vfs_netif()
@ -1737,6 +1742,26 @@ class Lwip::File_system final : public Vfs::File_system, public Lwip::Directory
status_callback();
}
/**
* Lwip::Nic_netif::Wakeup_scheduler interface
*
* Called from Lwip::Nic_netif.
*/
void schedule_nic_server_wakeup() override
{
_peer.schedule_wakeup();
}
/**
* Remote_io interface
*
* Called from VFS user when going idle.
*/
void wakeup_remote_peer() override
{
Lwip::Nic_netif::wakeup_nic_server();
}
void enqueue(Vfs_handle &handle)
{
Handle_element *elem = new (handle.alloc())
@ -1802,14 +1827,17 @@ class Lwip::File_system final : public Vfs::File_system, public Lwip::Directory
public:
File_system(Vfs::Env &vfs_env, Genode::Xml_node config)
: _ep(vfs_env.env().ep()), _netif(vfs_env, config)
:
_ep(vfs_env.env().ep()), _netif(vfs_env, config)
{ }
/**
* Reconfigure the LwIP Nic interface with the VFS config hook
*/
void apply_config(Genode::Xml_node const &node) override {
_netif.configure(node); }
void apply_config(Genode::Xml_node const &node) override
{
_netif.configure(node);
}
/*********************

View File

@ -194,7 +194,7 @@ struct Genode::Directory : Noncopyable, Interface
_handle->seek(i * sizeof(entry._dirent));
while (!_handle->fs().queue_read(_handle, sizeof(entry._dirent)))
_io.progress();
_io.commit_and_wait();
Vfs::File_io_service::Read_result read_result;
Vfs::file_size out_count = 0;
@ -209,7 +209,7 @@ struct Genode::Directory : Noncopyable, Interface
if (read_result != Vfs::File_io_service::READ_QUEUED)
break;
_io.progress();
_io.commit_and_wait();
}
if ((read_result != Vfs::File_io_service::READ_OK) ||
@ -298,7 +298,7 @@ struct Genode::Directory : Noncopyable, Interface
Vfs::file_size count = sizeof(buf)-1;
Vfs::file_size out_count = 0;
while (!link_handle->fs().queue_read(link_handle, count)) {
_io.progress();
_io.commit_and_wait();
}
File_io_service::Read_result result;
@ -310,7 +310,7 @@ struct Genode::Directory : Noncopyable, Interface
if (result != File_io_service::READ_QUEUED)
break;
_io.progress();
_io.commit_and_wait();
};
if (result != File_io_service::READ_OK)
@ -463,7 +463,7 @@ class Genode::Readonly_file : public File
_handle->seek(at.value);
while (!_handle->fs().queue_read(_handle, bytes))
_io.progress();
_io.commit_and_wait();
Vfs::File_io_service::Read_result result;
@ -474,7 +474,7 @@ class Genode::Readonly_file : public File
if (result != Vfs::File_io_service::READ_QUEUED)
break;
_io.progress();
_io.commit_and_wait();
};
/*
@ -720,7 +720,7 @@ class Genode::Writeable_file : Noncopyable
static void _sync(Vfs::Vfs_handle &handle, Vfs::Env::Io &io)
{
while (handle.fs().queue_sync(&handle) == false)
io.progress();
io.commit_and_wait();
for (bool sync_done = false; !sync_done; ) {
@ -740,7 +740,7 @@ class Genode::Writeable_file : Noncopyable
}
if (!sync_done)
io.progress();
io.commit_and_wait();
}
}
@ -786,7 +786,7 @@ class Genode::Writeable_file : Noncopyable
stalled = true; }
if (stalled)
io.progress();
io.commit_and_wait();
}
return write_error ? Append_result::WRITE_ERROR
: Append_result::OK;

View File

@ -46,7 +46,17 @@ struct Vfs::Env : Interface
*/
struct Io : Interface, Genode::Noncopyable
{
virtual void progress() = 0;
/**
* Trigger the deferred wakeup of remote peers
*/
virtual void commit() = 0;
/**
* Wakeup remote peers and wait for I/O progress
*
* This method is intended for implementing synchronous I/O.
*/
virtual void commit_and_wait() = 0;
};
virtual Io &io() = 0;

View File

@ -60,7 +60,12 @@ class Vfs::Simple_env : public Vfs::Env, private Vfs::Env::Io
/**
* Vfs::Env::Io interface
*/
void progress() override
void commit() override { _deferred_wakeups.trigger(); }
/**
* Vfs::Env::Io interface
*/
void commit_and_wait() override
{
_deferred_wakeups.trigger();
_env.ep().wait_and_dispatch_one_io_signal();

View File

@ -108,10 +108,10 @@ class Fs_report::Session_component : public Genode::Rpc_object<Report::Session>
/* sync file operations before close */
while (!handle->fs().queue_sync(handle))
_io.progress();
_io.commit_and_wait();
while (handle->fs().complete_sync(handle) == Vfs::File_io_service::SYNC_QUEUED)
_io.progress();
_io.commit_and_wait();
handle->close();
}

View File

@ -89,10 +89,7 @@ class Vfs_server::Session_component : private Session_resources,
private:
Vfs::File_system &_vfs;
using Deferred_wakeups = Vfs::Remote_io::Deferred_wakeups;
Deferred_wakeups &_deferred_wakeups;
Vfs::Env::Io &_io;
Genode::Entrypoint &_ep;
@ -197,7 +194,6 @@ class Vfs_server::Session_component : private Session_resources,
{
drop_packet_from_submit_queue();
packet.succeeded(false);
Genode::log("consume_and_ack_invalid_packet");
_stream.try_ack_packet(packet);
overall_progress = true;
@ -278,12 +274,7 @@ class Vfs_server::Session_component : private Session_resources,
}
if (node.acknowledgement_pending()) {
auto packet = node.dequeue_acknowledgement();
if (!packet.succeeded())
Genode::warning("_try_acknowledge_jobs failed packet");
_stream.try_ack_packet(packet);
_stream.try_ack_packet(node.dequeue_acknowledgement());
progress = true;
}
@ -389,7 +380,7 @@ class Vfs_server::Session_component : private Session_resources,
if (progress == Process_packets_result::PROGRESS)
_io_progress_handler.handle_io_progress();
_deferred_wakeups.trigger();
_io.commit();
}
/**
@ -454,7 +445,7 @@ class Vfs_server::Session_component : private Session_resources,
Genode::Cap_quota cap_quota,
size_t tx_buf_size,
Vfs::File_system &vfs,
Deferred_wakeups &deferred_wakeups,
Vfs::Env::Io &io,
Session_queue &active_sessions,
Io_progress_handler &io_progress_handler,
char const *root_path,
@ -463,7 +454,7 @@ class Vfs_server::Session_component : private Session_resources,
Session_resources(env.pd(), env.rm(), ram_quota, cap_quota, tx_buf_size),
Session_rpc_object(_packet_ds.cap(), env.rm(), env.ep().rpc_ep()),
_vfs(vfs),
_deferred_wakeups(deferred_wakeups),
_io(io),
_ep(env.ep()),
_io_progress_handler(io_progress_handler),
_active_sessions(active_sessions),
@ -867,7 +858,7 @@ class Vfs_server::Root : public Genode::Root_component<Session_component>,
if (yield)
Genode::Signal_transmitter(_reactivate_handler).submit();
_vfs_env.deferred_wakeups().trigger();
_vfs_env.io().commit();
}
protected:
@ -952,7 +943,7 @@ class Vfs_server::Root : public Genode::Root_component<Session_component>,
Genode::Ram_quota{ram_quota},
Genode::Cap_quota{cap_quota},
tx_buf_size, _vfs_env.root_dir(),
_vfs_env.deferred_wakeups(),
_vfs_env.io(),
_active_sessions, *this,
session_root.base(), writeable);

View File

@ -226,22 +226,20 @@ struct Block_session_component : Rpc_object<Block::Session>,
using Block::Request_stream::try_acknowledge;
using Block::Request_stream::wakeup_client_if_needed;
using Vfs_peers = Vfs::Remote_io::Deferred_wakeups;
Vfs_block::File &_file;
Vfs_peers &_vfs_peers;
Vfs::Env::Io &_io;
Block_session_component(Region_map &rm,
Entrypoint &ep,
Dataspace_capability ds,
Signal_context_capability sigh,
Vfs_block::File &file,
Vfs_peers &vfs_peers)
Vfs::Env::Io &io)
:
Request_stream { rm, ds, ep, sigh, file.block_info() },
_ep { ep },
_file { file },
_vfs_peers { vfs_peers }
_ep { ep },
_file { file },
_io { io }
{
_ep.manage(*this);
}
@ -308,7 +306,7 @@ struct Block_session_component : Rpc_object<Block::Session>,
}
}
_vfs_peers.trigger();
_io.commit();
wakeup_client_if_needed();
}
@ -385,7 +383,7 @@ struct Main : Rpc_object<Typed_root<Block::Session>>
_block_session.construct(_env.rm(), _env.ep(),
_block_ds->cap(),
_request_handler, *_block_file,
_vfs_env.deferred_wakeups());
_vfs_env.io());
return _block_session->cap();
} catch (...) {

View File

@ -304,7 +304,7 @@ struct Write_test : public Stress_test
handle->fs().queue_sync(handle);
while (handle->fs().complete_sync(handle) ==
Vfs::File_io_service::SYNC_QUEUED)
_io.progress();
_io.commit_and_wait();
count += n;
}
@ -382,7 +382,7 @@ struct Read_test : public Stress_test
while ((read_result =
handle->fs().complete_read(handle, tmp, sizeof(tmp), n)) ==
Vfs::File_io_service::READ_QUEUED)
_io.progress();
_io.commit_and_wait();
assert_read(read_result);
@ -457,7 +457,7 @@ struct Unlink_test : public Stress_test
while (dir_handle->fs().complete_read(dir_handle, (char*)&dirent,
sizeof(dirent), out_count) ==
Vfs::File_io_service::READ_QUEUED)
_io.progress();
_io.commit_and_wait();
subpath.append(dirent.name.buf);
switch (dirent.type) {
@ -540,11 +540,11 @@ void Component::construct(Genode::Env &env)
auto vfs_root_sync = [&] ()
{
while (!vfs_root_handle->fs().queue_sync(vfs_root_handle))
vfs_env.io().progress();
vfs_env.io().commit_and_wait();
while (vfs_root_handle->fs().complete_sync(vfs_root_handle) ==
Vfs::File_io_service::SYNC_QUEUED)
vfs_env.io().progress();
vfs_env.io().commit_and_wait();
};
char path[Vfs::MAX_PATH_LEN];