Skip to content

Commit edb956e

Browse files
notrojclaude
andcommitted
mod_auth_digest: Do less while holding client_lock:
* modules/aaa/mod_auth_digest.c (client_note_renewed): Removed. (client_generate): Take a renewed flag and count it under the lock already held; log the gc summary and any rmm_free failure after releasing the lock. (gc): Return the first rmm_free failure as the result, and the count through a new argument, instead of logging. (note_digest_auth_failure): Adjust. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
1 parent 3cdf60c commit edb956e

1 file changed

Lines changed: 66 additions & 53 deletions

File tree

‎modules/aaa/mod_auth_digest.c‎

Lines changed: 66 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -713,15 +713,6 @@ static int client_exists(client_id_t key, const request_rec *r)
713713
return found;
714714
}
715715

716-
/* Note that a client entry was created to replace one which had been
717-
* garbage collected. */
718-
static void client_note_renewed(void)
719-
{
720-
apr_global_mutex_lock(client_lock);
721-
client_list->num_renewed++;
722-
apr_global_mutex_unlock(client_lock);
723-
}
724-
725716
/* Identifies the authenticated user of r, within the protection space the
726717
* configuration defines - the origin server and realm, narrowed by any
727718
* AuthDigestDomain - for binding a client entry to. A keyed hash, so that
@@ -847,12 +838,17 @@ static enum nonce_state client_update_nonce(request_rec *r,
847838
}
848839

849840
/* A simple garbage-collecter to remove unused clients. It removes the
850-
* last entry in each bucket and updates the counters. Returns the
851-
* number of removed entries.
841+
* last entry in each bucket and updates the counters, returning the
842+
* number of removed entries in *num_removed. The result is the first
843+
* failure to free an entry, if any, for the caller to log once the lock
844+
* is released.
852845
*/
853-
static unsigned long gc(server_rec *s)
846+
static apr_status_t gc(unsigned long *num_removed)
854847
{
855-
unsigned long num_removed = 0, idx;
848+
apr_status_t rv = APR_SUCCESS;
849+
unsigned long idx;
850+
851+
*num_removed = 0;
856852

857853
/* garbage collect one entry from each bucket */
858854

@@ -882,73 +878,91 @@ static unsigned long gc(server_rec *s)
882878

883879
*victim = entry->next;
884880
err = rmm_free(client_rmm, entry);
885-
num_removed++;
881+
(*num_removed)++;
886882

887-
if (err) {
888-
/* Nothing we can really do but log... */
889-
ap_log_error(APLOG_MARK, APLOG_ERR, err, s, APLOGNO(10007)
890-
"Failed to free auth_digest client allocation");
883+
if (err && rv == APR_SUCCESS) {
884+
rv = err;
891885
}
892886
}
893887
}
894888

895-
/* update counters and log */
889+
/* update counters */
896890

897-
client_list->num_entries -= num_removed;
898-
client_list->num_removed += num_removed;
891+
client_list->num_entries -= *num_removed;
892+
client_list->num_removed += *num_removed;
899893

900-
return num_removed;
894+
return rv;
901895
}
902896

903897
/*
904-
* Add a new client to the list, under a newly issued id. Returns the id if
905-
* successful, zero otherwise. This triggers the garbage collection if
906-
* memory is low. (The new entry is not returned: see find_client().)
898+
* Add a new client to the list, under a newly issued id; renewed is set
899+
* when it replaces an entry which had been garbage collected. Returns the
900+
* id if successful, zero otherwise. This triggers the garbage collection
901+
* if memory is low. (The new entry is not returned: see find_client().)
907902
*/
908-
static client_id_t client_generate(request_rec *r)
903+
static client_id_t client_generate(request_rec *r, int renewed)
909904
{
910905
server_rec *s = r->server;
911906
int bucket;
912907
client_entry *entry;
913-
client_id_t key;
908+
client_id_t key = 0;
909+
int ran_gc = 0;
910+
unsigned long gc_removed = 0, created, removed, renewals;
911+
apr_status_t gc_rv = APR_SUCCESS;
914912

915913
apr_global_mutex_lock(client_lock);
916914

917915
/* try to allocate a new entry */
918916

919917
entry = rmm_malloc(client_rmm, sizeof(client_entry));
920918
if (!entry) {
921-
unsigned long num_removed = gc(s);
922-
ap_log_error(APLOG_MARK, APLOG_INFO, 0, s, APLOGNO(01766)
923-
"gc'd %lu client entries. Total new clients: "
924-
"%lu; Total removed clients: %lu; Total renewed clients: "
925-
"%lu", num_removed,
926-
client_list->num_created - client_list->num_renewed,
927-
client_list->num_removed, client_list->num_renewed);
919+
gc_rv = gc(&gc_removed);
920+
ran_gc = 1;
928921
entry = rmm_malloc(client_rmm, sizeof(client_entry));
929-
if (!entry) {
930-
apr_global_mutex_unlock(client_lock);
931-
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01769)
932-
"unable to allocate a client entry - failing the "
933-
"request, since this configuration needs one");
934-
return 0;
935-
}
936922
}
937923

