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 7d8691cbb..41cfda208 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 5d88011e7..31c23efd8 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 fc55fdd4b..be54ed027 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 d6a43ca30..2deead4aa 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 e9fa44d70..0b6050293 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 96124bd82..dc0b0f634 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 df422693a..78612b2b1 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 52fdfac16..5cb66a546 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 32933b799..1569f5afd 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 78943e211..e06c19c87 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 80d71780a..e1aebb7bd 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 ffdb743f8..c9bc07967 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 000000000..3e0c68b6d --- /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 069eef227..397396cd2 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 4b92ff26f..e15b97857 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 e07b87eed..025db5c63 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 4a479c3a1..7d01cba58 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 4fedddb44..ae8024773 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 989a7120c..273fc9a49 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 60b216f2c..979d8216e 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 1c2474abe..2b2e69490 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 ccdcb1123..dfe1c34d9 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 91e32be3b..aa0a1d760 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 dacb74ad4..d48b88c26 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 7e5a5ccca..ba810465a 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 793475caa..333a2dea6 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 8a6c3a611..f817be715 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 dc5fe8271..510e84060 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 7124bf817..33ea69e8c 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 9425c0593..1b508d1f8 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 03cdc2d44..5d8816e33 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 70009b3c2..0141c8320 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(); }