diff options
author | Hugo Landau <hlandau@openssl.org> | 2022-03-10 09:38:09 +0000 |
---|---|---|
committer | Pauli <ppzgs1@gmail.com> | 2022-03-13 11:43:26 +1100 |
commit | c0b7dac66edde45b8da80918f5b5b62d1e766a0c (patch) | |
tree | 7f19cfd89b2ea3f1117b162bdfde6811f45c1b16 /crypto | |
parent | abdb2278d2b65ae87bee3121be83322e4219b396 (diff) |
EVP_MD performance fix (refcount cache contention)
Partial fix for #17064. Avoid excessive writes to the cache line
containing the refcount for an EVP_MD object to avoid extreme
cache contention when using a single EVP_MD at high frequency on
multiple threads. This changes performance in 3.0 from being double
that of 1.1 to only slightly higher than that of 1.1.
Reviewed-by: Tim Hudson <tjh@openssl.org>
Reviewed-by: Tomas Mraz <tomas@openssl.org>
Reviewed-by: Paul Dale <pauli@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/17857)
Diffstat (limited to 'crypto')
-rw-r--r-- | crypto/evp/digest.c | 32 | ||||
-rw-r--r-- | crypto/evp/m_sigver.c | 2 |
2 files changed, 22 insertions, 12 deletions
diff --git a/crypto/evp/digest.c b/crypto/evp/digest.c index db2eed6355..cd930ebd7a 100644 --- a/crypto/evp/digest.c +++ b/crypto/evp/digest.c @@ -40,7 +40,7 @@ static void cleanup_old_md_data(EVP_MD_CTX *ctx, int force) } } -void evp_md_ctx_clear_digest(EVP_MD_CTX *ctx, int force) +void evp_md_ctx_clear_digest(EVP_MD_CTX *ctx, int force, int keep_fetched) { if (ctx->algctx != NULL) { if (ctx->digest != NULL && ctx->digest->freectx != NULL) @@ -65,13 +65,14 @@ void evp_md_ctx_clear_digest(EVP_MD_CTX *ctx, int force) #endif /* Non legacy code, this has to be later than the ctx->digest cleaning */ - EVP_MD_free(ctx->fetched_digest); - ctx->fetched_digest = NULL; - ctx->reqdigest = NULL; + if (!keep_fetched) { + EVP_MD_free(ctx->fetched_digest); + ctx->fetched_digest = NULL; + ctx->reqdigest = NULL; + } } -/* This call frees resources associated with the context */ -int EVP_MD_CTX_reset(EVP_MD_CTX *ctx) +static int evp_md_ctx_reset_ex(EVP_MD_CTX *ctx, int keep_fetched) { if (ctx == NULL) return 1; @@ -87,12 +88,19 @@ int EVP_MD_CTX_reset(EVP_MD_CTX *ctx) } #endif - evp_md_ctx_clear_digest(ctx, 0); - OPENSSL_cleanse(ctx, sizeof(*ctx)); + evp_md_ctx_clear_digest(ctx, 0, keep_fetched); + if (!keep_fetched) + OPENSSL_cleanse(ctx, sizeof(*ctx)); return 1; } +/* This call frees resources associated with the context */ +int EVP_MD_CTX_reset(EVP_MD_CTX *ctx) +{ + return evp_md_ctx_reset_ex(ctx, 0); +} + #ifndef FIPS_MODULE EVP_MD_CTX *evp_md_ctx_new_ex(EVP_PKEY *pkey, const ASN1_OCTET_STRING *id, OSSL_LIB_CTX *libctx, const char *propq) @@ -524,6 +532,7 @@ int EVP_MD_CTX_copy(EVP_MD_CTX *out, const EVP_MD_CTX *in) int EVP_MD_CTX_copy_ex(EVP_MD_CTX *out, const EVP_MD_CTX *in) { + int digest_change = 0; unsigned char *tmp_buf; if (in == NULL) { @@ -549,15 +558,16 @@ int EVP_MD_CTX_copy_ex(EVP_MD_CTX *out, const EVP_MD_CTX *in) return 0; } - EVP_MD_CTX_reset(out); - if (out->fetched_digest != NULL) + evp_md_ctx_reset_ex(out, 1); + digest_change = (out->fetched_digest != in->fetched_digest); + if (digest_change && out->fetched_digest != NULL) EVP_MD_free(out->fetched_digest); *out = *in; /* NULL out pointers in case of error */ out->pctx = NULL; out->algctx = NULL; - if (in->fetched_digest != NULL) + if (digest_change && in->fetched_digest != NULL) EVP_MD_up_ref(in->fetched_digest); if (in->algctx != NULL) { diff --git a/crypto/evp/m_sigver.c b/crypto/evp/m_sigver.c index 0993de0937..371bca5001 100644 --- a/crypto/evp/m_sigver.c +++ b/crypto/evp/m_sigver.c @@ -231,7 +231,7 @@ static int do_sigver_init(EVP_MD_CTX *ctx, EVP_PKEY_CTX **pctx, * We're about to get a new digest so clear anything associated with * an old digest. */ - evp_md_ctx_clear_digest(ctx, 1); + evp_md_ctx_clear_digest(ctx, 1, 0); /* legacy code support for engines */ ERR_set_mark(); |