From 3a1be725326bfe637355c461bd77993c0fda2173 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Tue, 23 Apr 2019 11:34:04 +0200 Subject: [PATCH] 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 --- CMakeLists.txt | 3 +- Makefile.am | 3 +- src/unix/linux-core.c | 72 +++++++++++++++++++++++++++++++++++++++++++ uv.gyp | 1 - 4 files changed, 74 insertions(+), 5 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 7b255119..b3890ddf 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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") diff --git a/Makefile.am b/Makefile.am index 22069625..07224f32 100644 --- a/Makefile.am +++ b/Makefile.am @@ -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 diff --git a/src/unix/linux-core.c b/src/unix/linux-core.c index 7edf61c9..36f1c544 100644 --- a/src/unix/linux-core.c +++ b/src/unix/linux-core.c @@ -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; +} diff --git a/uv.gyp b/uv.gyp index 0836dd27..46de9b76 100644 --- a/uv.gyp +++ b/uv.gyp @@ -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' ],