BUG/MEDIUM: stick-tables: Don't let table_process_entry() handle refcnt

Instead of having table_process_entry() decrement the session's ref
counter, do it outside, from the caller. Some were missed, such as when
an action was invalid, which would lead to the ref counter not being
decremented, and the session not being destroyable.
It makes more sense to do that from the caller, who just obtained the
ref counter, anyway.
This should be backporter up to 2.8.
This commit is contained in:
Olivier Houchard 2025-09-11 18:22:34 +02:00 committed by Olivier Houchard
parent 8c8e50e09a
commit 71199e394c

View File

@ -5335,10 +5335,11 @@ struct show_table_ctx {
/* Processes a single table entry <ts>. /* Processes a single table entry <ts>.
* returns 0 if it wants to be called again, 1 if has ended processing. * returns 0 if it wants to be called again, 1 if has ended processing.
*/ */
static int table_process_entry(struct appctx *appctx, struct stksess *ts, char **args) static int table_process_entry(struct appctx *appctx, struct stksess **tsptr, char **args)
{ {
struct show_table_ctx *ctx = appctx->svcctx; struct show_table_ctx *ctx = appctx->svcctx;
struct stktable *t = ctx->target; struct stktable *t = ctx->target;
struct stksess *ts = *tsptr;
long long value; long long value;
int data_type; int data_type;
int cur_arg; int cur_arg;
@ -5375,20 +5376,22 @@ static int table_process_entry(struct appctx *appctx, struct stksess *ts, char *
case STK_CLI_ACT_SHOW: case STK_CLI_ACT_SHOW:
chunk_reset(&trash); chunk_reset(&trash);
if (!table_dump_head_to_buffer(&trash, appctx, t, t)) { if (!table_dump_head_to_buffer(&trash, appctx, t, t)) {
stktable_release(t, ts);
return 0; return 0;
} }
HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &ts->lock); HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &ts->lock);
if (!table_dump_entry_to_buffer(&trash, appctx, t, ts)) { if (!table_dump_entry_to_buffer(&trash, appctx, t, ts)) {
HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &ts->lock); HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &ts->lock);
stktable_release(t, ts);
return 0; return 0;
} }
HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &ts->lock); HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &ts->lock);
stktable_release(t, ts);
break; break;
case STK_CLI_ACT_CLR: case STK_CLI_ACT_CLR:
/*
* Now matter if we managed to kill the stksess or not,
* the ref_cnt will be decremented, so let the caller know.
*/
*tsptr = NULL;
if (!stksess_kill(t, ts)) { if (!stksess_kill(t, ts)) {
/* don't delete an entry which is currently referenced */ /* don't delete an entry which is currently referenced */
return cli_err(appctx, "Entry currently in use, cannot remove\n"); return cli_err(appctx, "Entry currently in use, cannot remove\n");
@ -5403,7 +5406,7 @@ static int table_process_entry(struct appctx *appctx, struct stksess *ts, char *
if (strncmp(args[cur_arg], "data.", 5) != 0) { if (strncmp(args[cur_arg], "data.", 5) != 0) {
cli_err(appctx, "\"data.<type>\" followed by a value expected\n"); cli_err(appctx, "\"data.<type>\" followed by a value expected\n");
HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock); HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
stktable_touch_local(t, ts, 1); stktable_touch_local(t, ts, 0);
return 1; return 1;
} }
@ -5411,21 +5414,21 @@ static int table_process_entry(struct appctx *appctx, struct stksess *ts, char *
if (data_type < 0) { if (data_type < 0) {
cli_err(appctx, "Unknown data type\n"); cli_err(appctx, "Unknown data type\n");
HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock); HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
stktable_touch_local(t, ts, 1); stktable_touch_local(t, ts, 0);
return 1; return 1;
} }
if (!t->data_ofs[data_type]) { if (!t->data_ofs[data_type]) {
cli_err(appctx, "Data type not stored in this table\n"); cli_err(appctx, "Data type not stored in this table\n");
HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock); HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
stktable_touch_local(t, ts, 1); stktable_touch_local(t, ts, 0);
return 1; return 1;
} }
if (!*args[cur_arg+1] || strl2llrc(args[cur_arg+1], strlen(args[cur_arg+1]), &value) != 0) { if (!*args[cur_arg+1] || strl2llrc(args[cur_arg+1], strlen(args[cur_arg+1]), &value) != 0) {
cli_err(appctx, "Require a valid integer value to store\n"); cli_err(appctx, "Require a valid integer value to store\n");
HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock); HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
stktable_touch_local(t, ts, 1); stktable_touch_local(t, ts, 0);
return 1; return 1;
} }
@ -5434,7 +5437,7 @@ static int table_process_entry(struct appctx *appctx, struct stksess *ts, char *
if (!ptr) { if (!ptr) {
cli_err(appctx, "index out of range in this data array\n"); cli_err(appctx, "index out of range in this data array\n");
HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock); HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
stktable_touch_local(t, ts, 1); stktable_touch_local(t, ts, 0);
return 1; return 1;
} }
} }
@ -5469,7 +5472,7 @@ static int table_process_entry(struct appctx *appctx, struct stksess *ts, char *
} }
} }
HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock); HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
stktable_touch_local(t, ts, 1); stktable_touch_local(t, ts, 0);
break; break;
default: default:
@ -5488,6 +5491,7 @@ static int table_process_entry_per_key(struct appctx *appctx, char **args)
struct stktable *t = ctx->target; struct stktable *t = ctx->target;
struct stksess *ts; struct stksess *ts;
struct sample key; struct sample key;
int ret;
if (!*args[4]) if (!*args[4])
return cli_err(appctx, "Key value expected\n"); return cli_err(appctx, "Key value expected\n");
@ -5525,7 +5529,10 @@ static int table_process_entry_per_key(struct appctx *appctx, char **args)
} else } else
ts = stktable_lookup_key(t, &static_table_key); ts = stktable_lookup_key(t, &static_table_key);
return table_process_entry(appctx, ts, args); ret = table_process_entry(appctx, &ts, args);
if (ts)
stktable_release(t, ts);
return ret;
} }
/* Processes a single table entry matching a specific ptr passed in argument. /* Processes a single table entry matching a specific ptr passed in argument.
@ -5538,6 +5545,7 @@ static int table_process_entry_per_ptr(struct appctx *appctx, char **args)
ulong ptr; ulong ptr;
char *error; char *error;
struct stksess *ts; struct stksess *ts;
int ret;
if (!*args[4] || args[4][0] != '0' || args[4][1] != 'x') if (!*args[4] || args[4][0] != '0' || args[4][1] != 'x')
return cli_err(appctx, "Pointer expected (0xffff notation)\n"); return cli_err(appctx, "Pointer expected (0xffff notation)\n");
@ -5551,7 +5559,10 @@ static int table_process_entry_per_ptr(struct appctx *appctx, char **args)
if (!ts) if (!ts)
return cli_err(appctx, "No entry can be found matching ptr.\n"); return cli_err(appctx, "No entry can be found matching ptr.\n");
return table_process_entry(appctx, ts, args); ret = table_process_entry(appctx, &ts, args);
if (ts)
stktable_release(t, ts);
return ret;
} }
/* Prepares the appctx fields with the data-based filters from the command line. /* Prepares the appctx fields with the data-based filters from the command line.