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.
This commit is contained in:
+11
@@ -1446,6 +1446,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) {
|
||||
|
||||
Reference in New Issue
Block a user