From patchwork Fri Sep 21 16:14:04 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Burakov, Anatoly" X-Patchwork-Id: 45142 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 8BE0F1B156; Fri, 21 Sep 2018 18:15:05 +0200 (CEST) Received: from mga05.intel.com (mga05.intel.com [192.55.52.43]) by dpdk.org (Postfix) with ESMTP id E3F2E5F4A for ; Fri, 21 Sep 2018 18:14:30 +0200 (CEST) X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from orsmga001.jf.intel.com ([10.7.209.18]) by fmsmga105.fm.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 21 Sep 2018 09:14:29 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.54,285,1534834800"; d="scan'208";a="92588066" Received: from irvmail001.ir.intel.com ([163.33.26.43]) by orsmga001.jf.intel.com with ESMTP; 21 Sep 2018 09:14:13 -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 w8LGEC4r029225; Fri, 21 Sep 2018 17:14:12 +0100 Received: from sivswdev01.ir.intel.com (localhost [127.0.0.1]) by sivswdev01.ir.intel.com with ESMTP id w8LGECmk002911; Fri, 21 Sep 2018 17:14:12 +0100 Received: (from aburakov@localhost) by sivswdev01.ir.intel.com with LOCAL id w8LGECVF002904; Fri, 21 Sep 2018 17:14:12 +0100 From: Anatoly Burakov To: dev@dpdk.org Cc: laszlo.madarassy@ericsson.com, laszlo.vadkerti@ericsson.com, andras.kovacs@ericsson.com, winnie.tian@ericsson.com, daniel.andrasi@ericsson.com, janos.kobor@ericsson.com, geza.koblo@ericsson.com, srinath.mannam@broadcom.com, scott.branden@broadcom.com, ajit.khaparde@broadcom.com, keith.wiles@intel.com, bruce.richardson@intel.com, thomas@monjalon.net, shreyansh.jain@nxp.com, shahafs@mellanox.com, arybchenko@solarflare.com Date: Fri, 21 Sep 2018 17:14:04 +0100 Message-Id: <6b5567bfed124dbfda2d8ec13fb87fe4cd9cb859.1537546029.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] [PATCH v4 15/20] malloc: allow attaching to external memory chunks 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" In order to use external memory in multiple processes, we need to attach to primary process's memseg lists, so add a new API to do that. It is the responsibility of the user to ensure that memory is accessible and that it has been previously added to the malloc heap by another process. Signed-off-by: Anatoly Burakov --- lib/librte_eal/common/include/rte_malloc.h | 48 +++++++++-- lib/librte_eal/common/rte_malloc.c | 93 ++++++++++++++++++++++ lib/librte_eal/rte_eal_version.map | 1 + 3 files changed, 135 insertions(+), 7 deletions(-) diff --git a/lib/librte_eal/common/include/rte_malloc.h b/lib/librte_eal/common/include/rte_malloc.h index 40bae4478..ec59302de 100644 --- a/lib/librte_eal/common/include/rte_malloc.h +++ b/lib/librte_eal/common/include/rte_malloc.h @@ -268,6 +268,10 @@ rte_malloc_get_socket_stats(int socket, * * @note Multiple memory chunks can be added to the same heap * + * @note Before accessing this memory in other processes, it needs to be + * attached in each of those processes by calling + * ``rte_malloc_heap_memory_attach`` in each other process. + * * @note Memory must be previously allocated for DPDK to be able to use it as a * malloc heap. Failing to do so will result in undefined behavior, up to and * including segmentation faults. @@ -329,21 +333,48 @@ rte_malloc_heap_memory_add(const char *heap_name, void *va_addr, size_t len, int __rte_experimental rte_malloc_heap_memory_remove(const char *heap_name, void *va_addr, size_t len); +/** + * Attach to an already existing chunk of external memory in another process. + * + * @note This function must be called before any attempt is made to use an + * already existing external memory chunk. This function does *not* need to + * be called if a call to ``rte_malloc_heap_memory_add`` was made in the + * current process. + * + * @param heap_name + * Heap name to which this chunk of memory belongs + * @param va_addr + * Start address of memory chunk to attach to + * @param len + * Length of memory chunk to attach to + * @return + * 0 on successful attach + * -1 on unsuccessful attach, with rte_errno set to indicate cause for error: + * EINVAL - one of the parameters was invalid + * EPERM - attempted to attach memory to a reserved heap + * ENOENT - heap or memory chunk was not found + */ +int __rte_experimental +rte_malloc_heap_memory_attach(const char *heap_name, void *va_addr, size_t len); + /** * Creates a new empty malloc heap with a specified name. * * @note Heaps created via this call will automatically get assigned a unique * socket ID, which can be found using ``rte_malloc_heap_get_socket()`` * + * @note This function can only be called in primary process. + * * @param heap_name * Name of the heap to create. * * @return * - 0 on successful creation * - -1 in case of error, with rte_errno set to one of the following: - * EINVAL - ``heap_name`` was NULL, empty or too long - * EEXIST - heap by name of ``heap_name`` already exists - * ENOSPC - no more space in internal config to store a new heap + * EINVAL - ``heap_name`` was NULL, empty or too long + * EEXIST - heap by name of ``heap_name`` already exists + * ENOSPC - no more space in internal config to store a new heap + * E_RTE_SECONDARY - attempted to create a heap in secondary process */ int __rte_experimental rte_malloc_heap_create(const char *heap_name); @@ -357,16 +388,19 @@ rte_malloc_heap_create(const char *heap_name); * @note This function will return a failure result if not all memory segments * were removed from the heap prior to its destruction * + * @note This function can only be called in primary process. + * * @param heap_name * Name of the heap to create. * * @return * - 0 on success * - -1 in case of error, with rte_errno set to one of the following: - * EINVAL - ``heap_name`` was NULL, empty or too long - * ENOENT - heap by the name of ``heap_name`` was not found - * EPERM - attempting to destroy reserved heap - * EBUSY - heap still contains data + * EINVAL - ``heap_name`` was NULL, empty or too long + * ENOENT - heap by the name of ``heap_name`` was not found + * EPERM - attempting to destroy reserved heap + * EBUSY - heap still contains data + * E_RTE_SECONDARY - attempted to destroy a heap in secondary process */ int __rte_experimental rte_malloc_heap_destroy(const char *heap_name); diff --git a/lib/librte_eal/common/rte_malloc.c b/lib/librte_eal/common/rte_malloc.c index bfc49d0b7..01c112a46 100644 --- a/lib/librte_eal/common/rte_malloc.c +++ b/lib/librte_eal/common/rte_malloc.c @@ -418,6 +418,89 @@ rte_malloc_heap_memory_remove(const char *heap_name, void *va_addr, size_t len) return ret; } +struct sync_mem_walk_arg { + void *va_addr; + size_t len; + int result; +}; + +static int +attach_mem_walk(const struct rte_memseg_list *msl, void *arg) +{ + struct rte_mem_config *mcfg = rte_eal_get_configuration()->mem_config; + struct sync_mem_walk_arg *wa = arg; + size_t len = msl->page_sz * msl->memseg_arr.len; + + if (msl->base_va == wa->va_addr && + len == wa->len) { + struct rte_memseg_list *found_msl; + int msl_idx, ret; + + /* msl is const */ + msl_idx = msl - mcfg->memsegs; + found_msl = &mcfg->memsegs[msl_idx]; + + ret = rte_fbarray_attach(&found_msl->memseg_arr); + + if (ret < 0) + wa->result = -rte_errno; + else + wa->result = 0; + return 1; + } + return 0; +} + +int +rte_malloc_heap_memory_attach(const char *heap_name, void *va_addr, size_t len) +{ + struct rte_mem_config *mcfg = rte_eal_get_configuration()->mem_config; + struct malloc_heap *heap = NULL; + struct sync_mem_walk_arg wa; + int ret; + + if (heap_name == NULL || va_addr == NULL || len == 0 || + strnlen(heap_name, RTE_HEAP_NAME_MAX_LEN) == 0 || + strnlen(heap_name, RTE_HEAP_NAME_MAX_LEN) == + RTE_HEAP_NAME_MAX_LEN) { + rte_errno = EINVAL; + return -1; + } + rte_rwlock_read_lock(&mcfg->memory_hotplug_lock); + + /* find our heap */ + heap = find_named_heap(heap_name); + if (heap == NULL) { + rte_errno = ENOENT; + ret = -1; + goto unlock; + } + /* we shouldn't be able to attach to internal heaps */ + if (heap->socket_id < RTE_MAX_NUMA_NODES) { + rte_errno = EPERM; + ret = -1; + goto unlock; + } + + /* find corresponding memseg list to attach to */ + wa.va_addr = va_addr; + wa.len = len; + wa.result = -ENOENT; /* fail unless explicitly told to succeed */ + + /* we're already holding a read lock */ + rte_memseg_list_walk_thread_unsafe(attach_mem_walk, &wa); + + if (wa.result < 0) { + rte_errno = -wa.result; + ret = -1; + } else { + ret = 0; + } +unlock: + rte_rwlock_read_unlock(&mcfg->memory_hotplug_lock); + return ret; +} + int rte_malloc_heap_create(const char *heap_name) { @@ -425,6 +508,11 @@ rte_malloc_heap_create(const char *heap_name) struct malloc_heap *heap = NULL; int i, ret; + if (rte_eal_process_type() != RTE_PROC_PRIMARY) { + rte_errno = E_RTE_SECONDARY; + return -1; + } + if (heap_name == NULL || strnlen(heap_name, RTE_HEAP_NAME_MAX_LEN) == 0 || strnlen(heap_name, RTE_HEAP_NAME_MAX_LEN) == @@ -476,6 +564,11 @@ rte_malloc_heap_destroy(const char *heap_name) struct malloc_heap *heap = NULL; int ret; + if (rte_eal_process_type() != RTE_PROC_PRIMARY) { + rte_errno = E_RTE_SECONDARY; + return -1; + } + if (heap_name == NULL || strnlen(heap_name, RTE_HEAP_NAME_MAX_LEN) == 0 || strnlen(heap_name, RTE_HEAP_NAME_MAX_LEN) == diff --git a/lib/librte_eal/rte_eal_version.map b/lib/librte_eal/rte_eal_version.map index 8c66d0be9..920852042 100644 --- a/lib/librte_eal/rte_eal_version.map +++ b/lib/librte_eal/rte_eal_version.map @@ -322,6 +322,7 @@ EXPERIMENTAL { rte_malloc_heap_destroy; rte_malloc_heap_get_socket; rte_malloc_heap_memory_add; + rte_malloc_heap_memory_attach; rte_malloc_heap_memory_remove; rte_malloc_heap_socket_is_external; rte_mem_alloc_validator_register;