Blame SOURCES/libvirt-util-don-t-check-for-parallel-iteration-in-hash-related-functions.patch

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