#include #include #include #include #include "tools-util.h" static LIST_HEAD(shrinker_list); static DEFINE_MUTEX(shrinker_lock); int register_shrinker(struct shrinker *shrinker) { mutex_lock(&shrinker_lock); list_add_tail(&shrinker->list, &shrinker_list); mutex_unlock(&shrinker_lock); return 0; } void unregister_shrinker(struct shrinker *shrinker) { mutex_lock(&shrinker_lock); list_del(&shrinker->list); mutex_unlock(&shrinker_lock); } struct meminfo { u64 total; u64 available; }; static u64 parse_meminfo_line(const char *line) { u64 v; if (sscanf(line, " %llu kB", &v) < 1) die("sscanf error"); return v << 10; } static struct meminfo read_meminfo(void) { struct meminfo ret = { 0 }; size_t len, n = 0; char *line = NULL; const char *v; FILE *f; f = fopen("/proc/meminfo", "r"); if (!f) return ret; while ((len = getline(&line, &n, f)) != -1) { if ((v = strcmp_prefix(line, "MemTotal:"))) ret.total = parse_meminfo_line(v); if ((v = strcmp_prefix(line, "MemAvailable:"))) ret.available = parse_meminfo_line(v); } fclose(f); free(line); return ret; } void run_shrinkers(void) { struct shrinker *shrinker; struct meminfo info; s64 want_shrink; /* Fast out if there are no shrinkers to run. */ if (list_empty(&shrinker_list)) return; info = read_meminfo(); if (info.total && info.available) { want_shrink = (info.total >> 2) - info.available; if (want_shrink <= 0) return; } else { /* If we weren't able to read /proc/meminfo, we must be pretty * low: */ want_shrink = 8 << 20; } mutex_lock(&shrinker_lock); list_for_each_entry(shrinker, &shrinker_list, list) { struct shrink_control sc = { .nr_to_scan = want_shrink >> PAGE_SHIFT }; shrinker->scan_objects(shrinker, &sc); } mutex_unlock(&shrinker_lock); }