|
|
4e77bf |
From fa01d1d69ceeb4da685e6f39d11e9f5d05201589 Mon Sep 17 00:00:00 2001
|
|
|
4e77bf |
Message-Id: <fa01d1d69ceeb4da685e6f39d11e9f5d05201589@dist-git>
|
|
|
4e77bf |
From: Vincent Bernat <vincent@bernat.im>
|
|
|
4e77bf |
Date: Wed, 23 May 2018 12:45:29 +0200
|
|
|
4e77bf |
Subject: [PATCH] util: don't check for parallel iteration in hash-related
|
|
|
4e77bf |
functions
|
|
|
4e77bf |
|
|
|
4e77bf |
RHEL-7.6: https://bugzilla.redhat.com/show_bug.cgi?id=1576464
|
|
|
4e77bf |
RHEL-7.5.z: https://bugzilla.redhat.com/show_bug.cgi?id=1581364
|
|
|
4e77bf |
|
|
|
4e77bf |
This is the responsability of the caller to apply the correct lock
|
|
|
4e77bf |
before using these functions. Moreover, the use of a simple boolean
|
|
|
4e77bf |
was still racy: two threads may check the boolean and "lock" it
|
|
|
4e77bf |
simultaneously.
|
|
|
4e77bf |
|
|
|
4e77bf |
Users of functions from src/util/virhash.c have to be checked for
|
|
|
4e77bf |
correctness. Lookups and iteration should hold a RO
|
|
|
4e77bf |
lock. Modifications should hold a RW lock.
|
|
|
4e77bf |
|
|
|
4e77bf |
Most important uses seem to be covered. Callers have now a greater
|
|
|
4e77bf |
responsability, notably the ability to execute some operations while
|
|
|
4e77bf |
iterating were reliably forbidden before are now accepted.
|
|
|
4e77bf |
|
|
|
4e77bf |
Signed-off-by: Vincent Bernat <vincent@bernat.im>
|
|
|
4e77bf |
(cherry picked from commit 4d7384eb9ddef2008cb0cc165eb808f74bc83d6b)
|
|
|
4e77bf |
Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
|
|
|
4e77bf |
|
|
|
4e77bf |
Conflicts: src/util/virhash.c: Since
|
|
|
4e77bf |
3e7db8d3e8538bcd5deb1b111fb1233fc18831aa isn't backported,
|
|
|
4e77bf |
macro that is being removed has misaligned line breaks. It
|
|
|
4e77bf |
needs to be removed regardless.
|
|
|
4e77bf |
Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
|
|
|
4e77bf |
Reviewed-by: Jiri Denemark <jdenemar@redhat.com>
|
|
|
4e77bf |
---
|
|
|
4e77bf |
src/util/virhash.c | 37 --------------------
|
|
|
4e77bf |
tests/virhashtest.c | 83 ---------------------------------------------
|
|
|
4e77bf |
2 files changed, 120 deletions(-)
|
|
|
4e77bf |
|
|
|
4e77bf |
diff --git a/src/util/virhash.c b/src/util/virhash.c
|
|
|
4e77bf |
index 7fa2992f18..475c2b0281 100644
|
|
|
4e77bf |
--- a/src/util/virhash.c
|
|
|
4e77bf |
+++ b/src/util/virhash.c
|
|
|
4e77bf |
@@ -41,12 +41,6 @@ VIR_LOG_INIT("util.hash");
|
|
|
4e77bf |
|
|
|
4e77bf |
/* #define DEBUG_GROW */
|
|
|
4e77bf |
|
|
|
4e77bf |
-#define virHashIterationError(ret) \
|
|
|
4e77bf |
- do { \
|
|
|
4e77bf |
- VIR_ERROR(_("Hash operation not allowed during iteration")); \
|
|
|
4e77bf |
- return ret; \
|
|
|
4e77bf |
- } while (0)
|
|
|
4e77bf |
-
|
|
|
4e77bf |
/*
|
|
|
4e77bf |
* A single entry in the hash table
|
|
|
4e77bf |
*/
|
|
|
4e77bf |
@@ -66,10 +60,6 @@ struct _virHashTable {
|
|
|
4e77bf |
uint32_t seed;
|
|
|
4e77bf |
size_t size;
|
|
|
4e77bf |
size_t nbElems;
|
|
|
4e77bf |
- /* True iff we are iterating over hash entries. */
|
|
|
4e77bf |
- bool iterating;
|
|
|
4e77bf |
- /* Pointer to the current entry during iteration. */
|
|
|
4e77bf |
- virHashEntryPtr current;
|
|
|
4e77bf |
virHashDataFree dataFree;
|
|
|
4e77bf |
virHashKeyCode keyCode;
|
|
|
4e77bf |
virHashKeyEqual keyEqual;
|
|
|
4e77bf |
@@ -339,9 +329,6 @@ virHashAddOrUpdateEntry(virHashTablePtr table, const void *name,
|
|
|
4e77bf |
if ((table == NULL) || (name == NULL))
|
|
|
4e77bf |
return -1;
|
|
|
4e77bf |
|
|
|
4e77bf |
- if (table->iterating)
|
|
|
4e77bf |
- virHashIterationError(-1);
|
|
|
4e77bf |
-
|
|
|
4e77bf |
key = virHashComputeKey(table, name);
|
|
|
4e77bf |
|
|
|
4e77bf |
/* Check for duplicate entry */
|
|
|
4e77bf |
@@ -551,9 +538,6 @@ virHashRemoveEntry(virHashTablePtr table, const void *name)
|
|
|
4e77bf |
nextptr = table->table + virHashComputeKey(table, name);
|
|
|
4e77bf |
for (entry = *nextptr; entry; entry = entry->next) {
|
|
|
4e77bf |
if (table->keyEqual(entry->name, name)) {
|
|
|
4e77bf |
- if (table->iterating && table->current != entry)
|
|
|
4e77bf |
- virHashIterationError(-1);
|
|
|
4e77bf |
-
|
|
|
4e77bf |
if (table->dataFree)
|
|
|
4e77bf |
table->dataFree(entry->payload, entry->name);
|
|
|
4e77bf |
if (table->keyFree)
|
|
|
4e77bf |
@@ -593,18 +577,11 @@ virHashForEach(virHashTablePtr table, virHashIterator iter, void *data)
|
|
|
4e77bf |
if (table == NULL || iter == NULL)
|
|
|
4e77bf |
return -1;
|
|
|
4e77bf |
|
|
|
4e77bf |
- if (table->iterating)
|
|
|
4e77bf |
- virHashIterationError(-1);
|
|
|
4e77bf |
-
|
|
|
4e77bf |
- table->iterating = true;
|
|
|
4e77bf |
- table->current = NULL;
|
|
|
4e77bf |
for (i = 0; i < table->size; i++) {
|
|
|
4e77bf |
virHashEntryPtr entry = table->table[i];
|
|
|
4e77bf |
while (entry) {
|
|
|
4e77bf |
virHashEntryPtr next = entry->next;
|
|
|
4e77bf |
- table->current = entry;
|
|
|
4e77bf |
ret = iter(entry->payload, entry->name, data);
|
|
|
4e77bf |
- table->current = NULL;
|
|
|
4e77bf |
|
|
|
4e77bf |
if (ret < 0)
|
|
|
4e77bf |
goto cleanup;
|
|
|
4e77bf |
@@ -615,7 +592,6 @@ virHashForEach(virHashTablePtr table, virHashIterator iter, void *data)
|
|
|
4e77bf |
|
|
|
4e77bf |
ret = 0;
|
|
|
4e77bf |
cleanup:
|
|
|
4e77bf |
- table->iterating = false;
|
|
|
4e77bf |
return ret;
|
|
|
4e77bf |
}
|
|
|
4e77bf |
|
|
|
4e77bf |
@@ -643,11 +619,6 @@ virHashRemoveSet(virHashTablePtr table,
|
|
|
4e77bf |
if (table == NULL || iter == NULL)
|
|
|
4e77bf |
return -1;
|
|
|
4e77bf |
|
|
|
4e77bf |
- if (table->iterating)
|
|
|
4e77bf |
- virHashIterationError(-1);
|
|
|
4e77bf |
-
|
|
|
4e77bf |
- table->iterating = true;
|
|
|
4e77bf |
- table->current = NULL;
|
|
|
4e77bf |
for (i = 0; i < table->size; i++) {
|
|
|
4e77bf |
virHashEntryPtr *nextptr = table->table + i;
|
|
|
4e77bf |
|
|
|
4e77bf |
@@ -667,7 +638,6 @@ virHashRemoveSet(virHashTablePtr table,
|
|
|
4e77bf |
}
|
|
|
4e77bf |
}
|
|
|
4e77bf |
}
|
|
|
4e77bf |
- table->iterating = false;
|
|
|
4e77bf |
|
|
|
4e77bf |
return count;
|
|
|
4e77bf |
}
|
|
|
4e77bf |
@@ -723,23 +693,16 @@ void *virHashSearch(const virHashTable *ctable,
|
|
|
4e77bf |
if (table == NULL || iter == NULL)
|
|
|
4e77bf |
return NULL;
|
|
|
4e77bf |
|
|
|
4e77bf |
- if (table->iterating)
|
|
|
4e77bf |
- virHashIterationError(NULL);
|
|
|
4e77bf |
-
|
|
|
4e77bf |
- table->iterating = true;
|
|
|
4e77bf |
- table->current = NULL;
|
|
|
4e77bf |
for (i = 0; i < table->size; i++) {
|
|
|
4e77bf |
virHashEntryPtr entry;
|
|
|
4e77bf |
for (entry = table->table[i]; entry; entry = entry->next) {
|
|
|
4e77bf |
if (iter(entry->payload, entry->name, data)) {
|
|
|
4e77bf |
- table->iterating = false;
|
|
|
4e77bf |
if (name)
|
|
|
4e77bf |
*name = table->keyCopy(entry->name);
|
|
|
4e77bf |
return entry->payload;
|
|
|
4e77bf |
}
|
|
|
4e77bf |
}
|
|
|
4e77bf |
}
|
|
|
4e77bf |
- table->iterating = false;
|
|
|
4e77bf |
|
|
|
4e77bf |
return NULL;
|
|
|
4e77bf |
}
|
|
|
4e77bf |
diff --git a/tests/virhashtest.c b/tests/virhashtest.c
|
|
|
4e77bf |
index 9407f98c4b..77d724c4c6 100644
|
|
|
4e77bf |
--- a/tests/virhashtest.c
|
|
|
4e77bf |
+++ b/tests/virhashtest.c
|
|
|
4e77bf |
@@ -221,32 +221,6 @@ testHashRemoveForEachAll(void *payload ATTRIBUTE_UNUSED,
|
|
|
4e77bf |
}
|
|
|
4e77bf |
|
|
|
4e77bf |
|
|
|
4e77bf |
-const int testHashCountRemoveForEachForbidden = ARRAY_CARDINALITY(uuids);
|
|
|
4e77bf |
-
|
|
|
4e77bf |
-static int
|
|
|
4e77bf |
-testHashRemoveForEachForbidden(void *payload ATTRIBUTE_UNUSED,
|
|
|
4e77bf |
- const void *name,
|
|
|
4e77bf |
- void *data)
|
|
|
4e77bf |
-{
|
|
|
4e77bf |
- virHashTablePtr hash = data;
|
|
|
4e77bf |
- size_t i;
|
|
|
4e77bf |
-
|
|
|
4e77bf |
- for (i = 0; i < ARRAY_CARDINALITY(uuids_subset); i++) {
|
|
|
4e77bf |
- if (STREQ(uuids_subset[i], name)) {
|
|
|
4e77bf |
- int next = (i + 1) % ARRAY_CARDINALITY(uuids_subset);
|
|
|
4e77bf |
-
|
|
|
4e77bf |
- if (virHashRemoveEntry(hash, uuids_subset[next]) == 0) {
|
|
|
4e77bf |
- VIR_TEST_VERBOSE(
|
|
|
4e77bf |
- "\nentry \"%s\" should not be allowed to be removed",
|
|
|
4e77bf |
- uuids_subset[next]);
|
|
|
4e77bf |
- }
|
|
|
4e77bf |
- break;
|
|
|
4e77bf |
- }
|
|
|
4e77bf |
- }
|
|
|
4e77bf |
- return 0;
|
|
|
4e77bf |
-}
|
|
|
4e77bf |
-
|
|
|
4e77bf |
-
|
|
|
4e77bf |
static int
|
|
|
4e77bf |
testHashRemoveForEach(const void *data)
|
|
|
4e77bf |
{
|
|
|
4e77bf |
@@ -303,61 +277,6 @@ testHashSteal(const void *data ATTRIBUTE_UNUSED)
|
|
|
4e77bf |
}
|
|
|
4e77bf |
|
|
|
4e77bf |
|
|
|
4e77bf |
-static int
|
|
|
4e77bf |
-testHashIter(void *payload ATTRIBUTE_UNUSED,
|
|
|
4e77bf |
- const void *name ATTRIBUTE_UNUSED,
|
|
|
4e77bf |
- void *data ATTRIBUTE_UNUSED)
|
|
|
4e77bf |
-{
|
|
|
4e77bf |
- return 0;
|
|
|
4e77bf |
-}
|
|
|
4e77bf |
-
|
|
|
4e77bf |
-static int
|
|
|
4e77bf |
-testHashForEachIter(void *payload ATTRIBUTE_UNUSED,
|
|
|
4e77bf |
- const void *name ATTRIBUTE_UNUSED,
|
|
|
4e77bf |
- void *data)
|
|
|
4e77bf |
-{
|
|
|
4e77bf |
- virHashTablePtr hash = data;
|
|
|
4e77bf |
-
|
|
|
4e77bf |
- if (virHashAddEntry(hash, uuids_new[0], NULL) == 0)
|
|
|
4e77bf |
- VIR_TEST_VERBOSE("\nadding entries in ForEach should be forbidden");
|
|
|
4e77bf |
-
|
|
|
4e77bf |
- if (virHashUpdateEntry(hash, uuids_new[0], NULL) == 0)
|
|
|
4e77bf |
- VIR_TEST_VERBOSE("\nupdating entries in ForEach should be forbidden");
|
|
|
4e77bf |
-
|
|
|
4e77bf |
- if (virHashSteal(hash, uuids_new[0]) != NULL)
|
|
|
4e77bf |
- VIR_TEST_VERBOSE("\nstealing entries in ForEach should be forbidden");
|
|
|
4e77bf |
-
|
|
|
4e77bf |
- if (virHashSteal(hash, uuids_new[0]) != NULL)
|
|
|
4e77bf |
- VIR_TEST_VERBOSE("\nstealing entries in ForEach should be forbidden");
|
|
|
4e77bf |
-
|
|
|
4e77bf |
- if (virHashForEach(hash, testHashIter, NULL) >= 0)
|
|
|
4e77bf |
- VIR_TEST_VERBOSE("\niterating through hash in ForEach"
|
|
|
4e77bf |
- " should be forbidden");
|
|
|
4e77bf |
- return 0;
|
|
|
4e77bf |
-}
|
|
|
4e77bf |
-
|
|
|
4e77bf |
-static int
|
|
|
4e77bf |
-testHashForEach(const void *data ATTRIBUTE_UNUSED)
|
|
|
4e77bf |
-{
|
|
|
4e77bf |
- virHashTablePtr hash;
|
|
|
4e77bf |
- int ret = -1;
|
|
|
4e77bf |
-
|
|
|
4e77bf |
- if (!(hash = testHashInit(0)))
|
|
|
4e77bf |
- return -1;
|
|
|
4e77bf |
-
|
|
|
4e77bf |
- if (virHashForEach(hash, testHashForEachIter, hash)) {
|
|
|
4e77bf |
- VIR_TEST_VERBOSE("\nvirHashForEach didn't go through all entries");
|
|
|
4e77bf |
- goto cleanup;
|
|
|
4e77bf |
- }
|
|
|
4e77bf |
-
|
|
|
4e77bf |
- ret = 0;
|
|
|
4e77bf |
-
|
|
|
4e77bf |
- cleanup:
|
|
|
4e77bf |
- virHashFree(hash);
|
|
|
4e77bf |
- return ret;
|
|
|
4e77bf |
-}
|
|
|
4e77bf |
-
|
|
|
4e77bf |
-
|
|
|
4e77bf |
static int
|
|
|
4e77bf |
testHashRemoveSetIter(const void *payload ATTRIBUTE_UNUSED,
|
|
|
4e77bf |
const void *name,
|
|
|
4e77bf |
@@ -628,9 +547,7 @@ mymain(void)
|
|
|
4e77bf |
DO_TEST("Remove", Remove);
|
|
|
4e77bf |
DO_TEST_DATA("Remove in ForEach", RemoveForEach, Some);
|
|
|
4e77bf |
DO_TEST_DATA("Remove in ForEach", RemoveForEach, All);
|
|
|
4e77bf |
- DO_TEST_DATA("Remove in ForEach", RemoveForEach, Forbidden);
|
|
|
4e77bf |
DO_TEST("Steal", Steal);
|
|
|
4e77bf |
- DO_TEST("Forbidden ops in ForEach", ForEach);
|
|
|
4e77bf |
DO_TEST("RemoveSet", RemoveSet);
|
|
|
4e77bf |
DO_TEST("Search", Search);
|
|
|
4e77bf |
DO_TEST("GetItems", GetItems);
|
|
|
4e77bf |
--
|
|
|
4e77bf |
2.17.1
|
|
|
4e77bf |
|