|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [UNIKRAFT PATCH v2] lib/ukalloc: add ifmalloc compatibility interface
On 30.07.20, 23:53, "Hugo Lefeuvre" <Hugo.Lefeuvre@xxxxxxxxx> wrote:
Hi Simon,
thanks a lot for your comments, answers inline.
regards,
Hugo
On Thu, 2020-07-30 at 18:20 +0200, Simon Kuenzer wrote:
>
> Hey, I found to open questions. Let me know what you think.
>
> Thanks,
>
> Simon
>
> On 30.07.20 16:48, Hugo Lefeuvre wrote:
> >
> >
> > Add ifmalloc, the malloc compatibility interface. This interface
> > implements
> > a POSIX compliant allocation interface on top of a simple malloc()
> > and
> > free() interface. This interface is similar to ifpages, which does
> > the same
> > for palloc() and pfree().
> >
> > ifmalloc will be used for the port of TLSF and tinyalloc which do
> > not
> > support (posix_)memalign().
> >
> > Signed-off-by: Hugo Lefeuvre <hugo.lefeuvre@xxxxxxxxx>
> > ---
> > Changed since v1:
> > - update alloc.c file header
> > - use METADATA_IFMALLOC_SIZE_POW2 instead of sizeof(struct
> > metadata_ifmalloc)
> > - add unlikely where appropriate
> > - use align < sizeof(void *) instead of (align % sizeof(void *))
> > != 0
> > - minor optimizations and style-related changes
> >
> > lib/ukalloc/Config.uk | 5 ++
> > lib/ukalloc/alloc.c | 148
> > +++++++++++++++++++++++++++++++++++-
> > lib/ukalloc/exportsyms.uk | 4 +
> > lib/ukalloc/include/uk/alloc.h | 5 ++
> > lib/ukalloc/include/uk/alloc_impl.h | 27 +++++++
> > 5 files changed, 186 insertions(+), 3 deletions(-)
> >
> > diff --git a/lib/ukalloc/Config.uk b/lib/ukalloc/Config.uk
> > index 0de7464..c965d08 100644
> > --- a/lib/ukalloc/Config.uk
> > +++ b/lib/ukalloc/Config.uk
> > @@ -5,6 +5,11 @@ menuconfig LIBUKALLOC
> > select LIBUKDEBUG
> >
> > if LIBUKALLOC
> > + config LIBUKALLOC_IFMALLOC
> > + bool "Malloc compatibility interface"
> > + default n
> > + help
> > + Provide helpers for allocators defining
> > exclusively malloc and free
> > config LIBUKALLOC_IFSTATS
> > bool "Statistics interface"
> > default n
> > diff --git a/lib/ukalloc/alloc.c b/lib/ukalloc/alloc.c
> > index 127bc6f..160a0a4 100644
> > --- a/lib/ukalloc/alloc.c
> > +++ b/lib/ukalloc/alloc.c
> > @@ -1,8 +1,10 @@
> > /* SPDX-License-Identifier: BSD-3-Clause */
> > /*
> > * Authors: Florian Schmidt <florian.schmidt@xxxxxxxxx>
> > + * Hugo Lefeuvre <hugo.lefeuvre@xxxxxxxxx>
> > *
> > - * Copyright (c) 2017, NEC Europe Ltd., NEC Corporation. All
> > rights reserved.
> > + * Copyright (c) 2017-2020, NEC Laboratories Europe GmbH, NEC
> > Corporation,
> > + * All rights reserved.
> > *
> > * Redistribution and use in source and binary forms, with or
> > without
> > * modification, are permitted provided that the following
> > conditions
> > @@ -28,8 +30,6 @@
> > * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
> > OTHERWISE)
> > * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
> > ADVISED OF THE
> > * POSSIBILITY OF SUCH DAMAGE.
> > - *
> > - * THIS HEADER MAY NOT BE EXTRACTED OR MODIFIED IN ANY WAY.
> > */
> >
> > /* This is a very simple, naive implementation of malloc.
> > @@ -52,6 +52,7 @@
> > #include <uk/essentials.h>
> > #include <uk/assert.h>
> > #include <uk/arch/limits.h>
> > +#include <uk/arch/lcpu.h>
> >
> > #define size_to_num_pages(size) \
> > (ALIGN_UP((unsigned long)(size), __PAGE_SIZE) /
> > __PAGE_SIZE)
> > @@ -267,6 +268,147 @@ int uk_posix_memalign_ifpages(struct uk_alloc
> > *a,
> > return 0;
> > }
> >
> > +#if CONFIG_LIBUKALLOC_IFMALLOC
> > +
> > +struct metadata_ifmalloc {
> > + size_t size;
> > + void *base;
> > +};
> > +
> > +#define METADATA_IFMALLOC_SIZE_POW2 16
> > +UK_CTASSERT(!(sizeof(struct metadata_ifmalloc) >
> > METADATA_IFMALLOC_SIZE_POW2));
> > +
> > +static struct metadata_ifmalloc *uk_get_metadata_ifmalloc(const
> > void *ptr)
> > +{
> > + return (struct metadata_ifmalloc *)((uintptr_t) ptr -
> > + METADATA_IFMALLOC_SIZE_POW2);
> > +}
> > +
> > +static size_t uk_getmallocsize_ifmalloc(const void *ptr)
> > +{
> > + struct metadata_ifmalloc *metadata =
> > uk_get_metadata_ifmalloc(ptr);
> > + return (size_t) ((uintptr_t) metadata->base + metadata-
> > >
> > > size -
> > + (uintptr_t) ptr);
> > +}
> > +
> > +void uk_free_ifmalloc(struct uk_alloc *a, void *ptr)
> > +{
> > + struct metadata_ifmalloc *metadata;
> > +
> > + UK_ASSERT(a);
> > + UK_ASSERT(a->free_backend);
> > + if (!ptr)
> > + return;
> > +
> > + metadata = uk_get_metadata_ifmalloc(ptr);
> > + a->free_backend(a, metadata->base);
> > +}
> > +
> > +void *uk_malloc_ifmalloc(struct uk_alloc *a, size_t size)
> > +{
> > + struct metadata_ifmalloc *metadata;
> > + size_t realsize = size + METADATA_IFMALLOC_SIZE_POW2;
> > + void *ptr;
> > +
> > + UK_ASSERT(a);
> > + UK_ASSERT(a->malloc_backend);
> > +
> > + /* check for overflow */
> > + if (unlikely(realsize < size))
> > + return NULL;
> > +
> > + ptr = a->malloc_backend(a, realsize);
> > + if (!ptr)
> > + return NULL;
> > +
> > + metadata = ptr;
> > + metadata->size = realsize;
> > + metadata->base = ptr;
> > +
> > + return (void *) ((uintptr_t) ptr +
> > METADATA_IFMALLOC_SIZE_POW2);
> > +}
> > +
> > +void *uk_realloc_ifmalloc(struct uk_alloc *a, void *ptr, size_t
> > size)
> > +{
> > + void *retptr;
> > + size_t mallocsize;
> > +
> > + UK_ASSERT(a);
> > + if (!ptr)
> > + return uk_malloc_ifmalloc(a, size);
> > +
> > + if (ptr && !size) {
> > + uk_free_ifmalloc(a, ptr);
> > + return NULL;
> > + }
> > +
> > + retptr = uk_malloc_ifmalloc(a, size);
> > + if (!retptr)
> > + return NULL;
> > +
> > + mallocsize = uk_getmallocsize_ifmalloc(ptr);
> > +
> > + memcpy(retptr, ptr, MIN(size, mallocsize));
> > +
> > + uk_free_ifmalloc(a, ptr);
> > + return retptr;
> > +}
> > +
> > +int uk_posix_memalign_ifmalloc(struct uk_alloc *a,
> > + void **memptr, size_t align,
> > size_t size)
> > +{
> > + struct metadata_ifmalloc *metadata;
> > + size_t realsize, padding;
> > + uintptr_t intptr;
> > +
> > + UK_ASSERT(a);
> > + if (((align - 1) & align) != 0
> > + || align < sizeof(void *))
> > + return EINVAL;
> > +
> > + if (!size) {
> > + *memptr = NULL;
> Should we touch *memptr in case of failures? You seem not to do it
> in
> the other cases.
> https://man7.org/linux/man-pages/man3/posix_memalign.3.html
Taking a look at https://pubs.opengroup.org/onlinepubs/9699919799/funct
ions/posix_memalign.html, specifically:
"If size is 0, either:
* posix_memalign() shall not attempt to allocate any space, in which
case either an implementation-defined error number shall be returned,
or zero shall be returned with a null pointer returned in memptr, or
* posix_memalign() shall attempt to allocate some space and, if the
allocation succeeds, zero shall be returned and a pointer to the
allocated space shall be returned in memptr. The application shall
ensure that the pointer is not used to access an object."
Indeed, I prefer to return an error code instead of setting memptr and
returning zero. My fear is that some users might dereference memptr
after observing a zero return value. Do you think EINVAL is fine in
this case? In this case we could just remove `*memptr = NULL;`.
Note that this bug was already present in uk_posix_memalign_ifpages, I
intentionally reproduced it in the ifmalloc wrapper. It was introduced
in https://github.com/unikraft/unikraft/commit/a323fbd67ac3cb21139633b3
00a024538167493e
Good point. Personally, I prefer returning an error and not touching memptr,
since we have choice. That feels a bit more well-defined than the other
behavior.
In case we will come across while porting an application that expect the other
behavior, we may think of adding a menu config option to switch between them.
I really hope it is rare that someone calls posix_memalign() with size 0...
Can you add a brief comment that two described behavior exist for size = 0?
In order to keep uk_posix_memalign_ifpages() equivalent, can you remove
setting memptr also there for this case? With having the comment it is
fine to do this in the same patch.
> > + return EINVAL;
> > +}
> > +
> > + /* Store size information preceeding the memory block.
> > Since we return
> > + * pointers aligned at `align` we need to reserve at least
> > that much
> > + * space for the size information.
> > + */
> > + if (align < METADATA_IFMALLOC_SIZE_POW2) {
> > + align = METADATA_IFMALLOC_SIZE_POW2;
> > + padding = 0;
> > + } else {
> > + padding = METADATA_IFMALLOC_SIZE_POW2;
> > + }
> > +
> > + realsize = size + padding + align;
> > +
> > + /* check for overflow */
> > + if (unlikely(realsize < size))
> > + return NULL;
> Hum, you should return an errno. I would choose ENOMEM, thats closer
> inline with malloc:
>
> return ENOMEM;
Sounds good.
>
> >
> >
> > +
> > + intptr = (uintptr_t) a->malloc_backend(a, realsize);
> > +
> > + if (!intptr)
> > + return ENOMEM;
> > +
> > + *memptr = (void *) ALIGN_UP(intptr +
> > METADATA_IFMALLOC_SIZE_POW2,
> > + (uintptr_t) align);
> > +
> > + metadata = uk_get_metadata_ifmalloc(*memptr);
> > +
> > + /* check for underflow */
> > + UK_ASSERT(intptr <= (uintptr_t) metadata);
> > +
> > + metadata->size = realsize;
> > + metadata->base = (void *) intptr;
> > +
> > + return 0;
> > +}
> > +
> > +#endif
> > +
> > void uk_pfree_compat(struct uk_alloc *a, void *ptr,
> > unsigned long num_pages __unused)
> > {
> > diff --git a/lib/ukalloc/exportsyms.uk b/lib/ukalloc/exportsyms.uk
> > index 2c8a90f..21c1996 100644
> > --- a/lib/ukalloc/exportsyms.uk
> > +++ b/lib/ukalloc/exportsyms.uk
> > @@ -4,6 +4,10 @@ uk_malloc_ifpages
> > uk_free_ifpages
> > uk_realloc_ifpages
> > uk_posix_memalign_ifpages
> > +uk_malloc_ifmalloc
> > +uk_realloc_ifmalloc
> > +uk_posix_memalign_ifmalloc
> > +uk_free_ifmalloc
> > uk_calloc_compat
> > uk_memalign_compat
> > uk_realloc_compat
> > diff --git a/lib/ukalloc/include/uk/alloc.h
> > b/lib/ukalloc/include/uk/alloc.h
> > index 5bfa2f2..1457922 100644
> > --- a/lib/ukalloc/include/uk/alloc.h
> > +++ b/lib/ukalloc/include/uk/alloc.h
> > @@ -85,6 +85,11 @@ struct uk_alloc {
> > uk_alloc_memalign_func_t memalign;
> > uk_alloc_free_func_t free;
> >
> > +#if CONFIG_LIBUKALLOC_IFMALLOC
> > + uk_alloc_free_func_t free_backend;
> > + uk_alloc_malloc_func_t malloc_backend;
> > +#endif
> > +
> > /* page allocation interface */
> > uk_alloc_palloc_func_t palloc;
> > uk_alloc_pfree_func_t pfree;
> > diff --git a/lib/ukalloc/include/uk/alloc_impl.h
> > b/lib/ukalloc/include/uk/alloc_impl.h
> > index 8bcca94..b15f49e 100644
> > --- a/lib/ukalloc/include/uk/alloc_impl.h
> > +++ b/lib/ukalloc/include/uk/alloc_impl.h
> > @@ -62,6 +62,14 @@ int uk_posix_memalign_ifpages(struct uk_alloc
> > *a, void **memptr,
> > size_t align, size_t size);
> > void uk_free_ifpages(struct uk_alloc *a, void *ptr);
> >
> > +#if CONFIG_LIBUKALLOC_IFMALLOC
> > +void *uk_malloc_ifmalloc(struct uk_alloc *a, size_t size);
> > +void *uk_realloc_ifmalloc(struct uk_alloc *a, void *ptr, size_t
> > size);
> > +int uk_posix_memalign_ifmalloc(struct uk_alloc *a, void **memptr,
> > + size_t align, size_t size);
> > +void uk_free_ifmalloc(struct uk_alloc *a, void *ptr);
> > +#endif
> > +
> > /* Functionality that is provided based on malloc() and
> > posix_memalign() */
> > void *uk_calloc_compat(struct uk_alloc *a, size_t num, size_t
> > len);
> > void *uk_realloc_compat(struct uk_alloc *a, void *ptr, size_t
> > size);
> > @@ -88,6 +96,25 @@ void uk_pfree_compat(struct uk_alloc *a, void
> > *ptr, unsigned long num_pages);
> > uk_alloc_register((a));
> > \
> > } while (0)
> >
> > +#if CONFIG_LIBUKALLOC_IFMALLOC
> > +#define uk_alloc_init_malloc_ifmalloc(a, malloc_f, free_f,
> > addmem_f) \
> > + do {
> > \
> > + (a)->malloc = uk_malloc_ifmalloc;
> > \
> > + (a)->calloc = uk_calloc_compat;
> > \
> > + (a)->realloc = uk_realloc_ifmalloc;
> > \
> > + (a)->posix_memalign = uk_posix_memalign_ifmalloc;
> > \
> > + (a)->memalign = uk_memalign_compat;
> > \
> > + (a)->malloc_backend = (malloc_f);
> > \
> > + (a)->free_backend = (free_f);
> > \
> > + (a)->free = uk_free_ifmalloc;
> > \
> > + (a)->palloc = uk_palloc_compat;
> > \
> > + (a)->pfree = uk_pfree_compat;
> > \
> > + (a)->addmem = (addmem_f);
> > \
> > +
> > \
> > + uk_alloc_register((a));
> > \
> > + } while (0)
> > +#endif
> > +
> > /* Shortcut for doing a registration of an allocator that only
> > * implements palloc(), pfree(), addmem()
> > */
Thanks,
Simon
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |