From e44f65f3b244bfc9598fd72d381165ae6b2e3ec1 Mon Sep 17 00:00:00 2001 From: Norman Feske Date: Mon, 8 May 2017 19:55:54 +0200 Subject: [PATCH] core: RAM service based on 'Session_object' This patch reworks the implementation of core's RAM service to make use of the 'Session_object' and to remove the distinction between the "metadata" quota and the managed RAM quota. With the new implementation, the session implicitly allocates its metadata from its own account. So there is not need to handle 'Out_of_metadata' and 'Quota_exceeded' via different exceptions. Instead, the new version solely uses the 'Out_of_ram' exception. Furthermore, the 'Allocator::Out_of_memory' exception has become an alias for 'Out_of_ram', which simplifies the error handling. Issue #2398 --- repos/base-linux/src/core/include/core_env.h | 27 +- .../base-nova/src/core/native_pd_component.cc | 3 +- .../base-nova/src/core/ram_session_support.cc | 4 +- repos/base/include/base/allocator.h | 16 +- .../include/base/attached_io_mem_dataspace.h | 1 + .../include/base/attached_ram_dataspace.h | 2 +- repos/base/include/base/child.h | 2 +- repos/base/include/base/env.h | 4 +- repos/base/include/base/ram_allocator.h | 9 +- repos/base/include/base/session_object.h | 2 - repos/base/include/ram_session/ram_session.h | 4 +- repos/base/include/root/component.h | 5 +- repos/base/src/core/include/account.h | 175 +++++++++++ repos/base/src/core/include/core_env.h | 23 +- repos/base/src/core/include/ram_root.h | 49 +-- .../src/core/include/ram_session_component.h | 137 ++++----- repos/base/src/core/main.cc | 20 +- repos/base/src/core/ram_session_component.cc | 278 +++++++----------- .../base/internal/expanding_parent_client.h | 4 +- .../internal/expanding_ram_session_client.h | 12 +- repos/base/src/lib/base/child.cc | 2 +- repos/base/src/lib/base/child_process.cc | 2 +- repos/base/src/lib/base/heap.cc | 6 +- repos/base/src/lib/base/sliced_heap.cc | 6 +- repos/base/src/lib/base/thread.cc | 6 +- repos/dde_rump/include/util/allocator_fap.h | 2 +- repos/libports/src/lib/libc/libc_mem_alloc.cc | 7 +- repos/os/include/os/dynamic_rom_session.h | 8 +- repos/os/include/os/ram_session_guard.h | 2 +- .../platform/spec/x86/pci_session_component.h | 28 +- repos/os/src/init/main.cc | 4 +- repos/os/src/server/nic_bridge/component.h | 2 +- 32 files changed, 486 insertions(+), 366 deletions(-) create mode 100644 repos/base/src/core/include/account.h diff --git a/repos/base-linux/src/core/include/core_env.h b/repos/base-linux/src/core/include/core_env.h index 7d8691cbbd..41cfda2082 100644 --- a/repos/base-linux/src/core/include/core_env.h +++ b/repos/base-linux/src/core/include/core_env.h @@ -115,8 +115,6 @@ namespace Genode { Ram_session_component _ram_session; Synced_ram_session _synced_ram_session { _ram_session }; - Ram_session_capability const _ram_session_cap; - /* * The core-local PD session is provided by a real RPC object * dispatched by the same entrypoint as the signal-source RPC @@ -133,6 +131,14 @@ namespace Genode { Core_parent _core_parent { _heap, _services }; + typedef String<100> Ram_args; + + static Session::Resources _ram_resources() + { + return { Ram_quota { platform()->ram_alloc()->avail() }, + Cap_quota { 1000 } }; + } + public: /** @@ -143,13 +149,18 @@ namespace Genode { Platform_env_base(Ram_session_capability(), Cpu_session_capability(), Pd_session_capability()), - _ram_session(&_entrypoint, &_entrypoint, - platform()->ram_alloc(), platform()->core_mem_alloc(), - "ram_quota=4M", platform()->ram_alloc()->avail()), - _ram_session_cap(_entrypoint.manage(&_ram_session)), + _ram_session(_entrypoint, + _ram_resources(), + Session::Label("core"), + Session::Diag{false}, + *platform()->ram_alloc(), + *Platform_env_base::rm_session(), + Ram_session_component::any_phys_range()), _pd_session_component(_entrypoint), _pd_session_client(_entrypoint.manage(&_pd_session_component)) - { } + { + _ram_session.init_ram_account(); + } /** * Destructor @@ -165,7 +176,7 @@ namespace Genode { ******************************/ Parent *parent() override { return &_core_parent; } - Ram_session *ram_session() override { return &_synced_ram_session; } + Ram_session *ram_session() override { return &_ram_session; } Ram_session_capability ram_session_cap() override { return _ram_session.cap(); } Pd_session *pd_session() override { return &_pd_session_client; } Allocator *heap() override { log(__func__, ": not implemented"); return nullptr; } diff --git a/repos/base-nova/src/core/native_pd_component.cc b/repos/base-nova/src/core/native_pd_component.cc index 5d88011e7f..31c23efd87 100644 --- a/repos/base-nova/src/core/native_pd_component.cc +++ b/repos/base-nova/src/core/native_pd_component.cc @@ -26,8 +26,7 @@ Native_capability Native_pd_component::alloc_rpc_cap(Native_capability ep, try { return _pd_session._rpc_cap_factory.alloc(ep, entry, mtd); } - catch (Allocator::Out_of_memory) { - throw Pd_session::Out_of_metadata(); } + catch (Allocator::Out_of_memory) { throw Out_of_ram(); } } diff --git a/repos/base-nova/src/core/ram_session_support.cc b/repos/base-nova/src/core/ram_session_support.cc index fc55fdd4b3..be54ed027a 100644 --- a/repos/base-nova/src/core/ram_session_support.cc +++ b/repos/base-nova/src/core/ram_session_support.cc @@ -81,7 +81,7 @@ void Ram_session_component::_export_ram_ds(Dataspace_component *ds) { /* allocate the virtual region contiguous for the dataspace */ void * virt_ptr = alloc_region(ds, page_rounded_size); if (!virt_ptr) - throw Out_of_metadata(); + throw Core_virtual_memory_exhausted(); /* map it writeable for _clear_ds */ Nova::Utcb * const utcb = reinterpret_cast(Thread::myself()->utcb()); @@ -90,7 +90,7 @@ void Ram_session_component::_export_ram_ds(Dataspace_component *ds) { if (map_local(utcb, ds->phys_addr(), reinterpret_cast(virt_ptr), page_rounded_size >> get_page_size_log2(), rights_rw, true)) { platform()->region_alloc()->free(virt_ptr, page_rounded_size); - throw Out_of_metadata(); + throw Core_virtual_memory_exhausted(); } /* assign virtual address to the dataspace to be used by clear_ds */ diff --git a/repos/base/include/base/allocator.h b/repos/base/include/base/allocator.h index d6a43ca307..2deead4aa1 100644 --- a/repos/base/include/base/allocator.h +++ b/repos/base/include/base/allocator.h @@ -16,6 +16,7 @@ #include #include +#include namespace Genode { @@ -59,7 +60,7 @@ struct Genode::Allocator : Deallocator /** * Exception type */ - class Out_of_memory : public Exception { }; + typedef Out_of_ram Out_of_memory; /** * Destructor @@ -72,6 +73,9 @@ struct Genode::Allocator : Deallocator * \param size block size to allocate * \param out_addr resulting pointer to the new block, * undefined in the error case + * + * \throw Out_of_ram + * * \return true on success */ virtual bool alloc(size_t size, void **out_addr) = 0; @@ -83,6 +87,8 @@ struct Genode::Allocator : Deallocator * a non-void type. By providing this method, we prevent the * compiler from warning us about "dereferencing type-punned * pointer will break strict-aliasing rules". + * + * \throw Out_of_ram */ template bool alloc(size_t size, T **out_addr) { @@ -105,9 +111,11 @@ struct Genode::Allocator : Deallocator /** * Allocate block and signal error as an exception * - * \param size block size to allocate - * \return pointer to the new block - * \throw Out_of_memory + * \param size block size to allocate + * + * \throw Out_of_ram + * + * \return pointer to the new block */ void *alloc(size_t size) { diff --git a/repos/base/include/base/attached_io_mem_dataspace.h b/repos/base/include/base/attached_io_mem_dataspace.h index e9fa44d703..0b6050293b 100644 --- a/repos/base/include/base/attached_io_mem_dataspace.h +++ b/repos/base/include/base/attached_io_mem_dataspace.h @@ -48,6 +48,7 @@ class Genode::Attached_io_mem_dataspace * \throw Parent::Service_denied * \throw Insufficient_ram_quota * \throw Parent::Unavailable + * \throw Out_of_ram * \throw Rm_session::Attach_failed */ Attached_io_mem_dataspace(Env &env, Genode::addr_t base, Genode::size_t size, diff --git a/repos/base/include/base/attached_ram_dataspace.h b/repos/base/include/base/attached_ram_dataspace.h index 96124bd82e..dc0b0f634a 100644 --- a/repos/base/include/base/attached_ram_dataspace.h +++ b/repos/base/include/base/attached_ram_dataspace.h @@ -90,7 +90,7 @@ class Genode::Attached_ram_dataspace /** * Constructor * - * \throw Ram_session::Alloc_failed + * \throw Out_of_ram * \throw Rm_session::Attach_failed */ Attached_ram_dataspace(Ram_session &ram, Region_map &rm, diff --git a/repos/base/include/base/child.h b/repos/base/include/base/child.h index df422693a3..78612b2b1e 100644 --- a/repos/base/include/base/child.h +++ b/repos/base/include/base/child.h @@ -392,7 +392,7 @@ class Genode::Child : protected Rpc_object, * \throw Missing_dynamic_linker * \throw Invalid_executable * \throw Region_map::Attach_failed - * \throw Ram_session::Alloc_failed + * \throw Out_of_ram * * The other arguments correspond to those of 'Child::Child'. * diff --git a/repos/base/include/base/env.h b/repos/base/include/base/env.h index 52fdfac161..5cb66a5462 100644 --- a/repos/base/include/base/env.h +++ b/repos/base/include/base/env.h @@ -115,7 +115,7 @@ struct Genode::Env * \param id ID of recipient session * \param args description of the amount of quota to transfer * - * \throw Quota_exceeded quota could not be transferred + * \throw Out_of_ram * * The 'args' argument has the same principle format as the 'args' * argument of the 'session' operation. @@ -135,7 +135,7 @@ struct Genode::Env * constructors in the binary and shared libraries the binary depends on. If * the component requires static construction it needs to call this function * at construction time explicitly. For example, the libc implementation - * executes this function before constructing libc components. + * executes this function before constructing libc components. */ virtual void exec_static_constructors() = 0; }; diff --git a/repos/base/include/base/ram_allocator.h b/repos/base/include/base/ram_allocator.h index 32933b7998..1569f5afd1 100644 --- a/repos/base/include/base/ram_allocator.h +++ b/repos/base/include/base/ram_allocator.h @@ -33,11 +33,6 @@ namespace Genode { struct Genode::Ram_allocator { - class Alloc_failed : public Exception { }; - class Quota_exceeded : public Alloc_failed { }; - class Out_of_metadata : public Alloc_failed { }; - - /** * Allocate RAM dataspace * @@ -45,8 +40,8 @@ struct Genode::Ram_allocator * \param cached selects cacheability attributes of the memory, * uncached memory, i.e., for DMA buffers * - * \throw Quota_exceeded - * \throw Out_of_metadata + * \throw Out_of_ram + * \throw Out_of_caps * * \return capability to new RAM dataspace */ diff --git a/repos/base/include/base/session_object.h b/repos/base/include/base/session_object.h index 78943e211e..e06c19c875 100644 --- a/repos/base/include/base/session_object.h +++ b/repos/base/include/base/session_object.h @@ -65,14 +65,12 @@ class Genode::Session_object : public Ram_quota_guard, Cap_quota_guard(resources.cap_quota), _ep(ep), _diag(diag), _label(label) { - Cap_quota_guard::withdraw(Cap_quota{1}); _ep.manage(this); } ~Session_object() { _ep.dissolve(this); - Cap_quota_guard::replenish(Cap_quota{1}); } /** diff --git a/repos/base/include/ram_session/ram_session.h b/repos/base/include/ram_session/ram_session.h index 80d71780a0..e1aebb7bda 100644 --- a/repos/base/include/ram_session/ram_session.h +++ b/repos/base/include/ram_session/ram_session.h @@ -45,6 +45,8 @@ struct Genode::Ram_session : Session, Ram_allocator class Invalid_session : public Exception { }; class Undefined_ref_account : public Exception { }; + /* deprecated */ + typedef Out_of_ram Quota_exceeded; /** * Destructor @@ -100,7 +102,7 @@ struct Genode::Ram_session : Session, Ram_allocator *********************/ GENODE_RPC_THROW(Rpc_alloc, Ram_dataspace_capability, alloc, - GENODE_TYPE_LIST(Quota_exceeded, Out_of_metadata, Undefined_ref_account), + GENODE_TYPE_LIST(Out_of_ram, Out_of_caps, Undefined_ref_account), size_t, Cache_attribute); GENODE_RPC(Rpc_free, void, free, Ram_dataspace_capability); GENODE_RPC(Rpc_ref_account, void, ref_account, Capability); diff --git a/repos/base/include/root/component.h b/repos/base/include/root/component.h index ffdb743f8d..c9bc079670 100644 --- a/repos/base/include/root/component.h +++ b/repos/base/include/root/component.h @@ -164,10 +164,7 @@ class Genode::Root_component : public Rpc_object >, SESSION_TYPE *s = 0; try { s = _create_session(adjusted_args, affinity); } - catch (Allocator::Out_of_memory) { - error("out of memory for session creation, '", args, "'"); - throw Root::Unavailable(); - } + catch (Out_of_ram) { throw Insufficient_ram_quota(); } /* * Consider that the session-object constructor may already have diff --git a/repos/base/src/core/include/account.h b/repos/base/src/core/include/account.h new file mode 100644 index 0000000000..3e0c68b6db --- /dev/null +++ b/repos/base/src/core/include/account.h @@ -0,0 +1,175 @@ +/* + * \brief Resource account handling + * \author Norman Feske + * \date 2017-04-24 + */ + +/* + * Copyright (C) 2017 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +#ifndef _CORE__INCLUDE__ACCOUNT_H_ +#define _CORE__INCLUDE__ACCOUNT_H_ + +#include +#include +#include + +namespace Genode { template class Account; } + + +template +class Genode::Account +{ + private: + + Quota_guard &_quota_guard; + + Session::Label const &_label; + + UNIT const _initial_used = _quota_guard.used(); + + Lock mutable _lock; + + /* + * Reference account + */ + Account *_ref_account = nullptr; + + /* + * Registry of accounts that have this account as their reference + * account. + */ + Registry _ref_account_members; + + /* + * Role as reference-account user + */ + Constructible::Element> _ref_account_member; + + /** + * Assign 'this' as reference account of 'account' + */ + void _adopt(Account &account) + { + account._ref_account_member.construct(_ref_account_members, account); + account._ref_account = this; + } + + public: + + typedef typename Quota_guard::Limit_exceeded Limit_exceeded; + + class Unrelated_account : Exception { }; + + /** + * Constructor for creating a regular account that is rechargeable by + * the specified reference account + */ + Account(Quota_guard "a_guard, Session_label const &label, + Account &ref_account) + : _quota_guard(quota_guard), _label(label) { ref_account._adopt(*this); } + + /** + * Constructor used for creating the initial account + */ + Account(Quota_guard "a_guard, Session_label const &label) + : _quota_guard(quota_guard), _label(label) { } + + ~Account() + { + if (!_ref_account) return; + + Lock::Guard guard(_lock); + + if (_quota_guard.used().value > _initial_used.value) { + UNIT const dangling { _quota_guard.used().value - _initial_used.value }; + warning("destroying account with allocated (possibly leaking?) " + "resources (", dangling, " ", UNIT::name(),")"); + _quota_guard.replenish(dangling); + } + + /* transfer remaining quota to our reference account */ + _ref_account->_quota_guard.upgrade(_quota_guard.limit()); + + /* assign all sub accounts to our reference account */ + _ref_account_members.for_each([&] (Account &orphan) { + _ref_account->_adopt(orphan); }); + } + + /** + * Transfer quota to/from other account + * + * \throw Unrelated_account + * \throw Limit_exceeded + */ + void transfer_quota(Account &other, UNIT amount) + { + { + Lock::Guard guard(_lock); + + /* transfers are permitted only from/to the reference account */ + if (_ref_account != &other && other._ref_account != this) + throw Unrelated_account(); + + /* downgrade from this account */ + if (!_quota_guard.try_downgrade(amount)) + throw Limit_exceeded(); + } + + /* credit to 'other' */ + Lock::Guard guard(other._lock); + other._quota_guard.upgrade(amount); + } + + UNIT limit() const + { + Lock::Guard guard(_lock); + return _quota_guard.limit(); + } + + UNIT used() const + { + Lock::Guard guard(_lock); + return _quota_guard.used(); + } + + UNIT avail() const + { + Lock::Guard guard(_lock); + return _quota_guard.avail(); + } + + /** + * Withdraw quota from account + * + * Called when allocating physical resources + * + * \throw Limit_exceeded + */ + void withdraw(UNIT amount) + { + Lock::Guard guard(_lock); + _quota_guard.withdraw(amount); + } + + /** + * Replenish quota to account + * + * Called when releasing physical resources + */ + void replenish(UNIT amount) + { + Lock::Guard guard(_lock); + _quota_guard.replenish(amount); + } + + void print(Output &out) const { Genode::print(out, _quota_guard); } + + Session::Label label() const { return _label; } +}; + +#endif /* _CORE__INCLUDE__ACCOUNT_H_ */ diff --git a/repos/base/src/core/include/core_env.h b/repos/base/src/core/include/core_env.h index 069eef2278..397396cd23 100644 --- a/repos/base/src/core/include/core_env.h +++ b/repos/base/src/core/include/core_env.h @@ -134,6 +134,14 @@ namespace Genode { Core_parent _core_parent { _heap, _services }; + typedef String<100> Ram_args; + + static Session::Resources _ram_resources() + { + return { Ram_quota { platform()->ram_alloc()->avail() }, + Cap_quota { platform()->max_caps() } }; + } + public: /** @@ -143,13 +151,18 @@ namespace Genode { : _entrypoint(nullptr, ENTRYPOINT_STACK_SIZE, "entrypoint"), _region_map(_entrypoint), - _ram_session(&_entrypoint, &_entrypoint, - platform()->ram_alloc(), platform()->core_mem_alloc(), - "ram_quota=4M", platform()->ram_alloc()->avail()), - _ram_session_cap(_entrypoint.manage(&_ram_session)), + _ram_session(_entrypoint, + _ram_resources(), + Session::Label("core"), + Session::Diag{false}, + *platform()->ram_alloc(), + _region_map, + Ram_session_component::any_phys_range()), _pd_session_component(_entrypoint), _pd_session_client(_entrypoint.manage(&_pd_session_component)) - { } + { + _ram_session.init_ram_account(); + } /** * Destructor diff --git a/repos/base/src/core/include/ram_root.h b/repos/base/src/core/include/ram_root.h index 4b92ff26f8..e15b978576 100644 --- a/repos/base/src/core/include/ram_root.h +++ b/repos/base/src/core/include/ram_root.h @@ -24,41 +24,50 @@ namespace Genode { { private: - Range_allocator *_ram_alloc; - Rpc_entrypoint *_ds_ep; + Rpc_entrypoint &_ep; + Range_allocator &_phys_alloc; + Region_map &_local_rm; + + static Ram_session_component::Phys_range phys_range_from_args(char const *args) + { + addr_t const start = Arg_string::find_arg(args, "phys_start").ulong_value(0); + addr_t const size = Arg_string::find_arg(args, "phys_size").ulong_value(0); + addr_t const end = start + size - 1; + + return (start <= end) ? Ram_session_component::Phys_range { start, end } + : Ram_session_component::any_phys_range(); + } protected: Ram_session_component *_create_session(const char *args) { return new (md_alloc()) - Ram_session_component(_ds_ep, ep(), _ram_alloc, - md_alloc(), args); + Ram_session_component(_ep, + session_resources_from_args(args), + session_label_from_args(args), + session_diag_from_args(args), + _phys_alloc, _local_rm, + phys_range_from_args(args)); } void _upgrade_session(Ram_session_component *ram, const char *args) { - size_t ram_quota = Arg_string::find_arg(args, "ram_quota").ulong_value(0); - ram->upgrade_ram_quota(ram_quota); + ram->Ram_quota_guard::upgrade(ram_quota_from_args(args)); + ram->Cap_quota_guard::upgrade(cap_quota_from_args(args)); + ram->session_quota_upgraded(); } public: - /** - * Constructor - * - * \param session_ep entry point for managing ram session objects - * \param ds_ep entry point for managing dataspaces - * \param ram_alloc pool of memory to be assigned to ram sessions - * \param md_alloc meta-data allocator to be used by root component - */ - Ram_root(Rpc_entrypoint *session_ep, - Rpc_entrypoint *ds_ep, - Range_allocator *ram_alloc, - Allocator *md_alloc) + Ram_root(Rpc_entrypoint &ep, + Range_allocator &phys_alloc, + Region_map &local_rm, + Allocator &md_alloc) : - Root_component(session_ep, md_alloc), - _ram_alloc(ram_alloc), _ds_ep(ds_ep) { } + Root_component(&ep, &md_alloc), + _ep(ep), _phys_alloc(phys_alloc), _local_rm(local_rm) + { } }; } diff --git a/repos/base/src/core/include/ram_session_component.h b/repos/base/src/core/include/ram_session_component.h index e07b87eed1..025db5c633 100644 --- a/repos/base/src/core/include/ram_session_component.h +++ b/repos/base/src/core/include/ram_session_component.h @@ -18,25 +18,28 @@ #include #include #include -#include +#include #include #include +#include /* core includes */ #include #include +#include -namespace Genode { - - class Ram_session_component; - typedef List Ram_ref_account_members; -} +namespace Genode { class Ram_session_component; } -class Genode::Ram_session_component : public Rpc_object, - public Ram_ref_account_members::Element, +class Genode::Ram_session_component : public Session_object, public Dataspace_owner { + public: + + struct Phys_range { addr_t start, end; }; + + static Phys_range any_phys_range() { return { 0UL, ~0UL }; } + private: class Invalid_dataspace : public Exception { }; @@ -47,61 +50,46 @@ class Genode::Ram_session_component : public Rpc_object, */ static constexpr size_t SBS = get_page_size() - Sliced_heap::meta_data_size(); - using Ds_slab = Synced_allocator >; + using Ds_slab = Tslab; - Rpc_entrypoint *_ds_ep; - Rpc_entrypoint *_ram_session_ep; - Range_allocator *_ram_alloc; - size_t _quota_limit; - size_t _payload; /* quota used for payload */ - Allocator_guard _md_alloc; /* guarded meta-data allocator */ - Ds_slab _ds_slab; /* meta-data allocator */ - Ram_session_component *_ref_account; /* reference ram session */ - addr_t _phys_start; - addr_t _phys_end; + Rpc_entrypoint &_ep; - enum { MAX_LABEL_LEN = 64 }; - char _label[MAX_LABEL_LEN]; + Range_allocator &_phys_alloc; - /** - * List of RAM sessions that use us as their reference account + Constrained_ram_allocator _constrained_md_ram_alloc; + + Constructible _sliced_heap; + + /* + * Statically allocated initial slab block for '_ds_slab', needed to + * untangle the hen-and-egg problem of allocating the meta data for + * core's RAM allocator from itself. I also saves the allocation + * of one dataspace (along with a dataspace capability) per session. */ - Ram_ref_account_members _ref_members; - Lock _ref_members_lock; /* protect '_ref_members' */ + uint8_t _initial_sb[SBS]; - /** - * Register RAM session to use us as reference account - */ - void _register_ref_account_member(Ram_session_component *new_member); + Constructible _ds_slab; - /** - * Dissolve reference-account relationship of a member account - */ - void _remove_ref_account_member(Ram_session_component *member); - void _unsynchronized_remove_ref_account_member(Ram_session_component *member); + Phys_range const _phys_range; - /** - * Return portion of RAM quota that is currently in use - */ - size_t used_quota() { return _payload; } + Constructible > _ram_account; /** * Free dataspace */ void _free_ds(Dataspace_capability ds_cap); - /** - * Transfer quota to another RAM session - */ - void _transfer_quota(Ram_session_component *dst, size_t amount); - /******************************************** ** Platform-implemented support functions ** ********************************************/ + struct Core_virtual_memory_exhausted : Exception { }; + /** * Export RAM dataspace as shared memory block + * + * \throw Core_virtual_memory_exhausted */ void _export_ram_ds(Dataspace_component *ds); @@ -117,44 +105,24 @@ class Genode::Ram_session_component : public Rpc_object, public: - /** - * Constructor - * - * \param ds_ep server entry point to manage the - * dataspaces created by the Ram session - * \param ram_session_ep entry point that manages Ram sessions, - * used for looking up another ram session - * in transfer_quota() - * \param ram_alloc memory pool to manage - * \param md_alloc meta-data allocator - * \param md_ram_quota limit of meta-data backing store - * \param quota_limit initial quota limit - * - * The 'quota_limit' parameter is only used for the very - * first ram session in the system. All other ram session - * load their quota via 'transfer_quota'. - */ - Ram_session_component(Rpc_entrypoint *ds_ep, - Rpc_entrypoint *ram_session_ep, - Range_allocator *ram_alloc, - Allocator *md_alloc, - const char *args, - size_t quota_limit = 0); + Ram_session_component(Rpc_entrypoint &ep, + Resources resources, + Session_label const &label, + Diag diag, + Range_allocator &phys_alloc, + Region_map &local_rm, + Phys_range phys_range); - /** - * Destructor - */ ~Ram_session_component(); /** - * Accessors + * Initialize RAM account without providing a reference account + * + * This method is solely used to set up the initial RAM session within + * core. The RAM accounts of regular RAM session are initialized via + * 'ref_account'. */ - Ram_session_component *ref_account() { return _ref_account; } - - /** - * Register quota donation at allocator guard - */ - void upgrade_ram_quota(size_t ram_quota) { _md_alloc.upgrade(ram_quota); } + void init_ram_account() { _ram_account.construct(*this, _label); } /** * Get physical address of the RAM that backs a dataspace @@ -181,10 +149,19 @@ class Genode::Ram_session_component : public Rpc_object, ** RAM Session interface ** ***************************/ - void ref_account(Ram_session_capability); - void transfer_quota(Ram_session_capability, Ram_quota); - Ram_quota ram_quota() const override { return { _quota_limit}; } - Ram_quota used_ram() const override { return { _payload}; } + void ref_account(Ram_session_capability) override; + + void transfer_quota(Ram_session_capability, Ram_quota) override; + + Ram_quota ram_quota() const override + { + return _ram_account.constructed() ? _ram_account->limit() : Ram_quota { 0 }; + } + + Ram_quota used_ram() const override + { + return _ram_account.constructed() ? _ram_account->used() : Ram_quota { 0 }; + } }; #endif /* _CORE__INCLUDE__RAM_SESSION_COMPONENT_H_ */ diff --git a/repos/base/src/core/main.cc b/repos/base/src/core/main.cc index 4a479c3a18..7d01cba58a 100644 --- a/repos/base/src/core/main.cc +++ b/repos/base/src/core/main.cc @@ -140,9 +140,10 @@ class Core_child : public Child_policy /** * Constructor */ - Core_child(Registry &services, Ram_session &core_ram, - Capability core_ram_cap, Ram_quota ram_quota, - Cpu_session &core_cpu, Capability core_cpu_cap) + Core_child(Registry &services, + Ram_session &core_ram, Capability core_ram_cap, + Cpu_session &core_cpu, Capability core_cpu_cap, + Ram_quota ram_quota) : _entrypoint(nullptr, STACK_SIZE, "init_child", false), _services(services), @@ -249,11 +250,14 @@ int main() Registry &services = core_env()->services(); + static Ram_allocator &core_ram_alloc = *core_env()->ram_session(); + static Region_map &local_rm = *core_env()->rm_session(); + /* * Allocate session meta data on distinct dataspaces to enable independent * destruction (to enable quota trading) of session component objects. */ - static Sliced_heap sliced_heap(env_deprecated()->ram_session(), env_deprecated()->rm_session()); + static Sliced_heap sliced_heap(core_ram_alloc, local_rm); /* * Factory for creating RPC capabilities within core @@ -262,7 +266,7 @@ int main() static Pager_entrypoint pager_ep(rpc_cap_factory); - static Ram_root ram_root (e, e, platform()->ram_alloc(), &sliced_heap); + static Ram_root ram_root (*e, *platform()->ram_alloc(), local_rm, sliced_heap); static Rom_root rom_root (e, e, platform()->rom_fs(), &sliced_heap); static Rm_root rm_root (e, &sliced_heap, pager_ep); static Cpu_root cpu_root (e, e, &pager_ep, &sliced_heap, @@ -309,8 +313,10 @@ int main() "assigned to init"); static Reconstructible - init(services, *env_deprecated()->ram_session(), env_deprecated()->ram_session_cap(), - Ram_quota{avail_ram_quota}, core_cpu, core_cpu_cap); + init(services, + *env_deprecated()->ram_session(), env_deprecated()->ram_session_cap(), + core_cpu, core_cpu_cap, + Ram_quota{avail_ram_quota}); platform()->wait_for_exit(); diff --git a/repos/base/src/core/ram_session_component.cc b/repos/base/src/core/ram_session_component.cc index 4fedddb44e..ae8024773b 100644 --- a/repos/base/src/core/ram_session_component.cc +++ b/repos/base/src/core/ram_session_component.cc @@ -28,14 +28,14 @@ addr_t Ram_session_component::phys_addr(Ram_dataspace_capability ds) return dsc->phys_addr(); }; - return _ds_ep->apply(ds, lambda); + return _ep.apply(ds, lambda); } void Ram_session_component::_free_ds(Dataspace_capability ds_cap) { Dataspace_component *ds = nullptr; - _ds_ep->apply(ds_cap, [&] (Dataspace_component *c) + _ep.apply(ds_cap, [&] (Dataspace_component *c) { if (!c) return; if (!c->owner(this)) return; @@ -45,7 +45,7 @@ void Ram_session_component::_free_ds(Dataspace_capability ds_cap) size_t ds_size = ds->size(); /* tell entry point to forget the dataspace */ - _ds_ep->dissolve(ds); + _ep.dissolve(ds); /* remove dataspace from all RM sessions */ ds->detach_from_rm_sessions(); @@ -54,64 +54,14 @@ void Ram_session_component::_free_ds(Dataspace_capability ds_cap) _revoke_ram_ds(ds); /* free physical memory that was backing the dataspace */ - _ram_alloc->free((void *)ds->phys_addr(), ds_size); + _phys_alloc.free((void *)ds->phys_addr(), ds_size); - /* adjust payload */ - Lock::Guard lock_guard(_ref_members_lock); - _payload -= ds_size; + _ram_account->replenish(Ram_quota{ds_size}); }); /* call dataspace destructors and free memory */ if (ds) - destroy(&_ds_slab, ds); -} - - -void Ram_session_component::_transfer_quota(Ram_session_component *dst, size_t amount) -{ - /* check if recipient is a valid Ram_session_component */ - if (!dst) - throw Invalid_session(); - - /* check for reference account relationship */ - if ((ref_account() != dst) && (dst->ref_account() != this)) - throw Invalid_session(); - - /* decrease quota limit of this session - check against used quota */ - if (_quota_limit < amount + _payload) { - warning("insufficient quota for transfer: " - "'", Cstring(_label), "' to '", Cstring(dst->_label), "' " - "have ", (_quota_limit - _payload)/1024, " KiB, " - "need ", amount/1024, " KiB"); - throw Out_of_ram(); - } - - _quota_limit -= amount; - - /* increase quota_limit of recipient */ - dst->_quota_limit += amount; -} - - -void Ram_session_component::_register_ref_account_member(Ram_session_component *new_member) -{ - Lock::Guard lock_guard(_ref_members_lock); - _ref_members.insert(new_member); - new_member->_ref_account = this; -} - - -void Ram_session_component::_unsynchronized_remove_ref_account_member(Ram_session_component *member) -{ - member->_ref_account = 0; - _ref_members.remove(member); -} - - -void Ram_session_component::_remove_ref_account_member(Ram_session_component *member) -{ - Lock::Guard lock_guard(_ref_members_lock); - _unsynchronized_remove_ref_account_member(member); + destroy(*_ds_slab, ds); } @@ -124,14 +74,23 @@ Ram_dataspace_capability Ram_session_component::alloc(size_t ds_size, Cache_attr ds_size = align_addr(ds_size, 12); /* - * Check quota! + * Track quota usage * - * In the worst case, we need to allocate a new slab block for the - * meta data of the dataspace to be created - therefore, we add - * the slab block size here. + * We use a guard to roll back the withdrawal of the quota whenever + * we leave the method scope via an exception. The withdrawal is + * acknowledge just before successfully leaving the method. */ - if (used_quota() + SBS + ds_size > _quota_limit) - throw Quota_exceeded(); + Ram_quota_guard::Reservation dataspace_ram_costs(*this, Ram_quota{ds_size}); + + /* + * In the worst case, we need to allocate a new slab block for the + * meta data of the dataspace to be created. Therefore, we temporarily + * withdraw the slab block size here to trigger an exception if the + * account does not have enough room for the meta data. + */ + { + Ram_quota_guard::Reservation sbs_ram_costs(*this, Ram_quota{SBS}); + } /* * Allocate physical backing store @@ -150,11 +109,11 @@ Ram_dataspace_capability Ram_session_component::alloc(size_t ds_size, Cache_attr * preserve lower physical regions for device drivers, which may have DMA * constraints. */ - if (_phys_start == 0 && _phys_end == ~0UL) { + if (_phys_range.start == 0 && _phys_range.end == ~0UL) { addr_t const high_start = (sizeof(void *) == 4 ? 3UL : 4UL) << 30; for (size_t align_log2 = log2(ds_size); align_log2 >= 12; align_log2--) { - if (_ram_alloc->alloc_aligned(ds_size, &ds_addr, align_log2, - high_start, _phys_end).ok()) { + if (_phys_alloc.alloc_aligned(ds_size, &ds_addr, align_log2, + high_start, _phys_range.end).ok()) { alloc_succeeded = true; break; } @@ -164,14 +123,31 @@ Ram_dataspace_capability Ram_session_component::alloc(size_t ds_size, Cache_attr /* apply constraints or re-try because higher memory allocation failed */ if (!alloc_succeeded) { for (size_t align_log2 = log2(ds_size); align_log2 >= 12; align_log2--) { - if (_ram_alloc->alloc_aligned(ds_size, &ds_addr, align_log2, - _phys_start, _phys_end).ok()) { + if (_phys_alloc.alloc_aligned(ds_size, &ds_addr, align_log2, + _phys_range.start, _phys_range.end).ok()) { alloc_succeeded = true; break; } } } + /* + * Helper to release the allocated physical memory whenever we leave the + * scope via an exception. + */ + struct Phys_alloc_guard + { + Range_allocator &phys_alloc; + void * const ds_addr; + bool ack = false; + + Phys_alloc_guard(Range_allocator &phys_alloc, void *ds_addr) + : phys_alloc(phys_alloc), ds_addr(ds_addr) { } + + ~Phys_alloc_guard() { if (!ack) phys_alloc.free(ds_addr); } + + } phys_alloc_guard(_phys_alloc, ds_addr); + /* * Normally, init's quota equals the size of physical memory and this quota * is distributed among the processes. As we check the quota before @@ -180,38 +156,29 @@ Ram_dataspace_capability Ram_session_component::alloc(size_t ds_size, Cache_attr */ if (!alloc_succeeded) { error("out of physical memory while allocating ", ds_size, " bytes ", - "in range [", Hex(_phys_start), "-", Hex(_phys_end), "] - label ", - Cstring(_label)); - throw Quota_exceeded(); + "in range [", Hex(_phys_range.start), "-", Hex(_phys_range.end), "]"); + throw Out_of_ram(); } - Dataspace_component *ds; - try { - /* - * For non-cached RAM dataspaces, we mark the dataspace as write - * combined and expect the pager to evaluate this dataspace property - * when resolving page faults. - */ - ds = new (&_ds_slab) - Dataspace_component(ds_size, (addr_t)ds_addr, cached, true, this); - } catch (Allocator::Out_of_memory) { - warning("could not allocate metadata"); - /* cleanup unneeded resources */ - _ram_alloc->free(ds_addr); - - throw Out_of_metadata(); - } + /* + * For non-cached RAM dataspaces, we mark the dataspace as write + * combined and expect the pager to evaluate this dataspace property + * when resolving page faults. + * + * \throw Out_of_ram + * \throw Out_of_caps + */ + Dataspace_component *ds = new (*_ds_slab) + Dataspace_component(ds_size, (addr_t)ds_addr, cached, true, this); /* create native shared memory representation of dataspace */ - try { - _export_ram_ds(ds); - } catch (Out_of_metadata) { + try { _export_ram_ds(ds); } + catch (Core_virtual_memory_exhausted) { warning("could not export RAM dataspace of size ", ds->size()); - /* cleanup unneeded resources */ - destroy(&_ds_slab, ds); - _ram_alloc->free(ds_addr); - throw Quota_exceeded(); + /* cleanup unneeded resources */ + destroy(*_ds_slab, ds); + throw Out_of_ram(); } /* @@ -221,18 +188,19 @@ Ram_dataspace_capability Ram_session_component::alloc(size_t ds_size, Cache_attr */ _clear_ds(ds); - Dataspace_capability result = _ds_ep->manage(ds); + Dataspace_capability result = _ep.manage(ds); - Lock::Guard lock_guard(_ref_members_lock); - /* keep track of the used quota for actual payload */ - _payload += ds_size; + dataspace_ram_costs.acknowledge(); + phys_alloc_guard.ack = true; return static_cap_cast(result); } -void Ram_session_component::free(Ram_dataspace_capability ds_cap) { - _free_ds(ds_cap); } +void Ram_session_component::free(Ram_dataspace_capability ds_cap) +{ + _free_ds(ds_cap); +} size_t Ram_session_component::dataspace_size(Ram_dataspace_capability ds_cap) const @@ -241,7 +209,7 @@ size_t Ram_session_component::dataspace_size(Ram_dataspace_capability ds_cap) co return 0; size_t result = 0; - _ds_ep->apply(ds_cap, [&] (Dataspace_component *c) { + _ep.apply(ds_cap, [&] (Dataspace_component *c) { if (c && c->owner(this)) result = c->size(); }); @@ -251,102 +219,76 @@ size_t Ram_session_component::dataspace_size(Ram_dataspace_capability ds_cap) co void Ram_session_component::ref_account(Ram_session_capability ram_session_cap) { - /* the reference account cannot be defined twice */ - if (_ref_account) + /* the reference account can be defined only once */ + if (_ram_account.constructed()) return; if (this->cap() == ram_session_cap) return; - auto lambda = [this] (Ram_session_component *ref) { + _ep.apply(ram_session_cap, [&] (Ram_session_component *ram) { - /* check if recipient is a valid Ram_session_component */ - if (!ref) + if (!ram || !ram->_ram_account.constructed()) { + error("invalid RAM session specified as ref account"); throw Invalid_session(); + } - _ref_account = ref; - _ref_account->_register_ref_account_member(this); - }; - - _ram_session_ep->apply(ram_session_cap, lambda); + _ram_account.construct(*this, _label, *ram->_ram_account); + }); } void Ram_session_component::transfer_quota(Ram_session_capability ram_session_cap, Ram_quota amount) { - auto lambda = [&] (Ram_session_component *dst) { - _transfer_quota(dst, amount.value); }; + /* the reference account can be defined only once */ + if (!_ram_account.constructed()) + throw Undefined_ref_account(); if (this->cap() == ram_session_cap) return; - return _ram_session_ep->apply(ram_session_cap, lambda); + _ep.apply(ram_session_cap, [&] (Ram_session_component *ram) { + + if (!ram || !ram->_ram_account.constructed()) + throw Invalid_session(); + + try { + _ram_account->transfer_quota(*ram->_ram_account, amount); } + catch (Account::Unrelated_account) { + warning("attempt to transfer RAM quota to unrelated RAM session"); + throw Invalid_session(); } + catch (Account::Limit_exceeded) { + warning("RAM limit (", *_ram_account, ") exceeded " + "during transfer_quota(", amount, ")"); + throw Out_of_ram(); } + }); } -Ram_session_component::Ram_session_component(Rpc_entrypoint *ds_ep, - Rpc_entrypoint *ram_session_ep, - Range_allocator *ram_alloc, - Allocator *md_alloc, - const char *args, - size_t quota_limit) +Ram_session_component::Ram_session_component(Rpc_entrypoint &ep, + Resources resources, + Label const &label, + Diag diag, + Range_allocator &phys_alloc, + Region_map &local_rm, + Phys_range phys_range) : - _ds_ep(ds_ep), _ram_session_ep(ram_session_ep), _ram_alloc(ram_alloc), - _quota_limit(quota_limit), _payload(0), - _md_alloc(md_alloc, Arg_string::find_arg(args, "ram_quota").ulong_value(0)), - _ds_slab(&_md_alloc), _ref_account(0), - _phys_start(Arg_string::find_arg(args, "phys_start").ulong_value(0)) + Session_object(ep, resources, label, diag), + _ep(ep), + _phys_alloc(phys_alloc), + _constrained_md_ram_alloc(*this, *this, *this), + _phys_range(phys_range) { - Arg_string::find_arg(args, "label").string(_label, sizeof(_label), ""); - - size_t phys_size = Arg_string::find_arg(args, "phys_size").ulong_value(0); - /* sanitize overflow and interpret phys_size==0 as maximum phys address */ - if (_phys_start + phys_size <= _phys_start) - _phys_end = ~0UL; - else - _phys_end = _phys_start + phys_size - 1; + _sliced_heap.construct(_constrained_md_ram_alloc, local_rm); + _ds_slab.construct(*_sliced_heap, _initial_sb); } Ram_session_component::~Ram_session_component() { /* destroy all dataspaces */ - for (Dataspace_component *ds; (ds = _ds_slab()->first_object()); + Ds_slab &ds_slab = *_ds_slab; + for (Dataspace_component *ds; (ds = ds_slab.first_object()); _free_ds(ds->cap())); - - if (_payload != 0) - warning("remaining payload of ", _payload, " in ram session to destroy"); - - if (!_ref_account) return; - - /* transfer remaining quota to reference account */ - try { _transfer_quota(_ref_account, _quota_limit); } catch (...) { } - - /* remember our original reference account */ - Ram_session_component *orig_ref_account = _ref_account; - - /* remove reference to us from the reference account */ - _ref_account->_remove_ref_account_member(this); - - /* - * Now, the '_ref_account' member has become invalid. - */ - - Lock::Guard lock_guard(_ref_members_lock); - - /* assign all sub accounts to our original reference account */ - for (Ram_session_component *rsc; (rsc = _ref_members.first()); ) { - - _unsynchronized_remove_ref_account_member(rsc); - - /* - * This function grabs the '_ref_account_lock' of the '_ref_account', - * which is never identical to ourself. Hence, deadlock cannot happen - * here. - */ - orig_ref_account->_register_ref_account_member(rsc); - } - - _ref_account = 0; } diff --git a/repos/base/src/include/base/internal/expanding_parent_client.h b/repos/base/src/include/base/internal/expanding_parent_client.h index 989a7120c6..273fc9a495 100644 --- a/repos/base/src/include/base/internal/expanding_parent_client.h +++ b/repos/base/src/include/base/internal/expanding_parent_client.h @@ -108,8 +108,8 @@ class Genode::Expanding_parent_client : public Parent_client * immediately. The second upgrade attempt may fail too if the * parent handles the resource request asynchronously. In this * case, we escalate the problem to caller by propagating the - * 'Parent::Quota_exceeded' exception. Now, it is the job of the - * caller to issue (and respond to) a resource request. + * 'Out_of_ram' exception. Now, it is the job of the caller to + * issue (and respond to) a resource request. */ enum { NUM_ATTEMPTS = 2 }; return retry( diff --git a/repos/base/src/include/base/internal/expanding_ram_session_client.h b/repos/base/src/include/base/internal/expanding_ram_session_client.h index 60b216f2c1..979d8216ef 100644 --- a/repos/base/src/include/base/internal/expanding_ram_session_client.h +++ b/repos/base/src/include/base/internal/expanding_ram_session_client.h @@ -41,16 +41,8 @@ struct Genode::Expanding_ram_session_client : Upgradeable_client( - [&] () { - /* - * If the RAM session runs out of meta data, upgrade the - * session quota and retry. - */ - return retry( - [&] () { return Ram_session_client::alloc(size, cached); }, - [&] () { upgrade_ram(8*1024); }); - }, + return retry( + [&] () { return Ram_session_client::alloc(size, cached); }, [&] () { /* * The RAM service withdraws the meta data for the allocator diff --git a/repos/base/src/lib/base/child.cc b/repos/base/src/lib/base/child.cc index 1c2474abe1..2b2e694901 100644 --- a/repos/base/src/lib/base/child.cc +++ b/repos/base/src/lib/base/child.cc @@ -87,6 +87,7 @@ void Child::session_sigh(Signal_context_capability sigh) /** * Create session-state object for a dynamically created session * + * \throw Out_of_ram * \throw Insufficient_ram_quota * \throw Parent::Service_denied */ @@ -648,7 +649,6 @@ void Child::_try_construct_env_dependent_members() _parent_cap); } catch (Out_of_ram) { _error("out of RAM during ELF loading"); } - catch (Ram_session::Alloc_failed) { _error("RAM allocation failed during ELF loading"); } catch (Cpu_session::Thread_creation_failed) { _error("unable to create initial thread"); } catch (Cpu_session::Out_of_metadata) { _error("CPU session quota exhausted"); } catch (Process::Missing_dynamic_linker) { _error("dynamic linker unavailable"); } diff --git a/repos/base/src/lib/base/child_process.cc b/repos/base/src/lib/base/child_process.cc index ccdcb1123c..dfe1c34d95 100644 --- a/repos/base/src/lib/base/child_process.cc +++ b/repos/base/src/lib/base/child_process.cc @@ -102,7 +102,7 @@ Child::Process::Loaded_executable::Loaded_executable(Dataspace_capability elf_ds /* alloc dataspace */ Dataspace_capability ds_cap; try { ds_cap = ram.alloc(size); } - catch (Ram_session::Alloc_failed) { + catch (Out_of_ram) { error("allocation of read-write segment failed"); throw; }; /* attach dataspace */ diff --git a/repos/base/src/lib/base/heap.cc b/repos/base/src/lib/base/heap.cc index 91e32be3b8..aa0a1d7602 100644 --- a/repos/base/src/lib/base/heap.cc +++ b/repos/base/src/lib/base/heap.cc @@ -89,9 +89,9 @@ Heap::Dataspace *Heap::_allocate_dataspace(size_t size, bool enforce_separate_me try { new_ds_cap = _ds_pool.ram_alloc->alloc(size); ds_addr = _ds_pool.region_map->attach(new_ds_cap); - } catch (Ram_session::Alloc_failed) { - return 0; - } catch (Region_map::Attach_failed) { + } + catch (Out_of_ram) { return nullptr; } + catch (Region_map::Attach_failed) { warning("could not attach dataspace"); _ds_pool.ram_alloc->free(new_ds_cap); return 0; diff --git a/repos/base/src/lib/base/sliced_heap.cc b/repos/base/src/lib/base/sliced_heap.cc index dacb74ad4c..d48b88c262 100644 --- a/repos/base/src/lib/base/sliced_heap.cc +++ b/repos/base/src/lib/base/sliced_heap.cc @@ -49,11 +49,13 @@ bool Sliced_heap::alloc(size_t size, void **out_addr) try { ds_cap = _ram_alloc.alloc(size); block = _region_map.attach(ds_cap); - } catch (Region_map::Attach_failed) { + } + catch (Region_map::Attach_failed) { error("could not attach dataspace to local address space"); _ram_alloc.free(ds_cap); return false; - } catch (Ram_allocator::Alloc_failed) { + } + catch (Out_of_ram) { error("could not allocate dataspace with size ", size); return false; } diff --git a/repos/base/src/lib/base/thread.cc b/repos/base/src/lib/base/thread.cc index 7e5a5cccab..ba810465ae 100644 --- a/repos/base/src/lib/base/thread.cc +++ b/repos/base/src/lib/base/thread.cc @@ -65,9 +65,7 @@ void Stack::size(size_t const size) if (ds_addr != (addr_t)attach_addr) throw Thread::Out_of_stack_space(); } - catch (Ram_session::Alloc_failed) { - throw Thread::Stack_alloc_failed(); - } + catch (Out_of_ram) { throw Thread::Stack_alloc_failed(); } /* update stack information */ _base -= ds_size; @@ -110,7 +108,7 @@ Thread::_alloc_stack(size_t stack_size, char const *name, bool main_thread) if (attach_addr != (addr_t)env_stack_area_region_map->attach_at(ds_cap, attach_addr, ds_size)) throw Stack_alloc_failed(); } - catch (Ram_session::Alloc_failed) { throw Stack_alloc_failed(); } + catch (Out_of_ram) { throw Stack_alloc_failed(); } /* * Now the stack is backed by memory, so it is safe to access its members. diff --git a/repos/dde_rump/include/util/allocator_fap.h b/repos/dde_rump/include/util/allocator_fap.h index 793475caa9..333a2dea68 100644 --- a/repos/dde_rump/include/util/allocator_fap.h +++ b/repos/dde_rump/include/util/allocator_fap.h @@ -90,7 +90,7 @@ namespace Allocator { Region_map_client::attach_at(_ds_cap[_index], _index * BLOCK_SIZE, BLOCK_SIZE, 0); /* lookup phys. address */ _ds_phys[_index] = Genode::Dataspace_client(_ds_cap[_index]).phys_addr(); - } catch (Genode::Ram_session::Quota_exceeded) { + } catch (Genode::Out_of_ram) { warning("backend allocator exhausted"); _quota_exceeded = true; return false; diff --git a/repos/libports/src/lib/libc/libc_mem_alloc.cc b/repos/libports/src/lib/libc/libc_mem_alloc.cc index 8a6c3a6110..f817be715c 100644 --- a/repos/libports/src/lib/libc/libc_mem_alloc.cc +++ b/repos/libports/src/lib/libc/libc_mem_alloc.cc @@ -55,9 +55,10 @@ int Libc::Mem_alloc_impl::Dataspace_pool::expand(size_t size, Range_allocator *a try { new_ds_cap = _ram_session->alloc(size); local_addr = _region_map->attach(new_ds_cap); - } catch (Ram_session::Alloc_failed) { - return -2; - } catch (Region_map::Attach_failed) { + } + catch (Out_of_ram) { return -2; } + catch (Out_of_caps) { return -4; } + catch (Region_map::Attach_failed) { _ram_session->free(new_ds_cap); return -3; } diff --git a/repos/os/include/os/dynamic_rom_session.h b/repos/os/include/os/dynamic_rom_session.h index dc5fe82710..510e840606 100644 --- a/repos/os/include/os/dynamic_rom_session.h +++ b/repos/os/include/os/dynamic_rom_session.h @@ -83,9 +83,9 @@ class Genode::Dynamic_rom_session : public Rpc_object ds_reallocated = true; } } - catch (Ram_session::Quota_exceeded) { + catch (Out_of_ram) { - error("ouf of child quota while delivering dynamic ROM"); + error("ouf of child RAM quota while delivering dynamic ROM"); /* * XXX We may try to generate a resource request on @@ -98,10 +98,6 @@ class Genode::Dynamic_rom_session : public Rpc_object */ return true; } - catch (Ram_session::Out_of_metadata) { - error("ouf of RAM session quota while delivering dynamic ROM"); - return true; - } try { _content_producer.produce_content(_ds->local_addr(), diff --git a/repos/os/include/os/ram_session_guard.h b/repos/os/include/os/ram_session_guard.h index 7124bf817b..33ea69e8c2 100644 --- a/repos/os/include/os/ram_session_guard.h +++ b/repos/os/include/os/ram_session_guard.h @@ -96,7 +96,7 @@ class Genode::Ram_session_guard : public Genode::Ram_session Cache_attribute cached = CACHED) override { if (_used + size <= _used || _used + size > _quota) - throw Quota_exceeded(); + throw Out_of_ram(); Ram_dataspace_capability cap = _session.alloc(size, cached); diff --git a/repos/os/src/drivers/platform/spec/x86/pci_session_component.h b/repos/os/src/drivers/platform/spec/x86/pci_session_component.h index 9425c0593e..1b508d1f8d 100644 --- a/repos/os/src/drivers/platform/spec/x86/pci_session_component.h +++ b/repos/os/src/drivers/platform/spec/x86/pci_session_component.h @@ -330,7 +330,7 @@ class Platform::Session_component : public Genode::Rpc_object /* thrown by 'Quota_reservation' */ catch (Out_of_metadata) { throw; } /* thrown by 'Device_pd_policy' or 'Child' */ - catch (Genode::Ram_session::Alloc_failed) { throw Out_of_metadata(); } + catch (Genode::Out_of_ram) { throw Out_of_metadata(); } /* throw by 'Slave::Connection' */ catch (Genode::Insufficient_ram_quota) { throw Out_of_metadata(); } @@ -373,7 +373,7 @@ class Platform::Session_component : public Genode::Rpc_object } /* thrown by '_md_alloc' */ - catch (Genode::Allocator::Out_of_memory) { throw Out_of_metadata(); } + catch (Genode::Out_of_ram) { throw Out_of_metadata(); } /* thrown by 'Device_pd' */ catch (Out_of_metadata) { throw; } @@ -944,25 +944,25 @@ class Platform::Session_component : public Genode::Rpc_object /* transfer ram quota to session specific ram session */ try { _env_ram.transfer_quota(_ram, Genode::Ram_quota{size}); } + catch (Genode::Out_of_ram) { throw Out_of_metadata(); } catch (...) { throw Fatal(); } enum { UPGRADE_QUOTA = 4096 }; /* allocate dataspace from session specific ram session */ - Ram_capability ram_cap = Genode::retry( + Ram_capability ram_cap = Genode::retry( [&] () { - Ram_capability ram = Genode::retry( - [&] () { return _ram.alloc(size, Genode::UNCACHED); }, - [&] () { - if (!_env_ram.withdraw(UPGRADE_QUOTA)) { - _rollback(size); - } + try { + return _ram.alloc(size, Genode::UNCACHED); + } + catch (Genode::Out_of_ram) { - /* upgrade meta-data quota */ - _ram.upgrade_ram(UPGRADE_QUOTA); - }); + if (!_env_ram.withdraw(UPGRADE_QUOTA)) + _rollback(size); + + throw; + } - return ram; }, [&] () { /* @@ -973,7 +973,7 @@ class Platform::Session_component : public Genode::Rpc_object * UPGRADE_QUOTA steps. */ try { _env_ram.transfer_quota(_ram, Genode::Ram_quota{UPGRADE_QUOTA}); } - catch (...) { throw Out_of_metadata(); } + catch (...) { throw Genode::Out_of_ram(); } }); if (!ram_cap.valid()) diff --git a/repos/os/src/init/main.cc b/repos/os/src/init/main.cc index 03cdc2d448..5d8816e33d 100644 --- a/repos/os/src/init/main.cc +++ b/repos/os/src/init/main.cc @@ -297,7 +297,7 @@ void Init::Main::_handle_config() if (used_ram.value > avail_ram.value) { error("RAM exhausted while starting childen"); - throw Ram_session::Alloc_failed(); + throw Out_of_ram(); } try { @@ -326,8 +326,6 @@ void Init::Main::_handle_config() } catch (Out_of_ram) { warning("memory exhausted during child creation"); } - catch (Ram_session::Alloc_failed) { - warning("failed to allocate memory during child construction"); } catch (Child::Missing_name_attribute) { warning("skipped startup of nameless child"); } catch (Region_map::Attach_failed) { diff --git a/repos/os/src/server/nic_bridge/component.h b/repos/os/src/server/nic_bridge/component.h index 70009b3c24..0141c83208 100644 --- a/repos/os/src/server/nic_bridge/component.h +++ b/repos/os/src/server/nic_bridge/component.h @@ -220,7 +220,7 @@ class Net::Root : public Genode::Root_component } catch (Mac_allocator::Alloc_failed) { Genode::warning("Mac address allocation failed!"); throw Root::Unavailable(); - } catch(Ram_session::Quota_exceeded) { + } catch (Out_of_ram) { Genode::warning("insufficient 'ram_quota'"); throw Insufficient_ram_quota(); }