BUG/MINOR: hlua_fcn: restore server pairs iterator pointer consistency

Since 9c91b30 ("MINOR: server: remove prev_deleted server list"), hlua
server pair iterator may use and return invalid (stale) server pointer
if multiple servers were deleted between two iterations.

Indeed, the server refcount mechanism (using srv_take()) is no longer
sufficient as the prev_deleted mitigation was removed.

To ensure server pointer consistency between two yields, the new watcher
mechanism must be used (as it already the case for stats dumping).

Thus in this patch we slightly change the server iteration logic:
hlua_server_list_iterator_context struct now stores the next valid server
pointer, and a watcher is added to ensure this pointer is never stale.

Then in hlua_listable_servers_pairs_iterator(), this next pointer is used
to create the Lua server object, and the next valid pointer is obtained by
leveraging watcher_next().

No backport needed unless 9c91b30 ("MINOR: server: remove prev_deleted
server list") is. Please note that dynamic servers were not supported in
Lua prior to 2.8, so it doesn't make sense to backport this patch further
than 2.8.
This commit is contained in:
Aurelien DARRAGON 2024-12-11 10:42:11 +01:00
parent 647a290662
commit 358166ae6a
2 changed files with 23 additions and 15 deletions

View File

@ -230,8 +230,11 @@ struct hlua_server_list {
};
struct hlua_server_list_iterator_context {
struct server *cur;
struct proxy *px;
struct watcher srv_watch; /* watcher to automatically update next pointer
* on server deletion
*/
struct server *next; /* next server in list */
struct proxy *px; /* to retrieve first server */
};
#define HLUA_PATREF_FL_NONE 0x00

View File

@ -1896,29 +1896,33 @@ int hlua_listable_servers_pairs_iterator(lua_State *L)
{
int context_index;
struct hlua_server_list_iterator_context *ctx;
struct server *cur;
context_index = lua_upvalueindex(1);
ctx = lua_touserdata(L, context_index);
if (ctx->cur == NULL) {
if (ctx->px) {
/* First iteration, initialize list on the first server */
ctx->cur = ctx->px->srv;
} else {
/* Next server (next ptr is always valid, even if current
* server has the SRV_F_DELETED flag set)
*/
ctx->cur = ctx->cur->next;
cur = ctx->px->srv;
watcher_attach(&ctx->srv_watch, cur);
ctx->px = NULL;
}
else {
/* next iteration */
cur = ctx->next;
}
/* next server is null, end of iteration */
if (ctx->cur == NULL) {
/* cur server is null, end of iteration */
if (cur == NULL) {
lua_pushnil(L);
return 1;
}
lua_pushstring(L, ctx->cur->id);
hlua_fcn_new_server(L, ctx->cur);
/* compute next server */
ctx->next = watcher_next(&ctx->srv_watch, cur->next);
lua_pushstring(L, cur->id);
hlua_fcn_new_server(L, cur);
return 2;
}
@ -1935,7 +1939,8 @@ int hlua_listable_servers_pairs(lua_State *L)
ctx = lua_newuserdata(L, sizeof(*ctx));
ctx->px = hlua_srv_list->px;
ctx->cur = NULL;
ctx->next = NULL;
watcher_init(&ctx->srv_watch, &ctx->next, offsetof(struct server, watcher_list));
lua_pushcclosure(L, hlua_listable_servers_pairs_iterator, 1);
return 1;