Skip to content

Commit

Permalink
common: use close_range on Linux
Browse files Browse the repository at this point in the history
Fix rook/rook#10110, which occurs when _SC_OPEN_MAX/RLIMIT_NOFILE is
set to very large values (2^30), leaving fork_function pegging a core
busylooping.

The glibc wrappers closefrom(3)/close_range(3) are not available before
glibc 2.34, so we invoke the syscall directly. When glibc 2.34 is old
enough to be a reasonable hard minimum dependency, we should switch to
using closefrom.

If we're not running on (recent enough) Linux, we fall back to the
existing approach.

Fixes: https://tracker.ceph.com/issues/59125
Signed-off-by: edef <edef@edef.eu>
  • Loading branch information
edef1c committed Jan 17, 2024
1 parent 313921a commit 1a9d521
Show file tree
Hide file tree
Showing 2 changed files with 30 additions and 11 deletions.
9 changes: 9 additions & 0 deletions src/common/SubProcess.cc
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@
#include <sys/types.h>
#include <signal.h>
#endif
#ifdef __linux__
#include <sys/syscall.h>
#endif
#include <stdarg.h>
#include <fcntl.h>
#include <unistd.h>
Expand Down Expand Up @@ -200,6 +203,12 @@ int SubProcess::spawn() {
int maxfd = sysconf(_SC_OPEN_MAX);
if (maxfd == -1)
maxfd = 16384;

#ifdef __linux__
if (::syscall(SYS_close_range, STDERR_FILENO + 1, ~0U, 0) == 0)
maxfd = STDERR_FILENO;
#endif

for (int fd = 0; fd <= maxfd; fd++) {
if (fd == STDIN_FILENO && stdin_op != CLOSE)
continue;
Expand Down
32 changes: 21 additions & 11 deletions src/common/fork_function.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@
#ifndef _WIN32
#include <sys/wait.h>
#endif
#ifdef __linux__
#include <sys/syscall.h>
#endif
#include <sys/types.h>

#include "include/ceph_assert.h"
Expand Down Expand Up @@ -53,18 +56,25 @@ static inline int fork_function(
// we are forker (first child)

// close all fds
int maxfd = sysconf(_SC_OPEN_MAX);
if (maxfd == -1)
maxfd = 16384;
for (int fd = 0; fd <= maxfd; fd++) {
if (fd == STDIN_FILENO)
continue;
if (fd == STDOUT_FILENO)
continue;
if (fd == STDERR_FILENO)
continue;
::close(fd);
#ifdef __linux__
if (::syscall(SYS_close_range, STDERR_FILENO + 1, ~0U, 0)) {
#endif
// fall back to manually closing
int maxfd = sysconf(_SC_OPEN_MAX);
if (maxfd == -1)
maxfd = 16384;
for (int fd = 0; fd <= maxfd; fd++) {
if (fd == STDIN_FILENO)
continue;
if (fd == STDOUT_FILENO)
continue;
if (fd == STDERR_FILENO)
continue;
::close(fd);
}
#ifdef __linux__
}
#endif

sigset_t mask, oldmask;
int pid;
Expand Down

0 comments on commit 1a9d521

Please sign in to comment.