Capability quota accounting and trading

This patch mirrors the accounting and trading scheme that Genode employs
for physical memory to the accounting of capability allocations.

Capability quotas must now be explicitly assigned to subsystems by
specifying a 'caps=<amount>' attribute to init's start nodes.
Analogously to RAM quotas, cap quotas can be traded between clients and
servers as part of the session protocol. The capability budget of each
component is maintained by the component's corresponding PD session at
core.

At the current stage, the accounting is applied to RPC capabilities,
signal-context capabilities, and dataspace capabilities. Capabilities
that are dynamically allocated via core's CPU and TRACE service are not
yet covered. Also, the capabilities allocated by resource multiplexers
outside of core (like nitpicker) must be accounted by the respective
servers, which is not covered yet.

If a component runs out of capabilities, core's PD service prints a
warning to the log. To observe the consumption of capabilities per
component in detail, the PD service is equipped with a diagnostic
mode, which can be enabled via the 'diag' attribute in the target
node of init's routing rules. E.g., the following route enables the
diagnostic mode for the PD session of the "timer" component:

  <default-route>
    <service name="PD" unscoped_label="timer">
      <parent diag="yes"/>
    </service>
    ...
  </default-route>

For subsystems based on a sub-init instance, init can be configured
to report the capability-quota information of its subsystems by
adding the attribute 'child_caps="yes"' to init's '<report>'
config node. Init's own capability quota can be reported by adding
the attribute 'init_caps="yes"'.

Fixes #2398
This commit is contained in:
Norman Feske 2017-05-08 21:35:43 +02:00 committed by Christian Helmuth
parent 773e08976d
commit 1f4f119b1e
105 changed files with 1494 additions and 405 deletions

View File

@ -28,13 +28,13 @@ Native_pd_component::Native_pd_component(Pd_session_component &pd_session,
: :
_pd_session(pd_session) _pd_session(pd_session)
{ {
_pd_session._thread_ep.manage(this); _pd_session._ep.manage(this);
} }
Native_pd_component::~Native_pd_component() Native_pd_component::~Native_pd_component()
{ {
_pd_session._thread_ep.dissolve(this); _pd_session._ep.dissolve(this);
} }

View File

@ -14,5 +14,6 @@
#include <base/internal/native_env.h> #include <base/internal/native_env.h>
#include <assertion.h> #include <assertion.h>
void Genode::upgrade_pd_quota_non_blocking(Genode::size_t quota) { using namespace Genode;
ASSERT_NEVER_CALLED; }
void Genode::upgrade_pd_quota_non_blocking(Ram_quota, Cap_quota) { ASSERT_NEVER_CALLED; }

View File

@ -17,9 +17,8 @@
using namespace Genode; using namespace Genode;
void Pd_session_component::upgrade_ram_quota(size_t ram_quota) void Pd_session_component::session_quota_upgraded()
{ {
_md_alloc.upgrade(ram_quota); _pd.upgrade_slab(_sliced_heap);
_pd.upgrade_slab(_md_alloc);
} }

View File

@ -16,6 +16,7 @@
/* Genode includes */ /* Genode includes */
#include <base/stdint.h> #include <base/stdint.h>
#include <base/quota_guard.h>
namespace Genode namespace Genode
{ {
@ -26,7 +27,7 @@ namespace Genode
* needed when doing upgrades in situations where the environment is * needed when doing upgrades in situations where the environment is
* already locked due to the operation that triggered the upgrade. * already locked due to the operation that triggered the upgrade.
*/ */
void upgrade_pd_quota_non_blocking(size_t); void upgrade_pd_quota_non_blocking(Ram_quota, Cap_quota);
}; };
#endif /* _INCLUDE__BASE__INTERNAL__NATIVE_ENV_H_ */ #endif /* _INCLUDE__BASE__INTERNAL__NATIVE_ENV_H_ */

View File

@ -18,8 +18,9 @@
#include <base/internal/globals.h> #include <base/internal/globals.h>
#include <base/internal/native_env.h> #include <base/internal/native_env.h>
void Genode::upgrade_pd_quota_non_blocking(size_t quota) void Genode::upgrade_pd_quota_non_blocking(Ram_quota ram, Cap_quota caps)
{ {
internal_env().parent().upgrade(Parent::Env::pd(), internal_env().parent().upgrade(Parent::Env::pd(),
String<64>("ram_quota=", quota).string()); String<100>("ram_quota=", ram, ", "
"cap_quota=", caps).string());
} }

View File

@ -109,7 +109,8 @@ Rpc_exception_code Genode::ipc_call(Native_capability dst,
} }
}, },
[&] () { upgrade_pd_quota_non_blocking(3 * 1024 * sizeof(addr_t)); }); [&] () { upgrade_pd_quota_non_blocking(Ram_quota{3 * 1024 * sizeof(addr_t)},
Cap_quota{0}); });
return Rpc_exception_code(utcb.exception_code()); return Rpc_exception_code(utcb.exception_code());
} }
@ -154,7 +155,8 @@ Genode::Rpc_request Genode::ipc_reply_wait(Reply_capability const &,
default: break; default: break;
} }
}, },
[&] () { upgrade_pd_quota_non_blocking(3 * 1024 * sizeof(addr_t)); }); [&] () { upgrade_pd_quota_non_blocking(Ram_quota{3 * 1024 * sizeof(addr_t)},
Cap_quota{0}); });
copy_utcb_to_msg(utcb, request_msg); copy_utcb_to_msg(utcb, request_msg);

View File

@ -66,13 +66,22 @@ void Signal_transmitter::submit(unsigned cnt)
Signal_receiver::Signal_receiver() Signal_receiver::Signal_receiver()
{ {
retry<Pd_session::Out_of_metadata>( for (;;) {
[&] () { _cap = internal_env().pd().alloc_signal_source(); },
[&] () { Ram_quota ram_upgrade { 0 };
log("upgrading quota donation for PD session"); Cap_quota cap_upgrade { 0 };
internal_env().upgrade(Parent::Env::pd(), "ram_quota=8K");
try {
_cap = internal_env().pd().alloc_signal_source();
break;
}
catch (Out_of_ram) { ram_upgrade = Ram_quota { 2*1024*sizeof(long) }; }
catch (Out_of_caps) { cap_upgrade = Cap_quota { 4 }; }
internal_env().upgrade(Parent::Env::pd(),
String<100>("ram_quota=", ram_upgrade, ", "
"cap_quota=", cap_upgrade).string());
} }
);
} }
@ -98,17 +107,23 @@ Signal_context_capability Signal_receiver::manage(Signal_context * const c)
Lock::Guard context_guard(c->_lock); Lock::Guard context_guard(c->_lock);
if (c->_receiver) { throw Context_already_in_use(); } if (c->_receiver) { throw Context_already_in_use(); }
retry<Pd_session::Out_of_metadata>( for (;;) {
[&] () {
Ram_quota ram_upgrade { 0 };
Cap_quota cap_upgrade { 0 };
try {
/* use signal context as imprint */ /* use signal context as imprint */
c->_cap = env_deprecated()->pd_session()->alloc_context(_cap, (unsigned long)c); c->_cap = env_deprecated()->pd_session()->alloc_context(_cap, (unsigned long)c);
c->_receiver = this; c->_receiver = this;
_contexts.insert(&c->_receiver_le); _contexts.insert(&c->_receiver_le);
return c->_cap; return c->_cap;
}, }
[&] () { upgrade_pd_quota_non_blocking(1024 * sizeof(addr_t)); }); catch (Out_of_ram) { ram_upgrade = Ram_quota { 1024*sizeof(long) }; }
catch (Out_of_caps) { cap_upgrade = Cap_quota { 4 }; }
return c->_cap; upgrade_pd_quota_non_blocking(ram_upgrade, cap_upgrade);
}
} }

View File

@ -52,7 +52,7 @@ struct Sync_root : public Root_component<Session_component>
Session_component *_create_session(char const *args) override Session_component *_create_session(char const *args) override
{ {
try { return new (md_alloc()) Session_component(*this); } try { return new (md_alloc()) Session_component(*this); }
catch (...) { throw Root::Exception(); } catch (...) { throw Root::Invalid_args(); }
} }
Sync_root(Entrypoint &ep, Allocator &md_alloc) Sync_root(Entrypoint &ep, Allocator &md_alloc)

View File

@ -122,8 +122,8 @@ namespace Genode {
* method to issue out-of-order replies to * method to issue out-of-order replies to
* 'Signal_source::wait_for_signal' calls. * 'Signal_source::wait_for_signal' calls.
*/ */
Core_pd_session_component _pd_session_component; Core_pd_session_component _pd_session_component { _entrypoint };
Pd_session_client _pd_session_client; Pd_session_client _pd_session_client { _pd_session_component.cap() };
Registry<Service> _services; Registry<Service> _services;
@ -155,9 +155,7 @@ namespace Genode {
Session::Diag{false}, Session::Diag{false},
*platform()->ram_alloc(), *platform()->ram_alloc(),
*Platform_env_base::rm_session(), *Platform_env_base::rm_session(),
Ram_session_component::any_phys_range()), Ram_session_component::any_phys_range())
_pd_session_component(_entrypoint),
_pd_session_client(_entrypoint.manage(&_pd_session_component))
{ {
_ram_session.init_ram_account(); _ram_session.init_ram_account();
} }

View File

