161 lines
4.9 KiB
Diff
161 lines
4.9 KiB
Diff
Description: backport of dpdk 16.04-rc fix for LP: #1568838
|
|
|
|
Forwarded: n/a (already upstream)
|
|
Author: Christian Ehrhardt <christian.ehrhardt@canonical.com>
|
|
Last-Update: 2016-04-11
|
|
|
|
From 5d7bfb7337e917c8d97b43a75264789b01b6cfce Mon Sep 17 00:00:00 2001
|
|
From: Olivier Matz <olivier.matz@6wind.com>
|
|
Date: Wed, 6 Apr 2016 15:28:00 +0200
|
|
Subject: [PATCH] hash: fix race condition at creation
|
|
|
|
To avoid a race condition while creating a new hash object, the
|
|
list has to be locked before the lookup, and released only once the
|
|
new object is added in the list.
|
|
|
|
As the lock is held by the rte_ring_create(), move its creation at the
|
|
beginning of the function and only take the lock after the ring is
|
|
created to avoid a deadlock.
|
|
|
|
Fixes: 48a3991196 ("hash: replace with cuckoo hash implementation")
|
|
|
|
Signed-off-by: Olivier Matz <olivier.matz@6wind.com>
|
|
Acked-by: Pablo de Lara <pablo.de.lara.guarch@intel.com>
|
|
---
|
|
lib/librte_hash/rte_cuckoo_hash.c | 70 ++++++++++++++++++++++-----------------
|
|
1 file changed, 40 insertions(+), 30 deletions(-)
|
|
|
|
Index: dpdk/lib/librte_hash/rte_cuckoo_hash.c
|
|
===================================================================
|
|
--- dpdk.orig/lib/librte_hash/rte_cuckoo_hash.c
|
|
+++ dpdk/lib/librte_hash/rte_cuckoo_hash.c
|
|
@@ -296,19 +296,48 @@ rte_hash_create(const struct rte_hash_pa
|
|
if (params->extra_flag & RTE_HASH_EXTRA_FLAGS_TRANS_MEM_SUPPORT)
|
|
hw_trans_mem_support = 1;
|
|
|
|
+ /* Store all keys and leave the first entry as a dummy entry for lookup_bulk */
|
|
+ if (hw_trans_mem_support)
|
|
+ /*
|
|
+ * Increase number of slots by total number of indices
|
|
+ * that can be stored in the lcore caches
|
|
+ * except for the first cache
|
|
+ */
|
|
+ num_key_slots = params->entries + (RTE_MAX_LCORE - 1) *
|
|
+ LCORE_CACHE_SIZE + 1;
|
|
+ else
|
|
+ num_key_slots = params->entries + 1;
|
|
+
|
|
+ snprintf(ring_name, sizeof(ring_name), "HT_%s", params->name);
|
|
+ r = rte_ring_create(ring_name, rte_align32pow2(num_key_slots),
|
|
+ params->socket_id, 0);
|
|
+ if (r == NULL) {
|
|
+ RTE_LOG(ERR, HASH, "memory allocation failed\n");
|
|
+ goto err;
|
|
+ }
|
|
+
|
|
snprintf(hash_name, sizeof(hash_name), "HT_%s", params->name);
|
|
|
|
- /* Guarantee there's no existing */
|
|
- h = rte_hash_find_existing(params->name);
|
|
- if (h != NULL) {
|
|
+ rte_rwlock_write_lock(RTE_EAL_TAILQ_RWLOCK);
|
|
+
|
|
+ /* guarantee there's no existing: this is normally already checked
|
|
+ * by ring creation above */
|
|
+ TAILQ_FOREACH(te, hash_list, next) {
|
|
+ h = (struct rte_hash *) te->data;
|
|
+ if (strncmp(params->name, h->name, RTE_HASH_NAMESIZE) == 0)
|
|
+ break;
|
|
+ }
|
|
+ h = NULL;
|
|
+ if (te != NULL) {
|
|
rte_errno = EEXIST;
|
|
- return NULL;
|
|
+ te = NULL;
|
|
+ goto err_unlock;
|
|
}
|
|
|
|
te = rte_zmalloc("HASH_TAILQ_ENTRY", sizeof(*te), 0);
|
|
if (te == NULL) {
|
|
RTE_LOG(ERR, HASH, "tailq entry allocation failed\n");
|
|
- goto err;
|
|
+ goto err_unlock;
|
|
}
|
|
|
|
h = (struct rte_hash *)rte_zmalloc_socket(hash_name, sizeof(struct rte_hash),
|
|
@@ -316,7 +345,7 @@ rte_hash_create(const struct rte_hash_pa
|
|
|
|
if (h == NULL) {
|
|
RTE_LOG(ERR, HASH, "memory allocation failed\n");
|
|
- goto err;
|
|
+ goto err_unlock;
|
|
}
|
|
|
|
const uint32_t num_buckets = rte_align32pow2(params->entries)
|
|
@@ -328,23 +357,10 @@ rte_hash_create(const struct rte_hash_pa
|
|
|
|
if (buckets == NULL) {
|
|
RTE_LOG(ERR, HASH, "memory allocation failed\n");
|
|
- goto err;
|
|
+ goto err_unlock;
|
|
}
|
|
|
|
const uint32_t key_entry_size = sizeof(struct rte_hash_key) + params->key_len;
|
|
-
|
|
- /* Store all keys and leave the first entry as a dummy entry for lookup_bulk */
|
|
- if (hw_trans_mem_support)
|
|
- /*
|
|
- * Increase number of slots by total number of indices
|
|
- * that can be stored in the lcore caches
|
|
- * except for the first cache
|
|
- */
|
|
- num_key_slots = params->entries + (RTE_MAX_LCORE - 1) *
|
|
- LCORE_CACHE_SIZE + 1;
|
|
- else
|
|
- num_key_slots = params->entries + 1;
|
|
-
|
|
const uint64_t key_tbl_size = (uint64_t) key_entry_size * num_key_slots;
|
|
|
|
k = rte_zmalloc_socket(NULL, key_tbl_size,
|
|
@@ -352,7 +368,7 @@ rte_hash_create(const struct rte_hash_pa
|
|
|
|
if (k == NULL) {
|
|
RTE_LOG(ERR, HASH, "memory allocation failed\n");
|
|
- goto err;
|
|
+ goto err_unlock;
|
|
}
|
|
|
|
/*
|
|
@@ -395,14 +411,6 @@ rte_hash_create(const struct rte_hash_pa
|
|
h->cmp_jump_table_idx = KEY_OTHER_BYTES;
|
|
#endif
|
|
|
|
- snprintf(ring_name, sizeof(ring_name), "HT_%s", params->name);
|
|
- r = rte_ring_create(ring_name, rte_align32pow2(num_key_slots),
|
|
- params->socket_id, 0);
|
|
- if (r == NULL) {
|
|
- RTE_LOG(ERR, HASH, "memory allocation failed\n");
|
|
- goto err;
|
|
- }
|
|
-
|
|
if (hw_trans_mem_support) {
|
|
h->local_free_slots = rte_zmalloc_socket(NULL,
|
|
sizeof(struct lcore_cache) * RTE_MAX_LCORE,
|
|
@@ -429,13 +437,15 @@ rte_hash_create(const struct rte_hash_pa
|
|
for (i = 1; i < params->entries + 1; i++)
|
|
rte_ring_sp_enqueue(r, (void *)((uintptr_t) i));
|
|
|
|
- rte_rwlock_write_lock(RTE_EAL_TAILQ_RWLOCK);
|
|
te->data = (void *) h;
|
|
TAILQ_INSERT_TAIL(hash_list, te, next);
|
|
rte_rwlock_write_unlock(RTE_EAL_TAILQ_RWLOCK);
|
|
|
|
return h;
|
|
+err_unlock:
|
|
+ rte_rwlock_write_unlock(RTE_EAL_TAILQ_RWLOCK);
|
|
err:
|
|
+ rte_ring_free(r);
|
|
rte_free(te);
|
|
rte_free(h);
|
|
rte_free(buckets);
|