From 1ef27821bc1c2395d7d07cc8dba8cb2186f7feed Mon Sep 17 00:00:00 2001 From: sjaakola Date: Tue, 3 Feb 2026 15:34:58 +0200 Subject: [PATCH] MDEV-21935 Mariabackup file limits set incorrectly When a cluster donor node executes mariabackup SST, it will use same approximation for max open files limit as was set for the mariadbd process during the server startup. This may be a problem for installation where mariabackup execution would need higher open file count, and might crash for exceeding the too tight open file limit. The reason for this behavior is that when mariadbd server calculates the expected max open files count, it will record this open file count approximation as system ulimit value, both as soft and hard limit. Later, when the node operates as SST donor, it spawns mariabackup executable, which now inherits the ulmit setting used for the mariadbd process. Mariabackup tries to enforce open_files_limit variable value configured in [mariabackup] group in the my.cnf fle, but this will fail if hard ulimit value is smaller. The fix in this commit records the approximated max open file count only as soft ulimit value. If hard ulimit is higher or unlimited, there remains head room for the mariabackup to use higher open_files_limit configuration. --- extra/mariabackup/xtrabackup.cc | 5 ++++- mysys/my_file.c | 24 +++++++++++++++++++----- 2 files changed, 23 insertions(+), 6 deletions(-) diff --git a/extra/mariabackup/xtrabackup.cc b/extra/mariabackup/xtrabackup.cc index 3071206b201fa..2db71908e708d 100644 --- a/extra/mariabackup/xtrabackup.cc +++ b/extra/mariabackup/xtrabackup.cc @@ -4796,11 +4796,14 @@ static ulong xb_set_max_open_files(rlim_t max_file_limit) goto end; } - rlimit.rlim_cur = rlimit.rlim_max = max_file_limit; + rlimit.rlim_cur = max_file_limit; if (setrlimit(RLIMIT_NOFILE, &rlimit)) { /* Use original value */ max_file_limit = static_cast(old_cur); + + msg( "setrlimit failed %d %s limit S: %lu H: %lu", + errno, strerror(errno), rlimit.rlim_cur, rlimit.rlim_max); } else { rlimit.rlim_cur = 0; /* Safety if next call fails */ diff --git a/mysys/my_file.c b/mysys/my_file.c index c2b358f5e1e3a..3c065c0ab4493 100644 --- a/mysys/my_file.c +++ b/mysys/my_file.c @@ -50,23 +50,37 @@ static uint set_max_open_files(uint max_file_limit) { old_cur= (uint) rlimit.rlim_cur; DBUG_PRINT("info", ("rlim_cur: %u rlim_max: %u", - (uint) rlimit.rlim_cur, - (uint) rlimit.rlim_max)); + (uint) rlimit.rlim_cur, + (uint) rlimit.rlim_max)); if ((ulonglong) rlimit.rlim_cur == (ulonglong) RLIM_INFINITY || rlimit.rlim_cur >= max_file_limit) DBUG_RETURN(max_file_limit); - rlimit.rlim_cur= rlimit.rlim_max= max_file_limit; - if (setrlimit(RLIMIT_NOFILE, &rlimit)) + + /* Never lower the hard limit (rlim_max): lowering is irreversible for + non-privileged users and can prevent later increases. */ + if ((ulonglong) rlimit.rlim_max != (ulonglong) RLIM_INFINITY && + max_file_limit > rlimit.rlim_max) + { + /* Best effort: try raising hard limit only when needed. */ + rlimit.rlim_max= max_file_limit; + } + + /* Soft limit cannot exceed hard limit. */ + rlimit.rlim_cur= max_file_limit; + + if (setrlimit(RLIMIT_NOFILE, &rlimit)) { max_file_limit= old_cur; /* Use original value */ + } else { rlimit.rlim_cur= 0; /* Safety if next call fails */ (void) getrlimit(RLIMIT_NOFILE,&rlimit); DBUG_PRINT("info", ("rlim_cur: %u", (uint) rlimit.rlim_cur)); if (rlimit.rlim_cur) /* If call didn't fail */ - max_file_limit= (uint) rlimit.rlim_cur; + max_file_limit= (uint) rlimit.rlim_cur; } } + DBUG_PRINT("exit",("max_file_limit: %u", max_file_limit)); DBUG_RETURN(max_file_limit); }