From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from netronome.com (host-79-78-33-110.static.as9105.net [79.78.33.110]) by dpdk.org (Postfix) with ESMTP id 75D921B101 for ; Thu, 1 Nov 2018 20:53:31 +0100 (CET) Received: from netronome.com (localhost [127.0.0.1]) by netronome.com (8.15.2/8.15.2/Debian-10) with ESMTP id wA1JrVJ5019543 for ; Thu, 1 Nov 2018 19:53:31 GMT Received: (from root@localhost) by netronome.com (8.15.2/8.15.2/Submit) id wA1JrV9L019542 for dev@dpdk.org; Thu, 1 Nov 2018 19:53:31 GMT From: Alejandro Lucero To: dev@dpdk.org Date: Thu, 1 Nov 2018 19:53:30 +0000 Message-Id: <20181101195330.19464-8-alejandro.lucero@netronome.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20181101195330.19464-1-alejandro.lucero@netronome.com> References: <20181101195330.19464-1-alejandro.lucero@netronome.com> Subject: [dpdk-dev] [PATCH v2 7/7] mem: add thread unsafe version for checking DMA mask 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: , X-List-Received-Date: Thu, 01 Nov 2018 19:53:31 -0000 During memory initialization calling rte_mem_check_dma_mask leads to a deadlock because memory_hotplug_lock is locked by a writer, the current code in execution, and rte_memseg_walk tries to lock as a reader. This patch adds a thread_unsafe version which will call the final function specifying the memory_hotplug_lock does not need to be acquired. The patch also modified rte_mem_check_dma_mask as a intermediate step which will call the final function as before, implying memory_hotplug_lock will be acquired. PMDs should always use the version acquiring the lock with the thread_unsafe one being just for internal EAL memory code. Fixes: 223b7f1d5ef6 ("mem: add function for checking memseg IOVA") Signed-off-by: Alejandro Lucero --- lib/librte_eal/common/eal_common_memory.c | 24 +++++++++++++-- lib/librte_eal/common/include/rte_memory.h | 35 +++++++++++++++++++--- lib/librte_eal/common/malloc_heap.c | 2 +- lib/librte_eal/linuxapp/eal/eal_memory.c | 4 +-- lib/librte_eal/rte_eal_version.map | 1 + 5 files changed, 56 insertions(+), 10 deletions(-) diff --git a/lib/librte_eal/common/eal_common_memory.c b/lib/librte_eal/common/eal_common_memory.c index cc4f1d80f..87fd9921f 100644 --- a/lib/librte_eal/common/eal_common_memory.c +++ b/lib/librte_eal/common/eal_common_memory.c @@ -446,11 +446,12 @@ check_iova(const struct rte_memseg_list *msl __rte_unused, #endif /* check memseg iovas are within the required range based on dma mask */ -int __rte_experimental -rte_mem_check_dma_mask(uint8_t maskbits) +static int __rte_experimental +check_dma_mask(uint8_t maskbits, bool thread_unsafe) { struct rte_mem_config *mcfg = rte_eal_get_configuration()->mem_config; uint64_t mask; + int ret; /* sanity check */ if (maskbits > MAX_DMA_MASK_BITS) { @@ -462,7 +463,12 @@ rte_mem_check_dma_mask(uint8_t maskbits) /* create dma mask */ mask = ~((1ULL << maskbits) - 1); - if (rte_memseg_walk(check_iova, &mask)) + if (thread_unsafe) + ret = rte_memseg_walk_thread_unsafe(check_iova, &mask); + else + ret = rte_memseg_walk(check_iova, &mask); + + if (ret) /* * Dma mask precludes hugepage usage. * This device can not be used and we do not need to keep @@ -480,6 +486,18 @@ rte_mem_check_dma_mask(uint8_t maskbits) return 0; } +int __rte_experimental +rte_mem_check_dma_mask(uint8_t maskbits) +{ + return check_dma_mask(maskbits, false); +} + +int __rte_experimental +rte_mem_check_dma_mask_thread_unsafe(uint8_t maskbits) +{ + return check_dma_mask(maskbits, true); +} + /* * Set dma mask to use when memory initialization is done. * diff --git a/lib/librte_eal/common/include/rte_memory.h b/lib/librte_eal/common/include/rte_memory.h index abbfe2364..d970825df 100644 --- a/lib/librte_eal/common/include/rte_memory.h +++ b/lib/librte_eal/common/include/rte_memory.h @@ -463,16 +463,43 @@ unsigned rte_memory_get_nchannel(void); */ unsigned rte_memory_get_nrank(void); -/* check memsegs iovas are within a range based on dma mask */ +/** + * @warning + * @b EXPERIMENTAL: this API may change without prior notice + * + * Check if all currently allocated memory segments are compliant with + * supplied DMA address width. + * + * @param maskbits + * Address width to check against. + */ int __rte_experimental rte_mem_check_dma_mask(uint8_t maskbits); /** * @warning * @b EXPERIMENTAL: this API may change without prior notice * - * Set dma mask to use once memory initialization is done. - * Previous function rte_mem_check_dma_mask can not be used - * safely until memory has been initialized. + * Check if all currently allocated memory segments are compliant with + * supplied DMA address width. This function will use + * rte_memseg_walk_thread_unsafe instead of rte_memseg_walk implying + * memory_hotplug_lock will not be acquired avoiding deadlock during + * memory initialization. + * + * This function is just for EAL core memory internal use. Drivers should + * use the previous rte_mem_check_dma_mask. + * + * @param maskbits + * Address width to check against. + */ +int __rte_experimental rte_mem_check_dma_mask_thread_unsafe(uint8_t maskbits); + +/** + * @warning + * @b EXPERIMENTAL: this API may change without prior notice + * + * Set dma mask to use once memory initialization is done. Previous functions + * rte_mem_check_dma_mask and rte_mem_check_dma_mask_thread_unsafe can not be + * used safely until memory has been initialized. */ void __rte_experimental rte_mem_set_dma_mask(uint8_t maskbits); diff --git a/lib/librte_eal/common/malloc_heap.c b/lib/librte_eal/common/malloc_heap.c index c2c112aa6..c6a6d4f6b 100644 --- a/lib/librte_eal/common/malloc_heap.c +++ b/lib/librte_eal/common/malloc_heap.c @@ -334,7 +334,7 @@ alloc_pages_on_heap(struct malloc_heap *heap, uint64_t pg_sz, size_t elt_size, * executed. For 2) implies the new memory can not be added. */ if (mcfg->dma_maskbits && - rte_mem_check_dma_mask(mcfg->dma_maskbits)) { + rte_mem_check_dma_mask_thread_unsafe(mcfg->dma_maskbits)) { /* * Currently this can only happen if IOMMU is enabled * and the address width supported by the IOMMU hw is diff --git a/lib/librte_eal/linuxapp/eal/eal_memory.c b/lib/librte_eal/linuxapp/eal/eal_memory.c index c7935879a..c1b5e0791 100644 --- a/lib/librte_eal/linuxapp/eal/eal_memory.c +++ b/lib/librte_eal/linuxapp/eal/eal_memory.c @@ -1394,7 +1394,7 @@ eal_legacy_hugepage_init(void) addr = RTE_PTR_ADD(addr, (size_t)page_sz); } if (mcfg->dma_maskbits && - rte_mem_check_dma_mask(mcfg->dma_maskbits)) { + rte_mem_check_dma_mask_thread_unsafe(mcfg->dma_maskbits)) { RTE_LOG(ERR, EAL, "%s(): couldnt allocate memory due to IOVA exceeding limits of current DMA mask.\n", __func__); @@ -1641,7 +1641,7 @@ eal_legacy_hugepage_init(void) } if (mcfg->dma_maskbits && - rte_mem_check_dma_mask(mcfg->dma_maskbits)) { + rte_mem_check_dma_mask_thread_unsafe(mcfg->dma_maskbits)) { RTE_LOG(ERR, EAL, "%s(): couldn't allocate memory due to IOVA exceeding limits of current DMA mask.\n", __func__); diff --git a/lib/librte_eal/rte_eal_version.map b/lib/librte_eal/rte_eal_version.map index 51ee948ba..61bc5ca05 100644 --- a/lib/librte_eal/rte_eal_version.map +++ b/lib/librte_eal/rte_eal_version.map @@ -331,6 +331,7 @@ EXPERIMENTAL { rte_mem_alloc_validator_register; rte_mem_alloc_validator_unregister; rte_mem_check_dma_mask; + rte_mem_check_dma_mask_thread_unsafe; rte_mem_event_callback_register; rte_mem_event_callback_unregister; rte_mem_iova2virt; -- 2.17.1