Commit e8b562dbc0 for openssl.org

commit e8b562dbc041d80bcc3157b4fcc4b32c5b957ea8
Author: Neil Horman <nhorman@openssl.org>
Date:   Wed Apr 29 16:46:42 2026 -0400

    clean out lru list and write lock

    We don't need either anymore

    Reviewed-by: Saša NedvÄ›dický <sashan@openssl.org>
    Reviewed-by: Bob Beck <beck@openssl.org>
    Reviewed-by: Nikola Pajkovsky <nikolap@openssl.org>
    MergeDate: Tue Jun  9 18:17:14 2026
    (Merged from https://github.com/openssl/openssl/pull/31018)

diff --git a/crypto/property/property.c b/crypto/property/property.c
index 34736da529..124c0d6cdf 100644
--- a/crypto/property/property.c
+++ b/crypto/property/property.c
@@ -75,10 +75,10 @@ typedef struct {
 DEFINE_STACK_OF(IMPLEMENTATION)

 typedef struct query_st {
-    OSSL_LIST_MEMBER(lru_entry, struct query_st); /* member of our linked list */
     struct query_st *next;
     void *saptr; /* pointer to our owning STORED_ALGORITHM */
     int nid; /* nid of this query */
+    int archived; /* Mark entry as no longer findable */
     OSSL_PROVIDER *prov; /*provider this belongs to */
     uint64_t specific_hash; /* hash of [nid,prop_query,prov] tuple */
     uint64_t generic_hash; /* hash of [nid,prop_query] tuple */
@@ -86,9 +86,6 @@ typedef struct query_st {
     METHOD method; /* METHOD for this query */
 } QUERY;

-DEFINE_LIST_OF(lru_entry, QUERY);
-
-typedef OSSL_LIST(lru_entry) QUERY_LRU_LIST;

 typedef struct {
     int nid;
@@ -100,14 +97,6 @@ typedef struct {

     QUERY *cache_lists[MAX_CACHE_LINES];

-    /*
-     * This is a list of every element in our query
-     * cache.  NOTE: Its named lru list, but to avoid
-     * having to remove/insert to the list a bunch, it
-     * actually just uses a heuristic with the QUERY used
-     * flag to identify recently used QUERY elements
-     */
-    QUERY_LRU_LIST lru_list;
     /*
      * Lock to protect each shard of |algs| from concurrent writing,
      * when individual implementations or queries are inserted.  This is used
@@ -121,10 +110,11 @@ typedef struct {
 } STORED_ALGORITHMS;

 static int ossl_method_store_atomic_insert_to_list(STORED_ALGORITHMS *sa, QUERY *new);
-static int ossl_method_store_atomic_remove_from_list(STORED_ALGORITHMS *sa, QUERY *old);
+static int ossl_method_store_atomic_archive(STORED_ALGORITHMS *sa, QUERY *old);
 static QUERY *ossl_method_store_atomic_find_in_list(STORED_ALGORITHMS *sa, int nid,
     OSSL_PROVIDER *prov, uint64_t prop_hash);
 static void ossl_cache_lists_flush(STORED_ALGORITHMS *sa);
+static void ossl_cache_lists_free(STORED_ALGORITHMS *sa);

 struct ossl_method_store_st {
     OSSL_LIB_CTX *ctx;
@@ -245,24 +235,10 @@ static ossl_inline void impl_cache_free_unlinked(QUERY *elem)
     }
 }

-static ossl_inline void impl_cache_free(QUERY *elem)
-{
-    if (elem != NULL) {
-        STORED_ALGORITHMS *sa = elem->saptr;
-
-#ifndef NDEBUG
-        if (elem->ossl_list_lru_entry.list != NULL)
-            ossl_list_lru_entry_remove(&sa->lru_list, elem);
-#else
-        ossl_list_lru_entry_remove(&sa->lru_list, elem);
-#endif
-        impl_cache_free_unlinked(elem);
-    }
-}
-
 static void impl_cache_flush_alg(ALGORITHM *alg, STORED_ALGORITHMS *sa)
 {
-    QUERY *q, *qn;
+    QUERY *q;
+    int i;

     /*
      * Instead of iterating over the hashtable with the
@@ -270,24 +246,17 @@ static void impl_cache_flush_alg(ALGORITHM *alg, STORED_ALGORITHMS *sa)
      * linked list, as it much faster this way, as we avoid having
      * to visit lots of potentially empty nodes
      */
-    OSSL_LIST_FOREACH_DELSAFE(q, qn, lru_entry, &sa->lru_list)
-    {
-        /*
-         * Check for a match by nid, as we're only deleting QUERY elements
-         * that are for the nid specified in alg
-         */
-        if (q->nid == alg->nid) {
-            /*
-             * We can accelerate hash table operations here, by creating a key
-             * with a cached hash value, to avoid having to compute it again
-             * NOTE: Each QUERY contains 2 possible hash values, that we use in
-             * a priority order.  Every QUERY has a generic_hash, which is the computed
-             * hash of the [nid, prop_query] tuple, and may have a specific_hash,
-             * which is the computed has of the [nid, prop_query, provider] tuple.
-             * We use the specific hash if its available, otherwise use the
-             * generic_hash
-             */
-            ossl_method_store_atomic_remove_from_list(sa, q);
+    for (i = 0; i < MAX_CACHE_LINES; i++) {
+restart_list:
+        if (!CRYPTO_atomic_load_ptr((void **)&sa->cache_lists[i], (void **)&q, sa->alock))
+            return;
+        while (q != NULL) {
+            if (q->nid == alg->nid) {
+                ossl_method_store_atomic_archive(sa, q);
+                goto restart_list;
+            }
+            if (!CRYPTO_atomic_load_ptr((void **)&q->next, (void **)&q, sa->alock))
+                return;
         }
     }
 }
@@ -312,7 +281,7 @@ static void stored_algs_free(STORED_ALGORITHMS *sa)
     for (int i = 0; i < NUM_SHARDS; ++i) {
         ossl_sa_ALGORITHM_doall_arg(sa[i].algs, &alg_cleanup, &sa[i]);
         ossl_sa_ALGORITHM_free(sa[i].algs);
-        ossl_cache_lists_flush(&sa[i]);
+        ossl_cache_lists_free(&sa[i]);
         CRYPTO_THREAD_lock_free(sa[i].lock);
         CRYPTO_THREAD_lock_free(sa[i].alock);
     }
@@ -905,15 +874,33 @@ static void ossl_method_cache_flush(STORED_ALGORITHMS *sa, int nid)
 static void ossl_cache_lists_flush(STORED_ALGORITHMS *sa)
 {
     int i;
-    QUERY *idx;
+    QUERY *idx, *idxn;

     for (i = 0; i < MAX_CACHE_LINES; i++) {
-        for (;;) {
-            if (!CRYPTO_atomic_load_ptr((void **)&sa->cache_lists[i], (void **)&idx, sa->alock))
+        if (!CRYPTO_atomic_load_ptr((void **)&sa->cache_lists[i], (void **)&idx, sa->alock))
+            break;
+        while (idx != NULL) {
+            if (!CRYPTO_atomic_load_ptr((void **)&idx->next, (void **)&idxn, sa->alock))
                 break;
-            if (idx == NULL)
+            ossl_method_store_atomic_archive(sa, idx);
+            idx = idxn;
+        }
+    }
+}
+
+static void ossl_cache_lists_free(STORED_ALGORITHMS *sa)
+{
+    int i;
+    QUERY *idx, *idxn;
+
+    for (i = 0; i < MAX_CACHE_LINES; i++) {
+        if (!CRYPTO_atomic_load_ptr((void **)&sa->cache_lists[i], (void **)&idx, sa->alock))
+            break;
+        while (idx != NULL) {
+            if (!CRYPTO_atomic_load_ptr((void **)&idx->next, (void **)&idxn, sa->alock))
                 break;
-            ossl_method_store_atomic_remove_from_list(sa, idx);
+            impl_cache_free_unlinked(idx);
+            idx = idxn;
         }
     }
 }
@@ -985,47 +972,18 @@ int ossl_method_store_cache_get(OSSL_METHOD_STORE *store, OSSL_PROVIDER *prov,
     return ret;
 }

-static int ossl_method_store_atomic_remove_from_list(STORED_ALGORITHMS *sa, QUERY *old)
+static int ossl_method_store_atomic_archive(STORED_ALGORITHMS *sa, QUERY *old)
 {
-    int nid = old->nid % MAX_CACHE_LINES;
-    int ret = 0;
-    QUERY *idx, *next, *oldnext;
-
-    if (!CRYPTO_atomic_load_ptr((void **)&sa->cache_lists[nid], (void **)&idx, sa->alock))
-        goto out;
-    if (idx == old) {
-        if (!CRYPTO_atomic_load_ptr((void **)&idx->next, (void **)&next, sa->alock))
-            goto out;
-        if (!CRYPTO_atomic_store_ptr((void **)&sa->cache_lists[nid], (void **)&next, sa->alock))
-            goto out;
-        impl_cache_free(old);
-        ret = 1;
-        goto out;
-    }
-    while (idx != NULL) {
-        if (!CRYPTO_atomic_load_ptr((void **)&idx->next, (void **)&next, sa->alock))
-            goto out;
-        if (next == old) {
-        try_again:
-            if (!CRYPTO_atomic_load_ptr((void **)&old->next, (void **)&oldnext, sa->alock))
-                goto out;
-            if (!CRYPTO_atomic_cmp_exch_ptr((void **)&idx->next, (void **)&next, oldnext, sa->alock))
-                goto try_again;
-            impl_cache_free(old);
-            ret = 1;
-            goto out;
-        }
-        if (!CRYPTO_atomic_load_ptr((void **)&idx->next, (void **)&idx, sa->alock))
-            goto out;
-    }
-out:
-    return ret;
+    if (!CRYPTO_atomic_store_int(&old->archived, 1, sa->alock))
+        return 0;
+    return 1;
 }

 static QUERY *ossl_method_store_atomic_find_in_list(STORED_ALGORITHMS *sa, int nid,
     OSSL_PROVIDER *prov, uint64_t prop_hash)
 {
     int nididx = nid % MAX_CACHE_LINES;
+    int archived;
     QUERY *idx;
     QUERY *ret = NULL;

@@ -1033,7 +991,9 @@ static QUERY *ossl_method_store_atomic_find_in_list(STORED_ALGORITHMS *sa, int n
         goto out;

     while (idx != NULL) {
-        if (idx->nid == nid && idx->prop_hash == prop_hash && idx->prov == prov) {
+        if (CRYPTO_atomic_load_int(&idx->archived, &archived, sa->alock))
+            goto out;
+        if (archived == 0 && idx->nid == nid && idx->prop_hash == prop_hash && idx->prov == prov) {
             ret = idx;
             break;
         }
@@ -1079,16 +1039,16 @@ static ossl_inline int ossl_method_store_cache_set_locked(OSSL_METHOD_STORE *sto
     if (method == NULL) {
         p = ossl_method_store_atomic_find_in_list(sa, nid, prov, prop_hash);
         if (p != NULL)
-            ossl_method_store_atomic_remove_from_list(sa, p);
+            ossl_method_store_atomic_archive(sa, p);
         goto end;
     }

     p = ossl_method_store_atomic_find_in_list(sa, nid, prov, prop_hash);
     if (p != NULL) {
-        ossl_method_store_atomic_remove_from_list(sa, p);
+        ossl_method_store_atomic_archive(sa, p);
         p = ossl_method_store_atomic_find_in_list(sa, nid, NULL, prop_hash);
         if (p != NULL)
-            ossl_method_store_atomic_remove_from_list(sa, p);
+            ossl_method_store_atomic_archive(sa, p);
     }
     p = OPENSSL_malloc(sizeof(*p));
     if (p != NULL) {
@@ -1096,15 +1056,14 @@ static ossl_inline int ossl_method_store_cache_set_locked(OSSL_METHOD_STORE *sto
         p->saptr = sa;
         p->nid = nid;
         p->prov = prov;
+        p->archived = 0;
         p->prop_hash = prop_hash;
-        ossl_list_lru_entry_init_elem(p);
         p->method.method = method;
         p->method.up_ref = method_up_ref;
         p->method.free = method_destruct;
         if (!ossl_method_up_ref(&p->method))
             goto err;

-        ossl_list_lru_entry_insert_head(&sa->lru_list, p);
         ossl_method_store_atomic_insert_to_list(sa, p);

         /*
@@ -1117,10 +1076,8 @@ static ossl_inline int ossl_method_store_cache_set_locked(OSSL_METHOD_STORE *sto
             goto err;
         TSAN_BENIGN(p, "Unpublished value is safe on subsequent read");
         p->prov = NULL;
-        ossl_list_lru_entry_init_elem(p);
         if (!ossl_method_up_ref(&p->method))
             goto err;
-        ossl_list_lru_entry_insert_tail(&sa->lru_list, p);
         ossl_method_store_atomic_insert_to_list(sa, p);

         goto end;
@@ -1152,9 +1109,10 @@ int ossl_method_store_cache_set(OSSL_METHOD_STORE *store, OSSL_PROVIDER *prov,
         return 0;

     sa = stored_algs_shard(store, nid);
+#if 0
     if (!ossl_property_write_lock(sa))
         return 0;
-
+#endif
     /*
      * As with cache_get_locked, we do this to allow ourselves the opportunity to make sure
      * keylen isn't so large that the stack allocation of keylen bytes will case a stack
@@ -1162,6 +1120,8 @@ int ossl_method_store_cache_set(OSSL_METHOD_STORE *store, OSSL_PROVIDER *prov,
      */
     res = ossl_method_store_cache_set_locked(store, prov, nid, prop_query, keylen, sa, method,
         method_up_ref, method_destruct);
+#if 0
     ossl_property_unlock(sa);
+#endif
     return res;
 }