Revert "CHROMIUM: Add /dev/low-mem device for low-memory notification."
This reverts commit 7a62ca9c46c556ebb857e754d97c456faa82dc9d.
diff --git a/drivers/char/mem.c b/drivers/char/mem.c
index d041226c..43dd089 100644
--- a/drivers/char/mem.c
+++ b/drivers/char/mem.c
@@ -31,7 +31,6 @@
#include <linux/uio.h>
#include <linux/uaccess.h>
#include <linux/security.h>
-#include <linux/low-mem-notify.h>
#ifdef CONFIG_IA64
# include <linux/efi.h>
@@ -902,9 +901,6 @@
#ifdef CONFIG_PRINTK
[11] = { "kmsg", 0644, &kmsg_fops, 0 },
#endif
-#ifdef CONFIG_LOW_MEM_NOTIFY
- [12] = { "chromeos-low-mem", 0666, &low_mem_notify_fops, 0 },
-#endif
};
static int memory_open(struct inode *inode, struct file *filp)
diff --git a/include/linux/low-mem-notify.h b/include/linux/low-mem-notify.h
deleted file mode 100644
index 63bed13..0000000
--- a/include/linux/low-mem-notify.h
+++ /dev/null
@@ -1,150 +0,0 @@
-#ifndef _LINUX_LOW_MEM_NOTIFY_H
-#define _LINUX_LOW_MEM_NOTIFY_H
-
-#include <linux/mm.h>
-#include <linux/ratelimit.h>
-#include <linux/stddef.h>
-#include <linux/swap.h>
-
-/* We support up to this many different thresholds. */
-#define LOW_MEM_THRESHOLD_MAX 5
-
-extern unsigned long low_mem_thresholds[];
-extern unsigned int low_mem_threshold_count;
-extern unsigned int low_mem_threshold_last;
-extern const struct file_operations low_mem_notify_fops;
-extern bool low_mem_margin_enabled;
-extern unsigned long low_mem_lowest_seen_anon_mem;
-extern unsigned int low_mem_ram_vs_swap_weight;
-extern struct ratelimit_state low_mem_logging_ratelimit;
-
-#ifdef CONFIG_SYSFS
-extern void low_mem_threshold_notify(void);
-#else
-static inline void low_mem_threshold_notify(void)
-{
-}
-#endif
-
-/*
- * Compute available memory used by files that can be reclaimed quickly.
- */
-static inline unsigned long get_available_file_mem(void)
-{
- unsigned long file_mem =
- global_node_page_state(NR_ACTIVE_FILE) +
- global_node_page_state(NR_INACTIVE_FILE);
- unsigned long dirty_mem = global_node_page_state(NR_FILE_DIRTY);
- unsigned long min_file_mem = min_filelist_kbytes >> (PAGE_SHIFT - 10);
- unsigned long clean_file_mem = file_mem - dirty_mem;
- /* Conservatively estimate the amount of available_file_mem */
- unsigned long available_file_mem = (clean_file_mem > min_file_mem) ?
- (clean_file_mem - min_file_mem) : 0;
- return available_file_mem;
-}
-
-/*
- * Available anonymous memory.
- */
-static inline unsigned long get_available_anon_mem(void)
-{
- return global_node_page_state(NR_ACTIVE_ANON) +
- global_node_page_state(NR_INACTIVE_ANON);
-}
-
-/*
- * Compute "available" memory, that is either free memory or memory that can be
- * reclaimed quickly, adjusted for the presence of swap.
- */
-static inline unsigned long get_available_mem_adj(void)
-{
- /* free_mem is completely unallocated; clean file-backed memory
- * (file_mem - dirty_mem) is easy to reclaim, except for the last
- * min_filelist_kbytes. totalreserve_pages is the reserve of pages that
- * are not available to user space.
- */
- unsigned long raw_free_mem = global_zone_page_state(NR_FREE_PAGES);
- unsigned long free_mem = (raw_free_mem > totalreserve_pages) ?
- raw_free_mem - totalreserve_pages : 0;
- unsigned long available_mem = free_mem +
- get_available_file_mem();
- unsigned long swappable_pages = min_t(unsigned long,
- get_nr_swap_pages(), get_available_anon_mem());
- /*
- * The contribution of swap is reduced by a factor of
- * low_mem_ram_vs_swap_weight.
- */
- return available_mem + swappable_pages / low_mem_ram_vs_swap_weight;
-}
-
-#ifdef CONFIG_LOW_MEM_NOTIFY
-void low_mem_notify(void);
-
-extern atomic_t in_low_mem_check;
-
-/*
- * Returns TRUE if we are in a low memory state.
- */
-static inline bool low_mem_check(void)
-{
- static bool was_low_mem; /* = false, as per style guide */
- /* We declare a low-memory condition when a combination of RAM and swap
- * space is low.
- */
- unsigned long available_mem = get_available_mem_adj();
- /*
- * For backwards compatibility with the older margin interface, we will
- * trigger the /dev/chromeos-low_mem device when we are below the
- * lowest threshold
- */
- bool is_low_mem = available_mem < low_mem_thresholds[0];
- unsigned int threshold_lowest = UINT_MAX;
- int i;
-
- if (!low_mem_margin_enabled)
- return false;
-
- if (atomic_xchg(&in_low_mem_check, 1))
- return was_low_mem;
-
- if (unlikely(is_low_mem && !was_low_mem) &&
- __ratelimit(&low_mem_logging_ratelimit)) {
- pr_info("entering low_mem (avail RAM = %lu kB, avail swap %lu kB, avail file %lu kB, anon mem: %lu kB)\n",
- available_mem * PAGE_SIZE / 1024,
- get_nr_swap_pages() * PAGE_SIZE / 1024,
- get_available_file_mem() * PAGE_SIZE / 1024,
- get_available_anon_mem() * PAGE_SIZE / 1024);
- }
- was_low_mem = is_low_mem;
-
- if (is_low_mem)
- low_mem_notify();
-
- for (i = 0; i < low_mem_threshold_count; i++)
- if (available_mem < low_mem_thresholds[i]) {
- threshold_lowest = i;
- break;
- }
-
- /* we crossed one or more thresholds */
- if (unlikely(threshold_lowest < low_mem_threshold_last))
- low_mem_threshold_notify();
-
- low_mem_threshold_last = threshold_lowest;
-
- atomic_set(&in_low_mem_check, 0);
-
- return is_low_mem;
-}
-#else
-static inline void low_mem_notify(void)
-{
-}
-
-static inline bool low_mem_check(void)
-{
- return false;
-}
-#endif
-
-#endif
diff --git a/mm/Kconfig b/mm/Kconfig
index 70fd8ce..7fbb7d1 100644
--- a/mm/Kconfig
+++ b/mm/Kconfig
@@ -753,17 +753,6 @@
config ARCH_HAS_HUGEPD
bool
-config LOW_MEM_NOTIFY
- bool "Create device that lets processes detect low-memory conditions"
- default n
- help
- A process can poll the /dev/low_mem device to be notified of
- low-memory conditions. The process can then attempt to free memory
- before a OOM condition develops and the OOM killer takes over. This
- is meant to be used in systems with no or very little swap space. In
- the presence of large swap space, the system is likely to become
- unusable before the OOM killer is triggered.
-
config MAPPING_DIRTY_HELPERS
bool
diff --git a/mm/Makefile b/mm/Makefile
index ed6efd0..272e660 100644
--- a/mm/Makefile
+++ b/mm/Makefile
@@ -102,7 +102,6 @@
obj-$(CONFIG_USERFAULTFD) += userfaultfd.o
obj-$(CONFIG_IDLE_PAGE_TRACKING) += page_idle.o
obj-$(CONFIG_FRAME_VECTOR) += frame_vector.o
-obj-$(CONFIG_LOW_MEM_NOTIFY) += low-mem-notify.o
obj-$(CONFIG_DEBUG_PAGE_REF) += debug_page_ref.o
obj-$(CONFIG_HARDENED_USERCOPY) += usercopy.o
obj-$(CONFIG_PERCPU_STATS) += percpu-stats.o
diff --git a/mm/low-mem-notify.c b/mm/low-mem-notify.c
deleted file mode 100644
index 1a9e3f7..0000000
--- a/mm/low-mem-notify.c
+++ /dev/null
@@ -1,293 +0,0 @@
-/*
- * mm/low-mem-notify.c
- *
- * Sends low-memory notifications to processes via /dev/low-mem.
- *
- * Copyright (C) 2012 The Chromium OS Authors
- * This program is free software, released under the GPL.
- * Based on a proposal by Minchan Kim
- *
- * A process that polls /dev/low-mem is notified of a low-memory situation.
- * The intent is to allow the process to free some memory before the OOM killer
- * is invoked.
- *
- * A low-memory condition is estimated by subtracting anonymous memory
- * (i.e. process data segments), kernel memory, and a fixed amount of
- * file-backed memory from total memory. This is just a heuristic, as in
- * general we don't know how much memory can be reclaimed before we try to
- * reclaim it, and that's too expensive or too late.
- *
- * This is tailored to Chromium OS, where a single program (the browser)
- * controls most of the memory, and (currently) no swap space is used.
- */
-
-
-#include <linux/low-mem-notify.h>
-#include <linux/module.h>
-#include <linux/sched.h>
-#include <linux/wait.h>
-#include <linux/poll.h>
-#include <linux/slab.h>
-#include <linux/mm.h>
-#include <linux/ctype.h>
-
-#define MB (1 << 20)
-
-static DECLARE_WAIT_QUEUE_HEAD(low_mem_wait);
-static atomic_t low_mem_state = ATOMIC_INIT(0);
-atomic_t in_low_mem_check = ATOMIC_INIT(0);
-
-/* This is a list of thresholds in pages and should be in ascending order. */
-unsigned long low_mem_thresholds[LOW_MEM_THRESHOLD_MAX] = {
- 50 * MB / PAGE_SIZE };
-unsigned int low_mem_threshold_count = 1;
-
-/* last observed threshold */
-unsigned int low_mem_threshold_last = UINT_MAX;
-bool low_mem_margin_enabled = true;
-unsigned int low_mem_ram_vs_swap_weight = 4;
-
-/* Limit logging low memory to once per second. */
-DEFINE_RATELIMIT_STATE(low_mem_logging_ratelimit, 1 * HZ, 1);
-
-unsigned long low_mem_lowest_seen_anon_mem;
-const unsigned long low_mem_anon_mem_delta = 10 * MB / PAGE_SIZE;
-static struct kernfs_node *low_mem_available_dirent;
-
-struct low_mem_notify_file_info {
- unsigned long unused;
-};
-
-void low_mem_notify(void)
-{
- atomic_set(&low_mem_state, true);
- wake_up(&low_mem_wait);
-}
-
-static int low_mem_notify_open(struct inode *inode, struct file *file)
-{
- struct low_mem_notify_file_info *info;
- int err = 0;
-
- info = kmalloc(sizeof(*info), GFP_KERNEL);
- if (!info) {
- err = -ENOMEM;
- goto out;
- }
-
- file->private_data = info;
-out:
- return err;
-}
-
-static int low_mem_notify_release(struct inode *inode, struct file *file)
-{
- kfree(file->private_data);
- return 0;
-}
-
-static __poll_t low_mem_notify_poll(struct file *file, poll_table *wait)
-{
- unsigned int ret = 0;
-
- /* Update state to reflect any recent freeing. */
- atomic_set(&low_mem_state, low_mem_check());
-
- poll_wait(file, &low_mem_wait, wait);
-
- if (low_mem_margin_enabled && atomic_read(&low_mem_state) != 0)
- ret = POLLIN;
-
- return ret;
-}
-
-const struct file_operations low_mem_notify_fops = {
- .open = low_mem_notify_open,
- .release = low_mem_notify_release,
- .poll = low_mem_notify_poll,
-};
-EXPORT_SYMBOL(low_mem_notify_fops);
-
-#ifdef CONFIG_SYSFS
-
-#define LOW_MEM_ATTR(_name) \
- static struct kobj_attribute low_mem_##_name##_attr = \
- __ATTR(_name, 0644, low_mem_##_name##_show, \
- low_mem_##_name##_store)
-
-static ssize_t low_mem_margin_show(struct kobject *kobj,
- struct kobj_attribute *attr, char *buf)
-{
- if (low_mem_margin_enabled && low_mem_threshold_count) {
- int i;
- ssize_t written = 0;
-
- for (i = 0; i < low_mem_threshold_count; i++)
- written += sprintf(buf + written, "%lu ",
- low_mem_thresholds[i] * PAGE_SIZE / MB);
- written += sprintf(buf + written, "\n");
- return written;
- } else
- return sprintf(buf, "off\n");
-}
-
-static ssize_t low_mem_margin_store(struct kobject *kobj,
- struct kobj_attribute *attr,
- const char *buf, size_t count)
-{
- int i = 0, consumed = 0;
- const char *start = buf;
- char *endp;
- unsigned long thresholds[LOW_MEM_THRESHOLD_MAX];
-
- memset(thresholds, 0, sizeof(thresholds));
- /*
- * Even though the API does not say anything about this, the string in
- * buf is zero-terminated (as long as count < PAGE_SIZE) because buf is
- * a newly allocated zero-filled page. Most other sysfs handlers rely
- * on this too.
- */
- if (strncmp("off", buf, 3) == 0) {
- pr_info("low_mem: disabling notifier\n");
- low_mem_margin_enabled = false;
- return count;
- }
- if (strncmp("on", buf, 2) == 0) {
- pr_info("low_mem: enabling notifier\n");
- low_mem_margin_enabled = true;
- return count;
- }
- /*
- * This takes a space separated list of thresholds in ascending order,
- * and a trailing newline is optional.
- */
- while (consumed < count) {
- if (i >= LOW_MEM_THRESHOLD_MAX) {
- pr_warn("low-mem: too many thresholds");
- return -EINVAL;
- }
- /* special case for trailing newline */
- if (*start == '\n')
- break;
-
- thresholds[i] = simple_strtoul(start, &endp, 0);
- if ((endp == start) && *endp != '\n')
- return -EINVAL;
-
- /* make sure each is larger than the last one */
- if (i && thresholds[i] <= thresholds[i - 1]) {
- pr_warn("low-mem: thresholds not in increasing order: %lu then %lu\n",
- thresholds[i - 1], thresholds[i]);
- return -EINVAL;
- }
-
- if (thresholds[i] * (MB / PAGE_SIZE) > totalram_pages()) {
- pr_warn("low-mem: threshold too high\n");
- return -EINVAL;
- }
-
- consumed += endp - start + 1;
- start = endp + 1;
- i++;
- }
-
- low_mem_threshold_count = i;
- low_mem_margin_enabled = !!low_mem_threshold_count;
-
- /* Convert to pages outside the allocator fast path. */
- for (i = 0; i < low_mem_threshold_count; i++) {
- low_mem_thresholds[i] =
- thresholds[i] * (MB / PAGE_SIZE);
- pr_info("low_mem: threshold[%d] %lu MB\n", i,
- low_mem_thresholds[i] * PAGE_SIZE / MB);
- }
-
- return count;
-}
-LOW_MEM_ATTR(margin);
-
-static ssize_t low_mem_ram_vs_swap_weight_show(struct kobject *kobj,
- struct kobj_attribute *attr,
- char *buf)
-{
- return sprintf(buf, "%u\n", low_mem_ram_vs_swap_weight);
-}
-
-static ssize_t low_mem_ram_vs_swap_weight_store(struct kobject *kobj,
- struct kobj_attribute *attr,
- const char *buf, size_t count)
-{
- unsigned long weight;
- int err;
-
- err = kstrtoul(buf, 10, &weight);
- if (err)
- return -EINVAL;
- /* The special value 0 represents infinity. */
- low_mem_ram_vs_swap_weight = weight == 0 ?
- -1U : (unsigned int) weight;
- pr_info("low_mem: setting ram weight to %u\n",
- low_mem_ram_vs_swap_weight);
- return count;
-}
-LOW_MEM_ATTR(ram_vs_swap_weight);
-
-static ssize_t low_mem_available_show(struct kobject *kobj,
- struct kobj_attribute *attr,
- char *buf)
-{
- unsigned long available_mem = get_available_mem_adj();
-
- return sprintf(buf, "%lu\n",
- available_mem / (MB / PAGE_SIZE));
-}
-
-static ssize_t low_mem_available_store(struct kobject *kobj,
- struct kobj_attribute *attr,
- const char *buf, size_t count)
-{
- return -EINVAL;
-}
-LOW_MEM_ATTR(available);
-
-static struct attribute *low_mem_attrs[] = {
- &low_mem_margin_attr.attr,
- &low_mem_ram_vs_swap_weight_attr.attr,
- &low_mem_available_attr.attr,
- NULL,
-};
-
-static struct attribute_group low_mem_attr_group = {
- .attrs = low_mem_attrs,
- .name = "chromeos-low_mem",
-};
-
-void low_mem_threshold_notify(void)
-{
- if (low_mem_available_dirent)
- sysfs_notify_dirent(low_mem_available_dirent);
-}
-
-static int __init low_mem_init(void)
-{
- struct kernfs_node *low_mem_node;
- int err = sysfs_create_group(mm_kobj, &low_mem_attr_group);
- if (err)
- pr_err("low_mem: register sysfs failed\n");
-
- low_mem_node = sysfs_get_dirent(mm_kobj->sd, "chromeos-low_mem");
- if (low_mem_node) {
- low_mem_available_dirent =
- sysfs_get_dirent(low_mem_node, "available");
- sysfs_put(low_mem_node);
- }
-
- if (!low_mem_available_dirent)
- pr_warn("unable to find dirent for \"available\" attribute\n");
-
- low_mem_lowest_seen_anon_mem = totalram_pages();
- return err;
-}
-module_init(low_mem_init)
-
-#endif
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index 7e7d0bc5..3c4eb75 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -68,7 +68,6 @@
#include <linux/lockdep.h>
#include <linux/nmi.h>
#include <linux/psi.h>
-#include <linux/low-mem-notify.h>
#include <asm/sections.h>
#include <asm/tlbflush.h>
@@ -4287,7 +4286,6 @@
* several times in the row.
*/
if (*no_progress_loops > MAX_RECLAIM_RETRIES) {
- low_mem_notify();
/* Before OOM, exhaust highatomic_reserve */
return unreserve_highatomic_pageblock(ac, true);
}
@@ -4723,8 +4721,6 @@
finalise_ac(gfp_mask, &ac);
- low_mem_check();
-
/*
* Forbid the first pass from falling back to types that fragment
* memory until all local zones are considered.
diff --git a/tools/mm/low-mem-test.c b/tools/mm/low-mem-test.c
deleted file mode 100644
index e5cc839..0000000
--- a/tools/mm/low-mem-test.c
+++ /dev/null
@@ -1,178 +0,0 @@
-/* Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
- * This program is free software, released under the GPL.
- * Based on code by Minchan Kim
- *
- * User program that tests low-memory notifications.
- *
- * Compile with -lpthread
- * for instance
- * i686-pc-linux-gnu-gcc low-mem-test.c -o low-mem-test -lpthread
- *
- * Run as: low-mem-test <allocation size> <allocation interval (microseconds)>
- *
- * This program runs in two threads. One thread continuously allocates memory
- * in the given chunk size, waiting for the specified microsecond interval
- * between allocations. The other runs in a loop that waits for a low-memory
- * notification, then frees some of the memory that the first thread has
- * allocated.
- */
-
-#include <poll.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <stdio.h>
-#include <pthread.h>
-#include <stdlib.h>
-#include <string.h>
-
-int memory_chunk_size = 10000000;
-int wait_time_us = 10000;
-int autotesting;
-
-pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
-
-struct node {
- void *memory;
- struct node *prev;
- struct node *next;
-};
-
-struct node head, tail;
-
-void work(void)
-{
- int i;
-
- while (1) {
- struct node *new = malloc(sizeof(struct node));
- if (new == NULL) {
- perror("allocating node");
- exit(1);
- }
- new->memory = malloc(memory_chunk_size);
- if (new->memory == NULL) {
- perror("allocating chunk");
- exit(1);
- }
-
- pthread_mutex_lock(&mutex);
- new->next = &head;
- new->prev = head.prev;
- new->prev->next = new;
- new->next->prev = new;
- for (i = 0; i < memory_chunk_size / 4096; i++) {
- /* touch page */
- ((unsigned char *) new->memory)[i * 4096] = 1;
- }
-
- pthread_mutex_unlock(&mutex);
-
- if (!autotesting) {
- printf("+");
- fflush(stdout);
- }
-
- usleep(wait_time_us);
- }
-}
-
-void free_memory(void)
-{
- struct node *old;
- pthread_mutex_lock(&mutex);
- old = tail.next;
- if (old == &head) {
- fprintf(stderr, "no memory left to free\n");
- exit(1);
- }
- old->prev->next = old->next;
- old->next->prev = old->prev;
- free(old->memory);
- free(old);
- pthread_mutex_unlock(&mutex);
- if (!autotesting) {
- printf("-");
- fflush(stdout);
- }
-}
-
-void *poll_thread(void *dummy)
-{
- struct pollfd pfd;
- int fd = open("/dev/chromeos-low-mem", O_RDONLY);
- if (fd == -1) {
- perror("/dev/chromeos-low-mem");
- exit(1);
- }
-
- pfd.fd = fd;
- pfd.events = POLLIN;
-
- if (autotesting) {
- /* Check that there is no memory shortage yet. */
- poll(&pfd, 1, 0);
- if (pfd.revents != 0) {
- exit(0);
- } else {
- fprintf(stderr, "expected no events but "
- "poll() returned 0x%x\n", pfd.revents);
- exit(1);
- }
- }
-
- while (1) {
- poll(&pfd, 1, -1);
- if (autotesting) {
- /* Free several chunks and check that the notification
- * is gone. */
- free_memory();
- free_memory();
- free_memory();
- free_memory();
- free_memory();
- poll(&pfd, 1, 0);
- if (pfd.revents == 0) {
- exit(0);
- } else {
- fprintf(stderr, "expected no events but "
- "poll() returned 0x%x\n", pfd.revents);
- exit(1);
- }
- }
- free_memory();
- }
-}
-
-int main(int argc, char **argv)
-{
- pthread_t threadid;
-
- head.next = NULL;
- head.prev = &tail;
- tail.next = &head;
- tail.prev = NULL;
-
- if (argc != 3 && (argc != 2 || strcmp(argv[1], "autotesting"))) {
- fprintf(stderr,
- "usage: low-mem-test <alloc size in bytes> "
- "<alloc interval in microseconds>\n"
- "or: low-mem-test autotesting\n");
- exit(1);
- }
-
- if (argc == 2) {
- autotesting = 1;
- } else {
- memory_chunk_size = atoi(argv[1]);
- wait_time_us = atoi(argv[2]);
- }
-
- if (pthread_create(&threadid, NULL, poll_thread, NULL)) {
- perror("pthread");
- return 1;
- }
-
- work();
- return 0;
-}