diff --git a/repos/os/src/server/lx_fs/main.cc b/repos/os/src/server/lx_fs/main.cc
index 79637c3bb8..320e036273 100644
--- a/repos/os/src/server/lx_fs/main.cc
+++ b/repos/os/src/server/lx_fs/main.cc
@@ -16,9 +16,11 @@
*/
/* Genode includes */
+#include
#include
#include
#include
+#include
#include
#include
#include
@@ -35,27 +37,68 @@ namespace Lx_fs {
using namespace File_system;
using File_system::Packet_descriptor;
using File_system::Path;
+ using Genode::Attached_ram_dataspace;
+ using Genode::Attached_rom_dataspace;
struct Main;
- struct Session_component;
- struct Root;
+ class Session_resources;
+ class Session_component;
+ class Root;
+
+ /**
+ * Convenience utities for parsing quotas
+ */
+ Genode::Ram_quota parse_ram_quota(char const *args) {
+ return Genode::Ram_quota{ Genode::Arg_string::find_arg(args, "ram_quota").ulong_value(0)}; }
+ Genode::Cap_quota parse_cap_quota(char const *args) {
+ return Genode::Cap_quota{ Genode::Arg_string::find_arg(args, "cap_quota").ulong_value(0)}; }
+ Genode::size_t parse_tx_buf_size(char const *args) {
+ return Genode::Arg_string::find_arg(args, "tx_buf_size").ulong_value(0); }
}
-class Lx_fs::Session_component : public Session_rpc_object
+/**
+ * Base class to manage session quotas and allocations
+ */
+class Lx_fs::Session_resources
+{
+ protected:
+
+ Genode::Ram_quota_guard _ram_guard;
+ Genode::Cap_quota_guard _cap_guard;
+ Genode::Constrained_ram_allocator _ram_alloc;
+ Genode::Attached_ram_dataspace _packet_ds;
+ Genode::Heap _alloc;
+
+ Session_resources(Genode::Ram_allocator &ram,
+ Genode::Region_map ®ion_map,
+ Genode::Ram_quota ram_quota,
+ Genode::Cap_quota cap_quota,
+ Genode::size_t buffer_size)
+ :
+ _ram_guard(ram_quota), _cap_guard(cap_quota),
+ _ram_alloc(ram, _ram_guard, _cap_guard),
+ _packet_ds(_ram_alloc, region_map, buffer_size),
+ _alloc(_ram_alloc, region_map)
+ { }
+};
+
+
+class Lx_fs::Session_component : private Session_resources,
+ public Session_rpc_object
{
private:
- typedef File_system::Open_node Open_node;
+ using Open_node = File_system::Open_node;
+ using Signal_handler = Genode::Signal_handler;
Genode::Env &_env;
- Allocator &_md_alloc;
Directory &_root;
Id_space _open_node_registry { };
bool _writable;
Absolute_path const _root_dir;
- Signal_handler _process_packet_dispatcher;
+ Signal_handler _process_packet_dispatcher;
/******************************
@@ -69,7 +112,7 @@ class Lx_fs::Session_component : public Session_rpc_object
*/
void _process_packet_op(Packet_descriptor &packet, Open_node &open_node)
{
- size_t const length = packet.length();
+ size_t const length = packet.length();
/* resulting length */
size_t res_length = 0;
@@ -200,19 +243,20 @@ class Lx_fs::Session_component : public Session_rpc_object
/**
* Constructor
*/
- Session_component(size_t tx_buf_size,
- Genode::Env &env,
- char const *root_dir,
- bool writable,
- Allocator &md_alloc)
+ Session_component(Genode::Env &env,
+ Genode::Ram_quota ram_quota,
+ Genode::Cap_quota cap_quota,
+ size_t tx_buf_size,
+ char const *root_dir,
+ bool writable)
:
- Session_rpc_object(env.ram().alloc(tx_buf_size), env.rm(), env.ep().rpc_ep()),
- _env(env),
- _md_alloc(md_alloc),
- _root(*new (&_md_alloc) Directory(_md_alloc, root_dir, false)),
- _writable(writable),
- _root_dir(root_dir),
- _process_packet_dispatcher(env.ep(), *this, &Session_component::_process_packets)
+ 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() },
+ _env { env },
+ _root { *new (&_alloc) Directory { _alloc, root_dir, false } },
+ _writable { writable },
+ _root_dir { root_dir },
+ _process_packet_dispatcher { env.ep(), *this, &Session_component::_process_packets }
{
/*
* Register '_process_packets' dispatch function as signal
@@ -227,11 +271,37 @@ class Lx_fs::Session_component : public Session_rpc_object
*/
~Session_component()
{
- Dataspace_capability ds = tx_sink()->dataspace();
- _env.ram().free(static_cap_cast(ds));
- destroy(&_md_alloc, &_root);
+ List> node_list;
+
+ auto collect_fn = [&node_list, this] (Open_node &open_node) {
+ node_list.insert(new (_alloc) List_element{ &open_node });
+ };
+
+ try {
+ _open_node_registry.for_each(collect_fn);
+
+ while (node_list.first()) {
+
+ auto *e = node_list.first();
+ Node &node = e->object()->node();
+ destroy(_alloc, e->object());
+ destroy(_alloc, &node);
+ node_list.remove(e);
+ destroy(_alloc, e);
+ }
+
+ } catch (Id_space::Unknown_id const &) {
+ error("invalid handle while cleaning up");
+ }
+
+ destroy(&_alloc, &_root);
}
+ /**
+ * Increase quotas
+ */
+ void upgrade(Genode::Ram_quota ram) { _ram_guard.upgrade(ram); }
+ void upgrade(Genode::Cap_quota caps) { _cap_guard.upgrade(caps); }
/***************************
** File_system interface **
@@ -253,7 +323,7 @@ class Lx_fs::Session_component : public Session_rpc_object
File *file = dir.file(name.string(), mode, create);
Open_node *open_file =
- new (_md_alloc) Open_node(*file, _open_node_registry);
+ new (_alloc) Open_node(*file, _open_node_registry);
return open_file->id();
};
@@ -294,7 +364,7 @@ class Lx_fs::Session_component : public Session_rpc_object
Directory *dir = _root.subdir(path_str, create);
Open_node *open_dir =
- new (_md_alloc) Open_node(*dir, _open_node_registry);
+ new (_alloc) Open_node(*dir, _open_node_registry);
return Dir_handle { open_dir->id().value };
}
@@ -308,7 +378,7 @@ class Lx_fs::Session_component : public Session_rpc_object
Node *node = _root.node(path_str + 1);
Open_node *open_node =
- new (_md_alloc) Open_node(*node, _open_node_registry);
+ new (_alloc) Open_node(*node, _open_node_registry);
return open_node->id();
}
@@ -317,8 +387,8 @@ class Lx_fs::Session_component : public Session_rpc_object
{
auto close_fn = [&] (Open_node &open_node) {
Node &node = open_node.node();
- destroy(_md_alloc, &open_node);
- destroy(_md_alloc, &node);
+ destroy(_alloc, &open_node);
+ destroy(_alloc, &node);
};
try {
@@ -370,9 +440,6 @@ class Lx_fs::Session_component : public Session_rpc_object
char const *path_str = absolute_path.string();
_assert_valid_path(path_str);
- /* skip leading '/' */
- path_str++;
-
struct stat s;
int ret = lstat(path_str, &s);
if (ret == -1) {
@@ -451,9 +518,8 @@ class Lx_fs::Root : public Root_component
{
private:
- Genode::Env &_env;
-
- Genode::Attached_rom_dataspace _config { _env, "config" };
+ Genode::Env &_env;
+ Genode::Attached_rom_dataspace _config { _env, "config" };
static inline bool writeable_from_args(char const *args)
{
@@ -509,10 +575,11 @@ class Lx_fs::Root : public Root_component
writeable = policy.attribute_value("writeable", false) &&
writeable_from_args(args);
- size_t ram_quota =
- Arg_string::find_arg(args, "ram_quota" ).ulong_value(0);
- size_t tx_buf_size =
- Arg_string::find_arg(args, "tx_buf_size").ulong_value(0);
+ auto const initial_ram_usage { _env.pd().used_ram().value };
+ auto const initial_cap_usage { _env.pd().used_caps().value };
+ auto const ram_quota { parse_ram_quota(args).value };
+ auto const cap_quota { parse_cap_quota(args).value };
+ auto const tx_buf_size { parse_tx_buf_size(args) };
if (!tx_buf_size) {
Genode::error(label, " requested a session with a zero length transmission buffer");
@@ -531,8 +598,29 @@ class Lx_fs::Root : public Root_component
}
try {
- return new (md_alloc())
- Session_component(tx_buf_size, _env, root_dir, writeable, *md_alloc());
+ auto session = new (md_alloc())
+ Session_component { _env,
+ Genode::Ram_quota { ram_quota },
+ Genode::Cap_quota { cap_quota },
+ tx_buf_size,
+ absolute_root_directory(root_dir).string(),
+ writeable };
+
+ auto ram_used { _env.pd().used_ram().value - initial_ram_usage };
+ auto cap_used { _env.pd().used_caps().value - initial_cap_usage };
+
+ if ((ram_used > ram_quota) || (cap_used > cap_quota)) {
+ if (ram_used > ram_quota)
+ Genode::warning("ram donation is ", ram_quota,
+ " but used RAM is ", ram_used, "B"
+ ", '", label, "'");
+ if (cap_used > cap_quota)
+ Genode::warning("cap donation is ", cap_quota,
+ " but used caps is ", cap_used,
+ ", '", label, "'");
+ }
+
+ return session;
}
catch (Lookup_failed) {
Genode::error("session root directory \"", root, "\" "
@@ -541,6 +629,28 @@ class Lx_fs::Root : public Root_component
}
}
+ void _destroy_session(Session_component *session) override
+ {
+ Genode::destroy(md_alloc(), session);
+ }
+
+ /**
+ * Session upgrades are important for the lx_fs server,
+ * this allows sessions to open arbitrarily large amounts
+ * of handles without starving other sessions.
+ */
+ void _upgrade_session(Session_component *session,
+ char const *args) override
+ {
+ Genode::Ram_quota more_ram { parse_ram_quota(args) };
+ Genode::Cap_quota more_caps { parse_cap_quota(args) };
+
+ if (more_ram.value > 0)
+ session->upgrade(more_ram);
+ if (more_caps.value > 0)
+ session->upgrade(more_caps);
+ }
+
public:
Root(Genode::Env &env, Allocator &md_alloc)