mmap implementation for ANON mapping with desired address

Alexander Tormasov a.tormasov at innopolis.ru
Wed Aug 12 01:07:10 CEST 2020


I am trying to implement not-yet supported (as mentioned by nfeske@ in mailing list) option 
for mmap() related to anonymous mapping with pre-defined (desired) address.
Like libc function with  desired address out_addr.
   void *Libc::Mem_alloc_impl::alloc_at(void *out_addr, size_t size)

I use a couple of useful function in avl allocator. Anyway, I found that straight - forward 
implementation do not work because of allocation gaps filled together with main allocation.

In particular, if we want to allocate e.g. 0x10000 from address 0x500000 then we
typically allocate 0x13000 bytes, including ones for avl metadata/etc stored in the same
space, and receive virtual address range used, e.g. 0x500000 - 0x513000:

    /*
     * Calculate block size of needed backing store. The block must hold the
     * requested 'size' with the requested alignment, a new Dataspace structure
     * and space for AVL-node slab blocks if the allocation above failed.
     * Finally, we align the size to a 4K page.
     */
    size_t request_size = size + max((1 << align_log2), 1024) +
                          Allocator_avl::slab_block_size() + sizeof(Dataspace);

Software I used (golang runtime) sometimes try to expand previous allocation, e.g. it can
request allocation of 0x8000 bytes before previous range, like 0x4f8000 - 0x500000.
In that case I can’t perform the operation - because it will try to allocate 0xa000 bytes from 
desired address 0x4f8000 - and it obviously fail due to Range_conflict.

So, I split allocation to 2 parts - one for this gap by standard alloc() and random placement
and second one by my own alloc_at() with size exactly correspond to the requested one.

Implementation available as a patch to 20.05 at

https://github.com/tor-m6/genode/commit/78fc751bea8acc2b515e04bec9f3a883461510c7

Problem I see here is a free operation: it just free the block with requested address, and do
not touch others, gap-related blocks. For me it is not obvious that they need to be free,
because in the code (e.g. by unmap()) I do not see explicit free of other allocated structures,
in particular, dataspace extension or related block metadata.

Question: should I make additional efforts to trace and delete something else - except what
standard free does here:
    /* forward request to our local allocator */
    _alloc.free(addr);

Like for dataspace structure or address ranges for second «auxiliary» allocation?

PS Another potential problem is a probability to overlap of first «random address» allocation with
desired address. This happens with first attempt to implement allocator - it allocates address
from desired range, and immediately put here 0x18 bytes of Dataspace structure, and then fail
because requested address is already busy by this structure! Anyway, I consider such a 
probability relatively small with proposed approach and ignore it (may be I am wrong)






More information about the users mailing list