199a2dd95SBruce Richardson /* SPDX-License-Identifier: BSD-3-Clause
299a2dd95SBruce Richardson * Copyright(c) 2010-2014 Intel Corporation
399a2dd95SBruce Richardson */
499a2dd95SBruce Richardson
599a2dd95SBruce Richardson #ifndef MALLOC_ELEM_H_
699a2dd95SBruce Richardson #define MALLOC_ELEM_H_
799a2dd95SBruce Richardson
899a2dd95SBruce Richardson #include <stdbool.h>
999a2dd95SBruce Richardson
1048ff13efSDavid Marchand #include <rte_common.h>
1148ff13efSDavid Marchand
1299a2dd95SBruce Richardson #define MIN_DATA_SIZE (RTE_CACHE_LINE_SIZE)
1399a2dd95SBruce Richardson
1499a2dd95SBruce Richardson /* dummy definition of struct so we can use pointers to it in malloc_elem struct */
1599a2dd95SBruce Richardson struct malloc_heap;
1699a2dd95SBruce Richardson
1799a2dd95SBruce Richardson enum elem_state {
1899a2dd95SBruce Richardson ELEM_FREE = 0,
1999a2dd95SBruce Richardson ELEM_BUSY,
2099a2dd95SBruce Richardson ELEM_PAD /* element is a padding-only header */
2199a2dd95SBruce Richardson };
2299a2dd95SBruce Richardson
23*c6552d9aSTyler Retzlaff struct __rte_cache_aligned malloc_elem {
2499a2dd95SBruce Richardson struct malloc_heap *heap;
2599a2dd95SBruce Richardson struct malloc_elem *volatile prev;
2699a2dd95SBruce Richardson /**< points to prev elem in memseg */
2799a2dd95SBruce Richardson struct malloc_elem *volatile next;
2899a2dd95SBruce Richardson /**< points to next elem in memseg */
2999a2dd95SBruce Richardson LIST_ENTRY(malloc_elem) free_list;
3099a2dd95SBruce Richardson /**< list of free elements in heap */
3199a2dd95SBruce Richardson struct rte_memseg_list *msl;
322edd037cSDmitry Kozlyuk /** Element state, @c dirty and @c pad validity depends on it. */
332edd037cSDmitry Kozlyuk /* An extra bit is needed to represent enum elem_state as signed int. */
342edd037cSDmitry Kozlyuk enum elem_state state : 3;
352edd037cSDmitry Kozlyuk /** If state == ELEM_FREE: the memory is not filled with zeroes. */
362edd037cSDmitry Kozlyuk uint32_t dirty : 1;
372edd037cSDmitry Kozlyuk /** Reserved for future use. */
382edd037cSDmitry Kozlyuk uint32_t reserved : 28;
3999a2dd95SBruce Richardson uint32_t pad;
4099a2dd95SBruce Richardson size_t size;
4199a2dd95SBruce Richardson struct malloc_elem *orig_elem;
4299a2dd95SBruce Richardson size_t orig_size;
4399a2dd95SBruce Richardson #ifdef RTE_MALLOC_DEBUG
4499a2dd95SBruce Richardson uint64_t header_cookie; /* Cookie marking start of data */
4599a2dd95SBruce Richardson /* trailer cookie at start + size */
4699a2dd95SBruce Richardson #endif
476cc51b12SZhihong Peng #ifdef RTE_MALLOC_ASAN
486cc51b12SZhihong Peng size_t user_size;
496cc51b12SZhihong Peng uint64_t asan_cookie[2]; /* must be next to header_cookie */
506cc51b12SZhihong Peng #endif
51*c6552d9aSTyler Retzlaff };
5299a2dd95SBruce Richardson
536cc51b12SZhihong Peng static const unsigned int MALLOC_ELEM_HEADER_LEN = sizeof(struct malloc_elem);
546cc51b12SZhihong Peng
5599a2dd95SBruce Richardson #ifndef RTE_MALLOC_DEBUG
566cc51b12SZhihong Peng #ifdef RTE_MALLOC_ASAN
576cc51b12SZhihong Peng static const unsigned int MALLOC_ELEM_TRAILER_LEN = RTE_CACHE_LINE_SIZE;
586cc51b12SZhihong Peng #else
596cc51b12SZhihong Peng static const unsigned int MALLOC_ELEM_TRAILER_LEN;
606cc51b12SZhihong Peng #endif
6199a2dd95SBruce Richardson
6299a2dd95SBruce Richardson /* dummy function - just check if pointer is non-null */
6399a2dd95SBruce Richardson static inline int
malloc_elem_cookies_ok(const struct malloc_elem * elem)6499a2dd95SBruce Richardson malloc_elem_cookies_ok(const struct malloc_elem *elem){ return elem != NULL; }
6599a2dd95SBruce Richardson
6699a2dd95SBruce Richardson /* dummy function - no header if malloc_debug is not enabled */
6799a2dd95SBruce Richardson static inline void
set_header(struct malloc_elem * elem __rte_unused)6899a2dd95SBruce Richardson set_header(struct malloc_elem *elem __rte_unused){ }
6999a2dd95SBruce Richardson
7099a2dd95SBruce Richardson /* dummy function - no trailer if malloc_debug is not enabled */
7199a2dd95SBruce Richardson static inline void
set_trailer(struct malloc_elem * elem __rte_unused)7299a2dd95SBruce Richardson set_trailer(struct malloc_elem *elem __rte_unused){ }
7399a2dd95SBruce Richardson
7499a2dd95SBruce Richardson
7599a2dd95SBruce Richardson #else
766cc51b12SZhihong Peng static const unsigned int MALLOC_ELEM_TRAILER_LEN = RTE_CACHE_LINE_SIZE;
7799a2dd95SBruce Richardson
7899a2dd95SBruce Richardson #define MALLOC_HEADER_COOKIE 0xbadbadbadadd2e55ULL /**< Header cookie. */
7999a2dd95SBruce Richardson #define MALLOC_TRAILER_COOKIE 0xadd2e55badbadbadULL /**< Trailer cookie.*/
8099a2dd95SBruce Richardson
8199a2dd95SBruce Richardson /* define macros to make referencing the header and trailer cookies easier */
8299a2dd95SBruce Richardson #define MALLOC_ELEM_TRAILER(elem) (*((uint64_t*)RTE_PTR_ADD(elem, \
8399a2dd95SBruce Richardson elem->size - MALLOC_ELEM_TRAILER_LEN)))
8499a2dd95SBruce Richardson #define MALLOC_ELEM_HEADER(elem) (elem->header_cookie)
8599a2dd95SBruce Richardson
8699a2dd95SBruce Richardson static inline void
set_header(struct malloc_elem * elem)8799a2dd95SBruce Richardson set_header(struct malloc_elem *elem)
8899a2dd95SBruce Richardson {
8999a2dd95SBruce Richardson if (elem != NULL)
9099a2dd95SBruce Richardson MALLOC_ELEM_HEADER(elem) = MALLOC_HEADER_COOKIE;
9199a2dd95SBruce Richardson }
9299a2dd95SBruce Richardson
9399a2dd95SBruce Richardson static inline void
set_trailer(struct malloc_elem * elem)9499a2dd95SBruce Richardson set_trailer(struct malloc_elem *elem)
9599a2dd95SBruce Richardson {
9699a2dd95SBruce Richardson if (elem != NULL)
9799a2dd95SBruce Richardson MALLOC_ELEM_TRAILER(elem) = MALLOC_TRAILER_COOKIE;
9899a2dd95SBruce Richardson }
9999a2dd95SBruce Richardson
10099a2dd95SBruce Richardson /* check that the header and trailer cookies are set correctly */
10199a2dd95SBruce Richardson static inline int
malloc_elem_cookies_ok(const struct malloc_elem * elem)10299a2dd95SBruce Richardson malloc_elem_cookies_ok(const struct malloc_elem *elem)
10399a2dd95SBruce Richardson {
10499a2dd95SBruce Richardson return elem != NULL &&
10599a2dd95SBruce Richardson MALLOC_ELEM_HEADER(elem) == MALLOC_HEADER_COOKIE &&
10699a2dd95SBruce Richardson MALLOC_ELEM_TRAILER(elem) == MALLOC_TRAILER_COOKIE;
10799a2dd95SBruce Richardson }
10899a2dd95SBruce Richardson
10999a2dd95SBruce Richardson #endif
11099a2dd95SBruce Richardson
11199a2dd95SBruce Richardson #define MALLOC_ELEM_OVERHEAD (MALLOC_ELEM_HEADER_LEN + MALLOC_ELEM_TRAILER_LEN)
11299a2dd95SBruce Richardson
1136cc51b12SZhihong Peng #ifdef RTE_MALLOC_ASAN
1146cc51b12SZhihong Peng
115001d402cSVolodymyr Fialko /*
116001d402cSVolodymyr Fialko * ASAN_SHADOW_OFFSET should match to the corresponding
117001d402cSVolodymyr Fialko * value defined in gcc/libsanitizer/asan/asan_mapping.h
118001d402cSVolodymyr Fialko */
1196cc51b12SZhihong Peng #ifdef RTE_ARCH_X86_64
1206cc51b12SZhihong Peng #define ASAN_SHADOW_OFFSET 0x00007fff8000
121001d402cSVolodymyr Fialko #elif defined(RTE_ARCH_ARM64)
122001d402cSVolodymyr Fialko #define ASAN_SHADOW_OFFSET 0x001000000000
123f2a66612SDavid Christensen #elif defined(RTE_ARCH_PPC_64)
124f2a66612SDavid Christensen #define ASAN_SHADOW_OFFSET 0x020000000000
1256cc51b12SZhihong Peng #endif
1266cc51b12SZhihong Peng
1276cc51b12SZhihong Peng #define ASAN_SHADOW_GRAIN_SIZE 8
1286cc51b12SZhihong Peng #define ASAN_MEM_FREE_FLAG 0xfd
1296cc51b12SZhihong Peng #define ASAN_MEM_REDZONE_FLAG 0xfa
1306cc51b12SZhihong Peng #define ASAN_SHADOW_SCALE 3
1316cc51b12SZhihong Peng
1326cc51b12SZhihong Peng #define ASAN_MEM_SHIFT(mem) ((void *)((uintptr_t)(mem) >> ASAN_SHADOW_SCALE))
1336cc51b12SZhihong Peng #define ASAN_MEM_TO_SHADOW(mem) \
1346cc51b12SZhihong Peng RTE_PTR_ADD(ASAN_MEM_SHIFT(mem), ASAN_SHADOW_OFFSET)
1356cc51b12SZhihong Peng
1366cc51b12SZhihong Peng __rte_no_asan
1376cc51b12SZhihong Peng static inline void
asan_set_shadow(void * addr,char val)1386cc51b12SZhihong Peng asan_set_shadow(void *addr, char val)
1396cc51b12SZhihong Peng {
1406cc51b12SZhihong Peng *(char *)addr = val;
1416cc51b12SZhihong Peng }
1426cc51b12SZhihong Peng
1436cc51b12SZhihong Peng static inline void
asan_set_zone(void * ptr,size_t len,uint32_t val)1446cc51b12SZhihong Peng asan_set_zone(void *ptr, size_t len, uint32_t val)
1456cc51b12SZhihong Peng {
1466cc51b12SZhihong Peng size_t offset, i;
1476cc51b12SZhihong Peng void *shadow;
1486cc51b12SZhihong Peng size_t zone_len = len / ASAN_SHADOW_GRAIN_SIZE;
1496cc51b12SZhihong Peng if (len % ASAN_SHADOW_GRAIN_SIZE != 0)
1506cc51b12SZhihong Peng zone_len += 1;
1516cc51b12SZhihong Peng
1526cc51b12SZhihong Peng for (i = 0; i < zone_len; i++) {
1536cc51b12SZhihong Peng offset = i * ASAN_SHADOW_GRAIN_SIZE;
1546cc51b12SZhihong Peng shadow = ASAN_MEM_TO_SHADOW((uintptr_t)ptr + offset);
1556cc51b12SZhihong Peng asan_set_shadow(shadow, val);
1566cc51b12SZhihong Peng }
1576cc51b12SZhihong Peng }
1586cc51b12SZhihong Peng
1596cc51b12SZhihong Peng /*
1606cc51b12SZhihong Peng * When the memory is released, the release mark is
1616cc51b12SZhihong Peng * set in the corresponding range of the shadow area.
1626cc51b12SZhihong Peng */
1636cc51b12SZhihong Peng static inline void
asan_set_freezone(void * ptr,size_t size)1646cc51b12SZhihong Peng asan_set_freezone(void *ptr, size_t size)
1656cc51b12SZhihong Peng {
1666cc51b12SZhihong Peng asan_set_zone(ptr, size, ASAN_MEM_FREE_FLAG);
1676cc51b12SZhihong Peng }
1686cc51b12SZhihong Peng
1696cc51b12SZhihong Peng /*
1706cc51b12SZhihong Peng * When the memory is allocated, memory state must set as accessible.
1716cc51b12SZhihong Peng */
1726cc51b12SZhihong Peng static inline void
asan_clear_alloczone(struct malloc_elem * elem)1736cc51b12SZhihong Peng asan_clear_alloczone(struct malloc_elem *elem)
1746cc51b12SZhihong Peng {
1756cc51b12SZhihong Peng asan_set_zone((void *)elem, elem->size, 0x0);
1766cc51b12SZhihong Peng }
1776cc51b12SZhihong Peng
1786cc51b12SZhihong Peng static inline void
asan_clear_split_alloczone(struct malloc_elem * elem)1796cc51b12SZhihong Peng asan_clear_split_alloczone(struct malloc_elem *elem)
1806cc51b12SZhihong Peng {
1816cc51b12SZhihong Peng void *ptr = RTE_PTR_SUB(elem, MALLOC_ELEM_TRAILER_LEN);
1826cc51b12SZhihong Peng asan_set_zone(ptr, MALLOC_ELEM_OVERHEAD, 0x0);
1836cc51b12SZhihong Peng }
1846cc51b12SZhihong Peng
1856cc51b12SZhihong Peng /*
1866cc51b12SZhihong Peng * When the memory is allocated, the memory boundary is
1876cc51b12SZhihong Peng * marked in the corresponding range of the shadow area.
1886cc51b12SZhihong Peng * Requirement: redzone >= 16, is a power of two.
1896cc51b12SZhihong Peng */
1906cc51b12SZhihong Peng static inline void
asan_set_redzone(struct malloc_elem * elem,size_t user_size)1916cc51b12SZhihong Peng asan_set_redzone(struct malloc_elem *elem, size_t user_size)
1926cc51b12SZhihong Peng {
1936cc51b12SZhihong Peng uintptr_t head_redzone;
1946cc51b12SZhihong Peng uintptr_t tail_redzone;
1956cc51b12SZhihong Peng void *front_shadow;
1966cc51b12SZhihong Peng void *tail_shadow;
1976cc51b12SZhihong Peng uint32_t val;
1986cc51b12SZhihong Peng
1996cc51b12SZhihong Peng if (elem != NULL) {
2006cc51b12SZhihong Peng if (elem->state != ELEM_PAD)
2016cc51b12SZhihong Peng elem = RTE_PTR_ADD(elem, elem->pad);
2026cc51b12SZhihong Peng
2036cc51b12SZhihong Peng elem->user_size = user_size;
2046cc51b12SZhihong Peng
2056cc51b12SZhihong Peng /* Set mark before the start of the allocated memory */
2066cc51b12SZhihong Peng head_redzone = (uintptr_t)RTE_PTR_ADD(elem,
2076cc51b12SZhihong Peng MALLOC_ELEM_HEADER_LEN - ASAN_SHADOW_GRAIN_SIZE);
2086cc51b12SZhihong Peng front_shadow = ASAN_MEM_TO_SHADOW(head_redzone);
2096cc51b12SZhihong Peng asan_set_shadow(front_shadow, ASAN_MEM_REDZONE_FLAG);
2106cc51b12SZhihong Peng front_shadow = ASAN_MEM_TO_SHADOW(head_redzone
2116cc51b12SZhihong Peng - ASAN_SHADOW_GRAIN_SIZE);
2126cc51b12SZhihong Peng asan_set_shadow(front_shadow, ASAN_MEM_REDZONE_FLAG);
2136cc51b12SZhihong Peng
2146cc51b12SZhihong Peng /* Set mark after the end of the allocated memory */
2156cc51b12SZhihong Peng tail_redzone = (uintptr_t)RTE_PTR_ADD(elem,
2166cc51b12SZhihong Peng MALLOC_ELEM_HEADER_LEN
2176cc51b12SZhihong Peng + elem->user_size);
2186cc51b12SZhihong Peng tail_shadow = ASAN_MEM_TO_SHADOW(tail_redzone);
2196cc51b12SZhihong Peng val = (tail_redzone % ASAN_SHADOW_GRAIN_SIZE);
2206cc51b12SZhihong Peng val = (val == 0) ? ASAN_MEM_REDZONE_FLAG : val;
2216cc51b12SZhihong Peng asan_set_shadow(tail_shadow, val);
2226cc51b12SZhihong Peng tail_shadow = ASAN_MEM_TO_SHADOW(tail_redzone
2236cc51b12SZhihong Peng + ASAN_SHADOW_GRAIN_SIZE);
2246cc51b12SZhihong Peng asan_set_shadow(tail_shadow, ASAN_MEM_REDZONE_FLAG);
2256cc51b12SZhihong Peng }
2266cc51b12SZhihong Peng }
2276cc51b12SZhihong Peng
2286cc51b12SZhihong Peng /*
2296cc51b12SZhihong Peng * When the memory is released, the mark of the memory boundary
2306cc51b12SZhihong Peng * in the corresponding range of the shadow area is cleared.
2316cc51b12SZhihong Peng * Requirement: redzone >= 16, is a power of two.
2326cc51b12SZhihong Peng */
2336cc51b12SZhihong Peng static inline void
asan_clear_redzone(struct malloc_elem * elem)2346cc51b12SZhihong Peng asan_clear_redzone(struct malloc_elem *elem)
2356cc51b12SZhihong Peng {
2366cc51b12SZhihong Peng uintptr_t head_redzone;
2376cc51b12SZhihong Peng uintptr_t tail_redzone;
2386cc51b12SZhihong Peng void *head_shadow;
2396cc51b12SZhihong Peng void *tail_shadow;
2406cc51b12SZhihong Peng
2416cc51b12SZhihong Peng if (elem != NULL) {
2426cc51b12SZhihong Peng elem = RTE_PTR_ADD(elem, elem->pad);
2436cc51b12SZhihong Peng
2446cc51b12SZhihong Peng /* Clear mark before the start of the allocated memory */
2456cc51b12SZhihong Peng head_redzone = (uintptr_t)RTE_PTR_ADD(elem,
2466cc51b12SZhihong Peng MALLOC_ELEM_HEADER_LEN - ASAN_SHADOW_GRAIN_SIZE);
2476cc51b12SZhihong Peng head_shadow = ASAN_MEM_TO_SHADOW(head_redzone);
2486cc51b12SZhihong Peng asan_set_shadow(head_shadow, 0x00);
2496cc51b12SZhihong Peng head_shadow = ASAN_MEM_TO_SHADOW(head_redzone
2506cc51b12SZhihong Peng - ASAN_SHADOW_GRAIN_SIZE);
2516cc51b12SZhihong Peng asan_set_shadow(head_shadow, 0x00);
2526cc51b12SZhihong Peng
2536cc51b12SZhihong Peng /* Clear mark after the end of the allocated memory */
2546cc51b12SZhihong Peng tail_redzone = (uintptr_t)RTE_PTR_ADD(elem,
2556cc51b12SZhihong Peng MALLOC_ELEM_HEADER_LEN + elem->user_size);
2566cc51b12SZhihong Peng tail_shadow = ASAN_MEM_TO_SHADOW(tail_redzone);
2576cc51b12SZhihong Peng asan_set_shadow(tail_shadow, 0x00);
2586cc51b12SZhihong Peng tail_shadow = ASAN_MEM_TO_SHADOW(tail_redzone
2596cc51b12SZhihong Peng + ASAN_SHADOW_GRAIN_SIZE);
2606cc51b12SZhihong Peng asan_set_shadow(tail_shadow, 0x00);
2616cc51b12SZhihong Peng }
2626cc51b12SZhihong Peng }
2636cc51b12SZhihong Peng
2646cc51b12SZhihong Peng static inline size_t
old_malloc_size(struct malloc_elem * elem)2656cc51b12SZhihong Peng old_malloc_size(struct malloc_elem *elem)
2666cc51b12SZhihong Peng {
2676cc51b12SZhihong Peng if (elem->state != ELEM_PAD)
2686cc51b12SZhihong Peng elem = RTE_PTR_ADD(elem, elem->pad);
2696cc51b12SZhihong Peng
2706cc51b12SZhihong Peng return elem->user_size;
2716cc51b12SZhihong Peng }
2726cc51b12SZhihong Peng
2736cc51b12SZhihong Peng #else /* !RTE_MALLOC_ASAN */
2746cc51b12SZhihong Peng
2756cc51b12SZhihong Peng static inline void
asan_set_zone(void * ptr __rte_unused,size_t len __rte_unused,uint32_t val __rte_unused)2764d8bdd8bSAnatoly Burakov asan_set_zone(void *ptr __rte_unused, size_t len __rte_unused,
2774d8bdd8bSAnatoly Burakov uint32_t val __rte_unused) { }
2784d8bdd8bSAnatoly Burakov
2794d8bdd8bSAnatoly Burakov static inline void
asan_set_freezone(void * ptr __rte_unused,size_t size __rte_unused)2806cc51b12SZhihong Peng asan_set_freezone(void *ptr __rte_unused, size_t size __rte_unused) { }
2816cc51b12SZhihong Peng
2826cc51b12SZhihong Peng static inline void
asan_clear_alloczone(struct malloc_elem * elem __rte_unused)2836cc51b12SZhihong Peng asan_clear_alloczone(struct malloc_elem *elem __rte_unused) { }
2846cc51b12SZhihong Peng
2856cc51b12SZhihong Peng static inline void
asan_clear_split_alloczone(struct malloc_elem * elem __rte_unused)2866cc51b12SZhihong Peng asan_clear_split_alloczone(struct malloc_elem *elem __rte_unused) { }
2876cc51b12SZhihong Peng
2886cc51b12SZhihong Peng static inline void
asan_set_redzone(struct malloc_elem * elem __rte_unused,size_t user_size __rte_unused)2896cc51b12SZhihong Peng asan_set_redzone(struct malloc_elem *elem __rte_unused,
2906cc51b12SZhihong Peng size_t user_size __rte_unused) { }
2916cc51b12SZhihong Peng
2926cc51b12SZhihong Peng static inline void
asan_clear_redzone(struct malloc_elem * elem __rte_unused)2936cc51b12SZhihong Peng asan_clear_redzone(struct malloc_elem *elem __rte_unused) { }
2946cc51b12SZhihong Peng
2956cc51b12SZhihong Peng static inline size_t
old_malloc_size(struct malloc_elem * elem)2966cc51b12SZhihong Peng old_malloc_size(struct malloc_elem *elem)
2976cc51b12SZhihong Peng {
2986cc51b12SZhihong Peng return elem->size - elem->pad - MALLOC_ELEM_OVERHEAD;
2996cc51b12SZhihong Peng }
3006cc51b12SZhihong Peng #endif /* !RTE_MALLOC_ASAN */
3016cc51b12SZhihong Peng
30299a2dd95SBruce Richardson /*
30399a2dd95SBruce Richardson * Given a pointer to the start of a memory block returned by malloc, get
30499a2dd95SBruce Richardson * the actual malloc_elem header for that block.
30599a2dd95SBruce Richardson */
30699a2dd95SBruce Richardson static inline struct malloc_elem *
malloc_elem_from_data(const void * data)30799a2dd95SBruce Richardson malloc_elem_from_data(const void *data)
30899a2dd95SBruce Richardson {
30999a2dd95SBruce Richardson if (data == NULL)
31099a2dd95SBruce Richardson return NULL;
31199a2dd95SBruce Richardson
31299a2dd95SBruce Richardson struct malloc_elem *elem = RTE_PTR_SUB(data, MALLOC_ELEM_HEADER_LEN);
31399a2dd95SBruce Richardson if (!malloc_elem_cookies_ok(elem))
31499a2dd95SBruce Richardson return NULL;
31599a2dd95SBruce Richardson return elem->state != ELEM_PAD ? elem: RTE_PTR_SUB(elem, elem->pad);
31699a2dd95SBruce Richardson }
31799a2dd95SBruce Richardson
31899a2dd95SBruce Richardson /*
31999a2dd95SBruce Richardson * initialise a malloc_elem header
32099a2dd95SBruce Richardson */
32199a2dd95SBruce Richardson void
32299a2dd95SBruce Richardson malloc_elem_init(struct malloc_elem *elem,
32399a2dd95SBruce Richardson struct malloc_heap *heap,
32499a2dd95SBruce Richardson struct rte_memseg_list *msl,
32599a2dd95SBruce Richardson size_t size,
32699a2dd95SBruce Richardson struct malloc_elem *orig_elem,
3272edd037cSDmitry Kozlyuk size_t orig_size,
3282edd037cSDmitry Kozlyuk bool dirty);
32999a2dd95SBruce Richardson
33099a2dd95SBruce Richardson void
33199a2dd95SBruce Richardson malloc_elem_insert(struct malloc_elem *elem);
33299a2dd95SBruce Richardson
33399a2dd95SBruce Richardson /*
33499a2dd95SBruce Richardson * return true if the current malloc_elem can hold a block of data
33599a2dd95SBruce Richardson * of the requested size and with the requested alignment
33699a2dd95SBruce Richardson */
33799a2dd95SBruce Richardson int
33899a2dd95SBruce Richardson malloc_elem_can_hold(struct malloc_elem *elem, size_t size,
33999a2dd95SBruce Richardson unsigned int align, size_t bound, bool contig);
34099a2dd95SBruce Richardson
34199a2dd95SBruce Richardson /*
34299a2dd95SBruce Richardson * reserve a block of data in an existing malloc_elem. If the malloc_elem
34399a2dd95SBruce Richardson * is much larger than the data block requested, we split the element in two.
34499a2dd95SBruce Richardson */
34599a2dd95SBruce Richardson struct malloc_elem *
34699a2dd95SBruce Richardson malloc_elem_alloc(struct malloc_elem *elem, size_t size,
34799a2dd95SBruce Richardson unsigned int align, size_t bound, bool contig);
34899a2dd95SBruce Richardson
34999a2dd95SBruce Richardson /*
35099a2dd95SBruce Richardson * free a malloc_elem block by adding it to the free list. If the
35199a2dd95SBruce Richardson * blocks either immediately before or immediately after newly freed block
35299a2dd95SBruce Richardson * are also free, the blocks are merged together.
35399a2dd95SBruce Richardson */
35499a2dd95SBruce Richardson struct malloc_elem *
35599a2dd95SBruce Richardson malloc_elem_free(struct malloc_elem *elem);
35699a2dd95SBruce Richardson
35799a2dd95SBruce Richardson struct malloc_elem *
35899a2dd95SBruce Richardson malloc_elem_join_adjacent_free(struct malloc_elem *elem);
35999a2dd95SBruce Richardson
36099a2dd95SBruce Richardson /*
36199a2dd95SBruce Richardson * attempt to resize a malloc_elem by expanding into any free space
36299a2dd95SBruce Richardson * immediately after it in memory.
36399a2dd95SBruce Richardson */
36499a2dd95SBruce Richardson int
36599a2dd95SBruce Richardson malloc_elem_resize(struct malloc_elem *elem, size_t size);
36699a2dd95SBruce Richardson
36799a2dd95SBruce Richardson void
36899a2dd95SBruce Richardson malloc_elem_hide_region(struct malloc_elem *elem, void *start, size_t len);
36999a2dd95SBruce Richardson
37099a2dd95SBruce Richardson void
37199a2dd95SBruce Richardson malloc_elem_free_list_remove(struct malloc_elem *elem);
37299a2dd95SBruce Richardson
37399a2dd95SBruce Richardson /*
37499a2dd95SBruce Richardson * dump contents of malloc elem to a file.
37599a2dd95SBruce Richardson */
37699a2dd95SBruce Richardson void
37799a2dd95SBruce Richardson malloc_elem_dump(const struct malloc_elem *elem, FILE *f);
37899a2dd95SBruce Richardson
37999a2dd95SBruce Richardson /*
38099a2dd95SBruce Richardson * Given an element size, compute its freelist index.
38199a2dd95SBruce Richardson */
38299a2dd95SBruce Richardson size_t
38399a2dd95SBruce Richardson malloc_elem_free_list_index(size_t size);
38499a2dd95SBruce Richardson
38599a2dd95SBruce Richardson /*
38699a2dd95SBruce Richardson * Add element to its heap's free list.
38799a2dd95SBruce Richardson */
38899a2dd95SBruce Richardson void
38999a2dd95SBruce Richardson malloc_elem_free_list_insert(struct malloc_elem *elem);
39099a2dd95SBruce Richardson
39199a2dd95SBruce Richardson /*
39299a2dd95SBruce Richardson * Find biggest IOVA-contiguous zone within an element with specified alignment.
39399a2dd95SBruce Richardson */
39499a2dd95SBruce Richardson size_t
39599a2dd95SBruce Richardson malloc_elem_find_max_iova_contig(struct malloc_elem *elem, size_t align);
39699a2dd95SBruce Richardson
39799a2dd95SBruce Richardson #endif /* MALLOC_ELEM_H_ */
398