Skip to content

Commit 1181dee

Browse files
committed
Account for already used file descriptors when computing max open files
The process already has some existing file descriptors open, e.g. stdin, stdout and stderr, so we can't assume we can open as many files as the RLIMIT_NOFILE tells us. A different approach to this is to not use a static limit of maximum open files, but instead react to EMFILE when trying to open new files, and then close existing files, but as a stop gap we compute a more accurate static value for the maximum open files. Fixes #35
1 parent b8993dc commit 1181dee

1 file changed

Lines changed: 31 additions & 6 deletions

File tree

sparsebundlefs.cpp

Lines changed: 31 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
#include <errno.h>
2727
#include <fcntl.h>
2828
#include <inttypes.h>
29+
#include <poll.h>
2930
#include <stdarg.h>
3031
#include <stdio.h>
3132
#include <stdlib.h>
@@ -389,15 +390,39 @@ static int sparsebundle_read_buf(const char *path, struct fuse_bufvec **bufp,
389390
syslog(LOG_DEBUG, "asked to read %zu bytes at offset %ju using zero-copy read",
390391
length, uintmax_t(offset));
391392

392-
static struct rlimit fd_limit;
393-
static bool fd_limit_computed = false;
394-
if (!fd_limit_computed) {
393+
static rlim_t max_open_files = []() {
394+
struct rlimit fd_limit;
395395
getrlimit(RLIMIT_NOFILE, &fd_limit);
396-
fd_limit_computed = true;
397-
}
396+
auto fd_max = fd_limit.rlim_cur - 1;
397+
syslog(LOG_DEBUG, "maximum file descriptor number %ju", uintmax_t(fd_max));
398+
399+
// Check how many of the file descriptors are available
400+
std::vector<pollfd> file_descriptors(fd_max);
401+
for (unsigned i = 0; i < file_descriptors.size(); ++i) {
402+
file_descriptors[i].fd = i;
403+
// We don't really care about these states, but we have
404+
// to specify something for poll to give us the POLLNVAL
405+
// we do care about.
406+
file_descriptors[i].events = POLLRDNORM | POLLWRNORM;
407+
}
408+
if (poll(file_descriptors.data(), file_descriptors.size(), 0) == -1) {
409+
syslog(LOG_ERR, "failed to resolve available file descriptors: %s", strerror(errno));
410+
return fd_max;
411+
}
412+
413+
rlim_t available_fds = 0;
414+
for (auto file_descriptor : file_descriptors) {
415+
if (file_descriptor.revents & POLLNVAL)
416+
++available_fds;
417+
}
418+
syslog(LOG_DEBUG, "%ju available file descriptors (%ju in use)",
419+
uintmax_t(available_fds), uintmax_t(fd_max - available_fds));
420+
421+
return available_fds;
422+
}();
398423

399424
sparsebundle_t *sparsebundle = sparsebundle_current();
400-
if (sparsebundle->open_files.size() + 1 >= fd_limit.rlim_cur) {
425+
if (sparsebundle->open_files.size() + 1 >= max_open_files) {
401426
syslog(LOG_DEBUG, "hit max number of file descriptors");
402427
sparsebundle_read_buf_close_files();
403428
}

0 commit comments

Comments
 (0)