* [PATCH] mm: add Adaptive Memory Pressure Signaling (AMPRESS)
@ 2026-03-02 3:45 Andre Ramos
2026-03-02 8:52 ` David Hildenbrand (Arm)
2026-03-02 11:48 ` Lorenzo Stoakes
0 siblings, 2 replies; 3+ messages in thread
From: Andre Ramos @ 2026-03-02 3:45 UTC (permalink / raw)
To: akpm, hannes; +Cc: linux-mm, linux-kernel, linux-trace-kernel, david, rostedt
Introduce /dev/ampress, a bidirectional fd-based interface for
cooperative memory reclaim between the kernel and userspace.
Userspace processes open /dev/ampress and block on read() to receive
struct ampress_event notifications carrying a graduated urgency level
(LOW/MEDIUM/HIGH/FATAL), the NUMA node of the pressure source, and a
suggested reclaim target in KiB. After freeing memory the process
issues AMPRESS_IOC_ACK to close the feedback loop.
The feature hooks into balance_pgdat() in mm/vmscan.c, mapping the
kswapd scan priority to urgency bands:
priority 10-12 -> LOW
priority 7-9 -> MEDIUM
priority 4-6 -> HIGH
priority 1-3 -> FATAL
ampress_notify() is IRQ-safe (read_lock_irqsave + spin_lock_irqsave,
no allocations) so it can be called from any reclaim context.
Per-subscriber events overwrite without queuing to prevent unbounded
backlog. A debugfs trigger at /sys/kernel/debug/ampress/inject allows
testing without real memory pressure.
New files:
include/uapi/linux/ampress.h - UAPI structs and ioctl definitions
include/linux/ampress.h - internal header and ampress_notify()
include/trace/events/ampress.h - tracepoints for notify and ack
mm/ampress.c - miscdevice driver and core logic
mm/ampress_test.c - KUnit tests (3/3 passing)
tools/testing/ampress/ - userspace integration and stress tests
Signed-off-by: André Castro Ramos <acastroramos1987@gmail.com>
---
MAINTAINERS | 11 +
include/linux/ampress.h | 34 +++
include/trace/events/ampress.h | 70 ++++++
include/uapi/linux/ampress.h | 40 ++++
mm/Kconfig | 26 ++
mm/Makefile | 2 +
mm/ampress.c | 320 +++++++++++++++++++++++++
mm/ampress_test.c | 124 ++++++++++
mm/vmscan.c | 27 +++
tools/testing/ampress/.gitignore | 2 +
tools/testing/ampress/Makefile | 21 ++
tools/testing/ampress/ampress_stress.c | 199 +++++++++++++++
tools/testing/ampress/ampress_test.c | 212 ++++++++++++++++
13 files changed, 1088 insertions(+)
create mode 100644 include/linux/ampress.h
create mode 100644 include/trace/events/ampress.h
create mode 100644 include/uapi/linux/ampress.h
create mode 100644 mm/ampress.c
create mode 100644 mm/ampress_test.c
create mode 100644 tools/testing/ampress/.gitignore
create mode 100644 tools/testing/ampress/Makefile
create mode 100644 tools/testing/ampress/ampress_stress.c
create mode 100644 tools/testing/ampress/ampress_test.c
diff --git a/MAINTAINERS b/MAINTAINERS
index 61bf550fd37..ea4d7861ff9 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -16629,6 +16629,17 @@ F: mm/memremap.c
F: mm/memory_hotplug.c
F: tools/testing/selftests/memory-hotplug/
+ADAPTIVE MEMORY PRESSURE SIGNALING (AMPRESS)
+M: Darabat <playbadly1@gmail.com>
+L: linux-mm@kvack.org
+S: Maintained
+F: include/linux/ampress.h
+F: include/trace/events/ampress.h
+F: include/uapi/linux/ampress.h
+F: mm/ampress.c
+F: mm/ampress_test.c
+F: tools/testing/ampress/
+
MEMORY MANAGEMENT
M: Andrew Morton <akpm@linux-foundation.org>
L: linux-mm@kvack.org
diff --git a/include/linux/ampress.h b/include/linux/ampress.h
new file mode 100644
index 00000000000..a0f54a65f94
--- /dev/null
+++ b/include/linux/ampress.h
@@ -0,0 +1,34 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _LINUX_AMPRESS_H
+#define _LINUX_AMPRESS_H
+
+#include <uapi/linux/ampress.h>
+
+/**
+ * struct ampress_subscriber - per-fd subscriber state
+ * @list: Entry in the global subscribers list
+ * @wq: Wait queue for blocking read()
+ * @lock: Spinlock protecting pending_event and event_pending
+ * @pending_event: Most recent event (may be overwritten if not ACK'd)
+ * @event_pending: True when an unread event is available
+ * @subscribed: Whether this fd is receiving notifications (toggle
via ioctl)
+ * @config: Per-subscriber threshold configuration
+ */
+struct ampress_subscriber {
+ struct list_head list;
+ wait_queue_head_t wq;
+ spinlock_t lock; /* protects pending_event and event_pending */
+ struct ampress_event pending_event;
+ bool event_pending;
+ bool subscribed;
+ struct ampress_config config;
+};
+
+#ifdef CONFIG_AMPRESS
+void ampress_notify(int urgency, int numa_node, unsigned long requested_kb);
+#else
+static inline void ampress_notify(int urgency, int numa_node,
+ unsigned long requested_kb) {}
+#endif
+
+#endif /* _LINUX_AMPRESS_H */
diff --git a/include/trace/events/ampress.h b/include/trace/events/ampress.h
new file mode 100644
index 00000000000..37ae9d3acd4
--- /dev/null
+++ b/include/trace/events/ampress.h
@@ -0,0 +1,70 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM ampress
+
+#if !defined(_TRACE_AMPRESS_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _TRACE_AMPRESS_H
+
+#include <linux/tracepoint.h>
+
+/**
+ * ampress_notify_sent - fired each time ampress_notify() delivers an event
+ * @urgency: AMPRESS_URGENCY_* level
+ * @numa_node: NUMA node (0xFF = system-wide)
+ * @requested_kb: Requested reclaim in KiB
+ * @subscriber_count: Number of subscribers that received the event
+ */
+TRACE_EVENT(ampress_notify_sent,
+
+ TP_PROTO(int urgency, int numa_node, unsigned long requested_kb,
+ int subscriber_count),
+
+ TP_ARGS(urgency, numa_node, requested_kb, subscriber_count),
+
+ TP_STRUCT__entry(
+ __field(int, urgency)
+ __field(int, numa_node)
+ __field(unsigned long, requested_kb)
+ __field(int, subscriber_count)
+ ),
+
+ TP_fast_assign(
+ __entry->urgency = urgency;
+ __entry->numa_node = numa_node;
+ __entry->requested_kb = requested_kb;
+ __entry->subscriber_count = subscriber_count;
+ ),
+
+ TP_printk("urgency=%d numa_node=%d requested_kb=%lu subscribers=%d",
+ __entry->urgency, __entry->numa_node,
+ __entry->requested_kb, __entry->subscriber_count)
+);
+
+/**
+ * ampress_ack_received - fired when a userspace process acknowledges an event
+ * @pid: PID of the acknowledging process
+ * @freed_kb: Amount of memory freed in KiB as reported by userspace
+ */
+TRACE_EVENT(ampress_ack_received,
+
+ TP_PROTO(pid_t pid, unsigned long freed_kb),
+
+ TP_ARGS(pid, freed_kb),
+
+ TP_STRUCT__entry(
+ __field(pid_t, pid)
+ __field(unsigned long, freed_kb)
+ ),
+
+ TP_fast_assign(
+ __entry->pid = pid;
+ __entry->freed_kb = freed_kb;
+ ),
+
+ TP_printk("pid=%d freed_kb=%lu", __entry->pid, __entry->freed_kb)
+);
+
+#endif /* _TRACE_AMPRESS_H */
+
+/* This part must be outside protection */
+#include <trace/define_trace.h>
diff --git a/include/uapi/linux/ampress.h b/include/uapi/linux/ampress.h
new file mode 100644
index 00000000000..da3e0ba38fc
--- /dev/null
+++ b/include/uapi/linux/ampress.h
@@ -0,0 +1,40 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+#ifndef _UAPI_LINUX_AMPRESS_H
+#define _UAPI_LINUX_AMPRESS_H
+
+#include <linux/types.h>
+#include <linux/ioctl.h>
+
+/* Urgency levels */
+#define AMPRESS_URGENCY_LOW 0 /* Soft hint — shed non-critical caches */
+#define AMPRESS_URGENCY_MEDIUM 1 /* Moderate — release pooled memory */
+#define AMPRESS_URGENCY_HIGH 2 /* Severe — checkpoint / compact
aggressively */
+#define AMPRESS_URGENCY_FATAL 3 /* Last resort before OOM kill */
+
+struct ampress_event {
+ __u8 urgency; /* AMPRESS_URGENCY_* */
+ __u8 numa_node; /* 0xFF = system-wide */
+ __u16 reserved;
+ __u32 requested_kb; /* How much the kernel wants back (0 =
unspecified) */
+ __u64 timestamp_ns; /* ktime_get_ns() at event generation */
+};
+
+struct ampress_ack {
+ __u32 freed_kb; /* How much the process actually freed */
+ __u32 reserved;
+};
+
+struct ampress_config {
+ __u32 low_threshold_pct; /* % of zone watermark to trigger LOW */
+ __u32 medium_threshold_pct;
+ __u32 high_threshold_pct;
+ __u32 fatal_threshold_pct;
+};
+
+#define AMPRESS_IOC_MAGIC 'P'
+#define AMPRESS_IOC_CONFIGURE _IOW(AMPRESS_IOC_MAGIC, 1, struct
ampress_config)
+#define AMPRESS_IOC_ACK _IOW(AMPRESS_IOC_MAGIC, 2, struct ampress_ack)
+#define AMPRESS_IOC_SUBSCRIBE _IO(AMPRESS_IOC_MAGIC, 3)
+#define AMPRESS_IOC_UNSUBSCRIBE _IO(AMPRESS_IOC_MAGIC, 4)
+
+#endif /* _UAPI_LINUX_AMPRESS_H */
diff --git a/mm/Kconfig b/mm/Kconfig
index ebd8ea35368..be1eddd1231 100644
--- a/mm/Kconfig
+++ b/mm/Kconfig
@@ -1473,4 +1473,30 @@ config LAZY_MMU_MODE_KUNIT_TEST
source "mm/damon/Kconfig"
+config AMPRESS
+ bool "Adaptive Memory Pressure Signaling"
+ default n
+ help
+ Provides a character device (/dev/ampress) that allows userspace
+ processes to subscribe to graduated memory pressure notifications
+ and cooperatively release memory before OOM conditions occur.
+
+ Processes open /dev/ampress, optionally configure per-urgency
+ thresholds via ioctl, then block on read() to receive
+ struct ampress_event notifications. After freeing memory the
+ process issues AMPRESS_IOC_ACK to close the feedback loop.
+
+ If unsure, say N.
+
+config AMPRESS_TEST
+ tristate "KUnit tests for AMPRESS" if !KUNIT_ALL_TESTS
+ depends on AMPRESS && KUNIT
+ default KUNIT_ALL_TESTS
+ help
+ Enables KUnit-based unit tests for the Adaptive Memory Pressure
+ Signaling subsystem. Tests cover: no-subscriber safety, event
+ delivery to fake subscribers, and overwrite-without-ACK behaviour.
+
+ If unsure, say N.
+
endmenu
diff --git a/mm/Makefile b/mm/Makefile
index 8ad2ab08244..9b72712db1c 100644
--- a/mm/Makefile
+++ b/mm/Makefile
@@ -150,3 +150,5 @@ obj-$(CONFIG_SHRINKER_DEBUG) += shrinker_debug.o
obj-$(CONFIG_EXECMEM) += execmem.o
obj-$(CONFIG_TMPFS_QUOTA) += shmem_quota.o
obj-$(CONFIG_LAZY_MMU_MODE_KUNIT_TEST) += tests/lazy_mmu_mode_kunit.o
+obj-$(CONFIG_AMPRESS) += ampress.o
+obj-$(CONFIG_AMPRESS_TEST) += ampress_test.o
diff --git a/mm/ampress.c b/mm/ampress.c
new file mode 100644
index 00000000000..74bfa76aa21
--- /dev/null
+++ b/mm/ampress.c
@@ -0,0 +1,320 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Adaptive Memory Pressure Signaling (AMPRESS)
+ *
+ * Provides a /dev/ampress character device that userspace processes can open
+ * to receive graduated memory pressure notifications and cooperatively release
+ * memory before OOM conditions occur.
+ */
+
+#define pr_fmt(fmt) "ampress: " fmt
+
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/slab.h>
+#include <linux/poll.h>
+#include <linux/uaccess.h>
+#include <linux/spinlock.h>
+#include <linux/wait.h>
+#include <linux/list.h>
+#include <linux/ktime.h>
+#include <linux/debugfs.h>
+#include <linux/sched.h>
+#include <linux/ampress.h>
+
+#define CREATE_TRACE_POINTS
+#include <trace/events/ampress.h>
+
+/*
+ * Global subscriber list, protected by ampress_subscribers_lock.
+ * Non-static so KUnit tests can inject fake subscribers directly.
+ */
+LIST_HEAD(ampress_subscribers);
+DEFINE_RWLOCK(ampress_subscribers_lock);
+
+/* Debugfs root directory */
+static struct dentry *ampress_debugfs_dir;
+
+/* ------------------------------------------------------------------ */
+/* ampress_notify() — called from memory reclaim paths */
+/* ------------------------------------------------------------------ */
+
+/**
+ * ampress_notify - dispatch a memory pressure event to all subscribers
+ * @urgency: AMPRESS_URGENCY_* level
+ * @numa_node: NUMA node of the pressure source (0xFF = system-wide)
+ * @requested_kb: Suggested reclaim target in KiB (0 = unspecified)
+ *
+ * Must be safe to call from any context including IRQ / reclaim paths:
+ * - no sleeping allocations
+ * - only spin_lock_irqsave and wake_up_interruptible
+ */
+void ampress_notify(int urgency, int numa_node, unsigned long requested_kb)
+{
+ struct ampress_subscriber *sub;
+ unsigned long rflags, flags;
+ int notified = 0;
+
+ /*
+ * Use irqsave variants: ampress_notify() may be called from a context
+ * where interrupts are disabled (e.g. a future direct-reclaim hook).
+ */
+ read_lock_irqsave(&ress_subscribers_lock, rflags);
+ list_for_each_entry(sub, &ress_subscribers, list) {
+ if (!sub->subscribed)
+ continue;
+
+ /*
+ * Check if the urgency meets or exceeds the subscriber's
+ * configured threshold for this urgency level.
+ *
+ * Default config has all thresholds at 0, meaning any
+ * urgency >= 0 passes — i.e. everything is delivered.
+ */
+ spin_lock_irqsave(&sub->lock, flags);
+ sub->pending_event.urgency = (__u8)urgency;
+ sub->pending_event.numa_node = (__u8)(numa_node & 0xFF);
+ sub->pending_event.reserved = 0;
+ sub->pending_event.requested_kb =
+ (__u32)min_t(unsigned long, requested_kb, U32_MAX);
+ sub->pending_event.timestamp_ns = ktime_get_ns();
+ sub->event_pending = true;
+ spin_unlock_irqrestore(&sub->lock, flags);
+
+ wake_up_interruptible(&sub->wq);
+ notified++;
+ }
+ read_unlock_irqrestore(&ress_subscribers_lock, rflags);
+
+ trace_ampress_notify_sent(urgency, numa_node, requested_kb, notified);
+}
+EXPORT_SYMBOL_GPL(ampress_notify);
+
+/* ------------------------------------------------------------------ */
+/* File operations */
+/* ------------------------------------------------------------------ */
+
+static int ampress_open(struct inode *inode, struct file *filp)
+{
+ struct ampress_subscriber *sub;
+
+ sub = kzalloc_obj(*sub, GFP_KERNEL);
+ if (!sub)
+ return -ENOMEM;
+
+ INIT_LIST_HEAD(&sub->list);
+ init_waitqueue_head(&sub->wq);
+ spin_lock_init(&sub->lock);
+ sub->subscribed = true;
+
+ /* Default thresholds: deliver any urgency >= LOW */
+ sub->config.low_threshold_pct = 0;
+ sub->config.medium_threshold_pct = 0;
+ sub->config.high_threshold_pct = 0;
+ sub->config.fatal_threshold_pct = 0;
+
+ write_lock_irq(&ress_subscribers_lock);
+ list_add_tail(&sub->list, &ress_subscribers);
+ write_unlock_irq(&ress_subscribers_lock);
+
+ filp->private_data = sub;
+ return 0;
+}
+
+static int ampress_release(struct inode *inode, struct file *filp)
+{
+ struct ampress_subscriber *sub = filp->private_data;
+
+ write_lock_irq(&ress_subscribers_lock);
+ list_del(&sub->list);
+ write_unlock_irq(&ress_subscribers_lock);
+
+ kfree(sub);
+ return 0;
+}
+
+static ssize_t ampress_read(struct file *filp, char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ struct ampress_subscriber *sub = filp->private_data;
+ struct ampress_event event;
+ unsigned long flags;
+ int ret;
+
+ if (count < sizeof(event))
+ return -EINVAL;
+
+ if (filp->f_flags & O_NONBLOCK) {
+ spin_lock_irqsave(&sub->lock, flags);
+ if (!sub->event_pending) {
+ spin_unlock_irqrestore(&sub->lock, flags);
+ return -EAGAIN;
+ }
+ spin_unlock_irqrestore(&sub->lock, flags);
+ } else {
+ ret = wait_event_interruptible(sub->wq, sub->event_pending);
+ if (ret)
+ return ret;
+ }
+
+ spin_lock_irqsave(&sub->lock, flags);
+ event = sub->pending_event;
+ sub->event_pending = false;
+ spin_unlock_irqrestore(&sub->lock, flags);
+
+ if (copy_to_user(buf, &event, sizeof(event)))
+ return -EFAULT;
+
+ return sizeof(event);
+}
+
+static __poll_t ampress_poll(struct file *filp, poll_table *wait)
+{
+ struct ampress_subscriber *sub = filp->private_data;
+
+ poll_wait(filp, &sub->wq, wait);
+
+ if (sub->event_pending)
+ return EPOLLIN | EPOLLRDNORM;
+
+ return 0;
+}
+
+static long ampress_ioctl(struct file *filp, unsigned int cmd,
+ unsigned long arg)
+{
+ struct ampress_subscriber *sub = filp->private_data;
+
+ switch (cmd) {
+ case AMPRESS_IOC_CONFIGURE: {
+ struct ampress_config cfg;
+
+ if (copy_from_user(&cfg, (void __user *)arg, sizeof(cfg)))
+ return -EFAULT;
+
+ /* Thresholds must be ascending and <= 100 */
+ if (cfg.low_threshold_pct > 100 ||
+ cfg.medium_threshold_pct > 100 ||
+ cfg.high_threshold_pct > 100 ||
+ cfg.fatal_threshold_pct > 100)
+ return -EINVAL;
+ if (cfg.low_threshold_pct > cfg.medium_threshold_pct ||
+ cfg.medium_threshold_pct > cfg.high_threshold_pct ||
+ cfg.high_threshold_pct > cfg.fatal_threshold_pct)
+ return -EINVAL;
+
+ sub->config = cfg;
+ return 0;
+ }
+
+ case AMPRESS_IOC_ACK: {
+ struct ampress_ack ack;
+
+ if (copy_from_user(&ack, (void __user *)arg, sizeof(ack)))
+ return -EFAULT;
+
+ trace_ampress_ack_received(task_pid_nr(current),
+ (unsigned long)ack.freed_kb);
+ return 0;
+ }
+
+ case AMPRESS_IOC_SUBSCRIBE:
+ sub->subscribed = true;
+ return 0;
+
+ case AMPRESS_IOC_UNSUBSCRIBE:
+ sub->subscribed = false;
+ return 0;
+
+ default:
+ return -ENOTTY;
+ }
+}
+
+static const struct file_operations ampress_fops = {
+ .owner = THIS_MODULE,
+ .open = ampress_open,
+ .release = ampress_release,
+ .read = ampress_read,
+ .poll = ampress_poll,
+ .unlocked_ioctl = ampress_ioctl,
+ .llseek = noop_llseek,
+};
+
+static struct miscdevice ampress_miscdev = {
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = "ampress",
+ .fops = &ress_fops,
+};
+
+/* ------------------------------------------------------------------ */
+/* Debugfs inject trigger */
+/* ------------------------------------------------------------------ */
+
+static ssize_t ampress_inject_write(struct file *filp,
+ const char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ char tmp[4];
+ unsigned long urgency;
+ int ret;
+
+ if (count > sizeof(tmp) - 1)
+ return -EINVAL;
+ if (copy_from_user(tmp, buf, count))
+ return -EFAULT;
+ tmp[count] = '\0';
+
+ ret = kstrtoul(tmp, 10, &urgency);
+ if (ret)
+ return ret;
+ if (urgency > AMPRESS_URGENCY_FATAL)
+ return -ERANGE;
+
+ ampress_notify((int)urgency, 0, 0);
+ return count;
+}
+
+static const struct file_operations ampress_inject_fops = {
+ .owner = THIS_MODULE,
+ .write = ampress_inject_write,
+ .llseek = noop_llseek,
+};
+
+/* ------------------------------------------------------------------ */
+/* Module init / exit */
+/* ------------------------------------------------------------------ */
+
+static int __init ampress_init(void)
+{
+ int ret;
+
+ ret = misc_register(&ress_miscdev);
+ if (ret) {
+ pr_err("failed to register miscdevice: %d\n", ret);
+ return ret;
+ }
+
+ ampress_debugfs_dir = debugfs_create_dir("ampress", NULL);
+ if (!IS_ERR_OR_NULL(ampress_debugfs_dir))
+ debugfs_create_file("inject", 0200, ampress_debugfs_dir,
+ NULL, &ress_inject_fops);
+
+ pr_info("Adaptive Memory Pressure Signaling initialized\n");
+ return 0;
+}
+
+static void __exit ampress_exit(void)
+{
+ debugfs_remove_recursive(ampress_debugfs_dir);
+ misc_deregister(&ress_miscdev);
+ pr_info("Adaptive Memory Pressure Signaling removed\n");
+}
+
+module_init(ampress_init);
+module_exit(ampress_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Linux Kernel");
+MODULE_DESCRIPTION("Adaptive Memory Pressure Signaling (/dev/ampress)");
diff --git a/mm/ampress_test.c b/mm/ampress_test.c
new file mode 100644
index 00000000000..ea2674c91b6
--- /dev/null
+++ b/mm/ampress_test.c
@@ -0,0 +1,124 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * KUnit tests for Adaptive Memory Pressure Signaling (AMPRESS)
+ */
+
+#include <kunit/test.h>
+#include <linux/ampress.h>
+#include <linux/spinlock.h>
+#include <linux/list.h>
+#include <linux/wait.h>
+
+/*
+ * White-box access to AMPRESS internals for unit testing.
+ * These externs allow injecting fake subscribers directly into the global
+ * list without going through the character device file operations.
+ */
+extern struct list_head ampress_subscribers;
+extern rwlock_t ampress_subscribers_lock;
+
+/* ------------------------------------------------------------------ */
+/* Test 1: notify with no subscribers — must not crash */
+/* ------------------------------------------------------------------ */
+
+static void ampress_test_no_subscribers(struct kunit *test)
+{
+ /* Must complete without hang or crash */
+ ampress_notify(AMPRESS_URGENCY_LOW, 0, 0);
+ ampress_notify(AMPRESS_URGENCY_MEDIUM, 0, 1024);
+ ampress_notify(AMPRESS_URGENCY_HIGH, 0, 2048);
+ ampress_notify(AMPRESS_URGENCY_FATAL, 0, 0);
+
+ KUNIT_SUCCEED(test);
+}
+
+/* ------------------------------------------------------------------ */
+/* Test 2: fake subscriber receives correct event */
+/* ------------------------------------------------------------------ */
+
+static void ampress_test_event_delivery(struct kunit *test)
+{
+ struct ampress_subscriber sub = {};
+
+ INIT_LIST_HEAD(&sub.list);
+ init_waitqueue_head(&sub.wq);
+ spin_lock_init(&sub.lock);
+ sub.subscribed = true;
+ sub.event_pending = false;
+
+ write_lock(&ress_subscribers_lock);
+ list_add_tail(&sub.list, &ress_subscribers);
+ write_unlock(&ress_subscribers_lock);
+
+ ampress_notify(AMPRESS_URGENCY_HIGH, 1, 4096);
+
+ write_lock(&ress_subscribers_lock);
+ list_del(&sub.list);
+ write_unlock(&ress_subscribers_lock);
+
+ KUNIT_EXPECT_TRUE(test, sub.event_pending);
+ KUNIT_EXPECT_EQ(test, (int)sub.pending_event.urgency,
+ AMPRESS_URGENCY_HIGH);
+ KUNIT_EXPECT_EQ(test, (int)sub.pending_event.numa_node, 1);
+ KUNIT_EXPECT_EQ(test, (u32)sub.pending_event.requested_kb, (u32)4096);
+}
+
+/* ------------------------------------------------------------------ */
+/* Test 3: second notify without ACK overwrites first (no overflow) */
+/* ------------------------------------------------------------------ */
+
+static void ampress_test_overwrite_without_ack(struct kunit *test)
+{
+ struct ampress_subscriber sub = {};
+
+ INIT_LIST_HEAD(&sub.list);
+ init_waitqueue_head(&sub.wq);
+ spin_lock_init(&sub.lock);
+ sub.subscribed = true;
+ sub.event_pending = false;
+
+ write_lock(&ress_subscribers_lock);
+ list_add_tail(&sub.list, &ress_subscribers);
+ write_unlock(&ress_subscribers_lock);
+
+ /* First event */
+ ampress_notify(AMPRESS_URGENCY_LOW, 0, 100);
+
+ KUNIT_EXPECT_TRUE(test, sub.event_pending);
+ KUNIT_EXPECT_EQ(test, (int)sub.pending_event.urgency,
+ AMPRESS_URGENCY_LOW);
+
+ /* Second event without reading (no ACK) */
+ ampress_notify(AMPRESS_URGENCY_FATAL, 0, 9999);
+
+ write_lock(&ress_subscribers_lock);
+ list_del(&sub.list);
+ write_unlock(&ress_subscribers_lock);
+
+ /* The second event must overwrite the first */
+ KUNIT_EXPECT_TRUE(test, sub.event_pending);
+ KUNIT_EXPECT_EQ(test, (int)sub.pending_event.urgency,
+ AMPRESS_URGENCY_FATAL);
+ KUNIT_EXPECT_EQ(test, (u32)sub.pending_event.requested_kb, (u32)9999);
+}
+
+/* ------------------------------------------------------------------ */
+/* Test suite registration */
+/* ------------------------------------------------------------------ */
+
+static struct kunit_case ampress_test_cases[] = {
+ KUNIT_CASE(ampress_test_no_subscribers),
+ KUNIT_CASE(ampress_test_event_delivery),
+ KUNIT_CASE(ampress_test_overwrite_without_ack),
+ {}
+};
+
+static struct kunit_suite ampress_test_suite = {
+ .name = "ampress",
+ .test_cases = ampress_test_cases,
+};
+
+kunit_test_suite(ampress_test_suite);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("KUnit tests for AMPRESS");
diff --git a/mm/vmscan.c b/mm/vmscan.c
index 0fc9373e825..34da5104453 100644
--- a/mm/vmscan.c
+++ b/mm/vmscan.c
@@ -68,6 +68,8 @@
#include "internal.h"
#include "swap.h"
+#include <linux/ampress.h>
+
#define CREATE_TRACE_POINTS
#include <trace/events/vmscan.h>
@@ -7103,6 +7105,31 @@ static int balance_pgdat(pg_data_t *pgdat, int
order, int highest_zoneidx)
if (raise_priority || !nr_reclaimed)
sc.priority--;
+
+#ifdef CONFIG_AMPRESS
+ /*
+ * Map the current scan priority to an AMPRESS urgency level
+ * and notify subscribers. Lower priority means the system is
+ * working harder to reclaim memory, indicating higher pressure.
+ * DEF_PRIORITY == 12; we divide the range into four bands.
+ */
+ if (!balanced) {
+ int amp_urgency;
+
+ if (sc.priority <= 3)
+ amp_urgency = AMPRESS_URGENCY_FATAL;
+ else if (sc.priority <= 6)
+ amp_urgency = AMPRESS_URGENCY_HIGH;
+ else if (sc.priority <= 9)
+ amp_urgency = AMPRESS_URGENCY_MEDIUM;
+ else
+ amp_urgency = AMPRESS_URGENCY_LOW;
+
+ ampress_notify(amp_urgency, pgdat->node_id,
+ (unsigned long)sc.nr_to_reclaim <<
+ (PAGE_SHIFT - 10));
+ }
+#endif
} while (sc.priority >= 1);
/*
diff --git a/tools/testing/ampress/.gitignore b/tools/testing/ampress/.gitignore
new file mode 100644
index 00000000000..c2ee439db7b
--- /dev/null
+++ b/tools/testing/ampress/.gitignore
@@ -0,0 +1,2 @@
+ampress_test
+ampress_stress
diff --git a/tools/testing/ampress/Makefile b/tools/testing/ampress/Makefile
new file mode 100644
index 00000000000..d175dee7c22
--- /dev/null
+++ b/tools/testing/ampress/Makefile
@@ -0,0 +1,21 @@
+# SPDX-License-Identifier: GPL-2.0
+# Makefile for AMPRESS userspace tests
+
+CC := gcc
+CFLAGS := -Wall -Wextra -O2
+LDFLAGS := -static
+
+PROGS := ampress_test ampress_stress
+
+.PHONY: all clean
+
+all: $(PROGS)
+
+ampress_test: ampress_test.c
+ $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $<
+
+ampress_stress: ampress_stress.c
+ $(CC) $(CFLAGS) $(LDFLAGS) -pthread -o $@ $<
+
+clean:
+ rm -f $(PROGS)
diff --git a/tools/testing/ampress/ampress_stress.c
b/tools/testing/ampress/ampress_stress.c
new file mode 100644
index 00000000000..7894abd764b
--- /dev/null
+++ b/tools/testing/ampress/ampress_stress.c
@@ -0,0 +1,199 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * ampress_stress.c — Concurrency / stress test for /dev/ampress
+ *
+ * Launches 64 reader threads that each open /dev/ampress independently and
+ * read in a tight loop for 10 seconds. A 65th "driver" thread injects events
+ * via the debugfs trigger. Checks for UAF, corruption, and hangs.
+ *
+ * Build: gcc -Wall -Wextra -static -pthread -o ampress_stress ampress_stress.c
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <pthread.h>
+#include <time.h>
+#include <sys/poll.h>
+#include <linux/types.h>
+
+#define AMPRESS_URGENCY_LOW 0
+#define AMPRESS_URGENCY_MEDIUM 1
+#define AMPRESS_URGENCY_HIGH 2
+#define AMPRESS_URGENCY_FATAL 3
+
+struct ampress_event {
+ __u8 urgency;
+ __u8 numa_node;
+ __u16 reserved;
+ __u32 requested_kb;
+ __u64 timestamp_ns;
+};
+
+#define DEVICE_PATH "/dev/ampress"
+#define DEBUGFS_INJECT "/sys/kernel/debug/ampress/inject"
+#define NUM_READERS 64
+#define TEST_DURATION 10 /* seconds */
+
+static _Atomic int g_stop;
+static unsigned long g_events_read[NUM_READERS];
+
+struct reader_arg {
+ int idx;
+};
+
+static void *reader_thread(void *arg)
+{
+ struct reader_arg *a = arg;
+ int fd;
+ struct pollfd pfd;
+
+ fd = open(DEVICE_PATH, O_RDONLY | O_NONBLOCK);
+ if (fd < 0) {
+ fprintf(stderr, "reader[%d]: open failed: %s\n",
+ a->idx, strerror(errno));
+ return (void *)(intptr_t)-1;
+ }
+
+ pfd.fd = fd;
+ pfd.events = POLLIN;
+
+ while (!g_stop) {
+ int ret = poll(&pfd, 1, 200);
+
+ if (ret < 0) {
+ if (errno == EINTR)
+ continue;
+ perror("poll");
+ break;
+ }
+ if (ret == 0)
+ continue;
+
+ if (pfd.revents & POLLIN) {
+ struct ampress_event ev;
+ ssize_t n = read(fd, &ev, sizeof(ev));
+
+ if (n < 0) {
+ if (errno == EAGAIN)
+ continue;
+ perror("read");
+ break;
+ }
+ if ((size_t)n == sizeof(ev)) {
+ /* Basic sanity checks */
+ if (ev.urgency > AMPRESS_URGENCY_FATAL) {
+ fprintf(stderr,
+ "reader[%d]: BAD urgency %u\n",
+ a->idx, ev.urgency);
+ close(fd);
+ return (void *)(intptr_t)-1;
+ }
+ g_events_read[a->idx]++;
+ }
+ }
+ }
+
+ close(fd);
+ return NULL;
+}
+
+static void *inject_thread(void *arg)
+{
+ int inject_fd;
+ int urgency = 0;
+ char buf[4];
+
+ (void)arg;
+
+ inject_fd = open(DEBUGFS_INJECT, O_WRONLY);
+ if (inject_fd < 0) {
+ fprintf(stderr, "inject: open %s failed: %s\n",
+ DEBUGFS_INJECT, strerror(errno));
+ return (void *)(intptr_t)-1;
+ }
+
+ while (!g_stop) {
+ buf[0] = '0' + (char)(urgency % 4);
+ buf[1] = '\n';
+ if (write(inject_fd, buf, 2) < 0) {
+ perror("inject write");
+ break;
+ }
+ urgency++;
+ usleep(5000); /* 5 ms between injections */
+ }
+
+ close(inject_fd);
+ return NULL;
+}
+
+int main(void)
+{
+ pthread_t readers[NUM_READERS];
+ pthread_t injector;
+ struct reader_arg args[NUM_READERS];
+ unsigned long total = 0;
+ int i, rc;
+ int failed = 0;
+
+ g_stop = 0;
+
+ /* Start reader threads */
+ for (i = 0; i < NUM_READERS; i++) {
+ args[i].idx = i;
+ rc = pthread_create(&readers[i], NULL, reader_thread, &args[i]);
+ if (rc) {
+ fprintf(stderr, "pthread_create reader[%d]: %s\n",
+ i, strerror(rc));
+ return 1;
+ }
+ }
+
+ /* Start inject thread */
+ rc = pthread_create(&injector, NULL, inject_thread, NULL);
+ if (rc) {
+ fprintf(stderr, "pthread_create injector: %s\n", strerror(rc));
+ /* Non-fatal: stress test can still run with real pressure */
+ }
+
+ printf("ampress_stress: %d readers running for %d seconds...\n",
+ NUM_READERS, TEST_DURATION);
+
+ sleep(TEST_DURATION);
+
+ g_stop = 1;
+
+ for (i = 0; i < NUM_READERS; i++) {
+ void *retval;
+
+ pthread_join(readers[i], &retval);
+ if ((intptr_t)retval != 0) {
+ fprintf(stderr, "reader[%d] failed\n", i);
+ failed++;
+ }
+ total += g_events_read[i];
+ }
+
+ if (rc == 0) {
+ void *retval;
+
+ pthread_join(injector, &retval);
+ }
+
+ printf("ampress_stress: total events read: %lu across %d threads\n",
+ total, NUM_READERS);
+
+ if (failed) {
+ fprintf(stderr, "ampress_stress: FAIL — %d threads reported errors\n",
+ failed);
+ return 1;
+ }
+
+ printf("ampress_stress: PASS\n");
+ return 0;
+}
diff --git a/tools/testing/ampress/ampress_test.c
b/tools/testing/ampress/ampress_test.c
new file mode 100644
index 00000000000..372705aaa0a
--- /dev/null
+++ b/tools/testing/ampress/ampress_test.c
@@ -0,0 +1,212 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * ampress_test.c — Userspace integration test for /dev/ampress
+ *
+ * Usage: ./ampress_test
+ *
+ * Opens /dev/ampress, optionally configures thresholds, then forks a child
+ * that exhausts memory via mmap while the parent polls for pressure events.
+ * Expects to see at least one HIGH-urgency event within 30 seconds; exits 0
+ * on success, 1 on timeout or error.
+ *
+ * Build: gcc -Wall -Wextra -static -o ampress_test ampress_test.c
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <signal.h>
+#include <time.h>
+#include <sys/mman.h>
+#include <sys/poll.h>
+#include <sys/wait.h>
+#include <sys/ioctl.h>
+
+/* Pull in UAPI types without kernel headers */
+#include <linux/types.h>
+
+/*
+ * Duplicate the UAPI definitions here so the test can be built with
+ * just a libc (--sysroot or installed kernel headers are not required).
+ */
+#define AMPRESS_URGENCY_LOW 0
+#define AMPRESS_URGENCY_MEDIUM 1
+#define AMPRESS_URGENCY_HIGH 2
+#define AMPRESS_URGENCY_FATAL 3
+
+struct ampress_event {
+ __u8 urgency;
+ __u8 numa_node;
+ __u16 reserved;
+ __u32 requested_kb;
+ __u64 timestamp_ns;
+};
+
+struct ampress_ack {
+ __u32 freed_kb;
+ __u32 reserved;
+};
+
+struct ampress_config {
+ __u32 low_threshold_pct;
+ __u32 medium_threshold_pct;
+ __u32 high_threshold_pct;
+ __u32 fatal_threshold_pct;
+};
+
+#define AMPRESS_IOC_MAGIC 'P'
+#define AMPRESS_IOC_CONFIGURE _IOW(AMPRESS_IOC_MAGIC, 1, struct
ampress_config)
+#define AMPRESS_IOC_ACK _IOW(AMPRESS_IOC_MAGIC, 2, struct ampress_ack)
+#define AMPRESS_IOC_SUBSCRIBE _IO(AMPRESS_IOC_MAGIC, 3)
+#define AMPRESS_IOC_UNSUBSCRIBE _IO(AMPRESS_IOC_MAGIC, 4)
+
+#define DEVICE_PATH "/dev/ampress"
+#define TIMEOUT_SEC 30
+#define PAGE_SZ 4096
+
+static const char *urgency_str(int u)
+{
+ switch (u) {
+ case AMPRESS_URGENCY_LOW: return "LOW";
+ case AMPRESS_URGENCY_MEDIUM: return "MEDIUM";
+ case AMPRESS_URGENCY_HIGH: return "HIGH";
+ case AMPRESS_URGENCY_FATAL: return "FATAL";
+ default: return "UNKNOWN";
+ }
+}
+
+/* Child: mmap in a tight loop to exhaust memory */
+static void child_exhaust(void)
+{
+ size_t chunk = 64 * 1024 * 1024; /* 64 MiB per iteration */
+ int iter = 0;
+
+ while (1) {
+ void *p = mmap(NULL, chunk, PROT_READ | PROT_WRITE,
+ MAP_PRIVATE | MAP_ANONYMOUS | MAP_POPULATE,
+ -1, 0);
+ if (p == MAP_FAILED) {
+ if (errno == ENOMEM) {
+ /* Slow down and keep retrying */
+ usleep(100000);
+ continue;
+ }
+ perror("mmap");
+ _exit(1);
+ }
+ /* Touch every page so they are actually allocated */
+ memset(p, (char)iter, chunk);
+ iter++;
+ }
+}
+
+int main(void)
+{
+ int fd;
+ pid_t child;
+ struct pollfd pfd;
+ time_t deadline;
+ int seen[4] = { 0, 0, 0, 0 };
+ int status;
+
+ fd = open(DEVICE_PATH, O_RDONLY);
+ if (fd < 0) {
+ perror("open " DEVICE_PATH);
+ return 1;
+ }
+
+ /* Configure thresholds (all 0 = default: deliver everything) */
+ struct ampress_config cfg = {
+ .low_threshold_pct = 0,
+ .medium_threshold_pct = 0,
+ .high_threshold_pct = 0,
+ .fatal_threshold_pct = 0,
+ };
+ if (ioctl(fd, AMPRESS_IOC_CONFIGURE, &cfg) < 0) {
+ perror("AMPRESS_IOC_CONFIGURE");
+ close(fd);
+ return 1;
+ }
+
+ child = fork();
+ if (child < 0) {
+ perror("fork");
+ close(fd);
+ return 1;
+ }
+ if (child == 0)
+ child_exhaust(); /* Never returns */
+
+ printf("ampress_test: child PID %d exhausting memory...\n", child);
+
+ deadline = time(NULL) + TIMEOUT_SEC;
+ pfd.fd = fd;
+ pfd.events = POLLIN;
+
+ while (time(NULL) < deadline) {
+ int remaining = (int)(deadline - time(NULL));
+ int ret = poll(&pfd, 1, remaining * 1000);
+
+ if (ret < 0) {
+ if (errno == EINTR)
+ continue;
+ perror("poll");
+ goto fail;
+ }
+ if (ret == 0) {
+ fprintf(stderr, "ampress_test: TIMEOUT — no HIGH event
received\n");
+ goto fail;
+ }
+
+ if (pfd.revents & POLLIN) {
+ struct ampress_event ev;
+ ssize_t n = read(fd, &ev, sizeof(ev));
+
+ if (n < 0) {
+ perror("read");
+ goto fail;
+ }
+ if ((size_t)n < sizeof(ev)) {
+ fprintf(stderr, "short read: %zd\n", n);
+ goto fail;
+ }
+
+ printf("ampress_test: urgency=%-6s numa=%u kb=%u ts=%llu\n",
+ urgency_str(ev.urgency), ev.numa_node,
+ ev.requested_kb,
+ (unsigned long long)ev.timestamp_ns);
+
+ if (ev.urgency <= AMPRESS_URGENCY_FATAL)
+ seen[ev.urgency] = 1;
+
+ /* ACK with a simulated freed amount */
+ struct ampress_ack ack = { .freed_kb = 16384 };
+
+ if (ioctl(fd, AMPRESS_IOC_ACK, &ack) < 0)
+ perror("AMPRESS_IOC_ACK (non-fatal)");
+
+ /* Success criterion: seen at least up to HIGH */
+ if (seen[AMPRESS_URGENCY_HIGH] ||
+ seen[AMPRESS_URGENCY_FATAL])
+ goto success;
+ }
+ }
+
+ fprintf(stderr, "ampress_test: TIMEOUT\n");
+fail:
+ kill(child, SIGKILL);
+ waitpid(child, &status, 0);
+ close(fd);
+ return 1;
+
+success:
+ printf("ampress_test: SUCCESS — received HIGH (or higher) event\n");
+ kill(child, SIGKILL);
+ waitpid(child, &status, 0);
+ close(fd);
+ return 0;
+}
--
2.51.0
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: [PATCH] mm: add Adaptive Memory Pressure Signaling (AMPRESS)
2026-03-02 3:45 [PATCH] mm: add Adaptive Memory Pressure Signaling (AMPRESS) Andre Ramos
@ 2026-03-02 8:52 ` David Hildenbrand (Arm)
2026-03-02 11:48 ` Lorenzo Stoakes
1 sibling, 0 replies; 3+ messages in thread
From: David Hildenbrand (Arm) @ 2026-03-02 8:52 UTC (permalink / raw)
To: Andre Ramos, akpm, hannes
Cc: linux-mm, linux-kernel, linux-trace-kernel, rostedt
On 3/2/26 04:45, Andre Ramos wrote:
> Introduce /dev/ampress, a bidirectional fd-based interface for
> cooperative memory reclaim between the kernel and userspace.
I'm very sure this should be tagged as RFC.
>
> Userspace processes open /dev/ampress and block on read() to receive
> struct ampress_event notifications carrying a graduated urgency level
> (LOW/MEDIUM/HIGH/FATAL), the NUMA node of the pressure source, and a
> suggested reclaim target in KiB. After freeing memory the process
> issues AMPRESS_IOC_ACK to close the feedback loop.
>
> The feature hooks into balance_pgdat() in mm/vmscan.c, mapping the
> kswapd scan priority to urgency bands:
> priority 10-12 -> LOW
> priority 7-9 -> MEDIUM
> priority 4-6 -> HIGH
> priority 1-3 -> FATAL
>
> ampress_notify() is IRQ-safe (read_lock_irqsave + spin_lock_irqsave,
> no allocations) so it can be called from any reclaim context.
> Per-subscriber events overwrite without queuing to prevent unbounded
> backlog. A debugfs trigger at /sys/kernel/debug/ampress/inject allows
> testing without real memory pressure.
[...]
>
> +ADAPTIVE MEMORY PRESSURE SIGNALING (AMPRESS)
> +M: Darabat <playbadly1@gmail.com>
> +L: linux-mm@kvack.org
> +S: Maintained
> +F: include/linux/ampress.h
> +F: include/trace/events/ampress.h
> +F: include/uapi/linux/ampress.h
> +F: mm/ampress.c
> +F: mm/ampress_test.c
> +F: tools/testing/ampress/
We generally don't make new kernel contributors MM maintainers.
But what sticks out more is the inconsistency between your name+mail and
"Darabat <playbadly1@gmail.com>".
--
Cheers,
David
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: [PATCH] mm: add Adaptive Memory Pressure Signaling (AMPRESS)
2026-03-02 3:45 [PATCH] mm: add Adaptive Memory Pressure Signaling (AMPRESS) Andre Ramos
2026-03-02 8:52 ` David Hildenbrand (Arm)
@ 2026-03-02 11:48 ` Lorenzo Stoakes
1 sibling, 0 replies; 3+ messages in thread
From: Lorenzo Stoakes @ 2026-03-02 11:48 UTC (permalink / raw)
To: Andre Ramos
Cc: akpm, hannes, linux-mm, linux-kernel, linux-trace-kernel, david, rostedt
NAK.
This is a super questionable conceptual idea that isn't appropriate to submit as
a non-RFC patch.
I'm with David on this.
On Mon, Mar 02, 2026 at 12:45:33AM -0300, Andre Ramos wrote:
> Introduce /dev/ampress, a bidirectional fd-based interface for
> cooperative memory reclaim between the kernel and userspace.
There's just absolutely no way we'd expose anything like this as a character
device.
>
> Userspace processes open /dev/ampress and block on read() to receive
> struct ampress_event notifications carrying a graduated urgency level
> (LOW/MEDIUM/HIGH/FATAL), the NUMA node of the pressure source, and a
> suggested reclaim target in KiB. After freeing memory the process
> issues AMPRESS_IOC_ACK to close the feedback loop.
This is really not how we want to expose kernel interfaces. This seems like a
hack you'd implement internally rather than something we'd consider having in
mainline.
You're also inserting some new lock acquisitions and a linked list waking up
some unlimited number of threads on a core reclaim path - no.
>
> The feature hooks into balance_pgdat() in mm/vmscan.c, mapping the
> kswapd scan priority to urgency bands:
> priority 10-12 -> LOW
> priority 7-9 -> MEDIUM
> priority 4-6 -> HIGH
> priority 1-3 -> FATAL
>
> ampress_notify() is IRQ-safe (read_lock_irqsave + spin_lock_irqsave,
> no allocations) so it can be called from any reclaim context.
> Per-subscriber events overwrite without queuing to prevent unbounded
> backlog. A debugfs trigger at /sys/kernel/debug/ampress/inject allows
> testing without real memory pressure.
This is far too little description, especially given you're submitting
everything as one patch (which is not how kernel development is done).
The patch doesn't deal with MGLRU, and feels like a 'let's hook into one
specific part of mm and just dump out information to a random place'.
You could reasonably obtain the same information from BPF no?
>
> New files:
> include/uapi/linux/ampress.h - UAPI structs and ioctl definitions
> include/linux/ampress.h - internal header and ampress_notify()
> include/trace/events/ampress.h - tracepoints for notify and ack
> mm/ampress.c - miscdevice driver and core logic
> mm/ampress_test.c - KUnit tests (3/3 passing)
> tools/testing/ampress/ - userspace integration and stress tests
This doesn't belong in a commit message.
>
> Signed-off-by: André Castro Ramos <acastroramos1987@gmail.com>
> ---
> MAINTAINERS | 11 +
> include/linux/ampress.h | 34 +++
> include/trace/events/ampress.h | 70 ++++++
> include/uapi/linux/ampress.h | 40 ++++
> mm/Kconfig | 26 ++
> mm/Makefile | 2 +
> mm/ampress.c | 320 +++++++++++++++++++++++++
> mm/ampress_test.c | 124 ++++++++++
> mm/vmscan.c | 27 +++
> tools/testing/ampress/.gitignore | 2 +
> tools/testing/ampress/Makefile | 21 ++
> tools/testing/ampress/ampress_stress.c | 199 +++++++++++++++
> tools/testing/ampress/ampress_test.c | 212 ++++++++++++++++
> 13 files changed, 1088 insertions(+)
This is not how you submit patches, this needed to be broken up into a series,
submitting a single patch changing 13 files and adding 1,088 lines isn't how
kernel development works.
> create mode 100644 include/linux/ampress.h
> create mode 100644 include/trace/events/ampress.h
> create mode 100644 include/uapi/linux/ampress.h
> create mode 100644 mm/ampress.c
> create mode 100644 mm/ampress_test.c
> create mode 100644 tools/testing/ampress/.gitignore
> create mode 100644 tools/testing/ampress/Makefile
> create mode 100644 tools/testing/ampress/ampress_stress.c
> create mode 100644 tools/testing/ampress/ampress_test.c
>
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 61bf550fd37..ea4d7861ff9 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -16629,6 +16629,17 @@ F: mm/memremap.c
> F: mm/memory_hotplug.c
> F: tools/testing/selftests/memory-hotplug/
>
> +ADAPTIVE MEMORY PRESSURE SIGNALING (AMPRESS)
> +M: Darabat <playbadly1@gmail.com>
> +L: linux-mm@kvack.org
> +S: Maintained
> +F: include/linux/ampress.h
> +F: include/trace/events/ampress.h
> +F: include/uapi/linux/ampress.h
> +F: mm/ampress.c
> +F: mm/ampress_test.c
> +F: tools/testing/ampress/
As David said, it's really not proper to add yourself as a maintainer without a
track record in the kernel and community trust.
Maintainership is a serious responsibility and really requires that you have
both demonstrated consistent technical understanding and an ability to work with
the community.
Obviously as a new contributor, neither have been demonstrated.
Also there's an existing convention of 'MEMORY MANAGEMENT - xxx' for mm entries
in MAINTAINERS.
Thanks, Lorenzo
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2026-03-02 11:48 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-03-02 3:45 [PATCH] mm: add Adaptive Memory Pressure Signaling (AMPRESS) Andre Ramos
2026-03-02 8:52 ` David Hildenbrand (Arm)
2026-03-02 11:48 ` Lorenzo Stoakes
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox