Skip to content

Commit

Permalink
Merge pull request #1443 from Sonicadvance1/squashfs_fixes
Browse files Browse the repository at this point in the history
FEXMountDaemon squashfs fixes.
  • Loading branch information
Sonicadvance1 authored Dec 15, 2021
2 parents fa6f1b1 + 5d0734a commit ea73c9d
Show file tree
Hide file tree
Showing 2 changed files with 65 additions and 9 deletions.
15 changes: 7 additions & 8 deletions Source/Common/RootFSSetup.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -155,14 +155,13 @@ bool SendSocketPipe(std::string const &MountPath) {
int Result = ppoll(&pfd, 1, &ts, nullptr);
if (Result == -1 || Result == 0) {
// didn't get ack back in time
// Close our read pipe
close(fds[0]);
// close our write pipe
close(fds[1]);

// close socket
close(socket_fd);
return false;
// Assume an overburdened system at this point
// If the FEXMountDaemon is alive but slept for more than our timeout
// then we can spuriously throw errors
//
// Returning false here would cause FEX to try and spin up a new FEXMountDaemon
// and then the FEXMountDaemon would check to see if the lock exists
// Then would early exit and not mount a new path
}

// We've sent the message which means we're done with the socket
Expand Down
59 changes: 58 additions & 1 deletion Source/Tools/FEXMountDaemon/Main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include <sys/wait.h>
#include <sys/inotify.h>
#include <sys/un.h>
#include <sys/resource.h>
#include <sys/select.h>
#include <sys/socket.h>
#include <sys/time.h>
Expand All @@ -35,7 +36,10 @@ namespace EPollWatcher {
static int epoll_fd{};
static std::thread EPollThread{};
static std::atomic<pid_t> EPollThreadTID{};
static rlimit MaxFDs{};
constexpr size_t static MAX_FD_DISTANCE = 32;
std::atomic<uint64_t> NumPipesWatched{};
std::atomic<size_t> NumFilesOpened{};
std::atomic<bool> EPollWatcherShutdown {false};
std::chrono::time_point<std::chrono::system_clock> TimeWhileZeroFDs{};
// Timeout is ten seconds
Expand All @@ -45,6 +49,49 @@ namespace EPollWatcher {
return NumPipesWatched.load();
}

size_t GetNumFilesOpen() {
// Walk /proc/self/fd/ to see how many open files we currently have
const std::filesystem::path self{"/proc/self/fd/"};

return std::distance(std::filesystem::directory_iterator{self}, std::filesystem::directory_iterator{});
}

void GetMaxFDs() {
// Get our kernel limit for the number of open files
if (getrlimit(RLIMIT_NOFILE, &MaxFDs) != 0) {
fprintf(stderr, "[FEXMountDaemon] getrlimit(RLIMIT_NOFILE) returned error %d %s\n", errno, strerror(errno));
}

// Walk /proc/self/fd/ to see how many open files we currently have
NumFilesOpened = GetNumFilesOpen();
}

void RaiseFDLimit() {
if (MaxFDs.rlim_cur == MaxFDs.rlim_max) {
fprintf(stderr, "[FEXMountDaemon] Our open FD limit is already set to max and we are wanting to increase it\n");
fprintf(stderr, "[FEXMountDaemon] FEXMountDaemon will now no longer be able to track new instances of FEX\n");
fprintf(stderr, "[FEXMountDaemon] Current limit is %zd(hard %zd) FDs and we are at %zd\n", MaxFDs.rlim_cur, MaxFDs.rlim_max, GetNumFilesOpen());
fprintf(stderr, "[FEXMountDaemon] Ask your administrator to raise your kernel's hard limit on open FDs\n");
return;
}

rlimit NewLimit = MaxFDs;

// Just multiply by two
NewLimit.rlim_cur <<= 1;

// Now limit to the hard max
NewLimit.rlim_cur = std::min(NewLimit.rlim_cur, NewLimit.rlim_max);

if (setrlimit(RLIMIT_NOFILE, &NewLimit) != 0) {
fprintf(stderr, "[FEXMountDaemon] Couldn't raise FD limit to %zd even though our hard limit is %zd\n", NewLimit.rlim_cur, NewLimit.rlim_max);
}
else {
// Set the new limit
MaxFDs = NewLimit;
}
}

void AddPipeToWatch(int pipe) {
struct epoll_event evt{};
evt.events = EPOLLERR; // This event will return when the read end of a pipe is closed
Expand All @@ -55,11 +102,20 @@ namespace EPollWatcher {
}
else {
++NumPipesWatched;

if ((NumPipesWatched + NumFilesOpened) >= (MaxFDs.rlim_cur - MAX_FD_DISTANCE)) {
// We are close to the maximum FD distance
// Try to raise the limit
RaiseFDLimit();
}
}
}

void RemovePipeToWatch(int pipe) {
int Result = epoll_ctl(epoll_fd, EPOLL_CTL_DEL, pipe, nullptr);

// Make sure to close the pipe to not leak the FD
close(pipe);
if (Result == -1) {
fprintf(stderr, "[FEXMountDaemon] epoll_ctl returned error %d %s\n", errno, strerror(errno));
}
Expand All @@ -81,7 +137,7 @@ namespace EPollWatcher {

// Spin while we are not shutting down
// Also spin while we have pipes to watch
while (!EPollWatcherShutdown.load() || NumPipesRemaining() != 0) {
while (!EPollWatcherShutdown.load()) {
// Loop every ten seconds
// epoll_pwait2 only available since kernel 5.11...
int Result = epoll_pwait(epoll_fd, Events, MAX_EVENTS, 10 * 1000, nullptr);
Expand Down Expand Up @@ -115,6 +171,7 @@ namespace EPollWatcher {
}

void SetupEPoll() {
GetMaxFDs();
epoll_fd = epoll_create1(EPOLL_CLOEXEC);
EPollThread = std::thread{EPollWatcher::EPollWatch};
}
Expand Down

0 comments on commit ea73c9d

Please sign in to comment.