trace session: fix double quota accounting

Fixes #4707.
This commit is contained in:
Christian Prochaska
2022-12-20 11:10:07 +01:00
committed by Christian Helmuth
parent b4f6f796d6
commit 0c465fbb4d
6 changed files with 34 additions and 81 deletions

View File

@ -29,7 +29,6 @@ namespace Genode { namespace Trace {
struct Policy_too_large : Exception { }; struct Policy_too_large : Exception { };
struct Nonexistent_subject : Exception { }; struct Nonexistent_subject : Exception { };
struct Already_traced : Exception { };
struct Source_is_dead : Exception { }; struct Source_is_dead : Exception { };
struct Nonexistent_policy : Exception { }; struct Nonexistent_policy : Exception { };
struct Traced_by_other_session : Exception { }; struct Traced_by_other_session : Exception { };

View File

@ -56,7 +56,6 @@ struct Genode::Trace::Session : Genode::Session
* *
* \throw Out_of_ram * \throw Out_of_ram
* \throw Out_of_caps * \throw Out_of_caps
* \throw Already_traced
* \throw Source_is_dead * \throw Source_is_dead
* \throw Nonexistent_policy * \throw Nonexistent_policy
* \throw Nonexistent_subject * \throw Nonexistent_subject
@ -113,7 +112,7 @@ struct Genode::Trace::Session : Genode::Session
GENODE_RPC_THROW(Rpc_unload_policy, void, unload_policy, GENODE_RPC_THROW(Rpc_unload_policy, void, unload_policy,
GENODE_TYPE_LIST(Nonexistent_policy), Policy_id); GENODE_TYPE_LIST(Nonexistent_policy), Policy_id);
GENODE_RPC_THROW(Rpc_trace, void, trace, GENODE_RPC_THROW(Rpc_trace, void, trace,
GENODE_TYPE_LIST(Out_of_ram, Out_of_caps, Already_traced, GENODE_TYPE_LIST(Out_of_ram, Out_of_caps,
Source_is_dead, Nonexistent_subject, Source_is_dead, Nonexistent_subject,
Nonexistent_policy, Nonexistent_policy,
Traced_by_other_session), Traced_by_other_session),

View File

@ -41,7 +41,7 @@ class Genode::Trace::Root : public Genode::Root_component<Session_component>
unsigned parent_levels = (unsigned)Arg_string::find_arg(args, "parent_levels").ulong_value(0); unsigned parent_levels = (unsigned)Arg_string::find_arg(args, "parent_levels").ulong_value(0);
if (arg_buffer_size > ram_quota) if (arg_buffer_size > ram_quota)
throw Service_denied(); throw Insufficient_ram_quota();
return new (md_alloc()) return new (md_alloc())
Session_component(*this->ep(), Session_component(*this->ep(),

View File

@ -96,18 +96,15 @@ class Genode::Trace::Subject
/** /**
* Clone dataspace into newly allocated dataspace * Clone dataspace into newly allocated dataspace
*/ */
bool setup(Ram_allocator &ram, Region_map &local_rm, void setup(Ram_allocator &ram, Region_map &local_rm,
Dataspace_capability &from_ds, size_t size) Dataspace_capability &from_ds, size_t size)
{ {
if (!from_ds.valid())
return false;
if (_size) if (_size)
flush(); flush();
_ds = ram.alloc(size); /* may throw */
_ram_ptr = &ram; _ram_ptr = &ram;
_size = size; _size = size;
_ds = ram.alloc(_size);
/* copy content */ /* copy content */
void *src = local_rm.attach(from_ds), void *src = local_rm.attach(from_ds),
@ -117,8 +114,6 @@ class Genode::Trace::Subject
local_rm.detach(src); local_rm.detach(src);
local_rm.detach(dst); local_rm.detach(dst);
return true;
} }
/** /**
@ -146,7 +141,6 @@ class Genode::Trace::Subject
Ram_dataspace _buffer { }; Ram_dataspace _buffer { };
Ram_dataspace _policy { }; Ram_dataspace _policy { };
Policy_id _policy_id { }; Policy_id _policy_id { };
size_t _allocated_memory { 0 };
Subject_info::State _state() Subject_info::State _state()
{ {
@ -217,9 +211,6 @@ class Genode::Trace::Subject
*/ */
bool has_source_id(unsigned id) const { return id == _source_id; } bool has_source_id(unsigned id) const { return id == _source_id; }
size_t allocated_memory() const { return _allocated_memory; }
void reset_allocated_memory() { _allocated_memory = 0; }
/** /**
* Start tracing * Start tracing
* *
@ -227,7 +218,6 @@ class Genode::Trace::Subject
* *
* \throw Out_of_ram * \throw Out_of_ram
* \throw Out_of_caps * \throw Out_of_caps
* \throw Already_traced
* \throw Source_is_dead * \throw Source_is_dead
* \throw Traced_by_other_session * \throw Traced_by_other_session
*/ */
@ -238,26 +228,31 @@ class Genode::Trace::Subject
/* check state and throw error in case subject is not traceable */ /* check state and throw error in case subject is not traceable */
_traceable_or_throw(); _traceable_or_throw();
_buffer.setup(ram, size); _buffer.setup(ram, size); /* may throw */
if(!_policy.setup(ram, local_rm, policy_ds, policy_size))
throw Already_traced(); try {
_policy.setup(ram, local_rm, policy_ds, policy_size);
} catch (...) {
_buffer.flush();
throw;
}
/* inform trace source about the new buffer */ /* inform trace source about the new buffer */
Locked_ptr<Source> source(_source); Locked_ptr<Source> source(_source);
if (!source->try_acquire(*this)) if (!source->try_acquire(*this)) {
_policy.flush();
_buffer.flush();
throw Traced_by_other_session(); throw Traced_by_other_session();
}
_policy_id = policy_id; _policy_id = policy_id;
_allocated_memory = policy_size + size;
source->trace(_policy.dataspace(), _buffer.dataspace()); source->trace(_policy.dataspace(), _buffer.dataspace());
} }
void pause() void pause()
{ {
/* inform trace source about the new buffer */
Locked_ptr<Source> source(_source); Locked_ptr<Source> source(_source);
if (source.valid()) if (source.valid())
@ -271,7 +266,6 @@ class Genode::Trace::Subject
*/ */
void resume() void resume()
{ {
/* inform trace source about the new buffer */
Locked_ptr<Source> source(_source); Locked_ptr<Source> source(_source);
if (!source.valid()) if (!source.valid())
@ -301,16 +295,16 @@ class Genode::Trace::Subject
Dataspace_capability buffer() const { return _buffer.dataspace(); } Dataspace_capability buffer() const { return _buffer.dataspace(); }
size_t release() void release()
{ {
/* inform trace source about the new buffer */
Locked_ptr<Source> source(_source); Locked_ptr<Source> source(_source);
/* source vanished */ /* source vanished */
if (!source.valid()) if (!source.valid())
return 0; return;
return _buffer.flush() + _policy.flush(); _buffer.flush();
_policy.flush();
} }
}; };
@ -375,18 +369,14 @@ class Genode::Trace::Subject_registry
/** /**
* Destroy subject, and release policy and trace buffers * Destroy subject, and release policy and trace buffers
*
* \return RAM resources released during destruction
*/ */
size_t _unsynchronized_destroy(Subject &s) void _unsynchronized_destroy(Subject &s)
{ {
_entries.remove(&s); _entries.remove(&s);
size_t const released_ram = s.release(); s.release();
destroy(&_md_alloc, &s); destroy(&_md_alloc, &s);
return released_ram;
}; };
/** /**
@ -471,18 +461,13 @@ class Genode::Trace::Subject_registry
/** /**
* Remove subject and release resources * Remove subject and release resources
*
* \return RAM resources released as a side effect for removing the
* subject (i.e., if the subject held a trace buffer or
* policy dataspace). The value does not account for
* memory allocated from the metadata allocator.
*/ */
size_t release(Subject_id subject_id) void release(Subject_id subject_id)
{ {
Mutex::Guard guard(_mutex); Mutex::Guard guard(_mutex);
Subject &subject = _unsynchronized_lookup_by_id(subject_id); Subject &subject = _unsynchronized_lookup_by_id(subject_id);
return _unsynchronized_destroy(subject); _unsynchronized_destroy(subject);
} }
Subject &lookup_by_id(Subject_id id) Subject &lookup_by_id(Subject_id id)

View File

@ -59,21 +59,12 @@ Policy_id Session_component::alloc_policy(size_t size)
*/ */
Policy_id const id(++_policy_cnt); Policy_id const id(++_policy_cnt);
Ram_quota const amount { size }; Ram_dataspace_capability ds_cap = _ram.alloc(size); /* may throw */
/*
* \throw Out_of_ram
*/
withdraw(amount);
try { try {
Dataspace_capability ds_cap = _ram.alloc(size);
_policies.insert(*this, id, _policies_slab, ds_cap, size); _policies.insert(*this, id, _policies_slab, ds_cap, size);
} catch (...) { } catch (...) {
_ram.free(ds_cap);
/* revert withdrawal or quota */
replenish(amount);
throw; throw;
} }
@ -89,7 +80,11 @@ Dataspace_capability Session_component::policy(Policy_id id)
void Session_component::unload_policy(Policy_id id) void Session_component::unload_policy(Policy_id id)
{ {
_policies.remove(*this, id); try {
Dataspace_capability ds_cap = _policies.dataspace(*this, id);
_policies.remove(*this, id);
_ram.free(static_cap_cast<Ram_dataspace>(ds_cap));
} catch (Nonexistent_policy) { }
} }
@ -98,32 +93,10 @@ void Session_component::trace(Subject_id subject_id, Policy_id policy_id,
{ {
size_t const policy_size = _policies.size(*this, policy_id); size_t const policy_size = _policies.size(*this, policy_id);
Ram_quota const required_ram { buffer_size + policy_size };
Trace::Subject &subject = _subjects.lookup_by_id(subject_id); Trace::Subject &subject = _subjects.lookup_by_id(subject_id);
/* revert quota from previous call to trace */ subject.trace(policy_id, _policies.dataspace(*this, policy_id),
if (subject.allocated_memory()) { policy_size, _ram, _local_rm, buffer_size);
replenish(Ram_quota{subject.allocated_memory()});
subject.reset_allocated_memory();
}
/*
* Account RAM needed for trace buffer and policy buffer to the trace
* session.
*
* \throw Out_of_ram
*/
withdraw(required_ram);
try {
subject.trace(policy_id, _policies.dataspace(*this, policy_id),
policy_size, _ram, _local_rm, buffer_size);
} catch (...) {
/* revert withdrawal or quota */
replenish(required_ram);
throw;
}
} }
@ -147,9 +120,7 @@ Dataspace_capability Session_component::buffer(Subject_id subject_id)
void Session_component::free(Subject_id subject_id) void Session_component::free(Subject_id subject_id)
{ {
Ram_quota const released_ram { _subjects.release(subject_id) }; _subjects.release(subject_id);
replenish(released_ram);
} }

View File

@ -192,7 +192,6 @@ class Main
} }
monitors.insert(new (_heap) Monitor(_trace, _env.rm(), id)); monitors.insert(new (_heap) Monitor(_trace, _env.rm(), id));
} }
catch (Trace::Already_traced ) { warn_msg("Already_traced" ); return; }
catch (Trace::Source_is_dead ) { warn_msg("Source_is_dead" ); return; } catch (Trace::Source_is_dead ) { warn_msg("Source_is_dead" ); return; }
catch (Trace::Nonexistent_policy ) { warn_msg("Nonexistent_policy" ); return; } catch (Trace::Nonexistent_policy ) { warn_msg("Nonexistent_policy" ); return; }
catch (Trace::Traced_by_other_session) { warn_msg("Traced_by_other_session"); return; } catch (Trace::Traced_by_other_session) { warn_msg("Traced_by_other_session"); return; }