platform: fix potential double insertion

When a session component has multiple IOMMU domains and `add_range()`
fails not on the first but on another domain, the range is not removed
from the first domain. This causes double insertion on the next try.

genodelabs/genode#5494
This commit is contained in:
Johannes Schlatow 2025-03-26 15:27:57 +01:00 committed by Norman Feske
parent 37ec1db5ea
commit e4704a1d39
2 changed files with 16 additions and 21 deletions

View File

@ -335,6 +335,7 @@ Session_component::alloc_dma_buffer(size_t const size, Cache cache)
Constrained_ram_allocator & _env_ram;
Heap & _heap;
Io_mmu_domain_registry & _domain_registry;
bool _cleanup { true };
Ram_dataspace_capability ram_cap { };
@ -344,19 +345,26 @@ Session_component::alloc_dma_buffer(size_t const size, Cache cache)
void disarm() { _cleanup = false; }
Guard(Constrained_ram_allocator & env_ram, Heap & heap)
: _env_ram(env_ram), _heap(heap)
Guard(Constrained_ram_allocator & env_ram,
Heap & heap,
Io_mmu_domain_registry & registry)
: _env_ram(env_ram), _heap(heap), _domain_registry(registry)
{ }
~Guard()
{
if (_cleanup && buf)
if (_cleanup && buf) {
/* make sure to remove buffer range from all domains */
_domain_registry.for_each_domain([&] (Io_mmu::Domain & domain) {
domain.remove_range({ buf->dma_addr, buf->size });
});
destroy(_heap, buf);
}
if (_cleanup && ram_cap.valid())
_env_ram.free(ram_cap);
}
} guard { _env_ram, heap() };
} guard { _env_ram, heap(), _domain_registry };
/*
* Check available quota beforehand and reflect the state back

View File

@ -74,23 +74,10 @@ void Intel::Io_mmu::Domain<TABLE>::add_range(Range const & range,
Page_flags flags { RW, NO_EXEC, USER, NO_GLOBAL,
RAM, Genode::CACHED };
auto cleanup_partial_translations = [&] () {
_translation_table.remove_translation(vaddr, size, _table_allocator,
!_intel_iommu.coherent_page_walk());
};
try {
_translation_table.insert_translation(vaddr, paddr, size, flags,
_table_allocator,
!_intel_iommu.coherent_page_walk(),
_intel_iommu.supported_page_sizes());
} catch (Out_of_ram) {
cleanup_partial_translations();
throw;
} catch (Out_of_caps) {
cleanup_partial_translations();
throw;
}
_translation_table.insert_translation(vaddr, paddr, size, flags,
_table_allocator,
!_intel_iommu.coherent_page_walk(),
_intel_iommu.supported_page_sizes());
if (_skip_invalidation)
return;