X-Git-Url: http://git.droids-corp.org/?a=blobdiff_plain;f=lib%2Flibrte_eal%2Fcommon%2Fmalloc_elem.c;h=ee79dcd9871b120ce53587c7f3e33f2e84289c06;hb=964b2f3bfb07ae95fcf4570269a6bc0e1c0affec;hp=2291ee13c897cf9efd18a6a65509d26206c82d7e;hpb=f21aa4ec9dffde2f313bba2cb477c1bdf2cbc93e;p=dpdk.git diff --git a/lib/librte_eal/common/malloc_elem.c b/lib/librte_eal/common/malloc_elem.c index 2291ee13c8..ee79dcd987 100644 --- a/lib/librte_eal/common/malloc_elem.c +++ b/lib/librte_eal/common/malloc_elem.c @@ -6,6 +6,7 @@ #include #include #include +#include #include #include @@ -17,6 +18,7 @@ #include #include +#include "eal_memalloc.h" #include "malloc_elem.h" #include "malloc_heap.h" @@ -26,11 +28,11 @@ * Initialize a general malloc_elem header structure */ void -malloc_elem_init(struct malloc_elem *elem, - struct malloc_heap *heap, const struct rte_memseg *ms, size_t size) +malloc_elem_init(struct malloc_elem *elem, struct malloc_heap *heap, + struct rte_memseg_list *msl, size_t size) { elem->heap = heap; - elem->ms = ms; + elem->msl = msl; elem->prev = NULL; elem->next = NULL; memset(&elem->free_list, 0, sizeof(elem->free_list)); @@ -93,6 +95,18 @@ malloc_elem_insert(struct malloc_elem *elem) next_elem->prev = elem; } +/* + * Attempt to find enough physically contiguous memory in this block to store + * our data. Assume that element has at least enough space to fit in the data, + * so we just check the page addresses. + */ +static bool +elem_check_phys_contig(const struct rte_memseg_list *msl, + void *start, size_t size) +{ + return eal_memalloc_is_contig(msl, start, size); +} + /* * calculate the starting point of where data of the requested size * and alignment would fit in the current element. If the data doesn't @@ -100,27 +114,59 @@ malloc_elem_insert(struct malloc_elem *elem) */ static void * elem_start_pt(struct malloc_elem *elem, size_t size, unsigned align, - size_t bound) + size_t bound, bool contig) { - const size_t bmask = ~(bound - 1); - uintptr_t end_pt = (uintptr_t)elem + - elem->size - MALLOC_ELEM_TRAILER_LEN; - uintptr_t new_data_start = RTE_ALIGN_FLOOR((end_pt - size), align); - uintptr_t new_elem_start; - - /* check boundary */ - if ((new_data_start & bmask) != ((end_pt - 1) & bmask)) { - end_pt = RTE_ALIGN_FLOOR(end_pt, bound); - new_data_start = RTE_ALIGN_FLOOR((end_pt - size), align); - end_pt = new_data_start + size; - if (((end_pt - 1) & bmask) != (new_data_start & bmask)) - return NULL; - } + size_t elem_size = elem->size; + + /* + * we're allocating from the end, so adjust the size of element by + * alignment size. + */ + while (elem_size >= size) { + const size_t bmask = ~(bound - 1); + uintptr_t end_pt = (uintptr_t)elem + + elem_size - MALLOC_ELEM_TRAILER_LEN; + uintptr_t new_data_start = RTE_ALIGN_FLOOR((end_pt - size), + align); + uintptr_t new_elem_start; + + /* check boundary */ + if ((new_data_start & bmask) != ((end_pt - 1) & bmask)) { + end_pt = RTE_ALIGN_FLOOR(end_pt, bound); + new_data_start = RTE_ALIGN_FLOOR((end_pt - size), + align); + end_pt = new_data_start + size; + + if (((end_pt - 1) & bmask) != (new_data_start & bmask)) + return NULL; + } - new_elem_start = new_data_start - MALLOC_ELEM_HEADER_LEN; + new_elem_start = new_data_start - MALLOC_ELEM_HEADER_LEN; - /* if the new start point is before the exist start, it won't fit */ - return (new_elem_start < (uintptr_t)elem) ? NULL : (void *)new_elem_start; + /* if the new start point is before the exist start, + * it won't fit + */ + if (new_elem_start < (uintptr_t)elem) + return NULL; + + if (contig) { + size_t new_data_size = end_pt - new_data_start; + + /* + * if physical contiguousness was requested and we + * couldn't fit all data into one physically contiguous + * block, try again with lower addresses. + */ + if (!elem_check_phys_contig(elem->msl, + (void *)new_data_start, + new_data_size)) { + elem_size -= align; + continue; + } + } + return (void *)new_elem_start; + } + return NULL; } /* @@ -129,9 +175,9 @@ elem_start_pt(struct malloc_elem *elem, size_t size, unsigned align, */ int malloc_elem_can_hold(struct malloc_elem *elem, size_t size, unsigned align, - size_t bound) + size_t bound, bool contig) { - return elem_start_pt(elem, size, align, bound) != NULL; + return elem_start_pt(elem, size, align, bound, contig) != NULL; } /* @@ -145,7 +191,7 @@ split_elem(struct malloc_elem *elem, struct malloc_elem *split_pt) const size_t old_elem_size = (uintptr_t)split_pt - (uintptr_t)elem; const size_t new_elem_size = elem->size - old_elem_size; - malloc_elem_init(split_pt, elem->heap, elem->ms, new_elem_size); + malloc_elem_init(split_pt, elem->heap, elem->msl, new_elem_size); split_pt->prev = elem; split_pt->next = next_elem; if (next_elem) @@ -245,8 +291,8 @@ malloc_elem_free_list_insert(struct malloc_elem *elem) /* * Remove the specified element from its heap's free list. */ -static void -elem_free_list_remove(struct malloc_elem *elem) +void +malloc_elem_free_list_remove(struct malloc_elem *elem) { LIST_REMOVE(elem, free_list); } @@ -259,14 +305,15 @@ elem_free_list_remove(struct malloc_elem *elem) */ struct malloc_elem * malloc_elem_alloc(struct malloc_elem *elem, size_t size, unsigned align, - size_t bound) + size_t bound, bool contig) { - struct malloc_elem *new_elem = elem_start_pt(elem, size, align, bound); + struct malloc_elem *new_elem = elem_start_pt(elem, size, align, bound, + contig); const size_t old_elem_size = (uintptr_t)new_elem - (uintptr_t)elem; const size_t trailer_size = elem->size - old_elem_size - size - MALLOC_ELEM_OVERHEAD; - elem_free_list_remove(elem); + malloc_elem_free_list_remove(elem); if (trailer_size > MALLOC_ELEM_OVERHEAD + MIN_DATA_SIZE) { /* split it, too much free space after elem */ @@ -340,7 +387,7 @@ malloc_elem_join_adjacent_free(struct malloc_elem *elem) erase = RTE_PTR_SUB(elem->next, MALLOC_ELEM_TRAILER_LEN); /* remove from free list, join to this one */ - elem_free_list_remove(elem->next); + malloc_elem_free_list_remove(elem->next); join_elem(elem, elem->next); /* erase header and trailer */ @@ -360,7 +407,7 @@ malloc_elem_join_adjacent_free(struct malloc_elem *elem) erase = RTE_PTR_SUB(elem, MALLOC_ELEM_TRAILER_LEN); /* remove from free list, join to this one */ - elem_free_list_remove(elem->prev); + malloc_elem_free_list_remove(elem->prev); new_elem = elem->prev; join_elem(new_elem, elem); @@ -379,7 +426,7 @@ malloc_elem_join_adjacent_free(struct malloc_elem *elem) * blocks either immediately before or immediately after newly freed block * are also free, the blocks are merged together. */ -int +struct malloc_elem * malloc_elem_free(struct malloc_elem *elem) { void *ptr; @@ -397,7 +444,99 @@ malloc_elem_free(struct malloc_elem *elem) memset(ptr, 0, data_len); - return 0; + return elem; +} + +/* assume all checks were already done */ +void +malloc_elem_hide_region(struct malloc_elem *elem, void *start, size_t len) +{ + struct malloc_elem *hide_start, *hide_end, *prev, *next; + size_t len_before, len_after; + + hide_start = start; + hide_end = RTE_PTR_ADD(start, len); + + prev = elem->prev; + next = elem->next; + + /* we cannot do anything with non-adjacent elements */ + if (next && next_elem_is_adjacent(elem)) { + len_after = RTE_PTR_DIFF(next, hide_end); + if (len_after >= MALLOC_ELEM_OVERHEAD + MIN_DATA_SIZE) { + /* split after */ + split_elem(elem, hide_end); + + malloc_elem_free_list_insert(hide_end); + } else if (len_after >= MALLOC_ELEM_HEADER_LEN) { + /* shrink current element */ + elem->size -= len_after; + memset(hide_end, 0, sizeof(*hide_end)); + + /* copy next element's data to our pad */ + memcpy(hide_end, next, sizeof(*hide_end)); + + /* pad next element */ + next->state = ELEM_PAD; + next->pad = len_after; + next->size -= len_after; + + /* next element busy, would've been merged otherwise */ + hide_end->pad = len_after; + hide_end->size += len_after; + + /* adjust pointers to point to our new pad */ + if (next->next) + next->next->prev = hide_end; + elem->next = hide_end; + } else if (len_after > 0) { + RTE_LOG(ERR, EAL, "Unaligned element, heap is probably corrupt\n"); + return; + } + } + + /* we cannot do anything with non-adjacent elements */ + if (prev && prev_elem_is_adjacent(elem)) { + len_before = RTE_PTR_DIFF(hide_start, elem); + if (len_before >= MALLOC_ELEM_OVERHEAD + MIN_DATA_SIZE) { + /* split before */ + split_elem(elem, hide_start); + + prev = elem; + elem = hide_start; + + malloc_elem_free_list_insert(prev); + } else if (len_before > 0) { + /* + * unlike with elements after current, here we don't + * need to pad elements, but rather just increase the + * size of previous element, copy the old header and set + * up trailer. + */ + void *trailer = RTE_PTR_ADD(prev, + prev->size - MALLOC_ELEM_TRAILER_LEN); + + memcpy(hide_start, elem, sizeof(*elem)); + hide_start->size = len; + + prev->size += len_before; + set_trailer(prev); + + /* update pointers */ + prev->next = hide_start; + if (next) + next->prev = hide_start; + + /* erase old trailer */ + memset(trailer, 0, MALLOC_ELEM_TRAILER_LEN); + /* erase old header */ + memset(elem, 0, sizeof(*elem)); + + elem = hide_start; + } + } + + remove_elem(elem); } /* @@ -423,7 +562,7 @@ malloc_elem_resize(struct malloc_elem *elem, size_t size) /* we now know the element fits, so remove from free list, * join the two */ - elem_free_list_remove(elem->next); + malloc_elem_free_list_remove(elem->next); join_elem(elem, elem->next); if (elem->size - new_size >= MIN_DATA_SIZE + MALLOC_ELEM_OVERHEAD) {