-
Notifications
You must be signed in to change notification settings - Fork 3.8k
Description
- Version: All current versions, to the best of my knowledge
- Platform: Any Linux container in OpenVZ/Virtuozzo, e.g.:
Linux vps1607355603 4.15.0 #1 SMP Tue Aug 25 11:59:26 MSK 2020 x86_64 x86_64 x86_64 GNU/Linux - Related Node.js issue: os.uptime returns the wrong value nodejs/node#36244 (for our exploration of the issue)
Lines 606 to 628 in 9c6cec8
| int uv_uptime(double* uptime) { | |
| static volatile int no_clock_boottime; | |
| struct timespec now; | |
| int r; | |
| /* Try CLOCK_BOOTTIME first, fall back to CLOCK_MONOTONIC if not available | |
| * (pre-2.6.39 kernels). CLOCK_MONOTONIC doesn't increase when the system | |
| * is suspended. | |
| */ | |
| if (no_clock_boottime) { | |
| retry: r = clock_gettime(CLOCK_MONOTONIC, &now); | |
| } | |
| else if ((r = clock_gettime(CLOCK_BOOTTIME, &now)) && errno == EINVAL) { | |
| no_clock_boottime = 1; | |
| goto retry; | |
| } | |
| if (r) | |
| return UV__ERR(errno); | |
| *uptime = now.tv_sec; | |
| return 0; | |
| } |
Hey there :) It appears that libuv in OpenVZ environments returns incorrect values. For instance, if one were to check the uptime using cat /proc/uptime and Node.js's os.uptime(), one would get the following results respectively: 3187731.82 and 6740816. In other words, libuv returns results that are higher than container's uptime. Same erroneous result is achieved with this code provided by @gireeshpunathil:
#include <time.h>
#include <errno.h>
#include <stdio.h>
int main() {
struct timespec now;
int r;
r = clock_gettime(CLOCK_BOOTTIME, &now);
if (r != 0) {
fprintf(stderr, "clock_gettime failed with %d\n", errno);
return errno;
}
fprintf(stderr, "system uptime: %ld\n", now.tv_sec);
return 0;
}To get into the root of the problem, we need to understand how OpenVZ operates. OpenVZ consists of a host Linux system with highly patched kernel, which then runs the containers. Unfortunately, all containers share the host kernel, but are provided with a separate simulation of /proc/ (procfs) filesystem for each container. Thus, the earlier mentioned 6740816 uptime from libuv coincides with the uptime of the physical host system.
In practice, this means that the clock_gettime is inherently unreliable on OpenVZ systems. It is suggested by @davedodo on a related node.js issue nodejs/node#36244 (comment) that sysinfo function works correctly with OpenVZ systems (like in Cygwin implementation). However, there might be other alternatives that I (we?) are unaware of.
It is my understanding that this issue concerns only OpenVZ/Virtuozo. Thus, in order to check, whether the system is an OpenVZ container, it appears sufficient to check that /proc/vz/veinfo file exists at launch time (it contains container ID, public IP of current container and current number of running processes).
I am not providing any PR at this point, because this issue may involve quite a bit of decision making on this issue, with a non-exhausting list of three alternatives:
- Rewrite
uv_uptimeentirely usingsysinfofor all cases - Check for OpenVZ at launch time to avoid
clock_gettimeinuv_uptimeon OpenVZ and usesysinfoinstead - Ignore the issue