@ -143,7 +143,7 @@ void Native_pd_component::_start(Dataspace_component &ds)
/* prefix name of Linux program (helps killing some zombies) */ /* prefix name of Linux program (helps killing some zombies) */
char const *prefix = "[Genode] "; char const *prefix = "[Genode] ";
char pname_buf[sizeof(_pd_session._label) + sizeof(prefix)]; char pname_buf[sizeof(_pd_session._label) + sizeof(prefix)];
snprintf(pname_buf, sizeof(pname_buf), "%s%s", prefix, _pd_session._label.string); snprintf(pname_buf, sizeof(pname_buf), "%s%s", prefix, _pd_session._label.string());
char *argv_buf[2]; char *argv_buf[2];
argv_buf[0] = pname_buf; argv_buf[0] = pname_buf;
argv_buf[1] = 0; argv_buf[1] = 0;
@ -184,7 +184,7 @@ Native_pd_component::Native_pd_component(Pd_session_component &pd_session,
: :
_pd_session(pd_session) _pd_session(pd_session)
{ {
_pd_session._thread_ep.manage(this); _pd_session._ep.manage(this);
} }
@ -193,14 +193,14 @@ Native_pd_component::~Native_pd_component()
if (_pid) if (_pid)
lx_kill(_pid, 9); lx_kill(_pid, 9);
_pd_session._thread_ep.dissolve(this); _pd_session._ep.dissolve(this);
} }
void Native_pd_component::start(Capability<Dataspace> binary) void Native_pd_component::start(Capability<Dataspace> binary)
{ {
/* lookup binary dataspace */ /* lookup binary dataspace */
_pd_session._thread_ep.apply(binary, [&] (Dataspace_component *ds) { _pd_session._ep.apply(binary, [&] (Dataspace_component *ds) {
if (ds) if (ds)
_start(*ds); _start(*ds);

View File

@ -28,7 +28,8 @@ struct Genode::Nova_native_pd : Pd_session::Native_pd
* \param entry server-side instruction pointer of the RPC handler * \param entry server-side instruction pointer of the RPC handler
* \param mtd NOVA message transfer descriptor * \param mtd NOVA message transfer descriptor
* *
* \throw Pd_session::Out_of_metadata * \throw Out_of_ram
* \throw Out_of_caps
* *
* \return new RPC object capability * \return new RPC object capability
*/ */
@ -41,7 +42,7 @@ struct Genode::Nova_native_pd : Pd_session::Native_pd
virtual void imprint_rpc_cap(Native_capability cap, unsigned long badge) = 0; virtual void imprint_rpc_cap(Native_capability cap, unsigned long badge) = 0;
GENODE_RPC_THROW(Rpc_alloc_rpc_cap, Native_capability, alloc_rpc_cap, GENODE_RPC_THROW(Rpc_alloc_rpc_cap, Native_capability, alloc_rpc_cap,
GENODE_TYPE_LIST(Pd_session::Out_of_metadata), GENODE_TYPE_LIST(Out_of_ram, Out_of_caps),
Native_capability, addr_t, addr_t); Native_capability, addr_t, addr_t);
GENODE_RPC(Rpc_imprint_rpc_cap, void, imprint_rpc_cap, GENODE_RPC(Rpc_imprint_rpc_cap, void, imprint_rpc_cap,
Native_capability, unsigned long); Native_capability, unsigned long);

View File

@ -24,6 +24,7 @@ Native_capability Native_pd_component::alloc_rpc_cap(Native_capability ep,
addr_t entry, addr_t mtd) addr_t entry, addr_t mtd)
{ {
try { try {
_pd_session._consume_cap(Pd_session_component::RPC_CAP);
return _pd_session._rpc_cap_factory.alloc(ep, entry, mtd); } return _pd_session._rpc_cap_factory.alloc(ep, entry, mtd); }
catch (Allocator::Out_of_memory) { throw Out_of_ram(); } catch (Allocator::Out_of_memory) { throw Out_of_ram(); }
@ -42,13 +43,13 @@ Native_pd_component::Native_pd_component(Pd_session_component &pd_session,
: :
_pd_session(pd_session) _pd_session(pd_session)
{ {
_pd_session._thread_ep.manage(this); _pd_session._ep.manage(this);
} }
Native_pd_component::~Native_pd_component() Native_pd_component::~Native_pd_component()
{ {
_pd_session._thread_ep.dissolve(this); _pd_session._ep.dissolve(this);
} }

View File

@ -34,19 +34,24 @@ Native_capability Rpc_entrypoint::_alloc_rpc_cap(Pd_session &pd, Native_capabili
Nova_native_pd_client native_pd(_native_pd_cap); Nova_native_pd_client native_pd(_native_pd_cap);
Untyped_capability new_obj_cap = for (;;) {
retry<Genode::Pd_session::Out_of_metadata>(
[&] () {
return native_pd.alloc_rpc_cap(ep, entry, 0);
},
[&] () {
internal_env().upgrade(Parent::Env::pd(), "ram_quota=16K");
});
Ram_quota ram_upgrade { 0 };
Cap_quota cap_upgrade { 0 };
try {
Untyped_capability new_obj_cap = native_pd.alloc_rpc_cap(ep, entry, 0);
native_pd.imprint_rpc_cap(new_obj_cap, new_obj_cap.local_name()); native_pd.imprint_rpc_cap(new_obj_cap, new_obj_cap.local_name());
return new_obj_cap; return new_obj_cap;
} }
catch (Out_of_ram) { ram_upgrade = Ram_quota { 2*1024*sizeof(long) }; }
catch (Out_of_caps) { cap_upgrade = Cap_quota { 4 }; }
env_deprecated()->parent()->upgrade(Parent::Env::pd(),
String<100>("ram_quota=", ram_upgrade, ", "
"cap_quota=", cap_upgrade).string());
}
}
void Rpc_entrypoint::_free_rpc_cap(Pd_session &pd, Native_capability cap) void Rpc_entrypoint::_free_rpc_cap(Pd_session &pd, Native_capability cap)

View File

@ -75,6 +75,7 @@ struct Genode::Allocator : Deallocator
* undefined in the error case * undefined in the error case
* *
* \throw Out_of_ram * \throw Out_of_ram
* \throw Out_of_caps
* *
* \return true on success * \return true on success
*/ */
@ -89,6 +90,7 @@ struct Genode::Allocator : Deallocator
* pointer will break strict-aliasing rules". * pointer will break strict-aliasing rules".
* *
* \throw Out_of_ram * \throw Out_of_ram
* \throw Out_of_caps
*/ */
template <typename T> bool alloc(size_t size, T **out_addr) template <typename T> bool alloc(size_t size, T **out_addr)
{ {
@ -114,6 +116,7 @@ struct Genode::Allocator : Deallocator
* \param size block size to allocate * \param size block size to allocate
* *
* \throw Out_of_ram * \throw Out_of_ram
* \throw Out_of_caps
* *
* \return pointer to the new block * \return pointer to the new block
*/ */

View File

@ -47,8 +47,10 @@ class Genode::Attached_io_mem_dataspace
* *
* \throw Parent::Service_denied * \throw Parent::Service_denied
* \throw Insufficient_ram_quota * \throw Insufficient_ram_quota
* \throw Insufficient_cap_quota
* \throw Parent::Unavailable * \throw Parent::Unavailable
* \throw Out_of_ram * \throw Out_of_ram
* \throw Out_of_caps
* \throw Rm_session::Attach_failed * \throw Rm_session::Attach_failed
*/ */
Attached_io_mem_dataspace(Env &env, Genode::addr_t base, Genode::size_t size, Attached_io_mem_dataspace(Env &env, Genode::addr_t base, Genode::size_t size,

View File

@ -91,6 +91,7 @@ class Genode::Attached_ram_dataspace
* Constructor * Constructor
* *
* \throw Out_of_ram * \throw Out_of_ram
* \throw Out_of_caps
* \throw Rm_session::Attach_failed * \throw Rm_session::Attach_failed
*/ */
Attached_ram_dataspace(Ram_session &ram, Region_map &rm, Attached_ram_dataspace(Ram_session &ram, Region_map &rm,

View File

@ -134,6 +134,15 @@ struct Genode::Child_policy
log("child \"", name(), "\" exited with exit value ", exit_value); log("child \"", name(), "\" exited with exit value ", exit_value);
} }
/**
* Reference PD session
*
* The PD session returned by this method is used for session cap-quota
* transfers.
*/
virtual Pd_session &ref_pd() = 0;
virtual Pd_session_capability ref_pd_cap() const = 0;
/** /**
* Reference RAM session * Reference RAM session
* *
@ -393,6 +402,7 @@ class Genode::Child : protected Rpc_object<Parent>,
* \throw Invalid_executable * \throw Invalid_executable
* \throw Region_map::Attach_failed * \throw Region_map::Attach_failed
* \throw Out_of_ram * \throw Out_of_ram
* \throw Out_of_caps
* *
* The other arguments correspond to those of 'Child::Child'. * The other arguments correspond to those of 'Child::Child'.
* *
@ -487,6 +497,25 @@ class Genode::Child : protected Rpc_object<Parent>,
Ram_transfer::Account &to = _service; Ram_transfer::Account &to = _service;
return to.cap(Ram_quota()); return to.cap(Ram_quota());
} }
/**
* Service (Cap_transfer::Account) interface
*/
void transfer(Pd_session_capability to, Cap_quota amount) override
{
Cap_transfer::Account &from = _service;
from.transfer(to, amount);
}
/**
* Service (Cap_transfer::Account) interface
*/
Pd_session_capability cap(Cap_quota) const override
{
Cap_transfer::Account &to = _service;
return to.cap(Cap_quota());
}
void wakeup() override { _service.wakeup(); } void wakeup() override { _service.wakeup(); }
bool operator == (Service const &other) const override bool operator == (Service const &other) const override
@ -662,6 +691,13 @@ class Genode::Child : protected Rpc_object<Parent>,
2*Rom_connection::RAM_QUOTA }; 2*Rom_connection::RAM_QUOTA };
} }
static Cap_quota env_cap_quota()
{
return { Cpu_connection::CAP_QUOTA + Ram_connection::CAP_QUOTA +
Pd_connection::CAP_QUOTA + Log_connection::CAP_QUOTA +
2*Rom_connection::CAP_QUOTA + 1 /* parent cap */ };
}
template <typename FN> template <typename FN>
void for_each_session(FN const &fn) const void for_each_session(FN const &fn) const
{ {
@ -676,7 +712,16 @@ class Genode::Child : protected Rpc_object<Parent>,
return _effective_quota(quota, env_ram_quota()); return _effective_quota(quota, env_ram_quota());
} }
/**
* Deduce env session costs from usable cap quota
*/
static Cap_quota effective_quota(Cap_quota quota)
{
return _effective_quota(quota, env_cap_quota());
}
Ram_session_capability ram_session_cap() const { return _ram.cap(); } Ram_session_capability ram_session_cap() const { return _ram.cap(); }
Pd_session_capability pd_session_cap() const { return _pd.cap(); }
Parent_capability parent_cap() const { return cap(); } Parent_capability parent_cap() const { return cap(); }
@ -684,6 +729,7 @@ class Genode::Child : protected Rpc_object<Parent>,
Ram_session const &ram() const { return _ram.session(); } Ram_session const &ram() const { return _ram.session(); }
Cpu_session &cpu() { return _cpu.session(); } Cpu_session &cpu() { return _cpu.session(); }
Pd_session &pd() { return _pd .session(); } Pd_session &pd() { return _pd .session(); }
Pd_session const &pd() const { return _pd .session(); }
/** /**
* Request factory for creating session-state objects * Request factory for creating session-state objects

View File

@ -52,10 +52,17 @@ class Genode::Connection_base : public Noncopyable
*/ */
Connection_base(); Connection_base();
void upgrade(Session::Resources resources)
{
String<80> const args("ram_quota=", resources.ram_quota, ", "
"cap_quota=", resources.cap_quota);
_env.upgrade(_id_space_element.id(), args.string());
}
void upgrade_ram(size_t bytes) void upgrade_ram(size_t bytes)
{ {
String<64> const args("ram_quota=", Ram_quota{bytes}); upgrade(Session::Resources { Ram_quota{bytes}, Cap_quota{0} });
_env.upgrade(_id_space_element.id(), args.string());
} }
}; };

View File

@ -93,8 +93,12 @@ struct Genode::Env
* \param affinity preferred CPU affinity for the session * \param affinity preferred CPU affinity for the session
* *
* \throw Service_denied * \throw Service_denied
* \throw Insufficient_cap_quota
* \throw Insufficient_ram_quota * \throw Insufficient_ram_quota
* \throw Unavailable * \throw Out_of_caps
* \throw Out_of_ram
*
* See the documentation of 'Parent::session'.
* *
* This method blocks until the session is available or an error * This method blocks until the session is available or an error
* occurred. * occurred.
@ -116,6 +120,9 @@ struct Genode::Env
* \param args description of the amount of quota to transfer * \param args description of the amount of quota to transfer
* *
* \throw Out_of_ram * \throw Out_of_ram
* \throw Out_of_caps
*
* See the documentation of 'Parent::upgrade'.
* *
* The 'args' argument has the same principle format as the 'args' * The 'args' argument has the same principle format as the 'args'
* argument of the 'session' operation. * argument of the 'session' operation.

View File

@ -39,7 +39,7 @@ struct Genode::Local_connection_base : Noncopyable
private: private:
static Args _init_args(Args const &args, size_t const &ram_quota, static Args _init_args(Args const &args, Session::Resources resources,
Session::Diag diag) Session::Diag diag)
{ {
/* copy original arguments into modifiable buffer */ /* copy original arguments into modifiable buffer */
@ -47,7 +47,9 @@ struct Genode::Local_connection_base : Noncopyable
strncpy(buf, args.string(), sizeof(buf)); strncpy(buf, args.string(), sizeof(buf));
Arg_string::set_arg(buf, sizeof(buf), "ram_quota", Arg_string::set_arg(buf, sizeof(buf), "ram_quota",
String<64>(ram_quota).string()); String<64>(resources.ram_quota.value).string());
Arg_string::set_arg(buf, sizeof(buf), "cap_quota",
String<64>(resources.cap_quota.value).string());
Arg_string::set_arg(buf, sizeof(buf), "diag", diag.enabled); Arg_string::set_arg(buf, sizeof(buf), "diag", diag.enabled);
/* return result as a copy */ /* return result as a copy */
@ -62,23 +64,35 @@ struct Genode::Local_connection_base : Noncopyable
Args const &args, Affinity const &affinity, Args const &args, Affinity const &affinity,
Session::Label const &label, Session::Label const &label,
Session::Diag diag, Session::Diag diag,
size_t ram_quota) Session::Resources resources)
{ {
enum { NUM_ATTEMPTS = 10 }; enum { NUM_ATTEMPTS = 10 };
for (unsigned i = 0; i < NUM_ATTEMPTS; i++) { for (unsigned i = 0; i < NUM_ATTEMPTS; i++) {
_session_state.construct(service, id_space, id, label, _session_state.construct(service, id_space, id, label,
_init_args(args, ram_quota, diag), _init_args(args, resources, diag),
affinity); affinity);
_session_state->service().initiate_request(*_session_state); _session_state->service().initiate_request(*_session_state);
if (_session_state->phase == Session_state::INSUFFICIENT_RAM_QUOTA) if (_session_state->alive())
ram_quota += 4096;
else
break; break;
switch (_session_state->phase) {
case Session_state::INSUFFICIENT_RAM_QUOTA:
resources.ram_quota.value += 4096;
break;
case Session_state::INSUFFICIENT_CAP_QUOTA:
resources.cap_quota.value += 1;
break;
default: break;
}
} }
if (_session_state->phase == Session_state::INSUFFICIENT_RAM_QUOTA) if (_session_state->phase == Session_state::INSUFFICIENT_RAM_QUOTA
|| _session_state->phase == Session_state::INSUFFICIENT_CAP_QUOTA)
warning("giving up to increase session quota for ", service.name(), " session " warning("giving up to increase session quota for ", service.name(), " session "
"after ", (int)NUM_ATTEMPTS, " attempts"); "after ", (int)NUM_ATTEMPTS, " attempts");
} }
@ -153,7 +167,8 @@ class Genode::Local_connection : Local_connection_base
Local_connection_base(service, id_space, id, args, affinity, Local_connection_base(service, id_space, id, args, affinity,
label.valid() ? label : label_from_args(args.string()), label.valid() ? label : label_from_args(args.string()),
diag, diag,
CONNECTION::RAM_QUOTA) Session::Resources { Ram_quota { CONNECTION::RAM_QUOTA },
Cap_quota { CONNECTION::CAP_QUOTA } })
{ {
service.wakeup(); service.wakeup();
} }

View File

@ -16,6 +16,7 @@
#include <util/list.h> #include <util/list.h>
#include <ram_session/client.h> #include <ram_session/client.h>
#include <pd_session/client.h>
#include <base/env.h> #include <base/env.h>
#include <base/session_state.h> #include <base/session_state.h>
#include <base/log.h> #include <base/log.h>
@ -33,7 +34,8 @@ namespace Genode {
} }
class Genode::Service : public Ram_transfer::Account class Genode::Service : public Ram_transfer::Account,
public Cap_transfer::Account
{ {
public: public:
@ -126,6 +128,7 @@ class Genode::Local_service : public Service
* *
* \throw Denied * \throw Denied
* \throw Insufficient_ram_quota * \throw Insufficient_ram_quota
* \throw Insufficient_cap_quota
*/ */
virtual SESSION &create(Args const &, Affinity) = 0; virtual SESSION &create(Args const &, Affinity) = 0;
@ -192,6 +195,8 @@ class Genode::Local_service : public Service
} }
catch (typename Factory::Denied) { catch (typename Factory::Denied) {
session.phase = Session_state::INVALID_ARGS; } session.phase = Session_state::INVALID_ARGS; }
catch (Insufficient_cap_quota) {
session.phase = Session_state::INSUFFICIENT_CAP_QUOTA; }
catch (Insufficient_ram_quota) { catch (Insufficient_ram_quota) {
session.phase = Session_state::INSUFFICIENT_RAM_QUOTA; } session.phase = Session_state::INSUFFICIENT_RAM_QUOTA; }
@ -199,7 +204,8 @@ class Genode::Local_service : public Service
case Session_state::UPGRADE_REQUESTED: case Session_state::UPGRADE_REQUESTED:
{ {
String<64> const args("ram_quota=", session.ram_upgrade); String<100> const args("ram_quota=", session.ram_upgrade, ", "
"cap_quota=", session.cap_upgrade);
_apply_to_rpc_obj(session, [&] (SESSION &rpc_obj) { _apply_to_rpc_obj(session, [&] (SESSION &rpc_obj) {
_factory.upgrade(rpc_obj, args.string()); }); _factory.upgrade(rpc_obj, args.string()); });
@ -220,6 +226,7 @@ class Genode::Local_service : public Service
case Session_state::INVALID_ARGS: case Session_state::INVALID_ARGS:
case Session_state::INSUFFICIENT_RAM_QUOTA: case Session_state::INSUFFICIENT_RAM_QUOTA:
case Session_state::INSUFFICIENT_CAP_QUOTA:
case Session_state::AVAILABLE: case Session_state::AVAILABLE:
case Session_state::CAP_HANDED_OUT: case Session_state::CAP_HANDED_OUT:
case Session_state::CLOSED: case Session_state::CLOSED:
@ -279,10 +286,19 @@ class Genode::Parent_service : public Service
catch (Out_of_ram) { catch (Out_of_ram) {
session.id_at_parent.destruct(); session.id_at_parent.destruct();
session.phase = Session_state::INVALID_ARGS; } session.phase = Session_state::INVALID_ARGS; }
catch (Out_of_caps) {
session.id_at_parent.destruct();
session.phase = Session_state::INVALID_ARGS; }
catch (Insufficient_ram_quota) { catch (Insufficient_ram_quota) {
session.id_at_parent.destruct(); session.id_at_parent.destruct();
session.phase = Session_state::INSUFFICIENT_RAM_QUOTA; } session.phase = Session_state::INSUFFICIENT_RAM_QUOTA; }
catch (Insufficient_cap_quota) {
session.id_at_parent.destruct();
session.phase = Session_state::INSUFFICIENT_CAP_QUOTA; }
catch (Parent::Service_denied) { catch (Parent::Service_denied) {
session.id_at_parent.destruct(); session.id_at_parent.destruct();
session.phase = Session_state::INVALID_ARGS; } session.phase = Session_state::INVALID_ARGS; }
@ -291,7 +307,8 @@ class Genode::Parent_service : public Service
case Session_state::UPGRADE_REQUESTED: case Session_state::UPGRADE_REQUESTED:
{ {
String<64> const args("ram_quota=", session.ram_upgrade); String<100> const args("ram_quota=", session.ram_upgrade, ", "
"cap_quota=", session.cap_upgrade);
if (!session.id_at_parent.constructed()) if (!session.id_at_parent.constructed())
error("invalid parent-session state: ", session); error("invalid parent-session state: ", session);
@ -300,6 +317,8 @@ class Genode::Parent_service : public Service
_env.upgrade(session.id_at_parent->id(), args.string()); } _env.upgrade(session.id_at_parent->id(), args.string()); }
catch (Out_of_ram) { catch (Out_of_ram) {
warning("RAM quota exceeded while upgrading parent session"); } warning("RAM quota exceeded while upgrading parent session"); }
catch (Out_of_caps) {
warning("cap quota exceeded while upgrading parent session"); }
session.confirm_ram_upgrade(); session.confirm_ram_upgrade();
session.phase = Session_state::CAP_HANDED_OUT; session.phase = Session_state::CAP_HANDED_OUT;
@ -317,6 +336,7 @@ class Genode::Parent_service : public Service
case Session_state::INVALID_ARGS: case Session_state::INVALID_ARGS:
case Session_state::INSUFFICIENT_RAM_QUOTA: case Session_state::INSUFFICIENT_RAM_QUOTA:
case Session_state::INSUFFICIENT_CAP_QUOTA:
case Session_state::AVAILABLE: case Session_state::AVAILABLE:
case Session_state::CAP_HANDED_OUT: case Session_state::CAP_HANDED_OUT:
case Session_state::CLOSED: case Session_state::CLOSED:
@ -398,6 +418,7 @@ class Genode::Child_service : public Async_service
private: private:
Ram_session_client _ram; Ram_session_client _ram;
Pd_session_client _pd;
public: public:
@ -408,10 +429,11 @@ class Genode::Child_service : public Async_service
Id_space<Parent::Server> &server_id_space, Id_space<Parent::Server> &server_id_space,
Session_state::Factory &factory, Session_state::Factory &factory,
Wakeup &wakeup, Wakeup &wakeup,
Ram_session_capability ram) Ram_session_capability ram,
Pd_session_capability pd)
: :
Async_service(name, server_id_space, factory, wakeup), Async_service(name, server_id_space, factory, wakeup),
_ram(ram) _ram(ram), _pd(pd)
{ } { }
/** /**
@ -426,6 +448,19 @@ class Genode::Child_service : public Async_service
* Ram_transfer::Account interface * Ram_transfer::Account interface
*/ */
Ram_session_capability cap(Ram_quota) const override { return _ram; } Ram_session_capability cap(Ram_quota) const override { return _ram; }
/**
* Cap_transfer::Account interface
*/
void transfer(Pd_session_capability to, Cap_quota amount) override
{
if (to.valid()) _pd.transfer_quota(to, amount);
}
/**
* Cap_transfer::Account interface
*/
Pd_session_capability cap(Cap_quota) const override { return _pd; }
}; };
#endif /* _INCLUDE__BASE__SERVICE_H_ */ #endif /* _INCLUDE__BASE__SERVICE_H_ */

View File

@ -65,12 +65,14 @@ class Genode::Session_object : public Ram_quota_guard,
Cap_quota_guard(resources.cap_quota), Cap_quota_guard(resources.cap_quota),
_ep(ep), _diag(diag), _label(label) _ep(ep), _diag(diag), _label(label)
{ {
Cap_quota_guard::withdraw(Cap_quota{1});
_ep.manage(this); _ep.manage(this);
} }
~Session_object() ~Session_object()
{ {
_ep.dissolve(this); _ep.dissolve(this);
Cap_quota_guard::replenish(Cap_quota{1});
} }
/** /**

View File

@ -59,6 +59,7 @@ class Genode::Session_state : public Parent::Client, public Parent::Server,
* Total of quota associated with this session * Total of quota associated with this session
*/ */
Ram_quota _donated_ram_quota { 0 }; Ram_quota _donated_ram_quota { 0 };
Cap_quota _donated_cap_quota { 0 };
Factory *_factory = nullptr; Factory *_factory = nullptr;
@ -80,6 +81,7 @@ class Genode::Session_state : public Parent::Client, public Parent::Server,
enum Phase { CREATE_REQUESTED, enum Phase { CREATE_REQUESTED,
INVALID_ARGS, INVALID_ARGS,
INSUFFICIENT_RAM_QUOTA, INSUFFICIENT_RAM_QUOTA,
INSUFFICIENT_CAP_QUOTA,
AVAILABLE, AVAILABLE,
CAP_HANDED_OUT, CAP_HANDED_OUT,
UPGRADE_REQUESTED, UPGRADE_REQUESTED,
@ -107,6 +109,7 @@ class Genode::Session_state : public Parent::Client, public Parent::Server,
Session_capability cap; Session_capability cap;
Ram_quota ram_upgrade { 0 }; Ram_quota ram_upgrade { 0 };
Cap_quota cap_upgrade { 0 };
void print(Output &out) const; void print(Output &out) const;
@ -150,10 +153,13 @@ class Genode::Session_state : public Parent::Client, public Parent::Server,
ram_upgrade = Ram_quota { 0 }; ram_upgrade = Ram_quota { 0 };
} }
void increase_donated_quota(Ram_quota added_ram_quota) void increase_donated_quota(Ram_quota added_ram_quota,
Cap_quota added_cap_quota)
{ {
_donated_ram_quota.value += added_ram_quota.value; _donated_ram_quota.value += added_ram_quota.value;
_donated_cap_quota.value += added_cap_quota.value;
ram_upgrade = added_ram_quota; ram_upgrade = added_ram_quota;
cap_upgrade = added_cap_quota;
} }
Parent::Client::Id id_at_client() const Parent::Client::Id id_at_client() const
@ -178,6 +184,7 @@ class Genode::Session_state : public Parent::Client, public Parent::Server,
void generate_server_side_info(Xml_generator &, Detail detail) const; void generate_server_side_info(Xml_generator &, Detail detail) const;
Ram_quota donated_ram_quota() const { return _donated_ram_quota; } Ram_quota donated_ram_quota() const { return _donated_ram_quota; }
Cap_quota donated_cap_quota() const { return _donated_cap_quota; }
bool alive() const bool alive() const
{ {
@ -186,6 +193,7 @@ class Genode::Session_state : public Parent::Client, public Parent::Server,
case CREATE_REQUESTED: case CREATE_REQUESTED:
case INVALID_ARGS: case INVALID_ARGS:
case INSUFFICIENT_RAM_QUOTA: case INSUFFICIENT_RAM_QUOTA:
case INSUFFICIENT_CAP_QUOTA:
case CLOSED: case CLOSED:
return false; return false;

View File

@ -57,9 +57,8 @@ class Genode::Parent
** Exception types ** ** Exception types **
*********************/ *********************/
class Exception : public ::Genode::Exception { }; struct Service_denied : Exception { };
class Service_denied : public Exception { }; struct Unavailable : Exception { };
class Unavailable : public Exception { };
typedef Rpc_in_buffer<64> Service_name; typedef Rpc_in_buffer<64> Service_name;
typedef Rpc_in_buffer<160> Session_args; typedef Rpc_in_buffer<160> Session_args;
@ -160,7 +159,9 @@ class Genode::Parent
* \param affinity preferred CPU affinity for the session * \param affinity preferred CPU affinity for the session
* *
* \throw Service_denied parent denies session request * \throw Service_denied parent denies session request
* \throw Insufficient_cap_quota donated cap quota does not suffice
* \throw Insufficient_ram_quota donated RAM quota does not suffice * \throw Insufficient_ram_quota donated RAM quota does not suffice
* \throw Out_of_caps session CAP quota exceeds our resources
* \throw Out_of_ram session RAM quota exceeds our resources * \throw Out_of_ram session RAM quota exceeds our resources
* *
* \return session capability of the new session is immediately * \return session capability of the new session is immediately
@ -182,8 +183,11 @@ class Genode::Parent
* Request session capability * Request session capability
* *
* \throw Service_denied * \throw Service_denied
* \throw Insufficient_cap_quota
* \throw Insufficient_ram_quota * \throw Insufficient_ram_quota
* *
* See 'session' for more documentation.
*
* In the exception case, the parent implicitly closes the session. * In the exception case, the parent implicitly closes the session.
*/ */
virtual Session_capability session_cap(Client::Id id) = 0; virtual Session_capability session_cap(Client::Id id) = 0;
@ -196,6 +200,7 @@ class Genode::Parent
* \param id ID of recipient session * \param id ID of recipient session
* \param args description of the amount of quota to transfer * \param args description of the amount of quota to transfer
* *
* \throw Out_of_caps
* \throw Out_of_ram * \throw Out_of_ram
* *
* The 'args' argument has the same principle format as the 'args' * The 'args' argument has the same principle format as the 'args'
@ -216,7 +221,7 @@ class Genode::Parent
*/ */
enum Session_response { SESSION_OK, SESSION_CLOSED, INVALID_ARGS, enum Session_response { SESSION_OK, SESSION_CLOSED, INVALID_ARGS,
INSUFFICIENT_RAM_QUOTA }; INSUFFICIENT_RAM_QUOTA, INSUFFICIENT_CAP_QUOTA };
/** /**
* Set state of a session provided by the child service * Set state of a session provided by the child service
@ -294,16 +299,17 @@ class Genode::Parent
Service_name const &); Service_name const &);
GENODE_RPC(Rpc_session_sigh, void, session_sigh, Signal_context_capability); GENODE_RPC(Rpc_session_sigh, void, session_sigh, Signal_context_capability);
GENODE_RPC_THROW(Rpc_session, Session_capability, session, GENODE_RPC_THROW(Rpc_session, Session_capability, session,
GENODE_TYPE_LIST(Service_denied, Out_of_ram, GENODE_TYPE_LIST(Service_denied, Out_of_caps,
Out_of_ram, Insufficient_cap_quota,
Insufficient_ram_quota, Unavailable), Insufficient_ram_quota, Unavailable),
Client::Id, Service_name const &, Session_args const &, Client::Id, Service_name const &, Session_args const &,
Affinity const &); Affinity const &);
GENODE_RPC_THROW(Rpc_session_cap, Session_capability, session_cap, GENODE_RPC_THROW(Rpc_session_cap, Session_capability, session_cap,
GENODE_TYPE_LIST(Service_denied, GENODE_TYPE_LIST(Service_denied, Insufficient_cap_quota,
Insufficient_ram_quota, Unavailable), Insufficient_ram_quota, Unavailable),
Client::Id); Client::Id);
GENODE_RPC_THROW(Rpc_upgrade, Upgrade_result, upgrade, GENODE_RPC_THROW(Rpc_upgrade, Upgrade_result, upgrade,
GENODE_TYPE_LIST(Out_of_ram), GENODE_TYPE_LIST(Out_of_ram, Out_of_caps),
Client::Id, Upgrade_args const &); Client::Id, Upgrade_args const &);
GENODE_RPC(Rpc_close, Close_result, close, Client::Id); GENODE_RPC(Rpc_close, Close_result, close, Client::Id);
GENODE_RPC(Rpc_session_response, void, session_response, GENODE_RPC(Rpc_session_response, void, session_response,

View File

@ -62,6 +62,15 @@ struct Genode::Pd_session_client : Rpc_client<Pd_session>
Capability<Region_map> linker_area() override { Capability<Region_map> linker_area() override {
return call<Rpc_linker_area>(); } return call<Rpc_linker_area>(); }
void ref_account(Capability<Pd_session> pd) override {
call<Rpc_ref_account>(pd); }
void transfer_quota(Capability<Pd_session> pd, Cap_quota amount) override {
call<Rpc_transfer_cap_quota>(pd, amount); }
Cap_quota cap_quota() const { return call<Rpc_cap_quota>(); }
Cap_quota used_caps() const { return call<Rpc_used_caps>(); }
Capability<Native_pd> native_pd() override { return call<Rpc_native_pd>(); } Capability<Native_pd> native_pd() override { return call<Rpc_native_pd>(); }
}; };

View File

@ -71,7 +71,8 @@ struct Genode::Pd_session : Session
typedef Capability<Signal_source> Signal_source_capability; typedef Capability<Signal_source> Signal_source_capability;
class Out_of_metadata : public Exception { }; class Invalid_session : public Exception { };
class Undefined_ref_account : public Exception { };
class Invalid_signal_source : public Exception { }; class Invalid_signal_source : public Exception { };
/** /**
@ -81,7 +82,8 @@ struct Genode::Pd_session : Session
* *
* The signal source provides an interface to wait for incoming signals. * The signal source provides an interface to wait for incoming signals.
* *
* \throw Out_of_metadata * \throw Out_of_ram
* \throw Out_of_caps
*/ */
virtual Signal_source_capability alloc_signal_source() = 0; virtual Signal_source_capability alloc_signal_source() = 0;
@ -102,7 +104,8 @@ struct Genode::Pd_session : Session
* originating from the allocated signal-context capability * originating from the allocated signal-context capability
* \return new signal-context capability * \return new signal-context capability
* *
* \throw Out_of_metadata * \throw Out_of_ram
* \throw Out_of_caps
* \throw Invalid_signal_source * \throw Invalid_signal_source
*/ */
virtual Capability<Signal_context> virtual Capability<Signal_context>
@ -141,7 +144,8 @@ struct Genode::Pd_session : Session
* *
* \param ep entry point that will use this capability * \param ep entry point that will use this capability
* *
* \throw Out_of_metadata if meta-data backing store is exhausted * \throw Out_of_ram if meta-data backing store is exhausted
* \throw Out_of_caps if 'cap_quota' is exceeded
* *
* \return new RPC capability * \return new RPC capability
*/ */
@ -177,6 +181,49 @@ struct Genode::Pd_session : Session
virtual Capability<Region_map> linker_area() = 0; virtual Capability<Region_map> linker_area() = 0;
/*******************************************
** Accounting for capability allocations **
*******************************************/
/**
* Define reference account for the PD session
*
* \throw Invalid_session
*/
virtual void ref_account(Capability<Pd_session>) = 0;
/**
* Transfer capability quota to another PD session
*
* \param pd_session receiver of quota donation
* \param amount amount of quota to donate
*
* \throw Out_of_caps
* \throw Invalid_session
* \throw Undefined_ref_account
*
* Quota can only be transfered if the specified PD session is either the
* reference account for this session or vice versa.
*/
virtual void transfer_quota(Capability<Pd_session> pd_session,
Cap_quota amount) = 0;
/**
* Return current capability-quota limit
*/
virtual Cap_quota cap_quota() const = 0;
/**
* Return number of capabilities allocated from the session
*/
virtual Cap_quota used_caps() const = 0;
Cap_quota avail_caps() const
{
return Cap_quota { cap_quota().value - used_caps().value };
}
/***************************************** /*****************************************
** Access to kernel-specific interface ** ** Access to kernel-specific interface **
*****************************************/ *****************************************/
@ -200,30 +247,41 @@ struct Genode::Pd_session : Session
GENODE_RPC(Rpc_assign_pci, bool, assign_pci, addr_t, uint16_t); GENODE_RPC(Rpc_assign_pci, bool, assign_pci, addr_t, uint16_t);
GENODE_RPC_THROW(Rpc_alloc_signal_source, Signal_source_capability, GENODE_RPC_THROW(Rpc_alloc_signal_source, Signal_source_capability,
alloc_signal_source, GENODE_TYPE_LIST(Out_of_metadata)); alloc_signal_source,
GENODE_TYPE_LIST(Out_of_ram, Out_of_caps));
GENODE_RPC(Rpc_free_signal_source, void, free_signal_source, Signal_source_capability); GENODE_RPC(Rpc_free_signal_source, void, free_signal_source, Signal_source_capability);
GENODE_RPC_THROW(Rpc_alloc_context, Capability<Signal_context>, alloc_context, GENODE_RPC_THROW(Rpc_alloc_context, Capability<Signal_context>, alloc_context,
GENODE_TYPE_LIST(Out_of_metadata, Invalid_signal_source), GENODE_TYPE_LIST(Out_of_ram, Out_of_caps, Invalid_signal_source),
Signal_source_capability, unsigned long); Signal_source_capability, unsigned long);
GENODE_RPC(Rpc_free_context, void, free_context, GENODE_RPC(Rpc_free_context, void, free_context,
Capability<Signal_context>); Capability<Signal_context>);
GENODE_RPC(Rpc_submit, void, submit, Capability<Signal_context>, unsigned); GENODE_RPC(Rpc_submit, void, submit, Capability<Signal_context>, unsigned);
GENODE_RPC_THROW(Rpc_alloc_rpc_cap, Native_capability, alloc_rpc_cap, GENODE_RPC_THROW(Rpc_alloc_rpc_cap, Native_capability, alloc_rpc_cap,
GENODE_TYPE_LIST(Out_of_metadata), Native_capability); GENODE_TYPE_LIST(Out_of_ram, Out_of_caps), Native_capability);
GENODE_RPC(Rpc_free_rpc_cap, void, free_rpc_cap, Native_capability); GENODE_RPC(Rpc_free_rpc_cap, void, free_rpc_cap, Native_capability);
GENODE_RPC(Rpc_address_space, Capability<Region_map>, address_space); GENODE_RPC(Rpc_address_space, Capability<Region_map>, address_space);
GENODE_RPC(Rpc_stack_area, Capability<Region_map>, stack_area); GENODE_RPC(Rpc_stack_area, Capability<Region_map>, stack_area);
GENODE_RPC(Rpc_linker_area, Capability<Region_map>, linker_area); GENODE_RPC(Rpc_linker_area, Capability<Region_map>, linker_area);
GENODE_RPC_THROW(Rpc_ref_account, void, ref_account,
GENODE_TYPE_LIST(Invalid_session), Capability<Pd_session>);
GENODE_RPC_THROW(Rpc_transfer_cap_quota, void, transfer_quota,
GENODE_TYPE_LIST(Out_of_caps, Invalid_session, Undefined_ref_account),
Capability<Pd_session>, Cap_quota);
GENODE_RPC(Rpc_cap_quota, Cap_quota, cap_quota);
GENODE_RPC(Rpc_used_caps, Cap_quota, used_caps);
GENODE_RPC(Rpc_native_pd, Capability<Native_pd>, native_pd); GENODE_RPC(Rpc_native_pd, Capability<Native_pd>, native_pd);
GENODE_RPC_INTERFACE(Rpc_assign_parent, Rpc_assign_pci, GENODE_RPC_INTERFACE(Rpc_assign_parent, Rpc_assign_pci,
Rpc_alloc_signal_source, Rpc_free_signal_source, Rpc_alloc_signal_source, Rpc_free_signal_source,
Rpc_alloc_context, Rpc_free_context, Rpc_submit, Rpc_alloc_context, Rpc_free_context, Rpc_submit,
Rpc_alloc_rpc_cap, Rpc_free_rpc_cap, Rpc_address_space, Rpc_alloc_rpc_cap, Rpc_free_rpc_cap, Rpc_address_space,
Rpc_stack_area, Rpc_linker_area, Rpc_native_pd); Rpc_stack_area, Rpc_linker_area, Rpc_ref_account,
Rpc_transfer_cap_quota, Rpc_cap_quota, Rpc_used_caps,
Rpc_native_pd);
}; };
#endif /* _INCLUDE__PD_SESSION__PD_SESSION_H_ */ #endif /* _INCLUDE__PD_SESSION__PD_SESSION_H_ */

View File

@ -26,7 +26,7 @@ class Genode::Rom_connection : public Connection<Rom_session>,
{ {
public: public:
class Rom_connection_failed : public Parent::Exception { }; class Rom_connection_failed : public Parent::Service_denied { };
enum { RAM_QUOTA = 6*1024UL }; enum { RAM_QUOTA = 6*1024UL };

View File

@ -151,6 +151,24 @@ class Genode::Root_component : public Rpc_object<Typed_root<SESSION_TYPE> >,
Ram_quota const remaining_ram_quota { ram_quota.value - needed }; Ram_quota const remaining_ram_quota { ram_quota.value - needed };
/*
* Validate that the client provided the amount of caps as mandated
* for the session interface.
*/
Cap_quota const cap_quota = cap_quota_from_args(args.string());
if (cap_quota.value < SESSION_TYPE::CAP_QUOTA)
throw Insufficient_cap_quota();
/*
* Account for the dataspace capability needed for allocating the
* session object from the sliced heap.
*/
if (cap_quota.value < 1)
throw Insufficient_cap_quota();
Cap_quota const remaining_cap_quota { cap_quota.value - 1 };
/* /*
* Deduce ram quota needed for allocating the session object from the * Deduce ram quota needed for allocating the session object from the
* donated ram quota. * donated ram quota.
@ -162,9 +180,13 @@ class Genode::Root_component : public Rpc_object<Typed_root<SESSION_TYPE> >,
Arg_string::set_arg(adjusted_args, sizeof(adjusted_args), Arg_string::set_arg(adjusted_args, sizeof(adjusted_args),
"ram_quota", String<64>(remaining_ram_quota).string()); "ram_quota", String<64>(remaining_ram_quota).string());
Arg_string::set_arg(adjusted_args, sizeof(adjusted_args),
"cap_quota", String<64>(remaining_cap_quota).string());
SESSION_TYPE *s = 0; SESSION_TYPE *s = 0;
try { s = _create_session(adjusted_args, affinity); } try { s = _create_session(adjusted_args, affinity); }
catch (Out_of_ram) { throw Insufficient_ram_quota(); } catch (Out_of_ram) { throw Insufficient_ram_quota(); }
catch (Out_of_caps) { throw Insufficient_cap_quota(); }
/* /*
* Consider that the session-object constructor may already have * Consider that the session-object constructor may already have
@ -281,7 +303,9 @@ class Genode::Root_component : public Rpc_object<Typed_root<SESSION_TYPE> >,
{ {
try { try {
return _create(args, affinity); } return _create(args, affinity); }
catch (Insufficient_ram_quota) { throw; } catch (Insufficient_ram_quota) { throw; }
catch (Insufficient_cap_quota) { throw; }
catch (...) { catch (...) {
throw typename Local_service<SESSION_TYPE>::Factory::Denied(); } throw typename Local_service<SESSION_TYPE>::Factory::Denied(); }
} }

View File

@ -33,9 +33,7 @@ struct Genode::Root
** Exception types ** ** Exception types **
*********************/ *********************/
class Exception : public ::Genode::Exception { };
class Unavailable : public Exception { }; class Unavailable : public Exception { };
class Quota_exceeded : public Exception { };
class Invalid_args : public Exception { }; class Invalid_args : public Exception { };
typedef Rpc_in_buffer<160> Session_args; typedef Rpc_in_buffer<160> Session_args;
@ -48,6 +46,7 @@ struct Genode::Root
* *
* \throw Unavailable * \throw Unavailable
* \throw Insufficient_ram_quota * \throw Insufficient_ram_quota
* \throw Insufficient_cap_quota
* \throw Invalid_args * \throw Invalid_args
* *
* \return capability to new session * \return capability to new session
@ -72,7 +71,7 @@ struct Genode::Root
GENODE_RPC_THROW(Rpc_session, Session_capability, session, GENODE_RPC_THROW(Rpc_session, Session_capability, session,
GENODE_TYPE_LIST(Unavailable, Insufficient_ram_quota, GENODE_TYPE_LIST(Unavailable, Insufficient_ram_quota,
Invalid_args), Insufficient_cap_quota, Invalid_args),
Session_args const &, Affinity const &); Session_args const &, Affinity const &);
GENODE_RPC_THROW(Rpc_upgrade, void, upgrade, GENODE_RPC_THROW(Rpc_upgrade, void, upgrade,
GENODE_TYPE_LIST(Invalid_args), GENODE_TYPE_LIST(Invalid_args),

View File

@ -188,7 +188,7 @@ _ZN6Genode18server_socket_pairEv T
_ZN6Genode20env_session_id_spaceEv T _ZN6Genode20env_session_id_spaceEv T
_ZN6Genode25env_stack_area_region_mapE B 4 _ZN6Genode25env_stack_area_region_mapE B 4
_ZN6Genode26env_stack_area_ram_sessionE B 4 _ZN6Genode26env_stack_area_ram_sessionE B 4
_ZN6Genode29upgrade_pd_quota_non_blockingEm T _ZN6Genode29upgrade_pd_quota_non_blockingENS_9Ram_quotaENS_9Cap_quotaE T
_ZN6Genode3Log3logEv T _ZN6Genode3Log3logEv T
_ZN6Genode3Log8_acquireENS0_4TypeE T _ZN6Genode3Log8_acquireENS0_4TypeE T
_ZN6Genode3Log8_releaseEv T _ZN6Genode3Log8_releaseEv T

View File

@ -115,7 +115,6 @@ namespace Genode {
Rpc_entrypoint _entrypoint; Rpc_entrypoint _entrypoint;
Core_region_map _region_map; Core_region_map _region_map;
Ram_session_component _ram_session; Ram_session_component _ram_session;
Ram_session_capability _ram_session_cap;
Synced_ram_session _synced_ram_session { _ram_session }; Synced_ram_session _synced_ram_session { _ram_session };
/* /*
@ -159,7 +158,8 @@ namespace Genode {
_region_map, _region_map,
Ram_session_component::any_phys_range()), Ram_session_component::any_phys_range()),
_pd_session_component(_entrypoint), _pd_session_component(_entrypoint),
_pd_session_client(_entrypoint.manage(&_pd_session_component)) _pd_session_client(_pd_session_component.cap()),
_heap(_ram_session, _region_map)
{ {
_ram_session.init_ram_account(); _ram_session.init_ram_account();
} }
@ -192,7 +192,7 @@ namespace Genode {
Cpu_session_capability cpu_session_cap() override Cpu_session_capability cpu_session_cap() override
{ {
warning(__func__, " not implemented"); warning(__FILE__, ":", __LINE__, " not implemented");
return Cpu_session_capability(); return Cpu_session_capability();
} }

View File

@ -30,20 +30,17 @@ class Genode::Core_pd_session_component : public Rpc_object<Pd_session>
{ {
private: private:
Rpc_entrypoint &_signal_source_ep; Rpc_entrypoint &_ep;
public: public:
/** /**
* Constructor * Constructor
*
* \param context_ep entrypoint that serves the signal-source
* components
*/ */
Core_pd_session_component(Rpc_entrypoint &signal_source_ep) Core_pd_session_component(Rpc_entrypoint &ep) : _ep(ep)
: {
_signal_source_ep(signal_source_ep) ep.manage(this);
{ } }
void assign_parent(Capability<Parent> parent) override void assign_parent(Capability<Parent> parent) override
{ {
@ -83,7 +80,7 @@ class Genode::Core_pd_session_component : public Rpc_object<Pd_session>
void submit(Capability<Signal_context> cap, unsigned cnt = 1) override void submit(Capability<Signal_context> cap, unsigned cnt = 1) override
{ {
_signal_source_ep.apply(cap, [&] (Signal_context_component *context) { _ep.apply(cap, [&] (Signal_context_component *context) {
if (!context) { if (!context) {
warning("invalid signal-context capability"); warning("invalid signal-context capability");
return; return;
@ -103,11 +100,17 @@ class Genode::Core_pd_session_component : public Rpc_object<Pd_session>
ASSERT_NEVER_CALLED; ASSERT_NEVER_CALLED;
} }
Capability<Region_map> address_space() { ASSERT_NEVER_CALLED; } Capability<Region_map> address_space() override { ASSERT_NEVER_CALLED; }
Capability<Region_map> stack_area() override { ASSERT_NEVER_CALLED; }
Capability<Region_map> linker_area() override { ASSERT_NEVER_CALLED; }
Capability<Region_map> stack_area() { ASSERT_NEVER_CALLED; } void ref_account(Capability<Pd_session>) override { ASSERT_NEVER_CALLED; }
Capability<Region_map> linker_area() { ASSERT_NEVER_CALLED; } void transfer_quota(Capability<Pd_session>, Cap_quota) override {
ASSERT_NEVER_CALLED; }
Cap_quota cap_quota() const { ASSERT_NEVER_CALLED; }
Cap_quota used_caps() const { ASSERT_NEVER_CALLED; }
Capability<Native_pd> native_pd() override { ASSERT_NEVER_CALLED; } Capability<Native_pd> native_pd() override { ASSERT_NEVER_CALLED; }
}; };

View File

@ -29,27 +29,29 @@ class Genode::Pd_root : public Genode::Root_component<Genode::Pd_session_compone
{ {
private: private:
Rpc_entrypoint &_thread_ep; Rpc_entrypoint &_ep;
Pager_entrypoint &_pager_ep; Pager_entrypoint &_pager_ep;
Allocator &_md_alloc; Ram_allocator &_ram_alloc;
Region_map &_local_rm;
protected: protected:
Pd_session_component *_create_session(const char *args) Pd_session_component *_create_session(const char *args)
{ {
/* XXX use separate entrypoint for PD sessions */ Pd_session_component *result = new (md_alloc())
return new (md_alloc()) Pd_session_component(_thread_ep, Pd_session_component(_ep,
_thread_ep, session_resources_from_args(args),
_thread_ep, session_label_from_args(args),
_md_alloc, session_diag_from_args(args),
_pager_ep, args); _ram_alloc, _local_rm, _pager_ep, args);
return result;
} }
void _upgrade_session(Pd_session_component *p, const char *args) void _upgrade_session(Pd_session_component *pd, const char *args)
{ {
size_t ram_quota = pd->Ram_quota_guard::upgrade(ram_quota_from_args(args));
Arg_string::find_arg(args, "ram_quota").ulong_value(0); pd->Cap_quota_guard::upgrade(cap_quota_from_args(args));
p->upgrade_ram_quota(ram_quota); pd->session_quota_upgraded();
} }
public: public:
@ -57,16 +59,20 @@ class Genode::Pd_root : public Genode::Root_component<Genode::Pd_session_compone
/** /**
* Constructor * Constructor
* *
* \param session_ep entry point for managing pd session objects * \param ep entry point for managing pd session objects,
* \param thread_ep entry point for managing threads * threads, and signal contexts
* \param ram_alloc allocator used for session-local allocations
* \param md_alloc meta-data allocator to be used by root component * \param md_alloc meta-data allocator to be used by root component
*/ */
Pd_root(Rpc_entrypoint *session_ep, Pd_root(Rpc_entrypoint &ep,
Rpc_entrypoint *thread_ep,
Pager_entrypoint &pager_ep, Pager_entrypoint &pager_ep,
Allocator *md_alloc) Ram_allocator &ram_alloc,
: Root_component<Pd_session_component>(session_ep, md_alloc), Region_map &local_rm,
_thread_ep(*thread_ep), _pager_ep(pager_ep), _md_alloc(*md_alloc) { } Allocator &md_alloc)
:
Root_component<Pd_session_component>(&ep, &md_alloc),
_ep(ep), _pager_ep(pager_ep), _ram_alloc(ram_alloc), _local_rm(local_rm)
{ }
}; };
#endif /* _CORE__INCLUDE__PD_ROOT_H_ */ #endif /* _CORE__INCLUDE__PD_ROOT_H_ */

View File

@ -17,9 +17,11 @@
#define _CORE__INCLUDE__PD_SESSION_COMPONENT_H_ #define _CORE__INCLUDE__PD_SESSION_COMPONENT_H_
/* Genode includes */ /* Genode includes */
#include <util/reconstructible.h>
#include <base/allocator_guard.h> #include <base/allocator_guard.h>
#include <base/session_label.h> #include <base/session_object.h>
#include <base/rpc_server.h> #include <base/registry.h>
#include <base/heap.h>
#include <pd_session/pd_session.h> #include <pd_session/pd_session.h>
#include <util/arg_string.h> #include <util/arg_string.h>
@ -33,88 +35,111 @@
#include <native_pd_component.h> #include <native_pd_component.h>
#include <region_map_component.h> #include <region_map_component.h>
#include <platform_generic.h> #include <platform_generic.h>
#include <account.h>
namespace Genode { class Pd_session_component; } namespace Genode { class Pd_session_component; }
class Genode::Pd_session_component : public Rpc_object<Pd_session> class Genode::Pd_session_component : public Session_object<Pd_session>
{ {
private: private:
/** Constrained_ram_allocator _constrained_md_ram_alloc;
* Read and store the PD label Sliced_heap _sliced_heap;
*/ Platform_pd _pd { &_sliced_heap, _label.string() };
struct Label {
enum { MAX_LEN = 64 };
char string[MAX_LEN];
Label(char const *args)
{
Arg_string::find_arg(args, "label").string(string,
sizeof(string), "");
}
} const _label;
Allocator_guard _md_alloc; /* guarded meta-data allocator */
Platform_pd _pd;
Capability<Parent> _parent; Capability<Parent> _parent;
Rpc_entrypoint &_thread_ep; Rpc_entrypoint &_ep;
Pager_entrypoint &_pager_ep; Pager_entrypoint &_pager_ep;
Signal_broker _signal_broker; Signal_broker _signal_broker { _sliced_heap, _ep, _ep };
Rpc_cap_factory _rpc_cap_factory; Rpc_cap_factory _rpc_cap_factory { _sliced_heap };
Native_pd_component _native_pd; Native_pd_component _native_pd;
Region_map_component _address_space; Region_map_component _address_space;
Region_map_component _stack_area; Region_map_component _stack_area;
Region_map_component _linker_area; Region_map_component _linker_area;
size_t _ram_quota(char const * args) { Constructible<Account<Cap_quota> > _cap_account;
return Arg_string::find_arg(args, "ram_quota").long_value(0); }
friend class Native_pd_component; friend class Native_pd_component;
enum Cap_type { RPC_CAP, SIG_SOURCE_CAP, SIG_CONTEXT_CAP, IGN_CAP };
char const *_name(Cap_type type)
{
switch (type) {
case RPC_CAP: return "RPC";
case SIG_SOURCE_CAP: return "signal-source";
case SIG_CONTEXT_CAP: return "signal-context";
default: return "";
}
}
/*
* \throw Out_of_caps
*/
void _consume_cap(Cap_type type)
{
try { Cap_quota_guard::withdraw(Cap_quota{1}); }
catch (Out_of_caps) {
diag("out of caps while consuming ", _name(type), " cap "
"(", _cap_account, ")");
throw;
}
diag("consumed ", _name(type), " cap (", _cap_account, ")");
}
void _released_cap_silent() { Cap_quota_guard::replenish(Cap_quota{1}); }
void _released_cap(Cap_type type)
{
_released_cap_silent();
diag("released ", _name(type), " cap (", _cap_account, ")");
}
public: public:
/** /**
* Constructor * Constructor
* *
* \param receiver_ep entrypoint holding signal-receiver component * \param ep entrypoint holding signal-receiver component
* objects * objects, signal contexts, thread objects
* \param context_ep global pool of all signal contexts * \param ram_alloc backing store for dynamically allocated
* \param md_alloc backing-store allocator for * session meta data
* signal-context component objects
*
* To maintain proper synchronization, 'receiver_ep' must be
* the same entrypoint as used for the signal-session component.
* The 'signal_context_ep' is only used for associative array
* to map signal-context capabilities to 'Signal_context_component'
* objects and as capability allocator for such objects.
*/ */
Pd_session_component(Rpc_entrypoint &thread_ep, Pd_session_component(Rpc_entrypoint &ep,
Rpc_entrypoint &receiver_ep, Resources resources,
Rpc_entrypoint &context_ep, Label const &label,
Allocator &md_alloc, Diag diag,
Ram_allocator &ram_alloc,
Region_map &local_rm,
Pager_entrypoint &pager_ep, Pager_entrypoint &pager_ep,
char const *args) char const *args)
: :
_label(args), Session_object(ep, resources, label, diag),
_md_alloc(&md_alloc, _ram_quota(args)), _constrained_md_ram_alloc(ram_alloc, *this, *this),
_pd(&_md_alloc, _label.string), _sliced_heap(_constrained_md_ram_alloc, local_rm),
_thread_ep(thread_ep), _pager_ep(pager_ep), _ep(ep), _pager_ep(pager_ep),
_signal_broker(_md_alloc, receiver_ep, context_ep), _rpc_cap_factory(_sliced_heap),
_rpc_cap_factory(_md_alloc),
_native_pd(*this, args), _native_pd(*this, args),
_address_space(thread_ep, _md_alloc, pager_ep, _address_space(ep, _sliced_heap, pager_ep,
platform()->vm_start(), platform()->vm_size()), platform()->vm_start(), platform()->vm_size()),
_stack_area(thread_ep, _md_alloc, pager_ep, 0, stack_area_virtual_size()), _stack_area (_ep, _sliced_heap, pager_ep, 0, stack_area_virtual_size()),
_linker_area(thread_ep, _md_alloc, pager_ep, 0, LINKER_AREA_SIZE) _linker_area(_ep, _sliced_heap, pager_ep, 0, LINKER_AREA_SIZE)
{ } { }
/** /**
* Register quota donation at allocator guard * Initialize cap account without providing a reference account
*
* This method is solely used to set up the initial PD session within
* core. The cap accounts of regular PD session are initialized via
* 'ref_account'.
*/ */
void upgrade_ram_quota(size_t ram_quota); void init_cap_account() { _cap_account.construct(*this, _label); }
/**
* Session_object interface
*/
void session_quota_upgraded() override;
/** /**
* Associate thread with PD * Associate thread with PD
@ -135,8 +160,6 @@ class Genode::Pd_session_component : public Rpc_object<Pd_session>
return _address_space; return _address_space;
} }
Session_label label() { return Session_label(_label.string); }
/************************** /**************************
** PD session interface ** ** PD session interface **
@ -147,42 +170,62 @@ class Genode::Pd_session_component : public Rpc_object<Pd_session>
Signal_source_capability alloc_signal_source() override Signal_source_capability alloc_signal_source() override
{ {
try { _consume_cap(SIG_SOURCE_CAP);
return _signal_broker.alloc_signal_source(); } try { return _signal_broker.alloc_signal_source(); }
catch (Genode::Allocator::Out_of_memory) { catch (Genode::Allocator::Out_of_memory) {
throw Pd_session::Out_of_metadata(); } _released_cap_silent();
throw Out_of_ram();
}
} }
void free_signal_source(Signal_source_capability sig_rec_cap) override { void free_signal_source(Signal_source_capability sig_rec_cap) override
_signal_broker.free_signal_source(sig_rec_cap); } {
_signal_broker.free_signal_source(sig_rec_cap);
_released_cap(SIG_SOURCE_CAP);
}
Signal_context_capability Signal_context_capability
alloc_context(Signal_source_capability sig_rec_cap, unsigned long imprint) override alloc_context(Signal_source_capability sig_rec_cap, unsigned long imprint) override
{ {
Cap_quota_guard::Reservation cap_costs(*this, Cap_quota{1});
try { try {
return _signal_broker.alloc_context(sig_rec_cap, imprint); } Signal_context_capability cap =
_signal_broker.alloc_context(sig_rec_cap, imprint);
cap_costs.acknowledge();
diag("consumed signal-context cap (", _cap_account, ")");
return cap;
}
catch (Genode::Allocator::Out_of_memory) { catch (Genode::Allocator::Out_of_memory) {
throw Pd_session::Out_of_metadata(); } throw Out_of_ram(); }
catch (Signal_broker::Invalid_signal_source) { catch (Signal_broker::Invalid_signal_source) {
throw Pd_session::Invalid_signal_source(); } throw Pd_session::Invalid_signal_source(); }
} }
void free_context(Signal_context_capability cap) override { void free_context(Signal_context_capability cap) override
_signal_broker.free_context(cap); } {
_signal_broker.free_context(cap);
_released_cap(SIG_CONTEXT_CAP);
}
void submit(Signal_context_capability cap, unsigned n) override { void submit(Signal_context_capability cap, unsigned n) override {
_signal_broker.submit(cap, n); } _signal_broker.submit(cap, n); }
/*
* \throw Out_of_caps by '_consume_cap'
* \throw Out_of_ram by '_rpc_cap_factory.alloc'
*/
Native_capability alloc_rpc_cap(Native_capability ep) override Native_capability alloc_rpc_cap(Native_capability ep) override
{ {
try { _consume_cap(RPC_CAP);
return _rpc_cap_factory.alloc(ep); } return _rpc_cap_factory.alloc(ep);
catch (Genode::Allocator::Out_of_memory) {
throw Pd_session::Out_of_metadata(); }
} }
void free_rpc_cap(Native_capability cap) override { void free_rpc_cap(Native_capability cap) override
_rpc_cap_factory.free(cap); } {
_rpc_cap_factory.free(cap);
_released_cap(RPC_CAP);
}
Capability<Region_map> address_space() { Capability<Region_map> address_space() {
return _address_space.cap(); } return _address_space.cap(); }
@ -193,6 +236,65 @@ class Genode::Pd_session_component : public Rpc_object<Pd_session>
Capability<Region_map> linker_area() { Capability<Region_map> linker_area() {
return _linker_area.cap(); } return _linker_area.cap(); }
void ref_account(Capability<Pd_session> pd_cap) override
{
/* the reference account can be defined only once */
if (_cap_account.constructed())
return;
if (this->cap() == pd_cap)
return;
_ep.apply(pd_cap, [&] (Pd_session_component *pd) {
if (!pd || !pd->_cap_account.constructed()) {
error("invalid PD session specified as ref account");
throw Invalid_session();
}
_cap_account.construct(*this, _label, *pd->_cap_account);
});
}
void transfer_quota(Capability<Pd_session> pd_cap, Cap_quota amount) override
{
/* the reference account can be defined only once */
if (!_cap_account.constructed())
throw Undefined_ref_account();
if (this->cap() == pd_cap)
return;
_ep.apply(pd_cap, [&] (Pd_session_component *pd) {
if (!pd || !pd->_cap_account.constructed())
throw Invalid_session();
try {
_cap_account->transfer_quota(*pd->_cap_account, amount);
diag("transferred ", amount, " caps "
"to '", pd->_cap_account->label(), "' (", _cap_account, ")");
}
catch (Account<Cap_quota>::Unrelated_account) {
warning("attempt to transfer cap quota to unrelated PD session");
throw Invalid_session(); }
catch (Account<Cap_quota>::Limit_exceeded) {
warning("cap limit (", *_cap_account, ") exceeded "
"during transfer_quota(", amount, ")");
throw Out_of_caps(); }
});
}
Cap_quota cap_quota() const
{
return _cap_account.constructed() ? _cap_account->limit() : Cap_quota { 0 };
}
Cap_quota used_caps() const
{
return _cap_account.constructed() ? _cap_account->used() : Cap_quota { 0 };
}
Capability<Native_pd> native_pd() { return _native_pd.cap(); } Capability<Native_pd> native_pd() { return _native_pd.cap(); }
}; };

View File

@ -387,7 +387,7 @@ class Genode::Trace::Subject_registry
} }
/** /**
* \throw Ram_session::Quota_exceeded * \throw Out_of_ram
*/ */
void import_new_sources(Source_registry &sources) void import_new_sources(Source_registry &sources)
{ {

View File

@ -125,12 +125,16 @@ class Core_child : public Child_policy
Registry<Service> &_services; Registry<Service> &_services;
Capability<Pd_session> _core_pd_cap;
Pd_session &_core_pd;
Capability<Ram_session> _core_ram_cap; Capability<Ram_session> _core_ram_cap;
Ram_session &_core_ram; Ram_session &_core_ram;
Capability<Cpu_session> _core_cpu_cap; Capability<Cpu_session> _core_cpu_cap;
Cpu_session &_core_cpu; Cpu_session &_core_cpu;
Cap_quota const _cap_quota;
Ram_quota const _ram_quota; Ram_quota const _ram_quota;
Child _child; Child _child;
@ -141,14 +145,17 @@ class Core_child : public Child_policy
* Constructor * Constructor
*/ */
Core_child(Registry<Service> &services, Core_child(Registry<Service> &services,
Pd_session &core_pd, Capability<Pd_session> core_pd_cap,
Ram_session &core_ram, Capability<Ram_session> core_ram_cap, Ram_session &core_ram, Capability<Ram_session> core_ram_cap,
Cpu_session &core_cpu, Capability<Cpu_session> core_cpu_cap, Cpu_session &core_cpu, Capability<Cpu_session> core_cpu_cap,
Ram_quota ram_quota) Cap_quota cap_quota, Ram_quota ram_quota)
: :
_entrypoint(nullptr, STACK_SIZE, "init_child", false), _entrypoint(nullptr, STACK_SIZE, "init_child", false),
_services(services), _services(services),
_core_pd_cap (core_pd_cap), _core_pd (core_pd),
_core_ram_cap(core_ram_cap), _core_ram(core_ram), _core_ram_cap(core_ram_cap), _core_ram(core_ram),
_core_cpu_cap(core_cpu_cap), _core_cpu(core_cpu), _core_cpu_cap(core_cpu_cap), _core_cpu(core_cpu),
_cap_quota(Child::effective_quota(cap_quota)),
_ram_quota(Child::effective_quota(ram_quota)), _ram_quota(Child::effective_quota(ram_quota)),
_child(*env_deprecated()->rm_session(), _entrypoint, *this) _child(*env_deprecated()->rm_session(), _entrypoint, *this)
{ {
@ -176,6 +183,12 @@ class Core_child : public Child_policy
return *service; return *service;
} }
void init(Pd_session &session, Capability<Pd_session> cap) override
{
session.ref_account(_core_pd_cap);
_core_pd.transfer_quota(cap, _cap_quota);
}
void init(Ram_session &session, Capability<Ram_session> cap) override void init(Ram_session &session, Capability<Ram_session> cap) override
{ {
session.ref_account(_core_ram_cap); session.ref_account(_core_ram_cap);
@ -188,6 +201,9 @@ class Core_child : public Child_policy
_core_cpu.transfer_quota(cap, Cpu_session::quota_lim_upscale(100, 100)); _core_cpu.transfer_quota(cap, Cpu_session::quota_lim_upscale(100, 100));
} }
Pd_session &ref_pd() { return _core_pd; }
Pd_session_capability ref_pd_cap() const { return _core_pd_cap; }
Ram_session &ref_ram() { return _core_ram; } Ram_session &ref_ram() { return _core_ram; }
Ram_session_capability ref_ram_cap() const { return _core_ram_cap; } Ram_session_capability ref_ram_cap() const { return _core_ram_cap; }
@ -271,7 +287,7 @@ int main()
static Rm_root rm_root (e, &sliced_heap, pager_ep); static Rm_root rm_root (e, &sliced_heap, pager_ep);
static Cpu_root cpu_root (e, e, &pager_ep, &sliced_heap, static Cpu_root cpu_root (e, e, &pager_ep, &sliced_heap,
Trace::sources()); Trace::sources());
static Pd_root pd_root (e, e, pager_ep, &sliced_heap); static Pd_root pd_root (*e, pager_ep, core_ram_alloc, local_rm, sliced_heap);
static Log_root log_root (e, &sliced_heap); static Log_root log_root (e, &sliced_heap);
static Io_mem_root io_mem_root (e, e, platform()->io_mem_alloc(), static Io_mem_root io_mem_root (e, e, platform()->io_mem_alloc(),
platform()->ram_alloc(), &sliced_heap); platform()->ram_alloc(), &sliced_heap);
@ -292,7 +308,27 @@ int main()
/* make platform-specific services known to service pool */ /* make platform-specific services known to service pool */
platform_add_local_services(e, &sliced_heap, &services); platform_add_local_services(e, &sliced_heap, &services);
/* create CPU session representing core */ /* calculate number of capabilities to be assigned to init */
size_t const preservered_cap_quota = 1000;
if (platform()->max_caps() < preservered_cap_quota) {
error("platform cap limit lower than preservation for core");
return -1;
}
size_t const avail_cap_quota = platform()->max_caps() - preservered_cap_quota;
/* PD session representing core */
static Pd_session_component
core_pd(*e,
Session::Resources { Ram_quota { 16*1024 },
Cap_quota { avail_cap_quota } },
Session::Label("core"), Session::Diag{false},
core_ram_alloc, local_rm, pager_ep, "");
core_pd.init_cap_account();
/* CPU session representing core */
static Cpu_session_component static Cpu_session_component
core_cpu(e, e, &pager_ep, &sliced_heap, Trace::sources(), core_cpu(e, e, &pager_ep, &sliced_heap, Trace::sources(),
"label=\"core\"", Affinity(), Cpu_session::QUOTA_LIMIT); "label=\"core\"", Affinity(), Cpu_session::QUOTA_LIMIT);
@ -309,14 +345,15 @@ int main()
size_t const avail_ram_quota = platform_ram_limit - preserved_ram_quota; size_t const avail_ram_quota = platform_ram_limit - preserved_ram_quota;
log("", avail_ram_quota / (1024*1024), " MiB RAM " log("", avail_ram_quota / (1024*1024), " MiB RAM and ", avail_cap_quota, " caps "
"assigned to init"); "assigned to init");
static Reconstructible<Core_child> static Reconstructible<Core_child>
init(services, init(services,
core_pd, core_pd.cap(),
*env_deprecated()->ram_session(), env_deprecated()->ram_session_cap(), *env_deprecated()->ram_session(), env_deprecated()->ram_session_cap(),
core_cpu, core_cpu_cap, core_cpu, core_cpu_cap,
Ram_quota{avail_ram_quota}); core_pd.cap_quota(), Ram_quota{avail_ram_quota});
platform()->wait_for_exit(); platform()->wait_for_exit();

View File

@ -17,8 +17,5 @@
using namespace Genode; using namespace Genode;
void Pd_session_component::upgrade_ram_quota(size_t ram_quota) void Pd_session_component::session_quota_upgraded() { }
{
_md_alloc.upgrade(ram_quota);
}

View File

@ -60,8 +60,10 @@ void Ram_session_component::_free_ds(Dataspace_capability ds_cap)
}); });
/* call dataspace destructors and free memory */ /* call dataspace destructors and free memory */
if (ds) if (ds) {
destroy(*_ds_slab, ds); destroy(*_ds_slab, ds);
Cap_quota_guard::replenish(Cap_quota{1});
}
} }
@ -92,6 +94,11 @@ Ram_dataspace_capability Ram_session_component::alloc(size_t ds_size, Cache_attr
Ram_quota_guard::Reservation sbs_ram_costs(*this, Ram_quota{SBS}); Ram_quota_guard::Reservation sbs_ram_costs(*this, Ram_quota{SBS});
} }
/*
* Each dataspace is an RPC object and thereby consumes a capability.
*/
Cap_quota_guard::Reservation dataspace_cap_costs(*this, Cap_quota{1});
/* /*
* Allocate physical backing store * Allocate physical backing store
* *
@ -191,6 +198,7 @@ Ram_dataspace_capability Ram_session_component::alloc(size_t ds_size, Cache_attr
Dataspace_capability result = _ep.manage(ds); Dataspace_capability result = _ep.manage(ds);
dataspace_ram_costs.acknowledge(); dataspace_ram_costs.acknowledge();
dataspace_cap_costs.acknowledge();
phys_alloc_guard.ack = true; phys_alloc_guard.ack = true;
return static_cap_cast<Ram_dataspace>(result); return static_cap_cast<Ram_dataspace>(result);

View File

@ -43,11 +43,6 @@ Io_port_session_component::Io_port_session_component(Range_allocator *io_port_al
case Range_allocator::Alloc_return::OUT_OF_METADATA: case Range_allocator::Alloc_return::OUT_OF_METADATA:
error("I/O port allocator ran out of meta data"); error("I/O port allocator ran out of meta data");
/*
* Do not throw 'Quota_exceeded' because the client cannot do
* anything about the meta data allocator of I/O ports.
*/
throw Root::Invalid_args(); throw Root::Invalid_args();
case Range_allocator::Alloc_return::OK: break; case Range_allocator::Alloc_return::OK: break;

View File

@ -31,8 +31,17 @@ struct Genode::Expanding_ram_session_client : Upgradeable_client<Genode::Ram_ses
Parent &parent = *env_deprecated()->parent(); Parent &parent = *env_deprecated()->parent();
parent.resource_request(String<128>("ram_quota=", amount).string()); parent.resource_request(String<128>("ram_quota=", amount).string());
} }
void _request_caps_from_parent(size_t amount)
{
Parent &parent = *env_deprecated()->parent();
parent.resource_request(String<128>("cap_quota=", amount).string());
}
Expanding_ram_session_client(Ram_session_capability cap, Parent::Client::Id id) Expanding_ram_session_client(Ram_session_capability cap, Parent::Client::Id id)
: Upgradeable_client<Genode::Ram_session_client>(cap, id) { } :
Upgradeable_client<Genode::Ram_session_client>(cap, id)
{ }
Ram_dataspace_capability alloc(size_t size, Cache_attribute cached = UNCACHED) override Ram_dataspace_capability alloc(size_t size, Cache_attribute cached = UNCACHED) override
{ {
@ -41,8 +50,20 @@ struct Genode::Expanding_ram_session_client : Upgradeable_client<Genode::Ram_ses
* to the parent and retry. * to the parent and retry.
*/ */
enum { NUM_ATTEMPTS = 2 }; enum { NUM_ATTEMPTS = 2 };
enum { UPGRADE_CAPS = 4 };
return retry<Out_of_ram>( return retry<Out_of_ram>(
[&] () {
return retry<Out_of_caps>(
[&] () { return Ram_session_client::alloc(size, cached); }, [&] () { return Ram_session_client::alloc(size, cached); },
[&] () {
try { upgrade_caps(UPGRADE_CAPS); }
catch (Out_of_caps) {
warning("cap quota exhausted, issuing resource request to parent");
_request_caps_from_parent(UPGRADE_CAPS);
}
},
NUM_ATTEMPTS);
},
[&] () { [&] () {
/* /*
* The RAM service withdraws the meta data for the allocator * The RAM service withdraws the meta data for the allocator

View File

@ -115,8 +115,8 @@ class Genode::Platform_env : public Env_deprecated,
** Emergency_ram_reserve interface ** ** Emergency_ram_reserve interface **
*************************************/ *************************************/
void release() { void release()
{
log("used before freeing emergency=", _resources.ram.used_ram()); log("used before freeing emergency=", _resources.ram.used_ram());
_resources.ram.free(_emergency_ram_ds); _resources.ram.free(_emergency_ram_ds);
log("used after freeing emergency=", _resources.ram.used_ram()); log("used after freeing emergency=", _resources.ram.used_ram());

View File

@ -35,10 +35,12 @@ struct Genode::Upgradeable_client : CLIENT
void upgrade_ram(size_t quota) void upgrade_ram(size_t quota)
{ {
char buf[128]; env_deprecated()->parent()->upgrade(_id, String<64>("ram_quota=", quota).string());
snprintf(buf, sizeof(buf), "ram_quota=%lu", quota); }
env_deprecated()->parent()->upgrade(_id, buf); void upgrade_caps(size_t quota)
{
env_deprecated()->parent()->upgrade(_id, String<64>("cap_quota=", quota).string());
} }
}; };

View File

@ -75,6 +75,7 @@ void Child::session_sigh(Signal_context_capability sigh)
if (session.phase == Session_state::AVAILABLE || if (session.phase == Session_state::AVAILABLE ||
session.phase == Session_state::INSUFFICIENT_RAM_QUOTA || session.phase == Session_state::INSUFFICIENT_RAM_QUOTA ||
session.phase == Session_state::INSUFFICIENT_CAP_QUOTA ||
session.phase == Session_state::INVALID_ARGS) { session.phase == Session_state::INVALID_ARGS) {
if (sigh.valid() && session.async_client_notify) if (sigh.valid() && session.async_client_notify)
@ -88,6 +89,7 @@ void Child::session_sigh(Signal_context_capability sigh)
* Create session-state object for a dynamically created session * Create session-state object for a dynamically created session
* *
* \throw Out_of_ram * \throw Out_of_ram
* \throw Insufficient_cap_quota
* \throw Insufficient_ram_quota * \throw Insufficient_ram_quota
* \throw Parent::Service_denied * \throw Parent::Service_denied
*/ */
@ -104,6 +106,11 @@ create_session(Child_policy::Name const &child_name, Service &service,
catch (Insufficient_ram_quota) { catch (Insufficient_ram_quota) {
error(child_name, " requested session with insufficient RAM quota"); error(child_name, " requested session with insufficient RAM quota");
throw; } throw; }
catch (Insufficient_cap_quota) {
error(child_name, " requested session with insufficient cap quota");
throw; }
catch (Allocator::Out_of_memory) { catch (Allocator::Out_of_memory) {
error(child_name, " session meta data could not be allocated"); error(child_name, " session meta data could not be allocated");
throw Out_of_ram(); } throw Out_of_ram(); }
@ -170,6 +177,7 @@ Session_capability Child::session(Parent::Client::Id id,
/* filter session affinity */ /* filter session affinity */
Affinity const filtered_affinity = _policy.filter_session_affinity(affinity); Affinity const filtered_affinity = _policy.filter_session_affinity(affinity);
Cap_quota const cap_quota = cap_quota_from_args(argbuf);
Ram_quota const ram_quota = ram_quota_from_args(argbuf); Ram_quota const ram_quota = ram_quota_from_args(argbuf);
/* portion of quota to keep for ourself to maintain the session meta data */ /* portion of quota to keep for ourself to maintain the session meta data */
@ -202,13 +210,18 @@ Session_capability Child::session(Parent::Client::Id id,
try { try {
Ram_transfer::Remote_account ref_ram_account { _policy.ref_ram(), _policy.ref_ram_cap() }; Ram_transfer::Remote_account ref_ram_account { _policy.ref_ram(), _policy.ref_ram_cap() };
Cap_transfer::Remote_account ref_cap_account { _policy.ref_pd(), _policy.ref_pd_cap() };
Ram_transfer::Remote_account ram_account { ram(), ram_session_cap() }; Ram_transfer::Remote_account ram_account { ram(), ram_session_cap() };
Cap_transfer::Remote_account cap_account { pd(), pd_session_cap() };
/* transfer the quota donation from the child's account to ourself */ /* transfer the quota donation from the child's account to ourself */
Ram_transfer ram_donation_from_child(ram_quota, ram_account, ref_ram_account); Ram_transfer ram_donation_from_child(ram_quota, ram_account, ref_ram_account);
Cap_transfer cap_donation_from_child(cap_quota, cap_account, ref_cap_account);
/* transfer session quota from ourself to the service provider */ /* transfer session quota from ourself to the service provider */
Ram_transfer ram_donation_to_service(forward_ram_quota, ref_ram_account, service); Ram_transfer ram_donation_to_service(forward_ram_quota, ref_ram_account, service);
Cap_transfer cap_donation_to_service(cap_quota, ref_cap_account, service);
/* try to dispatch session request synchronously */ /* try to dispatch session request synchronously */
service.initiate_request(session); service.initiate_request(session);
@ -223,9 +236,16 @@ Session_capability Child::session(Parent::Client::Id id,
throw Insufficient_ram_quota(); throw Insufficient_ram_quota();
} }
if (session.phase == Session_state::INSUFFICIENT_CAP_QUOTA) {
_revert_quota_and_destroy(session);
throw Insufficient_cap_quota();
}
/* finish transaction */ /* finish transaction */
ram_donation_from_child.acknowledge(); ram_donation_from_child.acknowledge();
cap_donation_from_child.acknowledge();
ram_donation_to_service.acknowledge(); ram_donation_to_service.acknowledge();
cap_donation_to_service.acknowledge();
} }
/* /*
* Release session meta data if one of the quota transfers went wrong. * Release session meta data if one of the quota transfers went wrong.
@ -234,6 +254,10 @@ Session_capability Child::session(Parent::Client::Id id,
session.destroy(); session.destroy();
throw Out_of_ram(); throw Out_of_ram();
} }
catch (Cap_transfer::Quota_exceeded) {
session.destroy();
throw Out_of_caps();
}
/* /*
* Copy out the session cap before we are potentially kicking off the * Copy out the session cap before we are potentially kicking off the
@ -261,7 +285,8 @@ Session_capability Child::session_cap(Client::Id id)
auto lamda = [&] (Session_state &session) { auto lamda = [&] (Session_state &session) {
if (session.phase == Session_state::INVALID_ARGS if (session.phase == Session_state::INVALID_ARGS
|| session.phase == Session_state::INSUFFICIENT_RAM_QUOTA) { || session.phase == Session_state::INSUFFICIENT_RAM_QUOTA
|| session.phase == Session_state::INSUFFICIENT_CAP_QUOTA) {
Session_state::Phase const phase = session.phase; Session_state::Phase const phase = session.phase;
@ -275,6 +300,7 @@ Session_capability Child::session_cap(Client::Id id)
switch (phase) { switch (phase) {
case Session_state::INVALID_ARGS: throw Parent::Service_denied(); case Session_state::INVALID_ARGS: throw Parent::Service_denied();
case Session_state::INSUFFICIENT_RAM_QUOTA: throw Insufficient_ram_quota(); case Session_state::INSUFFICIENT_RAM_QUOTA: throw Insufficient_ram_quota();
case Session_state::INSUFFICIENT_CAP_QUOTA: throw Insufficient_cap_quota();
default: break; default: break;
} }
} }
@ -318,29 +344,43 @@ Parent::Upgrade_result Child::upgrade(Client::Id id, Parent::Upgrade_args const
Ram_quota const ram_quota { Ram_quota const ram_quota {
Arg_string::find_arg(args.string(), "ram_quota").ulong_value(0) }; Arg_string::find_arg(args.string(), "ram_quota").ulong_value(0) };
Cap_quota const cap_quota {
Arg_string::find_arg(args.string(), "cap_quota").ulong_value(0) };
try { try {
Ram_transfer::Remote_account ref_ram_account { _policy.ref_ram(), _policy.ref_ram_cap() }; Ram_transfer::Remote_account ref_ram_account { _policy.ref_ram(), _policy.ref_ram_cap() };
Cap_transfer::Remote_account ref_cap_account { _policy.ref_pd(), _policy.ref_pd_cap() };
Ram_transfer::Remote_account ram_account { ram(), ram_session_cap() }; Ram_transfer::Remote_account ram_account { ram(), ram_session_cap() };
Cap_transfer::Remote_account cap_account { pd(), pd_session_cap() };
/* transfer quota from client to ourself */ /* transfer quota from client to ourself */
Ram_transfer ram_donation_from_child(ram_quota, ram_account, ref_ram_account); Ram_transfer ram_donation_from_child(ram_quota, ram_account, ref_ram_account);
Cap_transfer cap_donation_from_child(cap_quota, cap_account, ref_cap_account);
/* transfer session quota from ourself to the service provider */ /* transfer session quota from ourself to the service provider */
Ram_transfer ram_donation_to_service(ram_quota, ref_ram_account, session.service()); Ram_transfer ram_donation_to_service(ram_quota, ref_ram_account, session.service());
Cap_transfer cap_donation_to_service(cap_quota, ref_cap_account, session.service());
session.increase_donated_quota(ram_quota); session.increase_donated_quota(ram_quota, cap_quota);
session.phase = Session_state::UPGRADE_REQUESTED; session.phase = Session_state::UPGRADE_REQUESTED;
session.service().initiate_request(session); session.service().initiate_request(session);
/* finish transaction */ /* finish transaction */
ram_donation_from_child.acknowledge(); ram_donation_from_child.acknowledge();
cap_donation_from_child.acknowledge();
ram_donation_to_service.acknowledge(); ram_donation_to_service.acknowledge();
cap_donation_to_service.acknowledge();
} }
catch (Ram_transfer::Quota_exceeded) { catch (Ram_transfer::Quota_exceeded) {
warning(_policy.name(), ": RAM upgrade of ", session.service().name(), " failed"); warning(_policy.name(), ": RAM upgrade of ", session.service().name(), " failed");
throw Out_of_ram(); throw Out_of_ram();
} }
catch (Cap_transfer::Quota_exceeded) {
warning(_policy.name(), ": cap upgrade of ", session.service().name(), " failed");
throw Out_of_caps();
}
if (session.phase == Session_state::CAP_HANDED_OUT) { if (session.phase == Session_state::CAP_HANDED_OUT) {
result = UPGRADE_DONE; result = UPGRADE_DONE;
@ -361,11 +401,18 @@ void Child::_revert_quota_and_destroy(Session_state &session)
Ram_transfer::Account &service_ram_account = session.service(); Ram_transfer::Account &service_ram_account = session.service();
Ram_transfer::Remote_account child_ram_account(ram(), ram_session_cap()); Ram_transfer::Remote_account child_ram_account(ram(), ram_session_cap());
Cap_transfer::Remote_account ref_cap_account(_policy.ref_pd(), _policy.ref_pd_cap());
Cap_transfer::Account &service_cap_account = session.service();
Cap_transfer::Remote_account child_cap_account(pd(), pd_session_cap());
try { try {
/* transfer session quota from the service to ourself */ /* transfer session quota from the service to ourself */
Ram_transfer ram_donation_from_service(session.donated_ram_quota(), Ram_transfer ram_donation_from_service(session.donated_ram_quota(),
service_ram_account, ref_ram_account); service_ram_account, ref_ram_account);
Cap_transfer cap_donation_from_service(session.donated_cap_quota(),
service_cap_account, ref_cap_account);
/* /*
* Transfer session quota from ourself to the client (our child). In * Transfer session quota from ourself to the client (our child). In
* addition to the quota returned from the server, we also return the * addition to the quota returned from the server, we also return the
@ -377,9 +424,14 @@ void Child::_revert_quota_and_destroy(Session_state &session)
Ram_transfer ram_donation_to_client(returned_ram, Ram_transfer ram_donation_to_client(returned_ram,
ref_ram_account, child_ram_account); ref_ram_account, child_ram_account);
Cap_transfer cap_donation_to_client(session.donated_cap_quota(),
ref_cap_account, child_cap_account);
/* finish transaction */ /* finish transaction */
ram_donation_from_service.acknowledge(); ram_donation_from_service.acknowledge();
cap_donation_from_service.acknowledge();
ram_donation_to_client.acknowledge(); ram_donation_to_client.acknowledge();
cap_donation_to_client.acknowledge();
} }
catch (Ram_transfer::Quota_exceeded) { catch (Ram_transfer::Quota_exceeded) {
warning(_policy.name(), ": could not revert session RAM quota (", session, ")"); } warning(_policy.name(), ": could not revert session RAM quota (", session, ")"); }
@ -398,7 +450,8 @@ Child::Close_result Child::_close(Session_state &session)
* without involving the server * without involving the server
*/ */
if (session.phase == Session_state::INVALID_ARGS if (session.phase == Session_state::INVALID_ARGS
|| session.phase == Session_state::INSUFFICIENT_RAM_QUOTA) { || session.phase == Session_state::INSUFFICIENT_RAM_QUOTA
|| session.phase == Session_state::INSUFFICIENT_CAP_QUOTA) {
_revert_quota_and_destroy(session); _revert_quota_and_destroy(session);
return CLOSE_DONE; return CLOSE_DONE;
} }
@ -503,6 +556,12 @@ void Child::session_response(Server::Id id, Session_response response)
session.ready_callback->session_ready(session); session.ready_callback->session_ready(session);
break; break;
case Parent::INSUFFICIENT_CAP_QUOTA:
session.phase = Session_state::INSUFFICIENT_CAP_QUOTA;
if (session.ready_callback)
session.ready_callback->session_ready(session);
break;
case Parent::SESSION_OK: case Parent::SESSION_OK:
if (session.phase == Session_state::UPGRADE_REQUESTED) { if (session.phase == Session_state::UPGRADE_REQUESTED) {
session.phase = Session_state::CAP_HANDED_OUT; session.phase = Session_state::CAP_HANDED_OUT;
@ -649,6 +708,7 @@ void Child::_try_construct_env_dependent_members()
_parent_cap); _parent_cap);
} }
catch (Out_of_ram) { _error("out of RAM during ELF loading"); } catch (Out_of_ram) { _error("out of RAM during ELF loading"); }
catch (Out_of_caps) { _error("out of caps during ELF loading"); }
catch (Cpu_session::Thread_creation_failed) { _error("unable to create initial thread"); } catch (Cpu_session::Thread_creation_failed) { _error("unable to create initial thread"); }
catch (Cpu_session::Out_of_metadata) { _error("CPU session quota exhausted"); } catch (Cpu_session::Out_of_metadata) { _error("CPU session quota exhausted"); }
catch (Process::Missing_dynamic_linker) { _error("dynamic linker unavailable"); } catch (Process::Missing_dynamic_linker) { _error("dynamic linker unavailable"); }

View File

@ -123,24 +123,27 @@ namespace {
* the route between client and server, the session quota provided * the route between client and server, the session quota provided
* by the client may become successively diminished by intermediate * by the client may become successively diminished by intermediate
* components, prompting the server to deny the session request. * components, prompting the server to deny the session request.
*
* If the session creation failed due to insufficient session
* quota, we try to repeatedly increase the quota up to
* 'NUM_ATTEMPTS'.
*/ */
enum { NUM_ATTEMPTS = 10 };
/* extract session quota as specified by the 'Connection' */ /* extract session quota as specified by the 'Connection' */
char argbuf[Parent::Session_args::MAX_SIZE]; char argbuf[Parent::Session_args::MAX_SIZE];
strncpy(argbuf, args.string(), sizeof(argbuf)); strncpy(argbuf, args.string(), sizeof(argbuf));
Ram_quota ram_quota = ram_quota_from_args(argbuf);
return retry<Insufficient_ram_quota>( Ram_quota ram_quota = ram_quota_from_args(argbuf);
[&] () { Cap_quota cap_quota = cap_quota_from_args(argbuf);
unsigned warn_after_attempts = 2;
for (unsigned cnt = 0;; cnt++) {
try {
Arg_string::set_arg(argbuf, sizeof(argbuf), "ram_quota", Arg_string::set_arg(argbuf, sizeof(argbuf), "ram_quota",
String<32>(ram_quota).string()); String<32>(ram_quota).string());
Arg_string::set_arg(argbuf, sizeof(argbuf), "cap_quota",
String<32>(cap_quota).string());
Session_capability cap = Session_capability cap =
_parent.session(id, name, Parent::Session_args(argbuf), affinity); _parent.session(id, name, Parent::Session_args(argbuf), affinity);
@ -149,30 +152,34 @@ namespace {
_block_for_session(); _block_for_session();
return _parent.session_cap(id); return _parent.session_cap(id);
}, }
[&] () {
/* catch (Insufficient_ram_quota) {
* If our RAM session has less quota available than the ram_quota = Ram_quota { ram_quota.value + 4096 }; }
* session quota, the session-quota transfer failed. In
* this case, we try to recover by issuing a resource catch (Insufficient_cap_quota) {
* request to the parent. cap_quota = Cap_quota { cap_quota.value + 4 }; }
*
* Otherwise, the session-quota transfer succeeded but catch (Out_of_ram) {
* the request was denied by the server.
*/
if (ram_quota.value > ram().avail_ram().value) { if (ram_quota.value > ram().avail_ram().value) {
Parent::Resource_args args(String<64>("ram_quota=", ram_quota)); Parent::Resource_args args(String<64>("ram_quota=", ram_quota));
_parent.resource_request(args); _parent.resource_request(args);
} else {
ram_quota = Ram_quota { ram_quota.value + 4096 };
} }
}, }
NUM_ATTEMPTS);
warning("giving up to increase session quota for ", name.string(), " session " catch (Out_of_caps) {
"after ", (int)NUM_ATTEMPTS, " attempts"); if (cap_quota.value > pd().avail_caps().value) {
Parent::Resource_args args(String<64>("cap_quota=", cap_quota));
_parent.resource_request(args);
}
}
throw Insufficient_ram_quota(); if (cnt == warn_after_attempts) {
warning("re-attempted ", name.string(), " session request ",
cnt, " times (args: ", Cstring(argbuf), ")");
warn_after_attempts *= 2;
}
}
} }
void upgrade(Parent::Client::Id id, Parent::Upgrade_args const &args) override void upgrade(Parent::Client::Id id, Parent::Upgrade_args const &args) override

View File

@ -187,6 +187,8 @@ void Root_proxy::_handle_session_request(Xml_node request)
_env.parent().session_response(id, Parent::INVALID_ARGS); } _env.parent().session_response(id, Parent::INVALID_ARGS); }
catch (Insufficient_ram_quota) { catch (Insufficient_ram_quota) {
_env.parent().session_response(id, Parent::INSUFFICIENT_RAM_QUOTA); } _env.parent().session_response(id, Parent::INSUFFICIENT_RAM_QUOTA); }
catch (Insufficient_cap_quota) {
_env.parent().session_response(id, Parent::INSUFFICIENT_CAP_QUOTA); }
catch (Root::Unavailable) { catch (Root::Unavailable) {
_env.parent().session_response(id, Parent::INVALID_ARGS); } _env.parent().session_response(id, Parent::INVALID_ARGS); }
} }
@ -196,8 +198,9 @@ void Root_proxy::_handle_session_request(Xml_node request)
_id_space.apply<Session>(id, [&] (Session &session) { _id_space.apply<Session>(id, [&] (Session &session) {
Ram_quota const ram_quota { request.attribute_value("ram_quota", 0UL) }; Ram_quota const ram_quota { request.attribute_value("ram_quota", 0UL) };
Cap_quota const cap_quota { request.attribute_value("cap_quota", 0UL) };
String<80> const args("ram_quota=", ram_quota); String<80> const args("ram_quota=", ram_quota, ", cap_quota=", cap_quota);
Root_client(session.service.root).upgrade(session.cap, args.string()); Root_client(session.service.root).upgrade(session.cap, args.string());

View File

@ -23,13 +23,19 @@ using namespace Genode;
Native_capability Rpc_entrypoint::_alloc_rpc_cap(Pd_session &pd, Native_capability Rpc_entrypoint::_alloc_rpc_cap(Pd_session &pd,
Native_capability ep, addr_t) Native_capability ep, addr_t)
{ {
Untyped_capability new_obj_cap = for (;;) {
retry<Genode::Pd_session::Out_of_metadata>(
[&] () { return pd.alloc_rpc_cap(_cap); },
[&] () { env_deprecated()->parent()->upgrade(Parent::Env::pd(),
"ram_quota=16K"); });
return new_obj_cap; Ram_quota ram_upgrade { 0 };
Cap_quota cap_upgrade { 0 };
try { return pd.alloc_rpc_cap(_cap); }
catch (Out_of_ram) { ram_upgrade = Ram_quota { 2*1024*sizeof(long) }; }
catch (Out_of_caps) { cap_upgrade = Cap_quota { 4 }; }
env_deprecated()->parent()->upgrade(Parent::Env::pd(),
String<100>("ram_quota=", ram_upgrade, ", "
"cap_quota=", cap_upgrade).string());
}
} }

View File

@ -33,6 +33,7 @@ struct Formatted_phase
case State::CREATE_REQUESTED: print(output, "CREATE_REQUESTED"); break; case State::CREATE_REQUESTED: print(output, "CREATE_REQUESTED"); break;
case State::INVALID_ARGS: print(output, "INVALID_ARGS"); break; case State::INVALID_ARGS: print(output, "INVALID_ARGS"); break;
case State::INSUFFICIENT_RAM_QUOTA: print(output, "INSUFFICIENT_RAM_QUOTA"); break; case State::INSUFFICIENT_RAM_QUOTA: print(output, "INSUFFICIENT_RAM_QUOTA"); break;
case State::INSUFFICIENT_CAP_QUOTA: print(output, "INSUFFICIENT_CAP_QUOTA"); break;
case State::AVAILABLE: print(output, "AVAILABLE"); break; case State::AVAILABLE: print(output, "AVAILABLE"); break;
case State::CAP_HANDED_OUT: print(output, "CAP_HANDED_OUT"); break; case State::CAP_HANDED_OUT: print(output, "CAP_HANDED_OUT"); break;
case State::UPGRADE_REQUESTED: print(output, "UPGRADE_REQUESTED"); break; case State::UPGRADE_REQUESTED: print(output, "UPGRADE_REQUESTED"); break;
@ -49,7 +50,7 @@ void Session_state::print(Output &out) const
print(out, "service=", _service.name(), " cid=", _id_at_client, " " print(out, "service=", _service.name(), " cid=", _id_at_client, " "
"args='", _args, "' state=", Formatted_phase(phase), " " "args='", _args, "' state=", Formatted_phase(phase), " "
"ram_quota=", _donated_ram_quota); "ram_quota=", _donated_ram_quota, ", cap_quota=", _donated_cap_quota);
} }
@ -77,6 +78,7 @@ void Session_state::generate_session_request(Xml_generator &xml) const
xml.node("upgrade", [&] () { xml.node("upgrade", [&] () {
xml.attribute("id", id_at_server->id().value); xml.attribute("id", id_at_server->id().value);
xml.attribute("ram_quota", ram_upgrade.value); xml.attribute("ram_quota", ram_upgrade.value);
xml.attribute("cap_quota", cap_upgrade.value);
}); });
break; break;
@ -88,6 +90,7 @@ void Session_state::generate_session_request(Xml_generator &xml) const
case INVALID_ARGS: case INVALID_ARGS:
case INSUFFICIENT_RAM_QUOTA: case INSUFFICIENT_RAM_QUOTA:
case INSUFFICIENT_CAP_QUOTA:
case AVAILABLE: case AVAILABLE:
case CAP_HANDED_OUT: case CAP_HANDED_OUT:
case CLOSED: case CLOSED:
@ -102,6 +105,7 @@ void Session_state::generate_client_side_info(Xml_generator &xml, Detail detail)
xml.attribute("label", _label); xml.attribute("label", _label);
xml.attribute("state", String<32>(Formatted_phase(phase))); xml.attribute("state", String<32>(Formatted_phase(phase)));
xml.attribute("ram", String<32>(_donated_ram_quota)); xml.attribute("ram", String<32>(_donated_ram_quota));
xml.attribute("caps", String<32>(_donated_cap_quota));
if (detail.args == Detail::ARGS) if (detail.args == Detail::ARGS)
xml.node("args", [&] () { xml.append_sanitized(_args.string()); }); xml.node("args", [&] () { xml.append_sanitized(_args.string()); });
@ -161,6 +165,7 @@ Session_state::Session_state(Service &service,
: :
_service(service), _service(service),
_donated_ram_quota(ram_quota_from_args(args.string())), _donated_ram_quota(ram_quota_from_args(args.string())),
_donated_cap_quota(cap_quota_from_args(args.string())),
_id_at_client(*this, client_id_space, client_id), _id_at_client(*this, client_id_space, client_id),
_label(label), _args(args), _affinity(affinity) _label(label), _args(args), _affinity(affinity)
{ } { }

View File

@ -229,21 +229,26 @@ Signal_context_capability Signal_receiver::manage(Signal_context *context)
/* register context at process-wide registry */ /* register context at process-wide registry */
signal_context_registry()->insert(&context->_registry_le); signal_context_registry()->insert(&context->_registry_le);
retry<Pd_session::Out_of_metadata>( for (;;) {
[&] () {
Ram_quota ram_upgrade { 0 };
Cap_quota cap_upgrade { 0 };
try {
/* use signal context as imprint */ /* use signal context as imprint */
context->_cap = env_deprecated()->pd_session()->alloc_context(_cap, (long)context); context->_cap = env_deprecated()->pd_session()->alloc_context(_cap, (long)context);
}, break;
[&] () { }
size_t const quota = 1024*sizeof(long); catch (Out_of_ram) { ram_upgrade = Ram_quota { 1024*sizeof(long) }; }
char buf[64]; catch (Out_of_caps) { cap_upgrade = Cap_quota { 4 }; }
snprintf(buf, sizeof(buf), "ram_quota=%ld", quota);
log("upgrading quota donation for PD session "
log("upgrading quota donation for PD session (", quota, " bytes)"); "(", ram_upgrade, " bytes, ", cap_upgrade, " caps)");
env_deprecated()->parent()->upgrade(Parent::Env::pd(), buf); env_deprecated()->parent()->upgrade(Parent::Env::pd(),
String<100>("ram_quota=", ram_upgrade, ", "
"cap_quota=", cap_upgrade).string());
} }
);
return context->_cap; return context->_cap;
} }

View File

@ -319,7 +319,6 @@ void Slab::insert_sb(void *ptr)
bool Slab::alloc(size_t size, void **out_addr) bool Slab::alloc(size_t size, void **out_addr)
{ {
/* too large for us ? */ /* too large for us ? */
if (size > _slab_size) { if (size > _slab_size) {
error("requested size ", size, " is larger then slab size ", error("requested size ", size, " is larger then slab size ",

View File

@ -98,8 +98,10 @@ class Test_child_policy : public Child_policy
Binary_name binary_name() const override { return "test-rm_fault"; } Binary_name binary_name() const override { return "test-rm_fault"; }
Ram_session &ref_ram() override { return _env.ram(); } Pd_session &ref_pd() override { return _env.pd(); }
Pd_session_capability ref_pd_cap() const override { return _env.pd_session_cap(); }
Ram_session &ref_ram() override { return _env.ram(); }
Ram_session_capability ref_ram_cap() const override { return _env.ram_session_cap(); } Ram_session_capability ref_ram_cap() const override { return _env.ram_session_cap(); }
void init(Ram_session &session, Ram_session_capability cap) override void init(Ram_session &session, Ram_session_capability cap) override
@ -111,6 +113,9 @@ class Test_child_policy : public Child_policy
void init(Pd_session &session, Pd_session_capability cap) override void init(Pd_session &session, Pd_session_capability cap) override
{ {
session.ref_account(_env.pd_session_cap());
_env.pd().transfer_quota(cap, Cap_quota{20});
Region_map_client address_space(session.address_space()); Region_map_client address_space(session.address_space());
address_space.fault_handler(_fault_handler_sigh); address_space.fault_handler(_fault_handler_sigh);
} }

View File

@ -59,6 +59,7 @@ class Launchpad_child : public Genode::Child_policy,
Genode::Ram_session_capability _ref_ram_cap; Genode::Ram_session_capability _ref_ram_cap;
Genode::Ram_session_client _ref_ram { _ref_ram_cap }; Genode::Ram_session_client _ref_ram { _ref_ram_cap };
Genode::Cap_quota const _cap_quota;
Genode::Ram_quota const _ram_quota; Genode::Ram_quota const _ram_quota;
Parent_services &_parent_services; Parent_services &_parent_services;
@ -97,6 +98,7 @@ class Launchpad_child : public Genode::Child_policy,
Genode::Allocator &alloc, Genode::Allocator &alloc,
Genode::Session_label const &label, Genode::Session_label const &label,
Binary_name const &elf_name, Binary_name const &elf_name,
Genode::Cap_quota cap_quota,
Genode::Ram_quota ram_quota, Genode::Ram_quota ram_quota,
Parent_services &parent_services, Parent_services &parent_services,
Child_services &child_services, Child_services &child_services,
@ -105,6 +107,7 @@ class Launchpad_child : public Genode::Child_policy,
_name(label), _elf_name(elf_name), _name(label), _elf_name(elf_name),
_env(env), _alloc(alloc), _env(env), _alloc(alloc),
_ref_ram_cap(env.ram_session_cap()), _ref_ram_cap(env.ram_session_cap()),
_cap_quota(Genode::Child::effective_quota(cap_quota)),
_ram_quota(Genode::Child::effective_quota(ram_quota)), _ram_quota(Genode::Child::effective_quota(ram_quota)),
_parent_services(parent_services), _parent_services(parent_services),
_child_services(child_services), _child_services(child_services),
@ -133,9 +136,19 @@ class Launchpad_child : public Genode::Child_policy,
Binary_name binary_name() const override { return _elf_name; } Binary_name binary_name() const override { return _elf_name; }
Genode::Pd_session &ref_pd() override { return _env.pd(); }
Genode::Pd_session_capability ref_pd_cap() const override { return _env.pd_session_cap(); }
Genode::Ram_session &ref_ram() override { return _ref_ram; } Genode::Ram_session &ref_ram() override { return _ref_ram; }
Genode::Ram_session_capability ref_ram_cap() const override { return _ref_ram_cap; } Genode::Ram_session_capability ref_ram_cap() const override { return _ref_ram_cap; }
void init(Genode::Pd_session &session,
Genode::Pd_session_capability cap) override
{
session.ref_account(_env.pd_session_cap());
_env.pd().transfer_quota(cap, _cap_quota);
}
void init(Genode::Ram_session &session, void init(Genode::Ram_session &session,
Genode::Ram_session_capability cap) override Genode::Ram_session_capability cap) override
{ {
@ -200,7 +213,8 @@ class Launchpad_child : public Genode::Child_policy,
Child_service(_child_services, service_name, Child_service(_child_services, service_name,
_session_requester.id_space(), _session_requester.id_space(),
_child.session_factory(), *this, _child.session_factory(), *this,
_child.ram_session_cap()); _child.ram_session_cap(),
_child.pd_session_cap());
} }
}; };
@ -233,6 +247,7 @@ class Launchpad
public: public:
typedef Genode::Cap_quota Cap_quota;
typedef Genode::Ram_quota Ram_quota; typedef Genode::Ram_quota Ram_quota;
Launchpad(Genode::Env &env, unsigned long initial_quota); Launchpad(Genode::Env &env, unsigned long initial_quota);
@ -254,7 +269,7 @@ class Launchpad
virtual void quota(unsigned long quota) { } virtual void quota(unsigned long quota) { }
virtual void add_launcher(Launchpad_child::Name const &binary_name, virtual void add_launcher(Launchpad_child::Name const &binary_name,
unsigned long default_quota, Cap_quota caps, unsigned long default_quota,
Genode::Dataspace_capability config_ds) { } Genode::Dataspace_capability config_ds) { }
virtual void add_child(Launchpad_child::Name const &, virtual void add_child(Launchpad_child::Name const &,
@ -266,7 +281,7 @@ class Launchpad
Genode::Allocator &) { } Genode::Allocator &) { }
Launchpad_child *start_child(Launchpad_child::Name const &binary_name, Launchpad_child *start_child(Launchpad_child::Name const &binary_name,
Ram_quota quota, Cap_quota cap_quota, Ram_quota ram_quota,
Genode::Dataspace_capability config_ds); Genode::Dataspace_capability config_ds);
/** /**

View File

@ -38,14 +38,15 @@ class Launch_entry : public Scout::Parent_element, public Loadbar_listener
/** /**
* Constructor * Constructor
*/ */
Launch_entry(Scout::Launcher::Name const &prg_name, unsigned long initial_quota, Launch_entry(Scout::Launcher::Name const &prg_name,
unsigned long caps, unsigned long initial_quota,
unsigned long max_quota, Launchpad *launchpad, unsigned long max_quota, Launchpad *launchpad,
Genode::Dataspace_capability config_ds) Genode::Dataspace_capability config_ds)
: :
_prg_name(prg_name), _prg_name(prg_name),
_block(Scout::Block::RIGHT), _loadbar(this, &Scout::label_font), _block(Scout::Block::RIGHT), _loadbar(this, &Scout::label_font),
_config(config_ds), _config(config_ds),
_launcher(prg_name, launchpad, initial_quota * 1024UL, &_config) _launcher(prg_name, launchpad, caps, initial_quota * 1024UL, &_config)
{ {
_block.append_launchertext(_prg_name.string(), &Scout::link_style, &_launcher); _block.append_launchertext(_prg_name.string(), &Scout::link_style, &_launcher);

View File

@ -21,6 +21,7 @@ using namespace Scout;
void Launcher::launch() void Launcher::launch()
{ {
_launchpad->start_child(prg_name(), _launchpad->start_child(prg_name(),
Launchpad::Cap_quota{caps()},
Launchpad::Ram_quota{quota()}, Launchpad::Ram_quota{quota()},
_config ? _config->config_ds() _config ? _config->config_ds()
: Genode::Dataspace_capability()); : Genode::Dataspace_capability());

View File

@ -127,12 +127,12 @@ class Launchpad_window : public Scout::Scrollbar_listener,
_status_entry.refresh(); _status_entry.refresh();
} }
void add_launcher(Launchpad_child::Name const &name, void add_launcher(Launchpad_child::Name const &name, Cap_quota caps,
unsigned long default_quota, unsigned long default_quota,
Genode::Dataspace_capability config_ds = Genode::Dataspace_capability()) override Genode::Dataspace_capability config_ds = Genode::Dataspace_capability()) override
{ {
Launch_entry<PT> *le; Launch_entry<PT> *le;
le = new Launch_entry<PT>(name, default_quota / 1024, le = new Launch_entry<PT>(name, caps.value, default_quota / 1024,
initial_quota() / 1024, initial_quota() / 1024,
this, config_ds); this, config_ds);
_launch_section.append(le); _launch_section.append(le);

View File

@ -149,7 +149,7 @@ Document *create_document()
b0->append_plaintext("that can be started by clicking on the application's name. Before starting an", &plain_style); b0->append_plaintext("that can be started by clicking on the application's name. Before starting an", &plain_style);
b0->append_plaintext("application, the user can define the amount of memory quota to donate to the", &plain_style); b0->append_plaintext("application, the user can define the amount of memory quota to donate to the", &plain_style);
b0->append_plaintext("new application by adjusting the red bar using the mouse.", &plain_style); b0->append_plaintext("new application by adjusting the red bar using the mouse.", &plain_style);
Launcher *l0 = new Launcher("launchpad", 1, 22*1024*1024); Launcher *l0 = new Launcher("launchpad", 1, 100000, 22*1024*1024);
b0->append_launchertext("Start the launchpad by clicking on this link...", &link_style, l0); b0->append_launchertext("Start the launchpad by clicking on this link...", &link_style, l0);
chapter->append(b0); chapter->append(b0);

View File

@ -231,6 +231,7 @@ class Scout::Launcher : public Anchor
int _active; int _active;
int _exec_once; int _exec_once;
Launchpad *_launchpad; Launchpad *_launchpad;
unsigned long const _caps;
unsigned long _quota; unsigned long _quota;
Launcher_config *_config; Launcher_config *_config;
@ -242,22 +243,30 @@ class Scout::Launcher : public Anchor
* Constructors * Constructors
*/ */
Launcher(Name const &prg_name, int exec_once = 0, Launcher(Name const &prg_name, int exec_once = 0,
unsigned long quota = 0, Launcher_config *config = 0) : unsigned long caps = 0, unsigned long quota = 0,
Launcher_config *config = 0)
:
_prg_name(prg_name), _active(1), _prg_name(prg_name), _active(1),
_exec_once(exec_once), _quota(quota), _config(config) { } _exec_once(exec_once), _caps(caps), _quota(quota), _config(config)
{ }
Launcher(Name const &prg_name, Launchpad *launchpad, Launcher(Name const &prg_name, Launchpad *launchpad,
unsigned long quota, Launcher_config *config = 0) : unsigned long caps, unsigned long quota,
_prg_name(prg_name), _launchpad(launchpad), _quota(quota), Launcher_config *config = 0)
_config(config) { } :
_prg_name(prg_name), _launchpad(launchpad),
_caps(caps), _quota(quota), _config(config)
{ }
int active() { return _active; } int active() const { return _active; }
Name prg_name() { return _prg_name; } Name prg_name() const { return _prg_name; }
void quota(unsigned long quota) { _quota = quota; } void quota(unsigned long quota) { _quota = quota; }
unsigned long quota() { return _quota; } unsigned long quota() const { return _quota; }
unsigned long caps() const { return _caps; }
Launcher_config *config() { return _config; } Launcher_config *config() { return _config; }

View File

@ -115,6 +115,7 @@ void Launcher::launch()
} }
_launchpad_ptr->start_child(prg_name(), _launchpad_ptr->start_child(prg_name(),
Launchpad::Cap_quota{caps()},
Launchpad::Ram_quota{quota()}, Launchpad::Ram_quota{quota()},
config_registry.config(prg_name().string())); config_registry.config(prg_name().string()));
} }

View File

@ -106,6 +106,8 @@ void Launchpad::process_config(Genode::Xml_node config_node)
Number_of_bytes default_ram_quota = Number_of_bytes default_ram_quota =
node.attribute_value("ram_quota", Number_of_bytes(0)); node.attribute_value("ram_quota", Number_of_bytes(0));
Launchpad::Cap_quota const cap_quota { node.attribute_value("caps", 0UL) };
/* /*
* Obtain configuration for the child * Obtain configuration for the child
*/ */
@ -137,13 +139,13 @@ void Launchpad::process_config(Genode::Xml_node config_node)
} }
/* add launchpad entry */ /* add launchpad entry */
add_launcher(*name, default_ram_quota, config_ds); add_launcher(*name, cap_quota, default_ram_quota, config_ds);
}); });
} }
Launchpad_child *Launchpad::start_child(Launchpad_child::Name const &binary_name, Launchpad_child *Launchpad::start_child(Launchpad_child::Name const &binary_name,
Ram_quota ram_quota, Cap_quota cap_quota, Ram_quota ram_quota,
Dataspace_capability config_ds) Dataspace_capability config_ds)
{ {
log("starting ", binary_name, " with quota ", ram_quota); log("starting ", binary_name, " with quota ", ram_quota);
@ -165,6 +167,17 @@ Launchpad_child *Launchpad::start_child(Launchpad_child::Name const &binary_name
ram_quota = Ram_quota { avail - preserved }; ram_quota = Ram_quota { avail - preserved };
} }
size_t const avail_caps = _env.pd().avail_caps().value;
if (cap_quota.value > avail_caps) {
warning("child's cap quota (", cap_quota.value, ") exceeds the "
"number of available capabilities (", avail_caps, ")");
size_t const preserved_caps = min(avail_caps, 25UL);
cap_quota = Cap_quota { avail_caps - preserved_caps };
}
size_t metadata_size = 4096*16 + sizeof(Launchpad_child); size_t metadata_size = 4096*16 + sizeof(Launchpad_child);
if (metadata_size > ram_quota.value) { if (metadata_size > ram_quota.value) {
@ -176,7 +189,8 @@ Launchpad_child *Launchpad::start_child(Launchpad_child::Name const &binary_name
try { try {
Launchpad_child *c = new (&_sliced_heap) Launchpad_child *c = new (&_sliced_heap)
Launchpad_child(_env, _heap, unique_name, binary_name, ram_quota, Launchpad_child(_env, _heap, unique_name, binary_name,
cap_quota, ram_quota,
_parent_services, _child_services, config_ds); _parent_services, _child_services, config_ds);
Lock::Guard lock_guard(_children_lock); Lock::Guard lock_guard(_children_lock);

View File

@ -45,16 +45,20 @@ class Report_rom_slave : public Genode::Noncopyable
static Name _name() { return "report_rom"; } static Name _name() { return "report_rom"; }
static Genode::Ram_quota _quota() { return { 1024*1024 }; } static Genode::Ram_quota _quota() { return { 1024*1024 }; }
static Genode::Cap_quota _caps() { return { 25 }; }
public: public:
Policy(Genode::Rpc_entrypoint &ep, Policy(Genode::Rpc_entrypoint &ep,
Genode::Region_map &rm, Genode::Region_map &rm,
Genode::Pd_session &ref_pd,
Genode::Pd_session_capability ref_pd_cap,
Genode::Ram_session &ref_ram, Genode::Ram_session &ref_ram,
Genode::Ram_session_capability ref_ram_cap, Genode::Ram_session_capability ref_ram_cap,
const char *config) const char *config)
: :
Genode::Slave::Policy(_name(), _name(), *this, ep, rm, Genode::Slave::Policy(_name(), _name(), *this, ep, rm,
ref_pd, ref_pd_cap, _caps(),
ref_ram, ref_ram_cap, _quota()) ref_ram, ref_ram_cap, _quota())
{ {
if (config) if (config)
@ -76,14 +80,15 @@ class Report_rom_slave : public Genode::Noncopyable
* \param ram RAM session used to allocate the configuration * \param ram RAM session used to allocate the configuration
* dataspace * dataspace
*/ */
Report_rom_slave(Genode::Pd_session &pd, Report_rom_slave(Genode::Region_map &rm,
Genode::Region_map &rm, Genode::Pd_session &pd,
Genode::Pd_session_capability pd_cap,
Genode::Ram_session &ram, Genode::Ram_session &ram,
Genode::Ram_session_capability ram_cap, Genode::Ram_session_capability ram_cap,
char const *config) char const *config)
: :
_ep(&pd, _ep_stack_size, "report_rom"), _ep(&pd, _ep_stack_size, "report_rom"),
_policy(_ep, rm, ram, ram_cap, config), _policy(_ep, rm, pd, pd_cap, ram, ram_cap, config),
_child(rm, _ep, _policy) _child(rm, _ep, _policy)
{ } { }

View File

@ -196,11 +196,10 @@ class Launcher::Fading_dialog : private Input_event_handler
_fader_slave_ep(&env.pd(), _fader_slave_ep_stack_size, "nit_fader"), _fader_slave_ep(&env.pd(), _fader_slave_ep_stack_size, "nit_fader"),
_nitpicker_connection(env, "menu"), _nitpicker_connection(env, "menu"),
_nitpicker_session(env, _nitpicker_connection, env.ep(), _fader_slave_ep, *this), _nitpicker_session(env, _nitpicker_connection, env.ep(), _fader_slave_ep, *this),
_nit_fader_slave(_fader_slave_ep, env.rm(), _nit_fader_slave(_fader_slave_ep, env.rm(), env.pd(), env.pd_session_cap(),
env.ram(), env.ram_session_cap(), env.ram(), env.ram_session_cap(), _nitpicker_service),
_nitpicker_service),
_nit_fader_connection(env.rm(), _nit_fader_slave.policy(), Slave::Args("label=menu")), _nit_fader_connection(env.rm(), _nit_fader_slave.policy(), Slave::Args("label=menu")),
_menu_view_slave(env.pd(), env.rm(), _menu_view_slave(env.rm(), env.pd(), env.pd_session_cap(),
env.ram(), env.ram_session_cap(), env.ram(), env.ram_session_cap(),
_nit_fader_connection, _nit_fader_connection,
_dialog_rom, _hover_report, initial_position) _dialog_rom, _hover_report, initial_position)

View File

@ -43,7 +43,7 @@ struct Launcher::Main
"</config>"; "</config>";
Report_rom_slave _report_rom_slave { Report_rom_slave _report_rom_slave {
_env.pd(), _env.rm(), _env.ram(), _env.ram_session_cap(), _env.rm(), _env.pd(), _env.pd_session_cap(), _env.ram(), _env.ram_session_cap(),
_report_rom_config }; _report_rom_config };
/** /**

View File

@ -75,11 +75,14 @@ class Launcher::Menu_view_slave
static Name _name() { return "menu_view"; } static Name _name() { return "menu_view"; }
static Genode::Ram_quota _quota() { return { 6*1024*1024 }; } static Genode::Ram_quota _quota() { return { 6*1024*1024 }; }
static Genode::Cap_quota _caps() { return { 25 }; }
public: public:
Policy(Genode::Rpc_entrypoint &ep, Policy(Genode::Rpc_entrypoint &ep,
Genode::Region_map &rm, Genode::Region_map &rm,
Genode::Pd_session &ref_pd,
Genode::Pd_session_capability ref_pd_cap,
Genode::Ram_session &ref_ram, Genode::Ram_session &ref_ram,
Genode::Ram_session_capability ref_ram_cap, Genode::Ram_session_capability ref_ram_cap,
Capability<Nitpicker::Session> nitpicker_session, Capability<Nitpicker::Session> nitpicker_session,
@ -88,6 +91,7 @@ class Launcher::Menu_view_slave
Position position) Position position)
: :
Genode::Slave::Policy(_name(), _name(), *this, ep, rm, Genode::Slave::Policy(_name(), _name(), *this, ep, rm,
ref_pd, ref_pd_cap, _caps(),
ref_ram, ref_ram_cap, _quota()), ref_ram, ref_ram_cap, _quota()),
_nitpicker(rm, nitpicker_session), _nitpicker(rm, nitpicker_session),
_dialog_rom(dialog_rom_session), _dialog_rom(dialog_rom_session),
@ -127,8 +131,9 @@ class Launcher::Menu_view_slave
/** /**
* Constructor * Constructor
*/ */
Menu_view_slave(Genode::Pd_session &pd, Menu_view_slave(Genode::Region_map &rm,
Genode::Region_map &rm, Genode::Pd_session &ref_pd,
Genode::Pd_session_capability ref_pd_cap,
Genode::Ram_session &ref_ram, Genode::Ram_session &ref_ram,
Genode::Ram_session_capability ref_ram_cap, Genode::Ram_session_capability ref_ram_cap,
Capability<Nitpicker::Session> nitpicker_session, Capability<Nitpicker::Session> nitpicker_session,
@ -136,8 +141,8 @@ class Launcher::Menu_view_slave
Capability<Report::Session> hover_report_session, Capability<Report::Session> hover_report_session,
Position initial_position) Position initial_position)
: :
_ep(&pd, _ep_stack_size, "nit_fader"), _ep(&ref_pd, _ep_stack_size, "nit_fader"),
_policy(_ep, rm, ref_ram, ref_ram_cap, _policy(_ep, rm, ref_pd, ref_pd_cap, ref_ram, ref_ram_cap,
nitpicker_session, dialog_rom_session, nitpicker_session, dialog_rom_session,
hover_report_session, initial_position), hover_report_session, initial_position),
_child(rm, _ep, _policy) _child(rm, _ep, _policy)

View File

@ -47,16 +47,20 @@ class Launcher::Nit_fader_slave
static Name _name() { return "nit_fader"; } static Name _name() { return "nit_fader"; }
static Genode::Ram_quota _quota() { return { 2*1024*1024 }; } static Genode::Ram_quota _quota() { return { 2*1024*1024 }; }
static Genode::Cap_quota _caps() { return { 25 }; }
public: public:
Policy(Rpc_entrypoint &ep, Policy(Rpc_entrypoint &ep,
Region_map &rm, Region_map &rm,
Pd_session &ref_pd,
Pd_session_capability ref_pd_cap,
Ram_session &ref_ram, Ram_session &ref_ram,
Ram_session_capability ref_ram_cap, Ram_session_capability ref_ram_cap,
Genode::Service &nitpicker_service) Genode::Service &nitpicker_service)
: :
Genode::Slave::Policy(_name(), _name(), *this, ep, rm, Genode::Slave::Policy(_name(), _name(), *this, ep, rm,
ref_pd, ref_pd_cap, _caps(),
ref_ram, ref_ram_cap, _quota()), ref_ram, ref_ram_cap, _quota()),
_nitpicker_service(nitpicker_service) _nitpicker_service(nitpicker_service)
{ {
@ -95,11 +99,13 @@ class Launcher::Nit_fader_slave
*/ */
Nit_fader_slave(Rpc_entrypoint &ep, Nit_fader_slave(Rpc_entrypoint &ep,
Genode::Region_map &rm, Genode::Region_map &rm,
Pd_session &ref_pd,
Pd_session_capability ref_pd_cap,
Ram_session &ref_ram, Ram_session &ref_ram,
Ram_session_capability ref_ram_cap, Ram_session_capability ref_ram_cap,
Genode::Service &nitpicker_service) Genode::Service &nitpicker_service)
: :
_policy(ep, rm, ref_ram, ref_ram_cap, nitpicker_service), _policy(ep, rm, ref_pd, ref_pd_cap, ref_ram, ref_ram_cap, nitpicker_service),
_child(rm, ep, _policy) _child(rm, ep, _policy)
{ {
visible(false); visible(false);

View File

@ -147,6 +147,18 @@ class Launcher::Subsystem_manager
return Ram_config { quantum, limit }; return Ram_config { quantum, limit };
} }
static Cap_quota _caps_config(Xml_node subsystem)
{
Cap_quota const caps { subsystem.attribute_value("caps", 0UL) };
if (caps.value)
return caps;
Genode::error("missing 'caps' attribute for ",
subsystem.attribute_value("name", Label()));
throw Invalid_config();
}
public: public:
Subsystem_manager(Genode::Env & env, Subsystem_manager(Genode::Env & env,
@ -166,8 +178,7 @@ class Launcher::Subsystem_manager
{ {
Child::Binary_name const binary_name = _binary_name(subsystem); Child::Binary_name const binary_name = _binary_name(subsystem);
Label const label = string_attribute(subsystem, "name", Label const label = string_attribute(subsystem, "name", Label(""));
Label(""));
Ram_config const ram_config = _ram_config(subsystem); Ram_config const ram_config = _ram_config(subsystem);
@ -177,9 +188,11 @@ class Launcher::Subsystem_manager
Child *child = new (_heap) Child *child = new (_heap)
Child(_ram, _heap, label, binary_name.string(), Child(_ram, _heap, label, binary_name.string(),
_env.pd(), _env.pd(),
_env.pd_session_cap(),
_env.ram(), _env.ram(),
_env.ram_session_cap(), _env.ram_session_cap(),
_env.rm(), _env.rm(),
_caps_config(subsystem),
ram_config.quantum, ram_config.limit, ram_config.quantum, ram_config.limit,
_yield_broadcast_handler, _yield_broadcast_handler,
_exited_child_sig_cap); _exited_child_sig_cap);

View File

@ -76,6 +76,8 @@ C++ class in 'include/hello_session/hello_session.h'
!{ !{
! static const char *service_name() { return "Hello"; } ! static const char *service_name() { return "Hello"; }
! !
! enum { CAP_QUOTA = 2 };
!
! virtual void say_hello() = 0; ! virtual void say_hello() = 0;
! virtual int add(int a, int b) = 0; ! virtual int add(int a, int b) = 0;
! !
@ -91,7 +93,12 @@ across component boundaries.
Furthermore, we use the interface to specify the name of the service by Furthermore, we use the interface to specify the name of the service by
providing the 'service_name' method. This method will later be used by both providing the 'service_name' method. This method will later be used by both
the server for announcing the service at its parent and the client for the server for announcing the service at its parent and the client for
requesting the creation of a "Hello" session. requesting the creation of a "Hello" session. The 'CAP_QUOTA' definition
specifies the amount of capabilities required to establish the session.
The specified amount is transferred from the client to the server at session
creation time. For the "Hello" session, two capabilities are required, namely
a dataspace capability for the server-side memory occupied by the session
object and the actual session capability that refers to the RPC interface.
The 'GENODE_RPC' macro is used to declare an RPC function. Its first argument The 'GENODE_RPC' macro is used to declare an RPC function. Its first argument
is a type name that is used to refer to the RPC function. The type name can is a type name that is used to refer to the RPC function. The type name can
@ -251,6 +258,7 @@ entry to init's 'config' file, which is located at 'build/bin/config'.
! <default-route> ! <default-route>
! <any-service> <parent/> <any-child/> </any-service> ! <any-service> <parent/> <any-child/> </any-service>
! </default-route> ! </default-route>
! <default caps="50"/>
! <start name="hello_server"> ! <start name="hello_server">
! <resource name="RAM" quantum="1M"/> ! <resource name="RAM" quantum="1M"/>
! <provides><service name="Hello"/></provides> ! <provides><service name="Hello"/></provides>
@ -345,7 +353,7 @@ of the session interface. For our case, the file
! : ! :
! /* create session */ ! /* create session */
! Genode::Connection<Hello::Session>(env, session(env.parent(), ! Genode::Connection<Hello::Session>(env, session(env.parent(),
! "ram_quota=4K")), ! "ram_quota=4K, cap_quota=4")),
! /* initialize RPC interface */ ! /* initialize RPC interface */
! Session_client(cap()) { } ! Session_client(cap()) { }
!}; !};
@ -413,6 +421,7 @@ at the _run/hello.run_ and look as follows:
! <default-route> ! <default-route>
! <any-service> <parent/> <any-child/> </any-service> ! <any-service> <parent/> <any-child/> </any-service>
! </default-route> ! </default-route>
! <default caps="50"/>
! <start name="hello_server"> ! <start name="hello_server">
! <resource name="RAM" quantum="1M"/> ! <resource name="RAM" quantum="1M"/>
! <provides> <service name="Hello"/> </provides> ! <provides> <service name="Hello"/> </provides>

View File

@ -43,6 +43,7 @@ run_genode_until {child ".*" exited with exit value 123.*\n} 10
grep_output {^\[init } grep_output {^\[init }
unify_output {\[init \-\> test\-ldso\] upgrading quota donation for .* \([0-9]+ bytes\)} "" unify_output {\[init \-\> test\-ldso\] upgrading quota donation for .* \([0-9]+ bytes\)} ""
unify_output {ram_quota=[0-9]+} "ram_quota=UNIFIED" unify_output {ram_quota=[0-9]+} "ram_quota=UNIFIED"
unify_output {cap_quota=[0-9]+} "cap_quota=UNIFIED"
trim_lines trim_lines
compare_output_to { compare_output_to {
@ -83,7 +84,7 @@ compare_output_to {
[init -> test-ldso] Catch exceptions in program [init -> test-ldso] Catch exceptions in program
[init -> test-ldso] --------------------------- [init -> test-ldso] ---------------------------
[init -> test-ldso] exception in remote procedure call: [init -> test-ldso] exception in remote procedure call:
[init -> test-ldso] Error: ROM-session creation failed (ram_quota=UNIFIED, label="unknown_file") [init -> test-ldso] Error: ROM-session creation failed (ram_quota=UNIFIED, cap_quota=UNIFIED, label="unknown_file")
[init -> test-ldso] Error: Could not open ROM session for "unknown_file" [init -> test-ldso] Error: Could not open ROM session for "unknown_file"
[init -> test-ldso] caught [init -> test-ldso] caught
[init -> test-ldso] exception in program: caught [init -> test-ldso] exception in program: caught

View File

@ -43,6 +43,7 @@ class Cli_monitor::Child_base : public Genode::Child_policy
class Quota_exceeded : public Genode::Exception { }; class Quota_exceeded : public Genode::Exception { };
typedef Genode::size_t size_t; typedef Genode::size_t size_t;
typedef Genode::Cap_quota Cap_quota;
typedef Genode::Registered<Genode::Parent_service> Parent_service; typedef Genode::Registered<Genode::Parent_service> Parent_service;
@ -55,9 +56,14 @@ class Cli_monitor::Child_base : public Genode::Child_policy
Genode::Session_label const _label; Genode::Session_label const _label;
Binary_name const _binary_name; Binary_name const _binary_name;
Genode::Pd_session_capability _ref_pd_cap;
Genode::Pd_session &_ref_pd;
Genode::Ram_session_capability _ref_ram_cap; Genode::Ram_session_capability _ref_ram_cap;
Genode::Ram_session &_ref_ram; Genode::Ram_session &_ref_ram;
Cap_quota _cap_quota;
size_t _ram_quota; size_t _ram_quota;
size_t _ram_limit; size_t _ram_limit;
@ -110,10 +116,12 @@ class Cli_monitor::Child_base : public Genode::Child_policy
Genode::Allocator &alloc, Genode::Allocator &alloc,
Name const &label, Name const &label,
Binary_name const &binary_name, Binary_name const &binary_name,
Genode::Pd_session &pd_session, Genode::Pd_session &ref_pd,
Genode::Pd_session_capability ref_pd_cap,
Genode::Ram_session &ref_ram, Genode::Ram_session &ref_ram,
Genode::Ram_session_capability ref_ram_cap, Genode::Ram_session_capability ref_ram_cap,
Genode::Region_map &local_rm, Genode::Region_map &local_rm,
Cap_quota cap_quota,
Genode::size_t ram_quota, Genode::size_t ram_quota,
Genode::size_t ram_limit, Genode::size_t ram_limit,
Genode::Signal_context_capability yield_response_sig_cap, Genode::Signal_context_capability yield_response_sig_cap,
@ -121,9 +129,10 @@ class Cli_monitor::Child_base : public Genode::Child_policy
: :
_ram(ram), _alloc(alloc), _ram(ram), _alloc(alloc),
_label(label), _binary_name(binary_name), _label(label), _binary_name(binary_name),
_ref_pd_cap (ref_pd_cap), _ref_pd (ref_pd),
_ref_ram_cap(ref_ram_cap), _ref_ram(ref_ram), _ref_ram_cap(ref_ram_cap), _ref_ram(ref_ram),
_ram_quota(ram_quota), _ram_limit(ram_limit), _cap_quota(cap_quota), _ram_quota(ram_quota), _ram_limit(ram_limit),
_entrypoint(&pd_session, ENTRYPOINT_STACK_SIZE, _label.string(), false), _entrypoint(&ref_pd, ENTRYPOINT_STACK_SIZE, _label.string(), false),
_config_policy(local_rm, "config", _entrypoint, &ref_ram), _config_policy(local_rm, "config", _entrypoint, &ref_ram),
_yield_response_sigh_cap(yield_response_sig_cap), _yield_response_sigh_cap(yield_response_sig_cap),
_exit_sig_cap(exit_sig_cap), _exit_sig_cap(exit_sig_cap),
@ -275,9 +284,18 @@ class Cli_monitor::Child_base : public Genode::Child_policy
Name name() const override { return _label; } Name name() const override { return _label; }
Binary_name binary_name() const override { return _binary_name; } Binary_name binary_name() const override { return _binary_name; }
Genode::Pd_session_capability ref_pd_cap() const override { return _ref_pd_cap; }
Genode::Pd_session &ref_pd() override { return _ref_pd; }
Genode::Ram_session_capability ref_ram_cap() const override { return _ref_ram_cap; } Genode::Ram_session_capability ref_ram_cap() const override { return _ref_ram_cap; }
Genode::Ram_session &ref_ram() override { return _ref_ram; } Genode::Ram_session &ref_ram() override { return _ref_ram; }
void init(Genode::Pd_session &session, Genode::Pd_session_capability cap) override
{
session.ref_account(_ref_pd_cap);
_ref_pd.transfer_quota(cap, _cap_quota);
}
void init(Genode::Ram_session &session, Genode::Ram_session_capability cap) override void init(Genode::Ram_session &session, Genode::Ram_session_capability cap) override
{ {
session.ref_account(_ref_ram_cap); session.ref_account(_ref_ram_cap);

View File

@ -34,6 +34,9 @@ struct Loader::Session_client : Genode::Rpc_client<Session>
void commit_rom_module(Name const &name) override { void commit_rom_module(Name const &name) override {
call<Rpc_commit_rom_module>(name); } call<Rpc_commit_rom_module>(name); }
void cap_quota(Cap_quota limit) override {
call<Rpc_cap_quota>(limit); }
void ram_quota(Ram_quota quantum) override { void ram_quota(Ram_quota quantum) override {
call<Rpc_ram_quota>(quantum); } call<Rpc_ram_quota>(quantum); }

View File

@ -26,11 +26,12 @@ struct Loader::Connection : Genode::Connection<Session>, Session_client
/** /**
* Constructor * Constructor
*/ */
Connection(Genode::Env &env, Ram_quota ram_quota) Connection(Genode::Env &env, Ram_quota ram_quota, Cap_quota cap_quota)
: :
Genode::Connection<Session>(env, session(env.parent(), Genode::Connection<Session>(env, session(env.parent(),
"ram_quota=%ld", "ram_quota=%ld, cap_quota=%ld",
ram_quota.value)), ram_quota.value,
CAP_QUOTA + cap_quota.value)),
Session_client(cap()) Session_client(cap())
{ } { }

View File

@ -19,6 +19,7 @@
#include <base/rpc_args.h> #include <base/rpc_args.h>
#include <dataspace/capability.h> #include <dataspace/capability.h>
#include <nitpicker_session/client.h> #include <nitpicker_session/client.h>
#include <pd_session/pd_session.h>
#include <base/signal.h> #include <base/signal.h>
#include <session/session.h> #include <session/session.h>
#include <util/geometry.h> #include <util/geometry.h>
@ -32,6 +33,7 @@ namespace Loader {
using Genode::Dataspace_capability; using Genode::Dataspace_capability;
using Genode::Signal_context_capability; using Genode::Signal_context_capability;
using Genode::Ram_quota; using Genode::Ram_quota;
using Genode::Cap_quota;
struct Session; struct Session;
} }
@ -90,6 +92,11 @@ struct Loader::Session : Genode::Session
*/ */
virtual void commit_rom_module(Name const &name) = 0; virtual void commit_rom_module(Name const &name) = 0;
/**
* Define capability quota assigned to the subsystem
*/
virtual void cap_quota(Cap_quota) = 0;
/** /**
* Define RAM quota assigned to the subsystem * Define RAM quota assigned to the subsystem
* *
@ -167,6 +174,7 @@ struct Loader::Session : Genode::Session
GENODE_RPC_THROW(Rpc_commit_rom_module, void, commit_rom_module, GENODE_RPC_THROW(Rpc_commit_rom_module, void, commit_rom_module,
GENODE_TYPE_LIST(Rom_module_does_not_exist), GENODE_TYPE_LIST(Rom_module_does_not_exist),
Name const &); Name const &);
GENODE_RPC(Rpc_cap_quota, void, cap_quota, Cap_quota);
GENODE_RPC(Rpc_ram_quota, void, ram_quota, Ram_quota); GENODE_RPC(Rpc_ram_quota, void, ram_quota, Ram_quota);
GENODE_RPC(Rpc_constrain_geometry, void, constrain_geometry, Area); GENODE_RPC(Rpc_constrain_geometry, void, constrain_geometry, Area);
GENODE_RPC(Rpc_parent_view, void, parent_view, Nitpicker::View_capability); GENODE_RPC(Rpc_parent_view, void, parent_view, Nitpicker::View_capability);
@ -182,7 +190,7 @@ struct Loader::Session : Genode::Session
GENODE_TYPE_LIST(View_does_not_exist)); GENODE_TYPE_LIST(View_does_not_exist));
GENODE_RPC_INTERFACE(Rpc_alloc_rom_module, Rpc_commit_rom_module, GENODE_RPC_INTERFACE(Rpc_alloc_rom_module, Rpc_commit_rom_module,
Rpc_ram_quota, Rpc_constrain_geometry, Rpc_cap_quota, Rpc_ram_quota, Rpc_constrain_geometry,
Rpc_parent_view, Rpc_view_ready_sigh, Rpc_fault_sigh, Rpc_parent_view, Rpc_view_ready_sigh, Rpc_fault_sigh,
Rpc_start, Rpc_view_geometry, Rpc_view_size); Rpc_start, Rpc_view_geometry, Rpc_view_size);
}; };

View File

@ -44,7 +44,9 @@ class Genode::Attached_mmio : public Attached_io_mem_dataspace,
* *
* \throw Parent::Service_denied * \throw Parent::Service_denied
* \throw Insufficient_ram_quota * \throw Insufficient_ram_quota
* \throw Parent::Unavailable * \throw Insufficient_cap_quota
* \throw Out_of_ram
* \throw Out_of_caps
* \throw Rm_session::Attach_failed * \throw Rm_session::Attach_failed
*/ */
Attached_mmio(Env &env, addr_t base, size_t size, Attached_mmio(Env &env, addr_t base, size_t size,

View File

@ -71,6 +71,9 @@ class Genode::Child_policy_dynamic_rom_file : public Rpc_object<Rom_session>,
* \param ram RAM session used to allocate the backing store * \param ram RAM session used to allocate the backing store
* for buffering ROM module data * for buffering ROM module data
* *
* \throw Out_of_ram
* \throw Out_of_caps
*
* If 'ram' is 0, the child policy is ineffective. * If 'ram' is 0, the child policy is ineffective.
*/ */
Child_policy_dynamic_rom_file(Region_map &rm, Child_policy_dynamic_rom_file(Region_map &rm,
@ -195,6 +198,7 @@ class Genode::Child_policy_dynamic_rom_file : public Rpc_object<Rom_session>,
case Session_state::INVALID_ARGS: case Session_state::INVALID_ARGS:
case Session_state::INSUFFICIENT_RAM_QUOTA: case Session_state::INSUFFICIENT_RAM_QUOTA:
case Session_state::INSUFFICIENT_CAP_QUOTA:
case Session_state::AVAILABLE: case Session_state::AVAILABLE:
case Session_state::CAP_HANDED_OUT: case Session_state::CAP_HANDED_OUT:
case Session_state::CLOSED: case Session_state::CLOSED:

View File

@ -98,6 +98,21 @@ class Genode::Dynamic_rom_session : public Rpc_object<Rom_session>
*/ */
return true; return true;
} }
catch (Out_of_caps) {
error("ouf of child cap quota while delivering dynamic ROM");
/*
* XXX We may try to generate a resource request on
* behalf of the child.
*/
/*
* Don't let the child try again to obtain a dataspace
* by pretending that the ROM module is up-to-date.
*/
return true;
}
try { try {
_content_producer.produce_content(_ds->local_addr<char>(), _content_producer.produce_content(_ds->local_addr<char>(),
@ -166,6 +181,9 @@ class Genode::Dynamic_rom_session : public Rpc_object<Rom_session>
if (!_ds.constructed()) if (!_ds.constructed())
_unsynchronized_update(); _unsynchronized_update();
if (!_ds.constructed())
return Rom_dataspace_capability();
Dataspace_capability ds_cap = _ds->cap(); Dataspace_capability ds_cap = _ds->cap();
return static_cap_cast<Rom_dataspace>(ds_cap); return static_cap_cast<Rom_dataspace>(ds_cap);

View File

@ -54,9 +54,12 @@ class Genode::Slave::Policy : public Child_policy
Label const _label; Label const _label;
Binary_name const _binary_name; Binary_name const _binary_name;
Pd_session &_ref_pd;
Pd_session_capability _ref_pd_cap;
Ram_session &_ref_ram; Ram_session &_ref_ram;
Ram_session_capability _ref_ram_cap; Ram_session_capability _ref_ram_cap;
Genode::Parent_service _binary_service; Genode::Parent_service _binary_service;
Cap_quota const _cap_quota;
Ram_quota const _ram_quota; Ram_quota const _ram_quota;
Parent_services &_parent_services; Parent_services &_parent_services;
Rpc_entrypoint &_ep; Rpc_entrypoint &_ep;
@ -83,14 +86,18 @@ class Genode::Slave::Policy : public Child_policy
Parent_services &parent_services, Parent_services &parent_services,
Rpc_entrypoint &ep, Rpc_entrypoint &ep,
Region_map &rm, Region_map &rm,
Pd_session &ref_pd,
Pd_session_capability ref_pd_cap,
Cap_quota cap_quota,
Ram_session &ref_ram, Ram_session &ref_ram,
Ram_session_capability ref_ram_cap, Ram_session_capability ref_ram_cap,
Ram_quota ram_quota) Ram_quota ram_quota)
: :
_label(label), _binary_name(binary_name), _label(label), _binary_name(binary_name),
_ref_pd(ref_pd), _ref_pd_cap(ref_pd_cap),
_ref_ram(ref_ram), _ref_ram_cap(ref_ram_cap), _ref_ram(ref_ram), _ref_ram_cap(ref_ram_cap),
_binary_service(Rom_session::service_name()), _binary_service(Rom_session::service_name()),
_ram_quota(ram_quota), _cap_quota(cap_quota), _ram_quota(ram_quota),
_parent_services(parent_services), _ep(ep), _parent_services(parent_services), _ep(ep),
_config_policy(rm, "config", _ep, &_ref_ram), _config_policy(rm, "config", _ep, &_ref_ram),
_session_requester(ep, _ref_ram, rm) _session_requester(ep, _ref_ram, rm)
@ -127,9 +134,18 @@ class Genode::Slave::Policy : public Child_policy
Binary_name binary_name() const override { return _binary_name; } Binary_name binary_name() const override { return _binary_name; }
Pd_session &ref_pd() override { return _ref_pd; }
Pd_session_capability ref_pd_cap() const override { return _ref_pd_cap; }
Ram_session &ref_ram() override { return _ref_ram; } Ram_session &ref_ram() override { return _ref_ram; }
Ram_session_capability ref_ram_cap() const override { return _ref_ram_cap; } Ram_session_capability ref_ram_cap() const override { return _ref_ram_cap; }
void init(Pd_session &session, Pd_session_capability cap) override
{
session.ref_account(_ref_pd_cap);
_ref_pd.transfer_quota(cap, _cap_quota);
}
void init(Ram_session &session, Ram_session_capability cap) override void init(Ram_session &session, Ram_session_capability cap) override
{ {
session.ref_account(_ref_ram_cap); session.ref_account(_ref_ram_cap);
@ -217,6 +233,7 @@ class Genode::Slave::Connection_base
case Session_state::INVALID_ARGS: case Session_state::INVALID_ARGS:
case Session_state::INSUFFICIENT_RAM_QUOTA: case Session_state::INSUFFICIENT_RAM_QUOTA:
case Session_state::INSUFFICIENT_CAP_QUOTA:
case Session_state::AVAILABLE: case Session_state::AVAILABLE:
case Session_state::CAP_HANDED_OUT: case Session_state::CAP_HANDED_OUT:
case Session_state::CLOSED: case Session_state::CLOSED:
@ -256,6 +273,22 @@ class Genode::Slave::Connection_base
return _policy.ref_ram_cap(); return _policy.ref_ram_cap();
} }
/**
* Service ('Cap_transfer::Account') interface
*/
void transfer(Pd_session_capability to, Cap_quota amount) override
{
if (to.valid()) _policy.ref_pd().transfer_quota(to, amount);
}
/**
* Service ('Cap_transfer::Account') interface
*/
Pd_session_capability cap(Cap_quota) const override
{
return _policy.ref_pd_cap();
}
} _service; } _service;
Local_connection<CONNECTION> _connection; Local_connection<CONNECTION> _connection;

View File

@ -71,7 +71,7 @@ compare_output_to {
[init -> test-report_rom] Reporter: start reporting (while the ROM client still listens) [init -> test-report_rom] Reporter: start reporting (while the ROM client still listens)
[init -> test-report_rom] ROM client: wait for update notification [init -> test-report_rom] ROM client: wait for update notification
[init -> test-report_rom] ROM client: try to open the same report again [init -> test-report_rom] ROM client: try to open the same report again
[init -> test-report_rom] Error: Report-session creation failed (label="brightness", ram_quota=14336, buffer_size=4096) [init -> test-report_rom] Error: Report-session creation failed (label="brightness", ram_quota=14336, cap_quota=3, buffer_size=4096)
[init -> test-report_rom] ROM client: catched Parent::Service_denied - OK [init -> test-report_rom] ROM client: catched Parent::Service_denied - OK
[init -> test-report_rom] --- test-report_rom finished --- [init -> test-report_rom] --- test-report_rom finished ---
} }

View File

@ -31,10 +31,12 @@ struct Cli_monitor::Child : Child_base, List<Child>::Element
Genode::Allocator &alloc, Genode::Allocator &alloc,
Name const &label, Name const &label,
Binary_name const &binary, Binary_name const &binary,
Genode::Pd_session &pd_session, Genode::Pd_session &ref_pd,
Genode::Pd_session_capability ref_pd_cap,
Genode::Ram_session &ref_ram, Genode::Ram_session &ref_ram,
Genode::Ram_session_capability ref_ram_cap, Genode::Ram_session_capability ref_ram_cap,
Genode::Region_map &local_rm, Genode::Region_map &local_rm,
Cap_quota cap_quota,
Genode::size_t ram_quota, Genode::size_t ram_quota,
Genode::size_t ram_limit, Genode::size_t ram_limit,
Genode::Signal_context_capability yield_response_sig_cap, Genode::Signal_context_capability yield_response_sig_cap,
@ -44,10 +46,12 @@ struct Cli_monitor::Child : Child_base, List<Child>::Element
alloc, alloc,
label, label,
binary, binary,
pd_session, ref_pd,
ref_pd_cap,
ref_ram, ref_ram,
ref_ram_cap, ref_ram_cap,
local_rm, local_rm,
cap_quota,
ram_quota, ram_quota,
ram_limit, ram_limit,
yield_response_sig_cap, yield_response_sig_cap,

View File

@ -172,7 +172,8 @@ struct Cli_monitor::Main
/* initialize generic commands */ /* initialize generic commands */
Registered<Help_command> _help_command { _commands }; Registered<Help_command> _help_command { _commands };
Registered<Kill_command> _kill_command { _commands, _children, _heap }; Registered<Kill_command> _kill_command { _commands, _children, _heap };
Registered<Start_command> _start_command { _commands, _ram, _heap, _env.pd(), Registered<Start_command> _start_command { _commands, _ram, _heap,
_env.pd(), _env.pd_session_cap(),
_env.ram(), _env.ram_session_cap(), _env.ram(), _env.ram_session_cap(),
_env.rm(), _children, _env.rm(), _children,
_subsystem_config_registry, _subsystem_config_registry,

View File

@ -34,7 +34,8 @@ class Cli_monitor::Start_command : public Command
Ram &_ram; Ram &_ram;
Genode::Allocator &_alloc; Genode::Allocator &_alloc;
Child_registry &_children; Child_registry &_children;
Genode::Pd_session &_pd; Genode::Pd_session &_ref_pd;
Genode::Pd_session_capability _ref_pd_cap;
Genode::Ram_session &_ref_ram; Genode::Ram_session &_ref_ram;
Genode::Ram_session_capability _ref_ram_cap; Genode::Ram_session_capability _ref_ram_cap;
Genode::Region_map &_local_rm; Genode::Region_map &_local_rm;
@ -50,6 +51,7 @@ class Cli_monitor::Start_command : public Command
size_t count = 1; size_t count = 1;
Genode::Number_of_bytes ram = 0; Genode::Number_of_bytes ram = 0;
Genode::Number_of_bytes ram_limit = 0; Genode::Number_of_bytes ram_limit = 0;
size_t caps = subsystem_node.attribute_value("caps", 0UL);
/* read default RAM quota from config */ /* read default RAM quota from config */
try { try {
@ -113,8 +115,10 @@ class Cli_monitor::Start_command : public Command
Child *child = 0; Child *child = 0;
try { try {
child = new (_alloc) child = new (_alloc)
Child(_ram, _alloc, label, binary_name, _pd, _ref_ram, Child(_ram, _alloc, label, binary_name,
_ref_ram_cap, _local_rm, ram, ram_limit, _ref_pd, _ref_pd_cap, _ref_ram,
_ref_ram_cap, _local_rm,
Genode::Cap_quota{caps}, ram, ram_limit,
_yield_response_sigh_cap, _exit_sig_cap); _yield_response_sigh_cap, _exit_sig_cap);
} }
catch (Genode::Parent::Service_denied) { catch (Genode::Parent::Service_denied) {
@ -160,7 +164,8 @@ class Cli_monitor::Start_command : public Command
Start_command(Ram &ram, Start_command(Ram &ram,
Genode::Allocator &alloc, Genode::Allocator &alloc,
Genode::Pd_session &pd, Genode::Pd_session &ref_pd,
Genode::Pd_session_capability ref_pd_cap,
Genode::Ram_session &ref_ram, Genode::Ram_session &ref_ram,
Genode::Ram_session_capability ref_ram_cap, Genode::Ram_session_capability ref_ram_cap,
Genode::Region_map &local_rm, Genode::Region_map &local_rm,
@ -170,8 +175,10 @@ class Cli_monitor::Start_command : public Command
Signal_context_capability exit_sig_cap) Signal_context_capability exit_sig_cap)
: :
Command("start", "create new subsystem"), Command("start", "create new subsystem"),
_ram(ram), _alloc(alloc), _children(children), _pd(pd), _ram(ram), _alloc(alloc), _children(children),
_ref_ram(ref_ram), _ref_ram_cap(ref_ram_cap), _local_rm(local_rm), _ref_pd(ref_pd), _ref_pd_cap(ref_pd_cap),
_ref_ram(ref_ram), _ref_ram_cap(ref_ram_cap),
_local_rm(local_rm),
_subsystem_configs(subsustem_configs), _subsystem_configs(subsustem_configs),
_yield_response_sigh_cap(yield_response_sigh_cap), _yield_response_sigh_cap(yield_response_sigh_cap),
_exit_sig_cap(exit_sig_cap) _exit_sig_cap(exit_sig_cap)

View File

@ -33,12 +33,16 @@ class Platform::Device_pd_policy
Device_pd_policy(Genode::Rpc_entrypoint &slave_ep, Device_pd_policy(Genode::Rpc_entrypoint &slave_ep,
Genode::Region_map &local_rm, Genode::Region_map &local_rm,
Genode::Pd_session &pd_ref,
Genode::Pd_session_capability pd_ref_cap,
Genode::Cap_quota cap_quota,
Genode::Ram_session &ram_ref, Genode::Ram_session &ram_ref,
Genode::Ram_session_capability ram_ref_cap, Genode::Ram_session_capability ram_ref_cap,
Genode::Ram_quota ram_quota, Genode::Ram_quota ram_quota,
Genode::Session_label const &label) Genode::Session_label const &label)
: :
Genode::Slave::Policy(label, "device_pd", *this, slave_ep, local_rm, Genode::Slave::Policy(label, "device_pd", *this, slave_ep, local_rm,
pd_ref, pd_ref_cap, cap_quota,
ram_ref, ram_ref_cap, ram_quota) ram_ref, ram_ref_cap, ram_quota)
{ } { }
}; };

View File

@ -202,6 +202,8 @@ class Platform::Session_component : public Genode::Rpc_object<Session>
Genode::Attached_rom_dataspace &_config; Genode::Attached_rom_dataspace &_config;
Genode::Ram_session_guard _env_ram; Genode::Ram_session_guard _env_ram;
Genode::Ram_session_capability _env_ram_cap; Genode::Ram_session_capability _env_ram_cap;
Genode::Pd_session &_env_pd;
Genode::Pd_session_capability _env_pd_cap;
Genode::Region_map &_local_rm; Genode::Region_map &_local_rm;
Genode::Heap _md_alloc; Genode::Heap _md_alloc;
Genode::Session_label const _label; Genode::Session_label const _label;
@ -254,6 +256,13 @@ class Platform::Session_component : public Genode::Rpc_object<Session>
enum { OVERHEAD = 4096 }; enum { OVERHEAD = 4096 };
try { _env_ram.transfer_quota(_ram, Genode::Ram_quota{OVERHEAD}); } try { _env_ram.transfer_quota(_ram, Genode::Ram_quota{OVERHEAD}); }
catch (...) { throw Genode::Insufficient_ram_quota(); } catch (...) { throw Genode::Insufficient_ram_quota(); }
/*
* XXX instead of eagerly upgrading the RAM session, upgrade it
* on demand, paid by the client's cap session quota.
*/
using namespace Genode;
_ram.upgrade(Session::Resources { Ram_quota{0}, Cap_quota{10} });
} }
bool const _ram_initialized = (_init_ram(), true); bool const _ram_initialized = (_init_ram(), true);
@ -291,7 +300,7 @@ class Platform::Session_component : public Genode::Rpc_object<Session>
private: private:
enum { RAM_QUOTA = 190 * 4096 }; enum { CAP_QUOTA = 60, RAM_QUOTA = 190 * 4096 };
Quota_reservation const _reservation; Quota_reservation const _reservation;
Device_pd_policy _policy; Device_pd_policy _policy;
@ -319,11 +328,15 @@ class Platform::Session_component : public Genode::Rpc_object<Session>
Genode::Rpc_entrypoint &ep, Genode::Rpc_entrypoint &ep,
Genode::Ram_session_guard &ref_ram, Genode::Ram_session_guard &ref_ram,
Genode::Ram_session_capability ref_ram_cap, Genode::Ram_session_capability ref_ram_cap,
Genode::Pd_session &ref_pd,
Genode::Pd_session_capability ref_pd_cap,
Genode::Session_label const &label) Genode::Session_label const &label)
try : try :
_reservation(ref_ram, RAM_QUOTA), _reservation(ref_ram, RAM_QUOTA),
_policy(ep, local_rm, _policy(ep, local_rm,
ref_ram, ref_ram_cap, Genode::Ram_quota{RAM_QUOTA}, label), ref_pd, ref_pd_cap, Genode::Cap_quota{CAP_QUOTA},
ref_ram, ref_ram_cap, Genode::Ram_quota{RAM_QUOTA},
label),
_child(local_rm, ep, _policy), _child(local_rm, ep, _policy),
_connection(_policy, Genode::Slave::Args()) _connection(_policy, Genode::Slave::Args())
{ } { }
@ -331,8 +344,18 @@ class Platform::Session_component : public Genode::Rpc_object<Session>
catch (Out_of_metadata) { throw; } catch (Out_of_metadata) { throw; }
/* thrown by 'Device_pd_policy' or 'Child' */ /* thrown by 'Device_pd_policy' or 'Child' */
catch (Genode::Out_of_ram) { throw Out_of_metadata(); } catch (Genode::Out_of_ram) { throw Out_of_metadata(); }
/* throw by 'Slave::Connection' */ catch (Genode::Out_of_caps) {
/* XXX reflect 'Out_of_caps' exception to client */
Genode::error("Out_of_caps during device-pd creation");
throw Out_of_metadata();
}
/* thrown by 'Slave::Connection' */
catch (Genode::Insufficient_ram_quota) { throw Out_of_metadata(); } catch (Genode::Insufficient_ram_quota) { throw Out_of_metadata(); }
/* thrown by 'Slave::Connection' */
catch (Genode::Insufficient_cap_quota) {
Genode::error("Insufficient_cap_quota during device-pd creation");
throw Out_of_metadata();
}
Device_pd_client &session() { return _connection; } Device_pd_client &session() { return _connection; }
@ -368,13 +391,19 @@ class Platform::Session_component : public Genode::Rpc_object<Session>
try { try {
_device_pd = new (_md_alloc) _device_pd = new (_md_alloc)
Device_pd(_local_rm, _device_pd_ep, _env_ram, Device_pd(_local_rm, _device_pd_ep, _env_ram, _env_ram_cap,
_env_ram_cap, _label); _env_pd, _env_pd_cap, _label);
} }
/* thrown by '_md_alloc' */ /* thrown by '_md_alloc' */
catch (Genode::Out_of_ram) { throw Out_of_metadata(); } catch (Genode::Out_of_ram) { throw Out_of_metadata(); }
catch (Genode::Out_of_caps) {
/* XXX reflect exception to client */
Genode::error("Out_of_caps during Device_pd construction");
throw Out_of_metadata();
}
/* thrown by 'Device_pd' */ /* thrown by 'Device_pd' */
catch (Out_of_metadata) { throw; } catch (Out_of_metadata) { throw; }
@ -609,6 +638,8 @@ class Platform::Session_component : public Genode::Rpc_object<Session>
_env_ram(env.ram(), env.ram_session_cap(), _env_ram(env.ram(), env.ram_session_cap(),
Genode::Arg_string::find_arg(args, "ram_quota").long_value(0)), Genode::Arg_string::find_arg(args, "ram_quota").long_value(0)),
_env_ram_cap(env.ram_session_cap()), _env_ram_cap(env.ram_session_cap()),
_env_pd(env.pd()),
_env_pd_cap(env.pd_session_cap()),
_local_rm(env.rm()), _local_rm(env.rm()),
_md_alloc(_env_ram, env.rm()), _md_alloc(_env_ram, env.rm()),
_label(Genode::label_from_args(args)), _label(Genode::label_from_args(args)),
@ -846,6 +877,10 @@ class Platform::Session_component : public Genode::Rpc_object<Session>
return _env.ep().rpc_ep().manage(dev); return _env.ep().rpc_ep().manage(dev);
} catch (Genode::Allocator::Out_of_memory) { } catch (Genode::Allocator::Out_of_memory) {
throw Out_of_metadata(); throw Out_of_metadata();
} catch (Genode::Out_of_caps) {
/* XXX reflect exception to client */
Genode::error("Out_of_caps during Device_component construction");
throw Out_of_metadata();
} }
}; };
return _env.ep().rpc_ep().apply(prev_device, lambda); return _env.ep().rpc_ep().apply(prev_device, lambda);
@ -945,24 +980,35 @@ class Platform::Session_component : public Genode::Rpc_object<Session>
/* transfer ram quota to session specific ram session */ /* transfer ram quota to session specific ram session */
try { _env_ram.transfer_quota(_ram, Genode::Ram_quota{size}); } try { _env_ram.transfer_quota(_ram, Genode::Ram_quota{size}); }
catch (Genode::Out_of_ram) { throw Out_of_metadata(); } catch (Genode::Out_of_ram) { throw Out_of_metadata(); }
catch (...) { throw Fatal(); } catch (Genode::Out_of_caps) {
Genode::error("Out_of_caps during alloc_dma_buffer (transfer_quota)");
throw Fatal();
}
catch (...) { }
enum { UPGRADE_QUOTA = 4096 }; enum { UPGRADE_QUOTA = 4096 };
/* allocate dataspace from session specific ram session */ /* allocate dataspace from session specific ram session */
Ram_capability ram_cap = Genode::retry<Genode::Out_of_ram>( Ram_capability ram_cap = Genode::retry<Genode::Out_of_ram>(
[&] () { [&] () {
try { Ram_capability ram = Genode::retry<Genode::Out_of_ram>(
return _ram.alloc(size, Genode::UNCACHED); [&] () {
try { return _ram.alloc(size, Genode::UNCACHED); }
catch (Genode::Out_of_caps) {
Genode::error("Out_of_caps during alloc_dma_buffer (alloc)");
throw Fatal();
} }
catch (Genode::Out_of_ram) { },
[&] () {
if (!_env_ram.withdraw(UPGRADE_QUOTA)) if (!_env_ram.withdraw(UPGRADE_QUOTA)) {
_rollback(size); _rollback(size);
throw;
} }
/* upgrade meta-data quota */
_ram.upgrade_ram(UPGRADE_QUOTA);
});
return ram;
}, },
[&] () { [&] () {
/* /*
@ -973,7 +1019,7 @@ class Platform::Session_component : public Genode::Rpc_object<Session>
* UPGRADE_QUOTA steps. * UPGRADE_QUOTA steps.
*/ */
try { _env_ram.transfer_quota(_ram, Genode::Ram_quota{UPGRADE_QUOTA}); } try { _env_ram.transfer_quota(_ram, Genode::Ram_quota{UPGRADE_QUOTA}); }
catch (...) { throw Genode::Out_of_ram(); } catch (Genode::Out_of_ram) { throw Out_of_metadata(); }
}); });
if (!ram_cap.valid()) if (!ram_cap.valid())

View File

@ -289,9 +289,20 @@ void Init::Child::report_state(Xml_generator &xml, Report_detail const &detail)
generate_ram_info(xml, _child.ram()); generate_ram_info(xml, _child.ram());
if (_requested_resources.constructed()) if (_requested_resources.constructed() && _requested_resources->ram.value)
xml.attribute("requested", String<32> { xml.attribute("requested", String<32>(_requested_resources->ram));
Number_of_bytes(_requested_resources->ram.value) }); });
}
if (detail.child_caps() && _child.pd_session_cap().valid()) {
xml.node("caps", [&] () {
xml.attribute("assigned", String<32>(_resources.assigned_cap_quota));
generate_caps_info(xml, _child.pd());
if (_requested_resources.constructed() && _requested_resources->caps.value)
xml.attribute("requested", String<32>(_requested_resources->caps));
}); });
} }
@ -320,6 +331,18 @@ void Init::Child::report_state(Xml_generator &xml, Report_detail const &detail)
} }
void Init::Child::init(Pd_session &session, Pd_session_capability cap)
{
session.ref_account(_env.pd_session_cap());
Cap_quota const quota { _resources.effective_cap_quota().value };
try { _env.pd().transfer_quota(cap, quota); }
catch (Out_of_caps) {
error(name(), ": unable to initialize cap quota of PD"); }
}
void Init::Child::init(Ram_session &session, Ram_session_capability cap) void Init::Child::init(Ram_session &session, Ram_session_capability cap)
{ {
session.ref_account(_env.ram_session_cap()); session.ref_account(_env.ram_session_cap());
@ -613,8 +636,10 @@ Init::Child::Child(Env &env,
Report_update_trigger &report_update_trigger, Report_update_trigger &report_update_trigger,
Xml_node start_node, Xml_node start_node,
Default_route_accessor &default_route_accessor, Default_route_accessor &default_route_accessor,
Default_caps_accessor &default_caps_accessor,
Name_registry &name_registry, Name_registry &name_registry,
Ram_quota ram_limit, Ram_quota ram_limit,
Cap_quota cap_limit,
Ram_limit_accessor &ram_limit_accessor, Ram_limit_accessor &ram_limit_accessor,
Prio_levels prio_levels, Prio_levels prio_levels,
Affinity::Space const &affinity_space, Affinity::Space const &affinity_space,
@ -628,8 +653,10 @@ Init::Child::Child(Env &env,
_default_route_accessor(default_route_accessor), _default_route_accessor(default_route_accessor),
_ram_limit_accessor(ram_limit_accessor), _ram_limit_accessor(ram_limit_accessor),
_name_registry(name_registry), _name_registry(name_registry),
_resources(_resources_from_start_node(start_node, prio_levels, affinity_space)), _resources(_resources_from_start_node(start_node, prio_levels, affinity_space,
_resources_checked((_check_ram_constraints(ram_limit), true)), default_caps_accessor.default_caps(), cap_limit)),
_resources_checked((_check_ram_constraints(ram_limit),
_check_cap_constraints(cap_limit), true)),
_parent_services(parent_services), _parent_services(parent_services),
_child_services(child_services), _child_services(child_services),
_session_requester(_env.ep().rpc_ep(), _env.ram(), _env.rm()) _session_requester(_env.ep().rpc_ep(), _env.ram(), _env.rm())
@ -637,6 +664,7 @@ Init::Child::Child(Env &env,
if (_verbose.enabled()) { if (_verbose.enabled()) {
log("child \"", _unique_name, "\""); log("child \"", _unique_name, "\"");
log(" RAM quota: ", _resources.effective_ram_quota()); log(" RAM quota: ", _resources.effective_ram_quota());
log(" cap quota: ", _resources.effective_cap_quota());
log(" ELF binary: ", _binary_name); log(" ELF binary: ", _binary_name);
log(" priority: ", _resources.priority); log(" priority: ", _resources.priority);
} }

View File

@ -48,6 +48,8 @@ class Init::Child : Child_policy, Routed_service::Wakeup
struct Default_route_accessor { virtual Xml_node default_route() = 0; }; struct Default_route_accessor { virtual Xml_node default_route() = 0; };
struct Default_caps_accessor { virtual Cap_quota default_caps() = 0; };
struct Ram_limit_accessor { virtual Ram_quota ram_limit() = 0; }; struct Ram_limit_accessor { virtual Ram_quota ram_limit() = 0; };
private: private:
@ -124,6 +126,7 @@ class Init::Child : Child_policy, Routed_service::Wakeup
long priority; long priority;
Affinity affinity; Affinity affinity;
Ram_quota assigned_ram_quota; Ram_quota assigned_ram_quota;
Cap_quota assigned_cap_quota;
size_t cpu_quota_pc; size_t cpu_quota_pc;
bool constrain_phys; bool constrain_phys;
@ -131,15 +134,39 @@ class Init::Child : Child_policy, Routed_service::Wakeup
{ {
return Genode::Child::effective_quota(assigned_ram_quota); return Genode::Child::effective_quota(assigned_ram_quota);
} }
Cap_quota effective_cap_quota() const
{
/* capabilities consumed by 'Genode::Child' */
Cap_quota const effective =
Genode::Child::effective_quota(assigned_cap_quota);
/* capabilities additionally consumed by init */
enum {
STATIC_COSTS = 1 /* possible heap backing-store
allocation for session object */
+ 1 /* buffered XML start node */
+ 2 /* dynamic ROM for config */
+ 2 /* dynamic ROM for session requester */
};
if (effective.value < STATIC_COSTS)
return Cap_quota{0};
return Cap_quota{effective.value - STATIC_COSTS};
}
}; };
Resources _resources_from_start_node(Xml_node start_node, Prio_levels prio_levels, Resources _resources_from_start_node(Xml_node start_node, Prio_levels prio_levels,
Affinity::Space const &affinity_space) Affinity::Space const &affinity_space,
Cap_quota default_cap_quota, Cap_quota cap_limit)
{ {
size_t cpu_quota_pc = 0; size_t cpu_quota_pc = 0;
bool constrain_phys = false; bool constrain_phys = false;
Number_of_bytes ram_bytes = 0; Number_of_bytes ram_bytes = 0;
size_t caps = start_node.attribute_value("caps", default_cap_quota.value);
start_node.for_each_sub_node("resource", [&] (Xml_node rsc) { start_node.for_each_sub_node("resource", [&] (Xml_node rsc) {
typedef String<8> Name; typedef String<8> Name;
@ -153,6 +180,10 @@ class Init::Child : Child_policy, Routed_service::Wakeup
if (name == "CPU") { if (name == "CPU") {
cpu_quota_pc = rsc.attribute_value("quantum", 0UL); cpu_quota_pc = rsc.attribute_value("quantum", 0UL);
} }
if (name == "CAP") {
caps = rsc.attribute_value("quantum", 0UL);
}
}); });
return Resources { log2(prio_levels.value), return Resources { log2(prio_levels.value),
@ -160,6 +191,7 @@ class Init::Child : Child_policy, Routed_service::Wakeup
Affinity(affinity_space, Affinity(affinity_space,
affinity_location_from_xml(affinity_space, start_node)), affinity_location_from_xml(affinity_space, start_node)),
Ram_quota { ram_bytes }, Ram_quota { ram_bytes },
Cap_quota { caps },
cpu_quota_pc, cpu_quota_pc,
constrain_phys }; constrain_phys };
} }
@ -171,6 +203,9 @@ class Init::Child : Child_policy, Routed_service::Wakeup
if (_resources.effective_ram_quota().value == 0) if (_resources.effective_ram_quota().value == 0)
warning(name(), ": no valid RAM quota defined"); warning(name(), ": no valid RAM quota defined");
if (_resources.effective_cap_quota().value == 0)
warning(name(), ": no valid cap quota defined");
/* /*
* If the configured RAM quota exceeds our own quota, we donate * If the configured RAM quota exceeds our own quota, we donate
* all remaining quota to the child. * all remaining quota to the child.
@ -183,6 +218,20 @@ class Init::Child : Child_policy, Routed_service::Wakeup
} }
} }
void _check_cap_constraints(Cap_quota cap_limit)
{
if (_resources.assigned_cap_quota.value == 0)
warning(name(), ": no valid cap quota defined");
if (_resources.assigned_cap_quota.value > cap_limit.value) {
warning(name(), ": assigned caps (", _resources.assigned_cap_quota.value, ") "
"exceed available caps (", cap_limit.value, ")");
_resources.assigned_cap_quota.value = cap_limit.value;
}
}
bool const _resources_checked; bool const _resources_checked;
Registry<Parent_service> &_parent_services; Registry<Parent_service> &_parent_services;
@ -255,10 +304,12 @@ class Init::Child : Child_policy, Routed_service::Wakeup
struct Requested_resources struct Requested_resources
{ {
Ram_quota const ram; Ram_quota const ram;
Cap_quota const caps;
Requested_resources(Parent::Resource_args const &args) Requested_resources(Parent::Resource_args const &args)
: :
ram (ram_quota_from_args(args.string())) ram (ram_quota_from_args(args.string())),
caps(cap_quota_from_args(args.string()))
{ } { }
}; };
@ -266,16 +317,20 @@ class Init::Child : Child_policy, Routed_service::Wakeup
Genode::Child _child { _env.rm(), _env.ep().rpc_ep(), *this }; Genode::Child _child { _env.rm(), _env.ep().rpc_ep(), *this };
struct Ram_accessor : Routed_service::Ram_accessor struct Ram_pd_accessor : Routed_service::Ram_accessor,
Routed_service::Pd_accessor
{ {
Genode::Child &_child; Genode::Child &_child;
Ram_accessor(Genode::Child &child) : _child(child) { } Ram_pd_accessor(Genode::Child &child) : _child(child) { }
Ram_session &ram() override { return _child.ram(); } Ram_session &ram() override { return _child.ram(); }
Ram_session_capability ram_cap() const override { return _child.ram_session_cap(); } Ram_session_capability ram_cap() const override { return _child.ram_session_cap(); }
} _ram_accessor { _child }; Pd_session &pd() override { return _child.pd(); }
Pd_session_capability pd_cap() const override { return _child.pd_session_cap(); }
} _ram_pd_accessor { _child };
/** /**
* Async_service::Wakeup callback * Async_service::Wakeup callback
@ -343,7 +398,7 @@ class Init::Child : Child_policy, Routed_service::Wakeup
new (_alloc) new (_alloc)
Routed_service(_child_services, this->name(), Routed_service(_child_services, this->name(),
_ram_accessor, _ram_pd_accessor, _ram_pd_accessor,
_session_requester.id_space(), _session_requester.id_space(),
_child.session_factory(), _child.session_factory(),
name, *this); name, *this);
@ -375,8 +430,10 @@ class Init::Child : Child_policy, Routed_service::Wakeup
Report_update_trigger &report_update_trigger, Report_update_trigger &report_update_trigger,
Xml_node start_node, Xml_node start_node,
Default_route_accessor &default_route_accessor, Default_route_accessor &default_route_accessor,
Default_caps_accessor &default_caps_accessor,
Name_registry &name_registry, Name_registry &name_registry,
Ram_quota ram_limit, Ram_quota ram_limit,
Cap_quota cap_limit,
Ram_limit_accessor &ram_limit_accessor, Ram_limit_accessor &ram_limit_accessor,
Prio_levels prio_levels, Prio_levels prio_levels,
Affinity::Space const &affinity_space, Affinity::Space const &affinity_space,
@ -391,6 +448,7 @@ class Init::Child : Child_policy, Routed_service::Wakeup
bool has_name(Child_policy::Name const &str) const { return str == name(); } bool has_name(Child_policy::Name const &str) const { return str == name(); }
Ram_quota ram_quota() const { return _resources.assigned_ram_quota; } Ram_quota ram_quota() const { return _resources.assigned_ram_quota; }
Cap_quota cap_quota() const { return _resources.assigned_cap_quota; }
void initiate_env_ram_session() void initiate_env_ram_session()
{ {
@ -451,9 +509,13 @@ class Init::Child : Child_policy, Routed_service::Wakeup
Child_policy::Name name() const override { return _unique_name; } Child_policy::Name name() const override { return _unique_name; }
Pd_session &ref_pd() override { return _env.pd(); }
Pd_session_capability ref_pd_cap() const override { return _env.pd_session_cap(); }
Ram_session &ref_ram() override { return _env.ram(); } Ram_session &ref_ram() override { return _env.ram(); }
Ram_session_capability ref_ram_cap() const override { return _env.ram_session_cap(); } Ram_session_capability ref_ram_cap() const override { return _env.ram_session_cap(); }
void init(Pd_session &, Pd_session_capability) override;
void init(Ram_session &, Ram_session_capability) override; void init(Ram_session &, Ram_session_capability) override;
void init(Cpu_session &, Cpu_session_capability) override; void init(Cpu_session &, Cpu_session_capability) override;

View File

@ -26,7 +26,7 @@ namespace Init { struct Main; }
struct Init::Main : State_reporter::Producer, Child::Default_route_accessor, struct Init::Main : State_reporter::Producer, Child::Default_route_accessor,
Child::Ram_limit_accessor Child::Default_caps_accessor, Child::Ram_limit_accessor
{ {
Env &_env; Env &_env;
@ -42,6 +42,8 @@ struct Init::Main : State_reporter::Producer, Child::Default_route_accessor,
Constructible<Buffered_xml> _default_route; Constructible<Buffered_xml> _default_route;
Cap_quota _default_caps { 0 };
unsigned _child_cnt = 0; unsigned _child_cnt = 0;
static Ram_quota _preserved_ram_from_config(Xml_node config) static Ram_quota _preserved_ram_from_config(Xml_node config)
@ -70,6 +72,32 @@ struct Init::Main : State_reporter::Producer, Child::Default_route_accessor,
return Ram_quota { avail_ram.value - preserved_ram.value }; return Ram_quota { avail_ram.value - preserved_ram.value };
} }
static Cap_quota _preserved_caps_from_config(Xml_node config)
{
size_t preserve = 20;
config.for_each_sub_node("resource", [&] (Xml_node node) {
if (node.attribute_value("name", String<16>()) == "CAP")
preserve = node.attribute_value("preserve", preserve); });
return Cap_quota { preserve };
}
Cap_quota _avail_caps()
{
Cap_quota const preserved_caps = _preserved_caps_from_config(_config.xml());
Cap_quota avail_caps { _env.pd().avail_caps().value };
if (preserved_caps.value > avail_caps.value) {
error("Capability preservation exceeds available capabilities");
return Cap_quota { 0 };
}
/* deduce preserved quota from available quota */
return Cap_quota { avail_caps.value - preserved_caps.value };
}
/** /**
* Child::Ram_limit_accessor interface * Child::Ram_limit_accessor interface
*/ */
@ -82,6 +110,9 @@ struct Init::Main : State_reporter::Producer, Child::Default_route_accessor,
if (detail.init_ram()) if (detail.init_ram())
xml.node("ram", [&] () { generate_ram_info (xml, _env.ram()); }); xml.node("ram", [&] () { generate_ram_info (xml, _env.ram()); });
if (detail.init_caps())
xml.node("caps", [&] () { generate_caps_info(xml, _env.pd()); });
if (detail.children()) if (detail.children())
_children.report_state(xml, detail); _children.report_state(xml, detail);
} }
@ -95,6 +126,11 @@ struct Init::Main : State_reporter::Producer, Child::Default_route_accessor,
: Xml_node("<empty/>"); : Xml_node("<empty/>");
} }
/**
* Default_caps_accessor interface
*/
Cap_quota default_caps() override { return _default_caps; }
State_reporter _state_reporter { _env, *this }; State_reporter _state_reporter { _env, *this };
Signal_handler<Main> _resource_avail_handler { Signal_handler<Main> _resource_avail_handler {
@ -258,6 +294,12 @@ void Init::Main::_handle_config()
_default_route.construct(_heap, _config.xml().sub_node("default-route")); } _default_route.construct(_heap, _config.xml().sub_node("default-route")); }
catch (...) { } catch (...) { }
_default_caps = Cap_quota { 0 };
try {
_default_caps = Cap_quota { _config.xml().sub_node("default")
.attribute_value("caps", 0UL) }; }
catch (...) { }
Prio_levels const prio_levels = prio_levels_from_xml(_config.xml()); Prio_levels const prio_levels = prio_levels_from_xml(_config.xml());
Affinity::Space const affinity_space = affinity_space_from_xml(_config.xml()); Affinity::Space const affinity_space = affinity_space_from_xml(_config.xml());
@ -278,9 +320,11 @@ void Init::Main::_handle_config()
/* initial RAM and caps limit before starting new children */ /* initial RAM and caps limit before starting new children */
Ram_quota const avail_ram = _avail_ram(); Ram_quota const avail_ram = _avail_ram();
Cap_quota const avail_caps = _avail_caps();
/* variable used to track the RAM and caps taken by new started children */ /* variable used to track the RAM and caps taken by new started children */
Ram_quota used_ram { 0 }; Ram_quota used_ram { 0 };
Cap_quota used_caps { 0 };
/* create new children */ /* create new children */
try { try {
@ -300,12 +344,18 @@ void Init::Main::_handle_config()
throw Out_of_ram(); throw Out_of_ram();
} }
if (used_caps.value > avail_caps.value) {
error("capabilities exhausted while starting childen");
throw Out_of_caps();
}
try { try {
Init::Child &child = *new (_heap) Init::Child &child = *new (_heap)
Init::Child(_env, _heap, *_verbose, Init::Child(_env, _heap, *_verbose,
Init::Child::Id { ++_child_cnt }, _state_reporter, Init::Child::Id { ++_child_cnt }, _state_reporter,
start_node, *this, _children, start_node, *this, *this, _children,
Ram_quota { avail_ram.value - used_ram.value }, Ram_quota { avail_ram.value - used_ram.value },
Cap_quota { avail_caps.value - used_caps.value },
*this, prio_levels, affinity_space, *this, prio_levels, affinity_space,
_parent_services, _child_services); _parent_services, _child_services);
_children.insert(&child); _children.insert(&child);
@ -317,6 +367,9 @@ void Init::Main::_handle_config()
used_ram = Ram_quota { used_ram.value used_ram = Ram_quota { used_ram.value
+ child.ram_quota().value + child.ram_quota().value
+ metadata_overhead }; + metadata_overhead };
used_caps = Cap_quota { used_caps.value
+ child.cap_quota().value };
} }
catch (Rom_connection::Rom_connection_failed) { catch (Rom_connection::Rom_connection_failed) {
/* /*
@ -326,6 +379,8 @@ void Init::Main::_handle_config()
} }
catch (Out_of_ram) { catch (Out_of_ram) {
warning("memory exhausted during child creation"); } warning("memory exhausted during child creation"); }
catch (Out_of_caps) {
warning("local capabilities exhausted during child creation"); }
catch (Child::Missing_name_attribute) { catch (Child::Missing_name_attribute) {
warning("skipped startup of nameless child"); } warning("skipped startup of nameless child"); }
catch (Region_map::Attach_failed) { catch (Region_map::Attach_failed) {

View File

@ -33,7 +33,9 @@ class Init::Report_detail : Genode::Noncopyable
bool _provided = false; bool _provided = false;
bool _session_args = false; bool _session_args = false;
bool _child_ram = false; bool _child_ram = false;
bool _child_caps = false;
bool _init_ram = false; bool _init_ram = false;
bool _init_caps = false;
public: public:
@ -47,7 +49,9 @@ class Init::Report_detail : Genode::Noncopyable
_provided = report.attribute_value("provided", false); _provided = report.attribute_value("provided", false);
_session_args = report.attribute_value("session_args", false); _session_args = report.attribute_value("session_args", false);
_child_ram = report.attribute_value("child_ram", false); _child_ram = report.attribute_value("child_ram", false);
_child_caps = report.attribute_value("child_caps", false);
_init_ram = report.attribute_value("init_ram", false); _init_ram = report.attribute_value("init_ram", false);
_init_caps = report.attribute_value("init_caps", false);
} }
bool children() const { return _children; } bool children() const { return _children; }
@ -56,7 +60,9 @@ class Init::Report_detail : Genode::Noncopyable
bool provided() const { return _provided; } bool provided() const { return _provided; }
bool session_args() const { return _session_args; } bool session_args() const { return _session_args; }
bool child_ram() const { return _child_ram; } bool child_ram() const { return _child_ram; }
bool child_caps() const { return _child_caps; }
bool init_ram() const { return _init_ram; } bool init_ram() const { return _init_ram; }
bool init_caps() const { return _init_caps; }
}; };

View File

@ -12,6 +12,7 @@
*/ */
/* Genode includes */ /* Genode includes */
#include <base/quota_transfer.h>
#include <os/session_policy.h> #include <os/session_policy.h>
/* local includes */ /* local includes */
@ -149,10 +150,14 @@ void Init::Server::session_closed(Session_state &session)
_report_update_trigger.trigger_report_update(); _report_update_trigger.trigger_report_update();
Ram_transfer::Account &service_ram_account = session.service(); Ram_transfer::Account &service_ram_account = session.service();
Cap_transfer::Account &service_cap_account = session.service();
service_ram_account.try_transfer(_env.ram_session_cap(), service_ram_account.try_transfer(_env.ram_session_cap(),
session.donated_ram_quota()); session.donated_ram_quota());
service_cap_account.try_transfer(_env.pd_session_cap(),
session.donated_cap_quota());
Parent::Server::Id id { session.id_at_client().value }; Parent::Server::Id id { session.id_at_client().value };
session.destroy(); session.destroy();
@ -183,7 +188,9 @@ void Init::Server::_handle_create_session_request(Xml_node request,
char argbuf[Parent::Session_args::MAX_SIZE]; char argbuf[Parent::Session_args::MAX_SIZE];
strncpy(argbuf, args.string(), sizeof(argbuf)); strncpy(argbuf, args.string(), sizeof(argbuf));
Cap_quota const cap_quota = cap_quota_from_args(argbuf);
Ram_quota const ram_quota = ram_quota_from_args(argbuf); Ram_quota const ram_quota = ram_quota_from_args(argbuf);
size_t const keep_quota = route.service.factory().session_costs(); size_t const keep_quota = route.service.factory().session_costs();
if (ram_quota.value < keep_quota) if (ram_quota.value < keep_quota)
@ -201,10 +208,13 @@ void Init::Server::_handle_create_session_request(Xml_node request,
/* transfer session quota */ /* transfer session quota */
try { try {
Ram_transfer::Remote_account env_ram_account(_env.ram(), _env.ram_session_cap()); Ram_transfer::Remote_account env_ram_account(_env.ram(), _env.ram_session_cap());
Cap_transfer::Remote_account env_cap_account(_env.pd(), _env.pd_session_cap());
Ram_transfer ram_transfer(forward_ram_quota, env_ram_account, route.service); Ram_transfer ram_transfer(forward_ram_quota, env_ram_account, route.service);
Cap_transfer cap_transfer(cap_quota, env_cap_account, route.service);
ram_transfer.acknowledge(); ram_transfer.acknowledge();
cap_transfer.acknowledge();
} }
catch (...) { catch (...) {
/* /*
@ -212,7 +222,8 @@ void Init::Server::_handle_create_session_request(Xml_node request,
* transfor the session quota to us prior issuing the session * transfor the session quota to us prior issuing the session
* request. * request.
*/ */
warning("unable to transfer session quota (", ram_quota, " bytes) " warning("unable to transfer session quota "
"(", ram_quota, " bytes, ", cap_quota, " caps) "
"of forwarded ", name, " session"); "of forwarded ", name, " session");
session.destroy(); session.destroy();
throw Parent::Service_denied(); throw Parent::Service_denied();
@ -233,6 +244,9 @@ void Init::Server::_handle_create_session_request(Xml_node request,
if (session.phase == Session_state::INSUFFICIENT_RAM_QUOTA) if (session.phase == Session_state::INSUFFICIENT_RAM_QUOTA)
throw Genode::Insufficient_ram_quota(); throw Genode::Insufficient_ram_quota();
if (session.phase == Session_state::INSUFFICIENT_CAP_QUOTA)
throw Genode::Insufficient_cap_quota();
} }
catch (Parent::Service_denied) { catch (Parent::Service_denied) {
_env.parent().session_response(Parent::Server::Id { id.value }, _env.parent().session_response(Parent::Server::Id { id.value },
@ -240,6 +254,9 @@ void Init::Server::_handle_create_session_request(Xml_node request,
catch (Genode::Insufficient_ram_quota) { catch (Genode::Insufficient_ram_quota) {
_env.parent().session_response(Parent::Server::Id { id.value }, _env.parent().session_response(Parent::Server::Id { id.value },
Parent::INSUFFICIENT_RAM_QUOTA); } Parent::INSUFFICIENT_RAM_QUOTA); }
catch (Genode::Insufficient_cap_quota) {
_env.parent().session_response(Parent::Server::Id { id.value },
Parent::INSUFFICIENT_CAP_QUOTA); }
} }
@ -249,23 +266,28 @@ void Init::Server::_handle_upgrade_session_request(Xml_node request,
_client_id_space.apply<Session_state>(id, [&] (Session_state &session) { _client_id_space.apply<Session_state>(id, [&] (Session_state &session) {
Ram_quota const ram_quota { request.attribute_value("ram_quota", 0UL) }; Ram_quota const ram_quota { request.attribute_value("ram_quota", 0UL) };
Cap_quota const cap_quota { request.attribute_value("cap_quota", 0UL) };
session.phase = Session_state::UPGRADE_REQUESTED; session.phase = Session_state::UPGRADE_REQUESTED;
try { try {
Ram_transfer::Remote_account env_ram_account(_env.ram(), _env.ram_session_cap()); Ram_transfer::Remote_account env_ram_account(_env.ram(), _env.ram_session_cap());
Cap_transfer::Remote_account env_cap_account(_env.pd(), _env.pd_session_cap());
Ram_transfer ram_transfer(ram_quota, env_ram_account, session.service()); Ram_transfer ram_transfer(ram_quota, env_ram_account, session.service());
Cap_transfer cap_transfer(cap_quota, env_cap_account, session.service());
ram_transfer.acknowledge(); ram_transfer.acknowledge();
cap_transfer.acknowledge();
} }
catch (...) { catch (...) {
warning("unable to upgrade session quota (", ram_quota, " bytes) " warning("unable to upgrade session quota "
"(", ram_quota, " bytes, ", cap_quota, " caps) "
"of forwarded ", session.service().name(), " session"); "of forwarded ", session.service().name(), " session");
return; return;
} }
session.increase_donated_quota(ram_quota); session.increase_donated_quota(ram_quota, cap_quota);
session.service().initiate_request(session); session.service().initiate_request(session);
session.service().wakeup(); session.service().wakeup();
}); });

View File

@ -71,11 +71,18 @@ class Init::Routed_service : public Async_service, public Abandonable
virtual Ram_session_capability ram_cap() const = 0; virtual Ram_session_capability ram_cap() const = 0;
}; };
struct Pd_accessor
{
virtual Pd_session &pd() = 0;
virtual Pd_session_capability pd_cap() const = 0;
};
private: private:
Child_name _child_name; Child_name _child_name;
Ram_accessor &_ram_accessor; Ram_accessor &_ram_accessor;
Pd_accessor &_pd_accessor;
Session_state::Factory &_factory; Session_state::Factory &_factory;
@ -94,6 +101,7 @@ class Init::Routed_service : public Async_service, public Abandonable
Routed_service(Registry<Routed_service> &services, Routed_service(Registry<Routed_service> &services,
Child_name const &child_name, Child_name const &child_name,
Ram_accessor &ram_accessor, Ram_accessor &ram_accessor,
Pd_accessor &pd_accessor,
Id_space<Parent::Server> &server_id_space, Id_space<Parent::Server> &server_id_space,
Session_state::Factory &factory, Session_state::Factory &factory,
Service::Name const &name, Service::Name const &name,
@ -101,7 +109,7 @@ class Init::Routed_service : public Async_service, public Abandonable
: :
Async_service(name, server_id_space, factory, wakeup), Async_service(name, server_id_space, factory, wakeup),
_child_name(child_name), _child_name(child_name),
_ram_accessor(ram_accessor), _ram_accessor(ram_accessor), _pd_accessor(pd_accessor),
_factory(factory), _registry_element(services, *this) _factory(factory), _registry_element(services, *this)
{ } { }
@ -124,6 +132,22 @@ class Init::Routed_service : public Async_service, public Abandonable
{ {
return _ram_accessor.ram_cap(); return _ram_accessor.ram_cap();
} }
/**
* Cap_transfer::Account interface
*/
void transfer(Pd_session_capability to, Cap_quota amount) override
{
if (to.valid()) _pd_accessor.pd().transfer_quota(to, amount);
}
/**
* Cap_transfer::Account interface
*/
Pd_session_capability cap(Cap_quota) const override
{
return _pd_accessor.pd_cap();
}
}; };
#endif /* _SRC__INIT__SERVICE_H_ */ #endif /* _SRC__INIT__SERVICE_H_ */

View File

@ -16,6 +16,7 @@
#include <util/string.h> #include <util/string.h>
#include <util/list.h> #include <util/list.h>
#include <session/session.h>
namespace Init { namespace Init {

View File

@ -136,13 +136,20 @@ namespace Init {
inline void generate_ram_info(Xml_generator &xml, Ram_session const &ram) inline void generate_ram_info(Xml_generator &xml, Ram_session const &ram)
{ {
typedef String<32> Value; typedef String<32> Value;
xml.attribute("quota", Value(ram.ram_quota())); xml.attribute("quota", Value(ram.ram_quota()));
xml.attribute("used", Value(ram.used_ram())); xml.attribute("used", Value(ram.used_ram()));
xml.attribute("avail", Value(ram.avail_ram())); xml.attribute("avail", Value(ram.avail_ram()));
} }
inline void generate_caps_info(Xml_generator &xml, Pd_session const &pd)
{
typedef String<32> Value;
xml.attribute("quota", Value(pd.cap_quota()));
xml.attribute("used", Value(pd.used_caps()));
xml.attribute("avail", Value(pd.avail_caps()));
}
/** /**
* Read priority-levels declaration from config * Read priority-levels declaration from config
*/ */

View File

@ -45,6 +45,7 @@ class Loader::Child : public Child_policy
Session_label const _label; Session_label const _label;
Name const _binary_name; Name const _binary_name;
Cap_quota const _cap_quota;
Ram_quota const _ram_quota; Ram_quota const _ram_quota;
Parent_services &_parent_services; Parent_services &_parent_services;
@ -62,6 +63,7 @@ class Loader::Child : public Child_policy
Allocator &alloc, Allocator &alloc,
Name const &binary_name, Name const &binary_name,
Session_label const &label, Session_label const &label,
Cap_quota cap_quota,
Ram_quota ram_quota, Ram_quota ram_quota,
Parent_services &parent_services, Parent_services &parent_services,
Service &local_rom_service, Service &local_rom_service,
@ -74,6 +76,7 @@ class Loader::Child : public Child_policy
_alloc(alloc), _alloc(alloc),
_label(label), _label(label),
_binary_name(binary_name), _binary_name(binary_name),
_cap_quota(Genode::Child::effective_quota(cap_quota)),
_ram_quota(Genode::Child::effective_quota(ram_quota)), _ram_quota(Genode::Child::effective_quota(ram_quota)),
_parent_services(parent_services), _parent_services(parent_services),
_local_nitpicker_service(local_nitpicker_service), _local_nitpicker_service(local_nitpicker_service),
@ -94,9 +97,18 @@ class Loader::Child : public Child_policy
Binary_name binary_name() const override { return _binary_name; } Binary_name binary_name() const override { return _binary_name; }
Pd_session &ref_pd() override { return _env.pd(); }
Pd_session_capability ref_pd_cap() const override { return _env.pd_session_cap(); }
Ram_session &ref_ram() override { return _env.ram(); } Ram_session &ref_ram() override { return _env.ram(); }
Ram_session_capability ref_ram_cap() const override { return _env.ram_session_cap(); } Ram_session_capability ref_ram_cap() const override { return _env.ram_session_cap(); }
void init(Pd_session &pd, Pd_session_capability pd_cap) override
{
pd.ref_account(ref_pd_cap());
ref_pd().transfer_quota(pd_cap, _cap_quota);
}
void init(Ram_session &ram, Ram_session_capability ram_cap) override void init(Ram_session &ram, Ram_session_capability ram_cap) override
{ {
ram.ref_account(ref_ram_cap()); ram.ref_account(ref_ram_cap());

View File

@ -14,7 +14,6 @@
/* Genode includes */ /* Genode includes */
#include <base/component.h> #include <base/component.h>
#include <base/heap.h> #include <base/heap.h>
#include <base/rpc_server.h>
#include <base/sleep.h> #include <base/sleep.h>
#include <loader_session/loader_session.h> #include <loader_session/loader_session.h>
#include <root/component.h> #include <root/component.h>
@ -204,9 +203,11 @@ class Loader::Session_component : public Rpc_object<Session>
Env &_env; Env &_env;
Session_label const _label; Session_label const _label;
Xml_node const _config; Xml_node const _config;
Cap_quota const _cap_quota;
Ram_quota const _ram_quota; Ram_quota const _ram_quota;
Ram_session_client_guard _local_ram { _env.ram_session_cap(), _ram_quota }; Ram_session_client_guard _local_ram { _env.ram_session_cap(), _ram_quota };
Heap _md_alloc { _local_ram, _env.rm() }; Heap _md_alloc { _local_ram, _env.rm() };
size_t _subsystem_cap_quota_limit = 0;
size_t _subsystem_ram_quota_limit = 0; size_t _subsystem_ram_quota_limit = 0;
Parent_services _parent_services; Parent_services _parent_services;
Rom_module_registry _rom_modules { _env, _config, _local_ram, _md_alloc }; Rom_module_registry _rom_modules { _env, _config, _local_ram, _md_alloc };
@ -243,10 +244,11 @@ class Loader::Session_component : public Rpc_object<Session>
/** /**
* Constructor * Constructor
*/ */
Session_component(Env &env, Session_label const &label, Session_component(Env &env, Session_label const &label, Xml_node config,
Xml_node config, Ram_quota quota) Cap_quota cap_quota, Ram_quota ram_quota)
: :
_env(env), _label(label), _config(config), _ram_quota(quota) _env(env), _label(label), _config(config),
_cap_quota(cap_quota), _ram_quota(ram_quota)
{ {
/* fetch all parent-provided ROMs according to the config */ /* fetch all parent-provided ROMs according to the config */
config.for_each_sub_node("parent-rom", [&] (Xml_node rom) config.for_each_sub_node("parent-rom", [&] (Xml_node rom)
@ -287,6 +289,11 @@ class Loader::Session_component : public Rpc_object<Session>
throw Rom_module_does_not_exist(); } throw Rom_module_does_not_exist(); }
} }
void cap_quota(Cap_quota caps) override
{
_subsystem_cap_quota_limit = caps.value;
}
void ram_quota(Ram_quota quantum) override void ram_quota(Ram_quota quantum) override
{ {
_subsystem_ram_quota_limit = quantum.value; _subsystem_ram_quota_limit = quantum.value;
@ -334,6 +341,10 @@ class Loader::Session_component : public Rpc_object<Session>
return; return;
} }
size_t const cap_quota = (_subsystem_cap_quota_limit > 0)
? min(_subsystem_cap_quota_limit, _cap_quota.value)
: _cap_quota.value;
size_t const ram_quota = (_subsystem_ram_quota_limit > 0) size_t const ram_quota = (_subsystem_ram_quota_limit > 0)
? min(_subsystem_ram_quota_limit, _ram_quota.value) ? min(_subsystem_ram_quota_limit, _ram_quota.value)
: _ram_quota.value; : _ram_quota.value;
@ -341,7 +352,7 @@ class Loader::Session_component : public Rpc_object<Session>
try { try {
_child.construct(_env, _md_alloc, binary_name.string(), _child.construct(_env, _md_alloc, binary_name.string(),
prefixed_label(_label, Session_label(label.string())), prefixed_label(_label, Session_label(label.string())),
Ram_quota{ram_quota}, Cap_quota{cap_quota}, Ram_quota{ram_quota},
_parent_services, _rom_service, _parent_services, _rom_service,
_cpu_service, _pd_service, _nitpicker_service, _cpu_service, _pd_service, _nitpicker_service,
_fault_sigh); _fault_sigh);
@ -381,6 +392,7 @@ class Loader::Root : public Root_component<Session_component>
catch (...) { } catch (...) { }
return new (md_alloc()) Session_component(_env, label, session_config, return new (md_alloc()) Session_component(_env, label, session_config,
cap_quota_from_args(args),
ram_quota_from_args(args)); ram_quota_from_args(args));
} }

View File

@ -32,6 +32,7 @@ class Bomb_child : public Child_policy
Env &_env; Env &_env;
Binary_name const _binary_name; Binary_name const _binary_name;
Name const _label; Name const _label;
Cap_quota const _cap_quota;
Ram_quota const _ram_quota; Ram_quota const _ram_quota;
Registry<Registered<Parent_service> > &_parent_services; Registry<Registered<Parent_service> > &_parent_services;
@ -45,11 +46,13 @@ class Bomb_child : public Child_policy
Bomb_child(Env &env, Bomb_child(Env &env,
Name const &binary_name, Name const &binary_name,
Name const &label, Name const &label,
Cap_quota const cap_quota,
Ram_quota const ram_quota, Ram_quota const ram_quota,
Registry<Registered<Parent_service> > &parent_services, Registry<Registered<Parent_service> > &parent_services,
unsigned generation) unsigned generation)
: :
_env(env), _binary_name(binary_name), _label(label), _env(env), _binary_name(binary_name), _label(label),
_cap_quota(Child::effective_quota(cap_quota)),
_ram_quota(Child::effective_quota(ram_quota)), _ram_quota(Child::effective_quota(ram_quota)),
_parent_services(parent_services) _parent_services(parent_services)
{ {
@ -68,12 +71,21 @@ class Bomb_child : public Child_policy
Binary_name binary_name() const override { return _binary_name; } Binary_name binary_name() const override { return _binary_name; }
void init(Pd_session &pd, Pd_session_capability pd_cap) override
{
pd.ref_account(_env.pd_session_cap());
_env.pd().transfer_quota(pd_cap, _cap_quota);
}
void init(Ram_session &ram, Ram_session_capability ram_cap) override void init(Ram_session &ram, Ram_session_capability ram_cap) override
{ {
ram.ref_account(_env.ram_session_cap()); ram.ref_account(_env.ram_session_cap());
_env.ram().transfer_quota(ram_cap, _ram_quota); _env.ram().transfer_quota(ram_cap, _ram_quota);
} }
Pd_session &ref_pd() override { return _env.pd(); }
Pd_session_capability ref_pd_cap() const override { return _env.pd_session_cap(); }
Ram_session &ref_ram() override { return _env.ram(); } Ram_session &ref_ram() override { return _env.ram(); }
Ram_session_capability ref_ram_cap() const override { return _env.ram_session_cap(); } Ram_session_capability ref_ram_cap() const override { return _env.ram_session_cap(); }
@ -177,6 +189,17 @@ struct Bomb
" - not enough memory."); " - not enough memory.");
return; return;
} }
size_t const avail_caps = env.pd().avail_caps().value;
size_t const preserved_caps = children*10;
if (avail_caps < preserved_caps) {
log("I ran out of capabilities.");
return;
}
Cap_quota const cap_quota { (avail_caps - preserved_caps) / children };
if (generation == 0) { if (generation == 0) {
log("I'm a leaf node - generation 0"); log("I'm a leaf node - generation 0");
return; return;
@ -192,7 +215,7 @@ struct Bomb
unique_child_name(child_registry, unique_child_name(child_registry,
binary_name, binary_name,
generation - 1), generation - 1),
ram_amount, cap_quota, ram_amount,
parent_services, generation - 1); parent_services, generation - 1);
} }

View File

@ -24,7 +24,7 @@ struct Main
Env &env; Env &env;
int counter { -1 }; int counter { -1 };
Loader::Connection loader { env, Ram_quota{8*1024*1024} }; Loader::Connection loader { env, Ram_quota{8*1024*1024}, Cap_quota{100} };
Timer::Connection timer { env }; Timer::Connection timer { env };
Signal_handler<Main> timer_handler { env.ep(), *this, &Main::handle_timer }; Signal_handler<Main> timer_handler { env.ep(), *this, &Main::handle_timer };

View File

@ -36,6 +36,7 @@ struct Test::Policy
Policy(Env &env, Name const &name) Policy(Env &env, Name const &name)
: :
Slave::Policy(name, name, *this, env.ep().rpc_ep(), env.rm(), Slave::Policy(name, name, *this, env.ep().rpc_ep(), env.rm(),
env.pd(), env.pd_session_cap(), Cap_quota{100},
env.ram(), env.ram_session_cap(), Ram_quota{1024*1024}) env.ram(), env.ram_session_cap(), Ram_quota{1024*1024})
{ } { }
}; };

View File

@ -70,6 +70,7 @@ class Test_child : public Genode::Child_policy
private: private:
Env &_env; Env &_env;
Cap_quota const _cap_quota { 30 };
Ram_quota const _ram_quota { 1024*1024 }; Ram_quota const _ram_quota { 1024*1024 };
Binary_name const _binary_name; Binary_name const _binary_name;
Signal_context_capability _sigh; Signal_context_capability _sigh;
@ -101,6 +102,9 @@ class Test_child : public Genode::Child_policy
Binary_name binary_name() const override { return _binary_name; } Binary_name binary_name() const override { return _binary_name; }
Pd_session &ref_pd() override { return _env.pd(); }
Pd_session_capability ref_pd_cap() const override { return _env.pd_session_cap(); }
Ram_session &ref_ram() override { return _env.ram(); } Ram_session &ref_ram() override { return _env.ram(); }
Ram_session_capability ref_ram_cap() const override { return _env.ram_session_cap(); } Ram_session_capability ref_ram_cap() const override { return _env.ram_session_cap(); }
@ -116,8 +120,11 @@ class Test_child : public Genode::Child_policy
cpu.exception_sigh(_sigh); cpu.exception_sigh(_sigh);
} }
void init(Pd_session &pd, Pd_session_capability) override void init(Pd_session &pd, Pd_session_capability pd_cap) override
{ {
pd.ref_account(ref_pd_cap());
ref_pd().transfer_quota(pd_cap, _cap_quota);
/* register handler for unresolvable page faults */ /* register handler for unresolvable page faults */
Region_map_client address_space(pd.address_space()); Region_map_client address_space(pd.address_space());
address_space.fault_handler(_sigh); address_space.fault_handler(_sigh);
@ -162,7 +169,7 @@ struct Faulting_loader_child_test
void start_iteration(Env &env, Signal_context_capability fault_sigh) void start_iteration(Env &env, Signal_context_capability fault_sigh)
{ {
loader.construct(env, Ram_quota{1024*1024}); loader.construct(env, Ram_quota{1024*1024}, Cap_quota{100});
/* register fault handler at loader session */ /* register fault handler at loader session */
loader->fault_sigh(fault_sigh); loader->fault_sigh(fault_sigh);
@ -207,7 +214,7 @@ struct Faulting_loader_grand_child_test
void start_iteration(Env &env, Signal_context_capability fault_sigh) void start_iteration(Env &env, Signal_context_capability fault_sigh)
{ {
loader.construct(env, Ram_quota{2*1024*1024}); loader.construct(env, Ram_quota{2*1024*1024}, Cap_quota{100});
/* import config into loader session */ /* import config into loader session */
{ {

View File

@ -25,7 +25,7 @@ struct Test::Main
{ {
Env &_env; Env &_env;
Loader::Connection _loader { _env, Ram_quota{8*1024*1024} }; Loader::Connection _loader { _env, Ram_quota{8*1024*1024}, Cap_quota{100} };
Timer::Connection _timer { _env }; Timer::Connection _timer { _env };
Loader::Area _size; Loader::Area _size;

View File

@ -70,6 +70,7 @@ struct Test::Monitor
xml.node("start", [&] () { xml.node("start", [&] () {
xml.attribute("name", "test-resource_request"); xml.attribute("name", "test-resource_request");
xml.attribute("caps", 3000);
xml.node("resource", [&] () { xml.node("resource", [&] () {
xml.attribute("name", "RAM"); xml.attribute("name", "RAM");
xml.attribute("quantum", _ram_quota); xml.attribute("quantum", _ram_quota);

View File

@ -285,7 +285,7 @@ class Test::Parent
{ {
Parent &_parent; Parent &_parent;
enum { SLAVE_QUOTA = 10*1024*1024 }; enum { SLAVE_CAPS = 50, SLAVE_RAM = 10*1024*1024 };
void yield_response() override void yield_response() override
{ {
@ -296,7 +296,8 @@ class Test::Parent
: :
Slave::Policy(Label("child"), "test-resource_yield", Slave::Policy(Label("child"), "test-resource_yield",
*this, env.ep().rpc_ep(), env.rm(), *this, env.ep().rpc_ep(), env.rm(),
env.ram(), env.ram_session_cap(), Ram_quota{SLAVE_QUOTA}), env.pd(), env.pd_session_cap(), Cap_quota{SLAVE_CAPS},
env.ram(), env.ram_session_cap(), Ram_quota{SLAVE_RAM}),
_parent(parent) _parent(parent)
{ {
configure("<config child=\"yes\" />"); configure("<config child=\"yes\" />");

View File

@ -50,8 +50,11 @@ class Gdb_monitor::App_child : public Child_policy
Allocator &_alloc; Allocator &_alloc;
Pd_session_capability _ref_pd_cap { _env.pd_session_cap() };
Pd_session &_ref_pd { _env.pd() };
Ram_session_capability _ref_ram_cap { _env.ram_session_cap() }; Ram_session_capability _ref_ram_cap { _env.ram_session_cap() };
Ram_session_client _ref_ram { _ref_ram_cap }; Ram_session &_ref_ram { _env.ram() };
const char *_unique_name; const char *_unique_name;
@ -60,6 +63,7 @@ class Gdb_monitor::App_child : public Child_policy
Region_map &_rm; Region_map &_rm;
Ram_quota _ram_quota; Ram_quota _ram_quota;
Cap_quota _cap_quota;
Rpc_entrypoint _entrypoint; Rpc_entrypoint _entrypoint;
@ -112,6 +116,7 @@ class Gdb_monitor::App_child : public Child_policy
Allocator &alloc, Allocator &alloc,
char const *unique_name, char const *unique_name,
Ram_quota ram_quota, Ram_quota ram_quota,
Cap_quota cap_quota,
Signal_receiver &signal_receiver, Signal_receiver &signal_receiver,
Xml_node target_node) Xml_node target_node)
: :
@ -119,7 +124,7 @@ class Gdb_monitor::App_child : public Child_policy
_alloc(alloc), _alloc(alloc),
_unique_name(unique_name), _unique_name(unique_name),
_rm(_env.rm()), _rm(_env.rm()),
_ram_quota(ram_quota), _ram_quota(ram_quota), _cap_quota(cap_quota),
_entrypoint(&_env.pd(), STACK_SIZE, "GDB monitor entrypoint"), _entrypoint(&_env.pd(), STACK_SIZE, "GDB monitor entrypoint"),
_child_config(env.ram(), _rm, target_node), _child_config(env.ram(), _rm, target_node),
_config_policy("config", _child_config.dataspace(), &_entrypoint), _config_policy("config", _child_config.dataspace(), &_entrypoint),
@ -155,6 +160,10 @@ class Gdb_monitor::App_child : public Child_policy
Name name() const override { return _unique_name; } Name name() const override { return _unique_name; }
Pd_session &ref_pd() override { return _ref_pd; }
Pd_session_capability ref_pd_cap() const override { return _ref_pd_cap; }
Ram_session &ref_ram() override { return _ref_ram; } Ram_session &ref_ram() override { return _ref_ram; }
Ram_session_capability ref_ram_cap() const override { return _ref_ram_cap; } Ram_session_capability ref_ram_cap() const override { return _ref_ram_cap; }
@ -166,6 +175,13 @@ class Gdb_monitor::App_child : public Child_policy
_ref_ram.transfer_quota(cap, _ram_quota); _ref_ram.transfer_quota(cap, _ram_quota);
} }
void init(Pd_session &session,
Pd_session_capability cap) override
{
session.ref_account(_ref_pd_cap);
_ref_pd.transfer_quota(cap, _cap_quota);
}
Service &resolve_session_request(Service::Name const &service_name, Service &resolve_session_request(Service::Name const &service_name,
Session_state::Args const &args) override Session_state::Args const &args) override
{ {

View File

@ -469,6 +469,17 @@ extern "C" int fork()
Number_of_bytes ram_quota = genode_env->ram().avail_ram().value - preserved_ram_quota; Number_of_bytes ram_quota = genode_env->ram().avail_ram().value - preserved_ram_quota;
Cap_quota const avail_cap_quota = genode_env->pd().avail_caps();
Genode::size_t const preserved_caps = 100;
if (avail_cap_quota.value < preserved_caps) {
error("not enough available caps for preservation of ", preserved_caps);
return -1;
}
Cap_quota const cap_quota { avail_cap_quota.value - preserved_caps };
/* start the application */ /* start the application */
static Heap alloc(genode_env->ram(), genode_env->rm()); static Heap alloc(genode_env->ram(), genode_env->rm());
@ -483,6 +494,7 @@ extern "C" int fork()
alloc, alloc,
filename, filename,
Ram_quota{ram_quota}, Ram_quota{ram_quota},
cap_quota,
signal_receiver, signal_receiver,
target_node); target_node);

View File

@ -116,6 +116,15 @@ class Gdb_monitor::Pd_session_component : public Rpc_object<Pd_session>
Capability<Region_map> linker_area() override { Capability<Region_map> linker_area() override {
return _linker_area.Rpc_object<Region_map>::cap(); } return _linker_area.Rpc_object<Region_map>::cap(); }
void ref_account(Capability<Pd_session> pd) override {
warning("Pd_session::ref_account not implemented"); }
void transfer_quota(Capability<Pd_session> pd, Cap_quota amount) override {
warning("Pd_session::transfer_quota not implemented"); }
Cap_quota cap_quota() const { return _pd.cap_quota(); }
Cap_quota used_caps() const { return _pd.used_caps(); }
Capability<Native_pd> native_pd() override { Capability<Native_pd> native_pd() override {
return _pd.native_pd(); } return _pd.native_pd(); }
}; };

Some files were not shown because too many files have changed in this diff Show More