#include "proc_cpuview.h"
#include "utils.h"
+struct memory_stat {
+ uint64_t hierarchical_memory_limit;
+ uint64_t hierarchical_memsw_limit;
+ uint64_t total_cache;
+ uint64_t total_rss;
+ uint64_t total_rss_huge;
+ uint64_t total_shmem;
+ uint64_t total_mapped_file;
+ uint64_t total_dirty;
+ uint64_t total_writeback;
+ uint64_t total_swap;
+ uint64_t total_pgpgin;
+ uint64_t total_pgpgout;
+ uint64_t total_pgfault;
+ uint64_t total_pgmajfault;
+ uint64_t total_inactive_anon;
+ uint64_t total_active_anon;
+ uint64_t total_inactive_file;
+ uint64_t total_active_file;
+ uint64_t total_unevictable;
+};
+
int proc_getattr(const char *path, struct stat *sb)
{
struct timespec now;
static off_t get_procfile_size(const char *which)
{
- FILE *f = fopen(which, "r");
+ FILE *f = fopen(which, "re");
char *line = NULL;
size_t len = 0;
ssize_t sz, answer = 0;
int proc_open(const char *path, struct fuse_file_info *fi)
{
+ __do_free struct file_info *info = NULL;
int type = -1;
- struct file_info *info;
if (strcmp(path, "/proc/meminfo") == 0)
type = LXC_TYPE_PROC_MEMINFO;
/* set actual size to buffer size */
info->size = info->buflen;
- fi->fh = (unsigned long)info;
+ fi->fh = PTR_TO_UINT64(move_ptr(info));
return 0;
}
__do_free char *cg = NULL, *memswlimit_str = NULL, *memusage_str = NULL,
*memswusage_str = NULL;
struct fuse_context *fc = fuse_get_context();
- struct file_info *d = (struct file_info *)fi->fh;
+ struct file_info *d = INTTYPE_TO_PTR(fi->fh);
unsigned long memswlimit = 0, memlimit = 0, memusage = 0,
memswusage = 0, swap_total = 0, swap_free = 0;
ssize_t total_len = 0;
/* When no mem + swap limit is specified or swapaccount=0*/
if (!memswlimit) {
__do_free char *line = NULL;
+ __do_free void *fopen_cache = NULL;
__do_fclose FILE *f = NULL;
size_t linelen = 0;
- f = fopen("/proc/meminfo", "r");
+ f = fopen_cached("/proc/meminfo", "re", &fopen_cache);
if (!f)
return 0;
*io_merged_str = NULL, *io_service_bytes_str = NULL,
*io_wait_time_str = NULL, *io_service_time_str = NULL,
*line = NULL;
+ __do_free void *fopen_cache = NULL;
__do_fclose FILE *f = NULL;
struct fuse_context *fc = fuse_get_context();
- struct file_info *d = (struct file_info *)fi->fh;
+ struct file_info *d = INTTYPE_TO_PTR(fi->fh);
unsigned long read = 0, write = 0;
unsigned long read_merged = 0, write_merged = 0;
unsigned long read_sectors = 0, write_sectors = 0;
return read_file_fuse("/proc/diskstats", buf, size, d);
}
- f = fopen("/proc/diskstats", "r");
+ f = fopen_cached("/proc/diskstats", "re", &fopen_cache);
if (!f)
return 0;
static uint64_t get_reaper_start_time(pid_t pid)
{
+ __do_free void *fopen_cache = NULL;
__do_fclose FILE *f = NULL;
int ret;
uint64_t starttime;
return 0;
}
- f = fopen(path, "r");
+ f = fopen_cached(path, "re", &fopen_cache);
if (!f) {
/* Caller can check for EINVAL on 0. */
errno = EINVAL;
struct fuse_file_info *fi)
{
struct fuse_context *fc = fuse_get_context();
- struct file_info *d = (struct file_info *)fi->fh;
+ struct file_info *d = INTTYPE_TO_PTR(fi->fh);
double busytime = get_reaper_busy(fc->pid);
char *cache = d->buf;
ssize_t total_len = 0;
struct fuse_file_info *fi)
{
__do_free char *cg = NULL, *cpuset = NULL, *line = NULL;
+ __do_free void *fopen_cache = NULL;
__do_free struct cpuacct_usage *cg_cpu_usage = NULL;
__do_fclose FILE *f = NULL;
struct fuse_context *fc = fuse_get_context();
- struct file_info *d = (struct file_info *)fi->fh;
+ struct file_info *d = INTTYPE_TO_PTR(fi->fh);
size_t linelen = 0, total_len = 0;
int curcpu = -1; /* cpu numbering starts at 0 */
int physcpu = 0;
* If the cpuacct cgroup is present, it is used to calculate the container's
* CPU usage. If not, values from the host's /proc/stat are used.
*/
- if (read_cpuacct_usage_all(cg, cpuset, &cg_cpu_usage, &cg_cpu_usage_size) != 0) {
- lxcfs_v("%s\n", "proc_stat_read failed to read from cpuacct, "
- "falling back to the host's /proc/stat");
- }
+ if (read_cpuacct_usage_all(cg, cpuset, &cg_cpu_usage, &cg_cpu_usage_size) != 0)
+ lxcfs_v("%s\n", "proc_stat_read failed to read from cpuacct, falling back to the host's /proc/stat");
- f = fopen("/proc/stat", "r");
+ f = fopen_cached("/proc/stat", "re", &fopen_cache);
if (!f)
return 0;
continue;
if (!cpu_in_cpuset(physcpu, cpuset))
continue;
- curcpu ++;
+ curcpu++;
ret = sscanf(line, "%*s %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu",
&user,
new_idle = idle + (all_used - cg_used);
} else {
- lxcfs_error("cpu%d from %s has unexpected cpu time: %lu in /proc/stat, "
- "%lu in cpuacct.usage_all; unable to determine idle time\n",
- curcpu, cg, all_used, cg_used);
+ lxcfs_error("cpu%d from %s has unexpected cpu time: %" PRIu64 " in /proc/stat, %" PRIu64 " in cpuacct.usage_all; unable to determine idle time",
+ curcpu, cg, all_used, cg_used);
new_idle = idle;
}
- l = snprintf(cache, cache_size, "cpu%d %lu 0 %lu %lu 0 0 0 0 0 0\n",
- curcpu, cg_cpu_usage[physcpu].user, cg_cpu_usage[physcpu].system,
- new_idle);
+ l = snprintf(cache, cache_size,
+ "cpu%d %" PRIu64 " 0 %" PRIu64 " %" PRIu64 " 0 0 0 0 0 0\n",
+ curcpu, cg_cpu_usage[physcpu].user,
+ cg_cpu_usage[physcpu].system, new_idle);
if (l < 0) {
perror("Error writing to cache");
}
/* Note that "memory.stat" in cgroup2 is hierarchical by default. */
-static void parse_memstat(int version,
- char *memstat,
- unsigned long *cached,
- unsigned long *active_anon,
- unsigned long *inactive_anon,
- unsigned long *active_file,
- unsigned long *inactive_file,
- unsigned long *unevictable,
- unsigned long *shmem)
+static bool cgroup_parse_memory_stat(const char *cgroup, struct memory_stat *mstat)
{
- char *eol;
+ __do_close_prot_errno int fd = -EBADF;
+ __do_fclose FILE *f = NULL;
+ __do_free char *line = NULL;
+ bool unified;
+ size_t len = 0;
+ ssize_t linelen;
- while (*memstat) {
- if (startswith(memstat, is_unified_controller(version)
- ? "cache"
- : "total_cache")) {
- sscanf(memstat + 11, "%lu", cached);
- *cached /= 1024;
- } else if (startswith(memstat, is_unified_controller(version)
- ? "active_anon"
- : "total_active_anon")) {
- sscanf(memstat + 17, "%lu", active_anon);
- *active_anon /= 1024;
- } else if (startswith(memstat, is_unified_controller(version)
- ? "inactive_anon"
- : "total_inactive_anon")) {
- sscanf(memstat + 19, "%lu", inactive_anon);
- *inactive_anon /= 1024;
- } else if (startswith(memstat, is_unified_controller(version)
- ? "active_file"
- : "total_active_file")) {
- sscanf(memstat + 17, "%lu", active_file);
- *active_file /= 1024;
- } else if (startswith(memstat, is_unified_controller(version)
- ? "inactive_file"
- : "total_inactive_file")) {
- sscanf(memstat + 19, "%lu", inactive_file);
- *inactive_file /= 1024;
- } else if (startswith(memstat, is_unified_controller(version)
- ? "unevictable"
- : "total_unevictable")) {
- sscanf(memstat + 17, "%lu", unevictable);
- *unevictable /= 1024;
- } else if (startswith(memstat, is_unified_controller(version)
- ? "shmem"
- : "total_shmem")) {
- sscanf(memstat + 11, "%lu", shmem);
- *shmem /= 1024;
+ fd = cgroup_ops->get_memory_stats_fd(cgroup_ops, cgroup);
+ if (fd < 0)
+ return false;
+
+ f = fdopen(fd, "re");
+ if (!f)
+ return false;
+ /* Transferring ownership to fdopen(). */
+ move_fd(fd);
+
+ unified = pure_unified_layout(cgroup_ops);
+ while ((linelen = getline(&line, &len, f)) != -1) {
+ if (!unified && startswith(line, "hierarchical_memory_limit")) {
+ sscanf(line, "hierarchical_memory_limit %" PRIu64, &(mstat->hierarchical_memory_limit));
+ } else if (!unified && startswith(line, "hierarchical_memsw_limit")) {
+ sscanf(line, "hierarchical_memsw_limit %" PRIu64, &(mstat->hierarchical_memsw_limit));
+ } else if (startswith(line, unified ? "file" :"total_cache")) {
+ sscanf(line, unified ? "file %" PRIu64 : "total_cache %" PRIu64, &(mstat->total_cache));
+ } else if (!unified && startswith(line, "total_rss")) {
+ sscanf(line, "total_rss %" PRIu64, &(mstat->total_rss));
+ } else if (!unified && startswith(line, "total_rss_huge")) {
+ sscanf(line, "total_rss_huge %" PRIu64, &(mstat->total_rss_huge));
+ } else if (startswith(line, unified ? "shmem" : "total_shmem")) {
+ sscanf(line, unified ? "shmem %" PRIu64 : "total_shmem %" PRIu64, &(mstat->total_shmem));
+ } else if (startswith(line, unified ? "file_mapped" : "total_mapped_file")) {
+ sscanf(line, unified ? "file_mapped %" PRIu64 : "total_mapped_file %" PRIu64, &(mstat->total_mapped_file));
+ } else if (!unified && startswith(line, "total_dirty")) {
+ sscanf(line, "total_dirty %" PRIu64, &(mstat->total_dirty));
+ } else if (!unified && startswith(line, "total_writeback")) {
+ sscanf(line, "total_writeback %" PRIu64, &(mstat->total_writeback));
+ } else if (!unified && startswith(line, "total_swap")) {
+ sscanf(line, "total_swap %" PRIu64, &(mstat->total_swap));
+ } else if (!unified && startswith(line, "total_pgpgin")) {
+ sscanf(line, "total_pgpgin %" PRIu64, &(mstat->total_pgpgin));
+ } else if (!unified && startswith(line, "total_pgpgout")) {
+ sscanf(line, "total_pgpgout %" PRIu64, &(mstat->total_pgpgout));
+ } else if (startswith(line, unified ? "pgfault" : "total_pgfault")) {
+ sscanf(line, unified ? "pgfault %" PRIu64 : "total_pgfault %" PRIu64, &(mstat->total_pgfault));
+ } else if (startswith(line, unified ? "pgmajfault" : "total_pgmajfault")) {
+ sscanf(line, unified ? "pgmajfault %" PRIu64 : "total_pgmajfault %" PRIu64, &(mstat->total_pgmajfault));
+ } else if (startswith(line, unified ? "inactive_anon" : "total_inactive_anon")) {
+ sscanf(line, unified ? "inactive_anon %" PRIu64 : "total_inactive_anon %" PRIu64, &(mstat->total_inactive_anon));
+ } else if (startswith(line, unified ? "active_anon" : "total_active_anon")) {
+ sscanf(line, unified ? "active_anon %" PRIu64 : "total_active_anon %" PRIu64, &(mstat->total_active_anon));
+ } else if (startswith(line, unified ? "inactive_file" : "total_inactive_file")) {
+ sscanf(line, unified ? "inactive_file %" PRIu64 : "total_inactive_file %" PRIu64, &(mstat->total_inactive_file));
+ } else if (startswith(line, unified ? "active_file" : "total_active_file")) {
+ sscanf(line, unified ? "active_file %" PRIu64 : "total_active_file %" PRIu64, &(mstat->total_active_file));
+ } else if (startswith(line, unified ? "unevictable" : "total_unevictable")) {
+ sscanf(line, unified ? "unevictable %" PRIu64 : "total_unevictable %" PRIu64, &(mstat->total_unevictable));
}
- eol = strchr(memstat, '\n');
- if (!eol)
- return;
- memstat = eol+1;
}
+
+ return true;
}
static int proc_meminfo_read(char *buf, size_t size, off_t offset,
__do_free char *cgroup = NULL, *line = NULL,
*memusage_str = NULL, *memstat_str = NULL,
*memswlimit_str = NULL, *memswusage_str = NULL;
+ __do_free void *fopen_cache = NULL;
__do_fclose FILE *f = NULL;
struct fuse_context *fc = fuse_get_context();
struct lxcfs_opts *opts = (struct lxcfs_opts *) fuse_get_context()->private_data;
- struct file_info *d = (struct file_info *)fi->fh;
- unsigned long memlimit = 0, memusage = 0, memswlimit = 0,
- memswusage = 0, cached = 0, hosttotal = 0, active_anon = 0,
- inactive_anon = 0, active_file = 0, inactive_file = 0,
- unevictable = 0, shmem = 0, hostswtotal = 0;
+ struct file_info *d = INTTYPE_TO_PTR(fi->fh);
+ uint64_t memlimit = 0, memusage = 0, memswlimit = 0, memswusage = 0,
+ hosttotal = 0;
+ struct memory_stat mstat = {};
size_t linelen = 0, total_len = 0;
char *cache = d->buf;
size_t cache_size = d->buflen;
if (ret < 0)
return 0;
- ret = cgroup_ops->get_memory_stats(cgroup_ops, cgroup, &memstat_str);
- if (ret < 0)
+ if (!cgroup_parse_memory_stat(cgroup, &mstat))
return 0;
- parse_memstat(ret, memstat_str, &cached, &active_anon, &inactive_anon,
- &active_file, &inactive_file, &unevictable, &shmem);
/*
* Following values are allowed to fail, because swapaccount might be
memlimit /= 1024;
memusage /= 1024;
- f = fopen("/proc/meminfo", "r");
+ f = fopen_cached("/proc/meminfo", "re", &fopen_cache);
if (!f)
return 0;
memset(lbuf, 0, 100);
if (startswith(line, "MemTotal:")) {
- sscanf(line+sizeof("MemTotal:")-1, "%lu", &hosttotal);
+ sscanf(line+sizeof("MemTotal:")-1, "%" PRIu64, &hosttotal);
if (hosttotal < memlimit)
memlimit = hosttotal;
- snprintf(lbuf, 100, "MemTotal: %8lu kB\n", memlimit);
+ snprintf(lbuf, 100, "MemTotal: %8" PRIu64 " kB\n", memlimit);
printme = lbuf;
} else if (startswith(line, "MemFree:")) {
- snprintf(lbuf, 100, "MemFree: %8lu kB\n", memlimit - memusage);
+ snprintf(lbuf, 100, "MemFree: %8" PRIu64 " kB\n", memlimit - memusage);
printme = lbuf;
} else if (startswith(line, "MemAvailable:")) {
- snprintf(lbuf, 100, "MemAvailable: %8lu kB\n", memlimit - memusage + cached);
+ snprintf(lbuf, 100, "MemAvailable: %8" PRIu64 " kB\n", memlimit - memusage + mstat.total_cache / 1024);
printme = lbuf;
} else if (startswith(line, "SwapTotal:") && memswlimit > 0 &&
opts && opts->swap_off == false) {
- sscanf(line+sizeof("SwapTotal:")-1, "%lu", &hostswtotal);
- if (hostswtotal < memswlimit)
- memswlimit = hostswtotal;
- snprintf(lbuf, 100, "SwapTotal: %8lu kB\n", memswlimit);
+ memswlimit -= memlimit;
+ snprintf(lbuf, 100, "SwapTotal: %8" PRIu64 " kB\n", memswlimit);
printme = lbuf;
} else if (startswith(line, "SwapTotal:") && opts && opts->swap_off == true) {
- snprintf(lbuf, 100, "SwapTotal: %8lu kB\n", 0UL);
+ snprintf(lbuf, 100, "SwapTotal: %8" PRIu64 " kB\n", (uint64_t)0);
printme = lbuf;
} else if (startswith(line, "SwapFree:") && memswlimit > 0 &&
memswusage > 0 && opts && opts->swap_off == false) {
- unsigned long swaptotal = memswlimit,
- swapusage = memusage > memswusage
- ? 0
- : memswusage - memusage,
- swapfree = swapusage < swaptotal
- ? swaptotal - swapusage
- : 0;
- snprintf(lbuf, 100, "SwapFree: %8lu kB\n", swapfree);
+ uint64_t swaptotal = memswlimit,
+ swapusage = memusage > memswusage
+ ? 0
+ : memswusage - memusage,
+ swapfree = swapusage < swaptotal
+ ? swaptotal - swapusage
+ : 0;
+ snprintf(lbuf, 100, "SwapFree: %8" PRIu64 " kB\n", swapfree);
printme = lbuf;
} else if (startswith(line, "SwapFree:") && opts && opts->swap_off == true) {
- snprintf(lbuf, 100, "SwapFree: %8lu kB\n", 0UL);
+ snprintf(lbuf, 100, "SwapFree: %8" PRIu64 " kB\n", (uint64_t)0);
printme = lbuf;
} else if (startswith(line, "Slab:")) {
- snprintf(lbuf, 100, "Slab: %8lu kB\n", 0UL);
+ snprintf(lbuf, 100, "Slab: %8" PRIu64 " kB\n", (uint64_t)0);
printme = lbuf;
} else if (startswith(line, "Buffers:")) {
- snprintf(lbuf, 100, "Buffers: %8lu kB\n", 0UL);
+ snprintf(lbuf, 100, "Buffers: %8" PRIu64 " kB\n", (uint64_t)0);
printme = lbuf;
} else if (startswith(line, "Cached:")) {
- snprintf(lbuf, 100, "Cached: %8lu kB\n", cached);
+ snprintf(lbuf, 100, "Cached: %8" PRIu64 " kB\n",
+ mstat.total_cache / 1024);
printme = lbuf;
} else if (startswith(line, "SwapCached:")) {
- snprintf(lbuf, 100, "SwapCached: %8lu kB\n", 0UL);
+ snprintf(lbuf, 100, "SwapCached: %8" PRIu64 " kB\n", (uint64_t)0);
printme = lbuf;
} else if (startswith(line, "Active:")) {
- snprintf(lbuf, 100, "Active: %8lu kB\n",
- active_anon + active_file);
+ snprintf(lbuf, 100, "Active: %8" PRIu64 " kB\n",
+ (mstat.total_active_anon +
+ mstat.total_active_file) /
+ 1024);
printme = lbuf;
} else if (startswith(line, "Inactive:")) {
- snprintf(lbuf, 100, "Inactive: %8lu kB\n",
- inactive_anon + inactive_file);
+ snprintf(lbuf, 100, "Inactive: %8" PRIu64 " kB\n",
+ (mstat.total_inactive_anon +
+ mstat.total_inactive_file) /
+ 1024);
printme = lbuf;
} else if (startswith(line, "Active(anon)")) {
- snprintf(lbuf, 100, "Active(anon): %8lu kB\n", active_anon);
+ snprintf(lbuf, 100, "Active(anon): %8" PRIu64 " kB\n",
+ mstat.total_active_anon / 1024);
printme = lbuf;
} else if (startswith(line, "Inactive(anon)")) {
- snprintf(lbuf, 100, "Inactive(anon): %8lu kB\n", inactive_anon);
+ snprintf(lbuf, 100, "Inactive(anon): %8" PRIu64 " kB\n",
+ mstat.total_inactive_anon / 1024);
printme = lbuf;
} else if (startswith(line, "Active(file)")) {
- snprintf(lbuf, 100, "Active(file): %8lu kB\n", active_file);
+ snprintf(lbuf, 100, "Active(file): %8" PRIu64 " kB\n",
+ mstat.total_active_file / 1024);
printme = lbuf;
} else if (startswith(line, "Inactive(file)")) {
- snprintf(lbuf, 100, "Inactive(file): %8lu kB\n", inactive_file);
+ snprintf(lbuf, 100, "Inactive(file): %8" PRIu64 " kB\n",
+ mstat.total_inactive_file / 1024);
printme = lbuf;
} else if (startswith(line, "Unevictable")) {
- snprintf(lbuf, 100, "Unevictable: %8lu kB\n", unevictable);
+ snprintf(lbuf, 100, "Unevictable: %8" PRIu64 " kB\n",
+ mstat.total_unevictable / 1024);
+ printme = lbuf;
+ } else if (startswith(line, "Dirty")) {
+ snprintf(lbuf, 100, "Dirty: %8" PRIu64 " kB\n",
+ mstat.total_dirty / 1024);
+ printme = lbuf;
+ } else if (startswith(line, "Writeback")) {
+ snprintf(lbuf, 100, "Writeback: %8" PRIu64 " kB\n",
+ mstat.total_writeback / 1024);
+ printme = lbuf;
+ } else if (startswith(line, "AnonPages")) {
+ snprintf(lbuf, 100, "AnonPages: %8" PRIu64 " kB\n",
+ (mstat.total_active_anon +
+ mstat.total_inactive_anon - mstat.total_shmem) /
+ 1024);
+ printme = lbuf;
+ } else if (startswith(line, "Mapped")) {
+ snprintf(lbuf, 100, "Mapped: %8" PRIu64 " kB\n",
+ mstat.total_mapped_file / 1024);
printme = lbuf;
} else if (startswith(line, "SReclaimable")) {
- snprintf(lbuf, 100, "SReclaimable: %8lu kB\n", 0UL);
+ snprintf(lbuf, 100, "SReclaimable: %8" PRIu64 " kB\n", (uint64_t)0);
printme = lbuf;
} else if (startswith(line, "SUnreclaim")) {
- snprintf(lbuf, 100, "SUnreclaim: %8lu kB\n", 0UL);
+ snprintf(lbuf, 100, "SUnreclaim: %8" PRIu64 " kB\n", (uint64_t)0);
printme = lbuf;
} else if (startswith(line, "Shmem:")) {
- snprintf(lbuf, 100, "Shmem: %8lu kB\n", shmem);
+ snprintf(lbuf, 100, "Shmem: %8" PRIu64 " kB\n",
+ mstat.total_shmem / 1024);
printme = lbuf;
} else if (startswith(line, "ShmemHugePages")) {
- snprintf(lbuf, 100, "ShmemHugePages: %8lu kB\n", 0UL);
+ snprintf(lbuf, 100, "ShmemHugePages: %8" PRIu64 " kB\n", (uint64_t)0);
printme = lbuf;
} else if (startswith(line, "ShmemPmdMapped")) {
- snprintf(lbuf, 100, "ShmemPmdMapped: %8lu kB\n", 0UL);
+ snprintf(lbuf, 100, "ShmemPmdMapped: %8" PRIu64 " kB\n", (uint64_t)0);
+ printme = lbuf;
+ } else if (startswith(line, "AnonHugePages")) {
+ snprintf(lbuf, 100, "AnonHugePages: %8" PRIu64 " kB\n",
+ mstat.total_rss_huge / 1024);
printme = lbuf;
- } else
- printme = line;
+ } else {
+ printme = line;
+ }
l = snprintf(cache, cache_size, "%s", printme);
if (l < 0) {
}
int proc_read(const char *path, char *buf, size_t size, off_t offset,
- struct fuse_file_info *fi)
+ struct fuse_file_info *fi)
{
- struct file_info *f = (struct file_info *) fi->fh;
+ struct file_info *f = INTTYPE_TO_PTR(fi->fh);
switch (f->type) {
case LXC_TYPE_PROC_MEMINFO:
return proc_swaps_read(buf, size, offset, fi);
case LXC_TYPE_PROC_LOADAVG:
return proc_loadavg_read(buf, size, offset, fi);
- default:
- return -EINVAL;
}
+
+ return -EINVAL;
}