938-
/* now issue the id, in 1..CLIENT_ID_MAX, and add the entry */
924+
if (entry) {
925+
/* now issue the id, in 1..CLIENT_ID_MAX, and add the entry */
939926

940-
key = client_list->next_id = client_list->next_id % CLIENT_ID_MAX + 1;
941-
bucket = key % client_list->tbl_len;
927+
key = client_list->next_id = client_list->next_id % CLIENT_ID_MAX + 1;
928+
bucket = key % client_list->tbl_len;
942929

943-
memset(entry, 0, sizeof(client_entry));
944-
entry->key = key;
945-
entry->next = client_list->table[bucket];
946-
client_list->table[bucket] = entry;
947-
client_list->num_created++;
948-
client_list->num_entries++;
930+
memset(entry, 0, sizeof(client_entry));
931+
entry->key = key;
932+
entry->next = client_list->table[bucket];
933+
client_list->table[bucket] = entry;
934+
client_list->num_created++;
935+
client_list->num_entries++;
936+
client_list->num_renewed += !!renewed;
937+
}
938+
939+
/* for logging after the lock is released */
940+
created = client_list->num_created;
941+
removed = client_list->num_removed;
942+
renewals = client_list->num_renewed;
949943

950944
apr_global_mutex_unlock(client_lock);
951945

946+
if (gc_rv) {
947+
/* Nothing we can really do but log... */
948+
ap_log_error(APLOG_MARK, APLOG_ERR, gc_rv, s, APLOGNO(10007)
949+
"Failed to free auth_digest client allocation");
950+
}
951+
if (ran_gc) {
952+
ap_log_error(APLOG_MARK, APLOG_INFO, 0, s, APLOGNO(01766)
953+
"gc'd %lu client entries. Total new clients: "
954+
"%lu; Total removed clients: %lu; Total renewed clients: "
955+
"%lu", gc_removed, created - renewals, removed,
956+
renewals);
957+
}
958+
959+
if (!key) {
960+
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01769)
961+
"unable to allocate a client entry - failing the "
962+
"request, since this configuration needs one");
963+
return 0;
964+
}
965+
952966
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(01768)
953967
"allocated new client %" APR_UINT64_T_FMT, key);
954968

@@ -1266,7 +1280,7 @@ static int note_digest_auth_failure(request_rec *r,
12661280
if (resp->opaque == NULL) {
12671281
/* new client */
12681282
if (conf->check_nc || conf->nonce_lifetime == 0) {
1269-
if ((client_key = client_generate(r)) == 0) {
1283+
if ((client_key = client_generate(r, 0)) == 0) {
12701284
return HTTP_SERVICE_UNAVAILABLE;
12711285
}
12721286
opaque = client_id_to_opaque(r->pool, client_key);
@@ -1281,11 +1295,10 @@ static int note_digest_auth_failure(request_rec *r,
12811295
* a new entry; whether the challenge is stale is the caller's
12821296
* call, since credentials which failed are no less wrong for the
12831297
* opaque being unknown. */
1284-
if ((client_key = client_generate(r)) == 0) {
1298+
if ((client_key = client_generate(r, 1)) == 0) {
12851299
return HTTP_SERVICE_UNAVAILABLE;
12861300
}
12871301
opaque = client_id_to_opaque(r->pool, client_key);
1288-
client_note_renewed();
12891302
}
12901303
else {
12911304
/* Note that the nonce-count tracked for this client is left alone

0 commit comments

Comments
 (0)