From patchwork Fri Jul 6 13:17:32 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Burakov, Anatoly" X-Patchwork-Id: 42508 X-Patchwork-Delegate: thomas@monjalon.net Return-Path: X-Original-To: patchwork@dpdk.org Delivered-To: patchwork@dpdk.org Received: from [92.243.14.124] (localhost [127.0.0.1]) by dpdk.org (Postfix) with ESMTP id 5DF1B1BF43; Fri, 6 Jul 2018 15:17:58 +0200 (CEST) Received: from mga05.intel.com (mga05.intel.com [192.55.52.43]) by dpdk.org (Postfix) with ESMTP id 71BED1BF43 for ; Fri, 6 Jul 2018 15:17:56 +0200 (CEST) X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from fmsmga008.fm.intel.com ([10.253.24.58]) by fmsmga105.fm.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 06 Jul 2018 06:17:55 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.51,316,1526367600"; d="scan'208";a="53071166" Received: from irvmail001.ir.intel.com ([163.33.26.43]) by fmsmga008.fm.intel.com with ESMTP; 06 Jul 2018 06:17:35 -0700 Received: from sivswdev01.ir.intel.com (sivswdev01.ir.intel.com [10.237.217.45]) by irvmail001.ir.intel.com (8.14.3/8.13.6/MailSET/Hub) with ESMTP id w66DHYjX027500; Fri, 6 Jul 2018 14:17:34 +0100 Received: from sivswdev01.ir.intel.com (localhost [127.0.0.1]) by sivswdev01.ir.intel.com with ESMTP id w66DHYeL003825; Fri, 6 Jul 2018 14:17:34 +0100 Received: (from aburakov@localhost) by sivswdev01.ir.intel.com with LOCAL id w66DHYSA003821; Fri, 6 Jul 2018 14:17:34 +0100 From: Anatoly Burakov To: dev@dpdk.org Cc: srinath.mannam@broadcom.com, scott.branden@broadcom.com, ajit.khaparde@broadcom.com Date: Fri, 6 Jul 2018 14:17:32 +0100 Message-Id: <3a31e2adf03569582e4ecd1acdec80c599ee884e.1530881548.git.anatoly.burakov@intel.com> X-Mailer: git-send-email 1.7.0.7 In-Reply-To: References: In-Reply-To: References: Subject: [dpdk-dev] [RFC 11/11] memzone: enable reserving memory from named heaps X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "dev" Add ability to allocate memory for memzones from named heaps. The semantics are kept similar to regular allocations, and as much of the code as possible is shared. Signed-off-by: Anatoly Burakov --- lib/librte_eal/common/eal_common_memzone.c | 237 +++++++++++++++----- lib/librte_eal/common/include/rte_memzone.h | 183 +++++++++++++++ lib/librte_eal/rte_eal_version.map | 3 + 3 files changed, 373 insertions(+), 50 deletions(-) diff --git a/lib/librte_eal/common/eal_common_memzone.c b/lib/librte_eal/common/eal_common_memzone.c index 25c56052c..d37e7ae1d 100644 --- a/lib/librte_eal/common/eal_common_memzone.c +++ b/lib/librte_eal/common/eal_common_memzone.c @@ -98,17 +98,14 @@ find_heap_max_free_elem(int *s, unsigned align) return len; } -static const struct rte_memzone * -memzone_reserve_aligned_thread_unsafe(const char *name, size_t len, - int socket_id, unsigned int flags, unsigned int align, +static int +common_checks(const char *name, size_t len, unsigned int align, unsigned int bound) { struct rte_memzone *mz; struct rte_mem_config *mcfg; struct rte_fbarray *arr; size_t requested_len; - int mz_idx; - bool contig; /* get pointer to global configuration */ mcfg = rte_eal_get_configuration()->mem_config; @@ -118,14 +115,14 @@ memzone_reserve_aligned_thread_unsafe(const char *name, size_t len, if (arr->count >= arr->len) { RTE_LOG(ERR, EAL, "%s(): No more room in config\n", __func__); rte_errno = ENOSPC; - return NULL; + return -1; } if (strlen(name) > sizeof(mz->name) - 1) { RTE_LOG(DEBUG, EAL, "%s(): memzone <%s>: name too long\n", __func__, name); rte_errno = ENAMETOOLONG; - return NULL; + return -1; } /* zone already exist */ @@ -133,7 +130,7 @@ memzone_reserve_aligned_thread_unsafe(const char *name, size_t len, RTE_LOG(DEBUG, EAL, "%s(): memzone <%s> already exists\n", __func__, name); rte_errno = EEXIST; - return NULL; + return -1; } /* if alignment is not a power of two */ @@ -141,7 +138,7 @@ memzone_reserve_aligned_thread_unsafe(const char *name, size_t len, RTE_LOG(ERR, EAL, "%s(): Invalid alignment: %u\n", __func__, align); rte_errno = EINVAL; - return NULL; + return -1; } /* alignment less than cache size is not allowed */ @@ -151,7 +148,7 @@ memzone_reserve_aligned_thread_unsafe(const char *name, size_t len, /* align length on cache boundary. Check for overflow before doing so */ if (len > SIZE_MAX - RTE_CACHE_LINE_MASK) { rte_errno = EINVAL; /* requested size too big */ - return NULL; + return -1; } len += RTE_CACHE_LINE_MASK; @@ -163,49 +160,23 @@ memzone_reserve_aligned_thread_unsafe(const char *name, size_t len, /* check that boundary condition is valid */ if (bound != 0 && (requested_len > bound || !rte_is_power_of_2(bound))) { rte_errno = EINVAL; - return NULL; - } - - if ((socket_id != SOCKET_ID_ANY) && - (socket_id >= RTE_MAX_NUMA_NODES || socket_id < 0)) { - rte_errno = EINVAL; - return NULL; - } - - if (!rte_eal_has_hugepages()) - socket_id = SOCKET_ID_ANY; - - contig = (flags & RTE_MEMZONE_IOVA_CONTIG) != 0; - /* malloc only cares about size flags, remove contig flag from flags */ - flags &= ~RTE_MEMZONE_IOVA_CONTIG; - - if (len == 0) { - /* len == 0 is only allowed for non-contiguous zones */ - if (contig) { - RTE_LOG(DEBUG, EAL, "Reserving zero-length contiguous memzones is not supported\n"); - rte_errno = EINVAL; - return NULL; - } - if (bound != 0) - requested_len = bound; - else { - requested_len = find_heap_max_free_elem(&socket_id, align); - if (requested_len == 0) { - rte_errno = ENOMEM; - return NULL; - } - } - } - - /* allocate memory on heap */ - void *mz_addr = malloc_heap_alloc(NULL, requested_len, socket_id, flags, - align, bound, contig); - if (mz_addr == NULL) { - rte_errno = ENOMEM; - return NULL; + return -1; } + return 0; +} +static const struct rte_memzone * +create_memzone(const char *name, void *mz_addr, size_t requested_len) +{ + struct rte_mem_config *mcfg; + struct rte_fbarray *arr; struct malloc_elem *elem = malloc_elem_from_data(mz_addr); + struct rte_memzone *mz; + int mz_idx; + + /* get pointer to global configuration */ + mcfg = rte_eal_get_configuration()->mem_config; + arr = &mcfg->memzones; /* fill the zone in config */ mz_idx = rte_fbarray_find_next_free(arr, 0); @@ -236,6 +207,134 @@ memzone_reserve_aligned_thread_unsafe(const char *name, size_t len, return mz; } +static const struct rte_memzone * +memzone_reserve_from_heap_aligned_thread_unsafe(const char *name, size_t len, + const char *heap_name, unsigned int flags, unsigned int align, + unsigned int bound) +{ + size_t requested_len = len; + void *mz_addr; + int heap_idx; + bool contig; + + /* this function sets rte_errno */ + if (common_checks(name, len, align, bound) < 0) + return NULL; + + heap_idx = malloc_heap_find_named_heap_idx(heap_name); + if (heap_idx < 0) { + rte_errno = ENOENT; + return NULL; + } + + contig = (flags & RTE_MEMZONE_IOVA_CONTIG) != 0; + /* malloc only cares about size flags, remove contig flag from flags */ + flags &= ~RTE_MEMZONE_IOVA_CONTIG; + + if (len == 0) { + /* len == 0 is only allowed for non-contiguous zones */ + if (contig) { + RTE_LOG(DEBUG, EAL, "Reserving zero-length contiguous memzones is not supported\n"); + rte_errno = EINVAL; + return NULL; + } + if (bound != 0) + requested_len = bound; + else { + requested_len = heap_max_free_elem(heap_idx, align); + if (requested_len == 0) { + rte_errno = ENOMEM; + return NULL; + } + } + } + + /* allocate memory on heap */ + mz_addr = malloc_heap_alloc_on_heap_id(NULL, requested_len, heap_idx, + flags, align, bound, contig); + if (mz_addr == NULL) { + rte_errno = ENOMEM; + return NULL; + } + return create_memzone(name, mz_addr, requested_len); +} + +static const struct rte_memzone * +memzone_reserve_aligned_thread_unsafe(const char *name, size_t len, + int socket_id, unsigned int flags, unsigned int align, + unsigned int bound) +{ + size_t requested_len = len; + bool contig; + void *mz_addr; + + /* this function sets rte_errno */ + if (common_checks(name, len, align, bound) < 0) + return NULL; + + if ((socket_id != SOCKET_ID_ANY) && + (socket_id >= RTE_MAX_NUMA_NODES || socket_id < 0)) { + rte_errno = EINVAL; + return NULL; + } + + if (!rte_eal_has_hugepages()) + socket_id = SOCKET_ID_ANY; + + contig = (flags & RTE_MEMZONE_IOVA_CONTIG) != 0; + /* malloc only cares about size flags, remove contig flag from flags */ + flags &= ~RTE_MEMZONE_IOVA_CONTIG; + + if (len == 0) { + /* len == 0 is only allowed for non-contiguous zones */ + if (contig) { + RTE_LOG(DEBUG, EAL, "Reserving zero-length contiguous memzones is not supported\n"); + rte_errno = EINVAL; + return NULL; + } + if (bound != 0) + requested_len = bound; + else { + requested_len = find_heap_max_free_elem(&socket_id, + align); + if (requested_len == 0) { + rte_errno = ENOMEM; + return NULL; + } + } + } + + /* allocate memory on heap */ + mz_addr = malloc_heap_alloc(NULL, requested_len, socket_id, flags, + align, bound, contig); + if (mz_addr == NULL) { + rte_errno = ENOMEM; + return NULL; + } + return create_memzone(name, mz_addr, requested_len); +} + +static const struct rte_memzone * +rte_memzone_reserve_from_heap_thread_safe(const char *name, size_t len, + const char *heap_name, unsigned int flags, unsigned int align, + unsigned int bound) +{ + struct rte_mem_config *mcfg; + const struct rte_memzone *mz = NULL; + + /* get pointer to global configuration */ + mcfg = rte_eal_get_configuration()->mem_config; + + rte_rwlock_write_lock(&mcfg->mlock); + + mz = memzone_reserve_from_heap_aligned_thread_unsafe(name, len, + heap_name, flags, align, bound); + + rte_rwlock_write_unlock(&mcfg->mlock); + + return mz; +} + static const struct rte_memzone * rte_memzone_reserve_thread_safe(const char *name, size_t len, int socket_id, unsigned int flags, unsigned int align, unsigned int bound) @@ -293,6 +392,44 @@ rte_memzone_reserve(const char *name, size_t len, int socket_id, flags, RTE_CACHE_LINE_SIZE, 0); } +/* + * Return a pointer to a correctly filled memzone descriptor (with a + * specified alignment and boundary). If the allocation cannot be done, + * return NULL. + */ +const struct rte_memzone * +rte_memzone_reserve_from_heap_bounded(const char *name, size_t len, + const char *heap_name, unsigned int flags, unsigned int align, + unsigned int bound) +{ + return rte_memzone_reserve_from_heap_thread_safe(name, len, heap_name, + flags, align, bound); +} + +/* + * Return a pointer to a correctly filled memzone descriptor (with a + * specified alignment). If the allocation cannot be done, return NULL. + */ +const struct rte_memzone * +rte_memzone_reserve_from_heap_aligned(const char *name, size_t len, + const char *heap_name, unsigned int flags, unsigned int align) +{ + return rte_memzone_reserve_from_heap_thread_safe(name, len, heap_name, + flags, align, 0); +} + +/* + * Return a pointer to a correctly filled memzone descriptor. If the + * allocation cannot be done, return NULL. + */ +const struct rte_memzone * +rte_memzone_reserve_from_heap(const char *name, size_t len, + const char *heap_name, unsigned int flags) +{ + return rte_memzone_reserve_from_heap_thread_safe(name, len, heap_name, + flags, RTE_CACHE_LINE_SIZE, 0); +} + int rte_memzone_free(const struct rte_memzone *mz) { diff --git a/lib/librte_eal/common/include/rte_memzone.h b/lib/librte_eal/common/include/rte_memzone.h index ef370fa6f..b27e5c421 100644 --- a/lib/librte_eal/common/include/rte_memzone.h +++ b/lib/librte_eal/common/include/rte_memzone.h @@ -258,6 +258,189 @@ const struct rte_memzone *rte_memzone_reserve_bounded(const char *name, size_t len, int socket_id, unsigned flags, unsigned align, unsigned bound); +/** + * Reserve a portion of physical memory from a specified named heap. + * + * This function reserves some memory and returns a pointer to a + * correctly filled memzone descriptor. If the allocation cannot be + * done, return NULL. + * + * @note Reserving memzones with len set to 0 will only attempt to allocate + * memzones from memory that is already available. It will not trigger any + * new allocations. + * + * @note Reserving IOVA-contiguous memzones with len set to 0 is not currently + * supported. + * + * @param name + * The name of the memzone. If it already exists, the function will + * fail and return NULL. + * @param len + * The size of the memory to be reserved. If it + * is 0, the biggest contiguous zone will be reserved. + * @param heap_name + * The name of the heap to reserve memory from. + * @param flags + * The flags parameter is used to request memzones to be + * taken from specifically sized hugepages. + * - RTE_MEMZONE_2MB - Reserved from 2MB pages + * - RTE_MEMZONE_1GB - Reserved from 1GB pages + * - RTE_MEMZONE_16MB - Reserved from 16MB pages + * - RTE_MEMZONE_16GB - Reserved from 16GB pages + * - RTE_MEMZONE_256KB - Reserved from 256KB pages + * - RTE_MEMZONE_256MB - Reserved from 256MB pages + * - RTE_MEMZONE_512MB - Reserved from 512MB pages + * - RTE_MEMZONE_4GB - Reserved from 4GB pages + * - RTE_MEMZONE_SIZE_HINT_ONLY - Allow alternative page size to be used if + * the requested page size is unavailable. + * If this flag is not set, the function + * will return error on an unavailable size + * request. + * - RTE_MEMZONE_IOVA_CONTIG - Ensure reserved memzone is IOVA-contiguous. + * This option should be used when allocating + * memory intended for hardware rings etc. + * @return + * A pointer to a correctly-filled read-only memzone descriptor, or NULL + * on error. + * On error case, rte_errno will be set appropriately: + * - E_RTE_NO_CONFIG - function could not get pointer to rte_config structure + * - E_RTE_SECONDARY - function was called from a secondary process instance + * - ENOSPC - the maximum number of memzones has already been allocated + * - EEXIST - a memzone with the same name already exists + * - ENOMEM - no appropriate memory area found in which to create memzone + * - EINVAL - invalid parameters + */ +__rte_experimental const struct rte_memzone * +rte_memzone_reserve_from_heap(const char *name, size_t len, + const char *heap_name, unsigned int flags); + +/** + * Reserve a portion of physical memory from a specified named heap with + * alignment on a specified boundary. + * + * This function reserves some memory with alignment on a specified + * boundary, and returns a pointer to a correctly filled memzone + * descriptor. If the allocation cannot be done or if the alignment + * is not a power of 2, returns NULL. + * + * @note Reserving memzones with len set to 0 will only attempt to allocate + * memzones from memory that is already available. It will not trigger any + * new allocations. + * + * @note Reserving IOVA-contiguous memzones with len set to 0 is not currently + * supported. + * + * @param name + * The name of the memzone. If it already exists, the function will + * fail and return NULL. + * @param len + * The size of the memory to be reserved. If it + * is 0, the biggest contiguous zone will be reserved. + * @param heap_name + * The name of the heap to reserve memory from. + * @param flags + * The flags parameter is used to request memzones to be + * taken from specifically sized hugepages. + * - RTE_MEMZONE_2MB - Reserved from 2MB pages + * - RTE_MEMZONE_1GB - Reserved from 1GB pages + * - RTE_MEMZONE_16MB - Reserved from 16MB pages + * - RTE_MEMZONE_16GB - Reserved from 16GB pages + * - RTE_MEMZONE_256KB - Reserved from 256KB pages + * - RTE_MEMZONE_256MB - Reserved from 256MB pages + * - RTE_MEMZONE_512MB - Reserved from 512MB pages + * - RTE_MEMZONE_4GB - Reserved from 4GB pages + * - RTE_MEMZONE_SIZE_HINT_ONLY - Allow alternative page size to be used if + * the requested page size is unavailable. + * If this flag is not set, the function + * will return error on an unavailable size + * request. + * - RTE_MEMZONE_IOVA_CONTIG - Ensure reserved memzone is IOVA-contiguous. + * This option should be used when allocating + * memory intended for hardware rings etc. + * @param align + * Alignment for resulting memzone. Must be a power of 2. + * @return + * A pointer to a correctly-filled read-only memzone descriptor, or NULL + * on error. + * On error case, rte_errno will be set appropriately: + * - E_RTE_NO_CONFIG - function could not get pointer to rte_config structure + * - E_RTE_SECONDARY - function was called from a secondary process instance + * - ENOSPC - the maximum number of memzones has already been allocated + * - EEXIST - a memzone with the same name already exists + * - ENOMEM - no appropriate memory area found in which to create memzone + * - EINVAL - invalid parameters + */ +__rte_experimental const struct rte_memzone * +rte_memzone_reserve_from_heap_aligned(const char *name, size_t len, + const char *heap_name, unsigned int flags, unsigned int align); + +/** + * Reserve a portion of physical memory from a specified named heap with + * specified alignment and boundary. + * + * This function reserves some memory with specified alignment and + * boundary, and returns a pointer to a correctly filled memzone + * descriptor. If the allocation cannot be done or if the alignment + * or boundary are not a power of 2, returns NULL. + * Memory buffer is reserved in a way, that it wouldn't cross specified + * boundary. That implies that requested length should be less or equal + * then boundary. + * + * @note Reserving memzones with len set to 0 will only attempt to allocate + * memzones from memory that is already available. It will not trigger any + * new allocations. + * + * @note Reserving IOVA-contiguous memzones with len set to 0 is not currently + * supported. + * + * @param name + * The name of the memzone. If it already exists, the function will + * fail and return NULL. + * @param len + * The size of the memory to be reserved. If it + * is 0, the biggest contiguous zone will be reserved. + * @param heap_name + * The name of the heap to reserve memory from. + * @param flags + * The flags parameter is used to request memzones to be + * taken from specifically sized hugepages. + * - RTE_MEMZONE_2MB - Reserved from 2MB pages + * - RTE_MEMZONE_1GB - Reserved from 1GB pages + * - RTE_MEMZONE_16MB - Reserved from 16MB pages + * - RTE_MEMZONE_16GB - Reserved from 16GB pages + * - RTE_MEMZONE_256KB - Reserved from 256KB pages + * - RTE_MEMZONE_256MB - Reserved from 256MB pages + * - RTE_MEMZONE_512MB - Reserved from 512MB pages + * - RTE_MEMZONE_4GB - Reserved from 4GB pages + * - RTE_MEMZONE_SIZE_HINT_ONLY - Allow alternative page size to be used if + * the requested page size is unavailable. + * If this flag is not set, the function + * will return error on an unavailable size + * request. + * - RTE_MEMZONE_IOVA_CONTIG - Ensure reserved memzone is IOVA-contiguous. + * This option should be used when allocating + * memory intended for hardware rings etc. + * @param align + * Alignment for resulting memzone. Must be a power of 2. + * @param bound + * Boundary for resulting memzone. Must be a power of 2 or zero. + * Zero value implies no boundary condition. + * @return + * A pointer to a correctly-filled read-only memzone descriptor, or NULL + * on error. + * On error case, rte_errno will be set appropriately: + * - E_RTE_NO_CONFIG - function could not get pointer to rte_config structure + * - E_RTE_SECONDARY - function was called from a secondary process instance + * - ENOSPC - the maximum number of memzones has already been allocated + * - EEXIST - a memzone with the same name already exists + * - ENOMEM - no appropriate memory area found in which to create memzone + * - EINVAL - invalid parameters + */ +__rte_experimental const struct rte_memzone * +rte_memzone_reserve_from_heap_bounded(const char *name, size_t len, + const char *heap_name, unsigned int flags, unsigned int align, + unsigned int bound); + /** * Free a memzone. * diff --git a/lib/librte_eal/rte_eal_version.map b/lib/librte_eal/rte_eal_version.map index cdde7eb3b..db1cfae6a 100644 --- a/lib/librte_eal/rte_eal_version.map +++ b/lib/librte_eal/rte_eal_version.map @@ -294,6 +294,9 @@ EXPERIMENTAL { rte_memseg_contig_walk; rte_memseg_list_walk; rte_memseg_walk; + rte_memzone_reserve_from_heap; + rte_memzone_reserve_from_heap_aligned; + rte_memzone_reserve_from_heap_bounded; rte_mp_action_register; rte_mp_action_unregister; rte_mp_reply;