linux: read free/total memory from /proc/meminfo

It was reported that uv_get_free_memory() and uv_get_total_memory()
report the wrong values inside an lxc container.

Libuv calls sysinfo(2) but that isn't intercepted by lxc. /proc/meminfo
however is because /proc is a FUSE fs inside the container.

This commit makes libuv try /proc/meminfo first and fall back to
sysinfo(2) in case /proc isn't mounted.

Fixes: https://github.com/libuv/libuv/issues/2249
PR-URL: https://github.com/libuv/libuv/pull/2258
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
This commit is contained in:
Ben Noordhuis 2019-04-23 11:34:04 +02:00
parent 1c2dc9c8d1
commit 3a1be72532
4 changed files with 74 additions and 5 deletions

View File

@ -297,8 +297,7 @@ if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
src/unix/linux-inotify.c
src/unix/linux-syscalls.c
src/unix/procfs-exepath.c
src/unix/sysinfo-loadavg.c
src/unix/sysinfo-memory.c)
src/unix/sysinfo-loadavg.c)
endif()
if(CMAKE_SYSTEM_NAME STREQUAL "NetBSD")

View File

@ -425,8 +425,7 @@ libuv_la_SOURCES += src/unix/linux-core.c \
src/unix/linux-syscalls.h \
src/unix/procfs-exepath.c \
src/unix/proctitle.c \
src/unix/sysinfo-loadavg.c \
src/unix/sysinfo-memory.c
src/unix/sysinfo-loadavg.c
test_run_tests_LDFLAGS += -lutil
endif

View File

@ -936,3 +936,75 @@ void uv__set_process_title(const char* title) {
prctl(PR_SET_NAME, title); /* Only copies first 16 characters. */
#endif
}
static uint64_t uv__read_proc_meminfo(const char* what) {
unsigned long rc;
ssize_t n;
char* p;
int fd;
char buf[4096]; /* Large enough to hold all of /proc/meminfo. */
rc = 0;
fd = uv__open_cloexec("/proc/meminfo", O_RDONLY);
if (fd == -1)
return 0;
n = read(fd, buf, sizeof(buf) - 1);
if (n <= 0)
goto out;
buf[n] = '\0';
p = strstr(buf, what);
if (p == NULL)
goto out;
p += strlen(what);
if (1 != sscanf(p, "%lu kB", &rc))
goto out;
rc *= 1024;
out:
if (uv__close_nocheckstdio(fd))
abort();
return rc;
}
uint64_t uv_get_free_memory(void) {
struct sysinfo info;
uint64_t rc;
rc = uv__read_proc_meminfo("MemFree:");
if (rc != 0)
return rc;
if (0 == sysinfo(&info))
return (uint64_t) info.freeram * info.mem_unit;
return 0;
}
uint64_t uv_get_total_memory(void) {
struct sysinfo info;
uint64_t rc;
rc = uv__read_proc_meminfo("MemTotal:");
if (rc != 0)
return rc;
if (0 == sysinfo(&info))
return (uint64_t) info.totalram * info.mem_unit;
return 0;
}

1
uv.gyp
View File

@ -241,7 +241,6 @@
'src/unix/linux-syscalls.h',
'src/unix/procfs-exepath.c',
'src/unix/sysinfo-loadavg.c',
'src/unix/sysinfo-memory.c',
],
'link_settings': {
'libraries': [ '-ldl', '-lrt' ],