You need to sign in or sign up before continuing.
Commit 90b84421 authored by Matt Stancliff's avatar Matt Stancliff
Browse files

Fix infinite loop on startup if ulimit too low

Fun fact: rlim_t is an unsigned long long on all platforms.

Continually subtracting from a rlim_t makes it get smaller
and smaller until it wraps, then you're up to 2^64-1.

This was causing an infinite loop on Redis startup if
your ulimit was extremely (almost comically) low.

The case of (f > oldlimit) would never be met in a case like:

    f = 150
    while (f > 20) f -= 128

Since f is unsigned, it can't go negative and would
take on values of:

    Iteration 1: 150 - 128 => 22
    Iteration 2:  22 - 128 => 18446744073709551510
    Iterations 3-∞: ...

To catch the wraparound, we use the previous value of f
stored in limit.rlimit_cur.  If we subtract from f and
get a larger number than the value it had previously,
we print an error and exit since we don't have enough
file descriptors to help the user at this point.

Thanks to @bs3g for the inspiration to fix this problem.
Patches existed from @bs3g at antirez#1227, but I needed to repair a few other
parts of Redis simultaneously, so I didn't get a chance to use them.
parent 4a25983f
......@@ -1519,6 +1519,17 @@ void adjustOpenFilesLimit(void) {
limit.rlim_max = f;
if (setrlimit(RLIMIT_NOFILE,&limit) != -1) break;
f -= REDIS_EVENTLOOP_FDSET_INCR;
if (f > limit.rlim_cur) {
/* Instead of getting smaller, f just got bigger.
* That means it wrapped around its unsigned floor
* and is now closer to 2^64. We can't help anymore. */
redisLog(REDIS_WARNING,"Failed to set max file limit. "
"You requested maxclients of %d "
"but your 'ulimit -n' is set to %llu. "
"Please increase your 'ulimit -n' to at least %llu.",
server.maxclients, oldlimit, maxfiles);
exit(1);
}
}
if (f < oldlimit) f = oldlimit;
if (f != maxfiles) {
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment