* [PATCH v2 00/10] Backport MEMCG changes from v5.17
@ 2022-08-08 12:55 David Oberhollenzer
2022-08-08 12:55 ` [PATCH v2 01/10] mm/memcg: Revert ("mm/memcg: optimize user context object stock access") David Oberhollenzer
` (10 more replies)
0 siblings, 11 replies; 12+ messages in thread
From: David Oberhollenzer @ 2022-08-08 12:55 UTC (permalink / raw)
To: linux-rt-users
Cc: williams, bigeasy, richard, joseph.salisbury, David Oberhollenzer
This is a backport of Sebastian's MEMCG changes to v5.15. With these
patches applied, it is possible to use memory cgroups together
with PREEMPT_RT on v5.15, just like on v5.17.
The patch set was tested on my end by building an x86_64 kernel
with PREEMPT_RT, cgroup debug and lockdep enabled. The kernel was
run in Qemu, where a small number of child cgroups were created,
with memory controller enabled for each and an instance of a small
test program running.
Changes in v2:
- Use the exact patch set merged upstream
David Oberhollenzer (1):
Allow MEMCG on PREEMPT_RT
Johannes Weiner (1):
mm/memcg: Opencode the inner part of obj_cgroup_uncharge_pages() in drain_obj_stock()
Michal Hocko (1):
mm/memcg: Revert ("mm/memcg: optimize user context object stock access")
Sebastian Andrzej Siewior (7):
mm/memcg: Disable threshold event handlers on PREEMPT_RT
mm/memcg: Protect per-CPU counter by disabling preemption on PREEMPT_RT where needed.
mm/memcg: Protect memcg_stock with a local_lock_t
mm/memcg: Disable migration instead of preemption in drain_all_stock().
mm/memcg: Add missing counter index which are not update in interrupt.
mm/memcg: Add a comment regarding the release `obj'.
mm/memcg: Only perform the debug checks on !PREEMPT_RT
.../admin-guide/cgroup-v1/memory.rst | 2 +
init/Kconfig | 1 -
mm/memcontrol.c | 232 +++++++++++-------
3 files changed, 146 insertions(+), 89 deletions(-)
--
2.37.1
^ permalink raw reply [flat|nested] 12+ messages in thread
* [PATCH v2 01/10] mm/memcg: Revert ("mm/memcg: optimize user context object stock access")
2022-08-08 12:55 [PATCH v2 00/10] Backport MEMCG changes from v5.17 David Oberhollenzer
@ 2022-08-08 12:55 ` David Oberhollenzer
2022-08-08 12:55 ` [PATCH v2 02/10] mm/memcg: Disable threshold event handlers on PREEMPT_RT David Oberhollenzer
` (9 subsequent siblings)
10 siblings, 0 replies; 12+ messages in thread
From: David Oberhollenzer @ 2022-08-08 12:55 UTC (permalink / raw)
To: linux-rt-users
Cc: williams, bigeasy, richard, joseph.salisbury, Michal Hocko,
Roman Gushchin, Johannes Weiner, Shakeel Butt,
David Oberhollenzer
From: Michal Hocko <mhocko@suse.com>
The optimisation is based on a micro benchmark where local_irq_save() is
more expensive than a preempt_disable(). There is no evidence that it is
visible in a real-world workload and there are CPUs where the opposite is
true (local_irq_save() is cheaper than preempt_disable()).
Based on micro benchmarks, the optimisation makes sense on PREEMPT_NONE
where preempt_disable() is optimized away. There is no improvement with
PREEMPT_DYNAMIC since the preemption counter is always available.
The optimization makes also the PREEMPT_RT integration more complicated
since most of the assumption are not true on PREEMPT_RT.
Revert the optimisation since it complicates the PREEMPT_RT integration
and the improvement is hardly visible.
[ bigeasy: Patch body around Michal's diff ]
Link: https://lore.kernel.org/all/YgOGkXXCrD%2F1k+p4@dhcp22.suse.cz
Link: https://lkml.kernel.org/r/YdX+INO9gQje6d0S@linutronix.de
Signed-off-by: Michal Hocko <mhocko@suse.com>
Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
Acked-by: Roman Gushchin <guro@fb.com>
Acked-by: Johannes Weiner <hannes@cmpxchg.org>
Reviewed-by: Shakeel Butt <shakeelb@google.com>
Acked-by: Michal Hocko <mhocko@suse.com>
[do: backported to v5.15]
Signed-off-by: David Oberhollenzer <goliath@infraroot.at>
---
mm/memcontrol.c | 94 ++++++++++++++-----------------------------------
1 file changed, 27 insertions(+), 67 deletions(-)
diff --git a/mm/memcontrol.c b/mm/memcontrol.c
index 971546bb99e0..a07e068989b4 100644
--- a/mm/memcontrol.c
+++ b/mm/memcontrol.c
@@ -2102,23 +2102,17 @@ void unlock_page_memcg(struct page *page)
}
EXPORT_SYMBOL(unlock_page_memcg);
-struct obj_stock {
+struct memcg_stock_pcp {
+ struct mem_cgroup *cached; /* this never be root cgroup */
+ unsigned int nr_pages;
+
#ifdef CONFIG_MEMCG_KMEM
struct obj_cgroup *cached_objcg;
struct pglist_data *cached_pgdat;
unsigned int nr_bytes;
int nr_slab_reclaimable_b;
int nr_slab_unreclaimable_b;
-#else
- int dummy[0];
#endif
-};
-
-struct memcg_stock_pcp {
- struct mem_cgroup *cached; /* this never be root cgroup */
- unsigned int nr_pages;
- struct obj_stock task_obj;
- struct obj_stock irq_obj;
struct work_struct work;
unsigned long flags;
@@ -2128,12 +2122,12 @@ static DEFINE_PER_CPU(struct memcg_stock_pcp, memcg_stock);
static DEFINE_MUTEX(percpu_charge_mutex);
#ifdef CONFIG_MEMCG_KMEM
-static void drain_obj_stock(struct obj_stock *stock);
+static void drain_obj_stock(struct memcg_stock_pcp *stock);
static bool obj_stock_flush_required(struct memcg_stock_pcp *stock,
struct mem_cgroup *root_memcg);
#else
-static inline void drain_obj_stock(struct obj_stock *stock)
+static inline void drain_obj_stock(struct memcg_stock_pcp *stock)
{
}
static bool obj_stock_flush_required(struct memcg_stock_pcp *stock,
@@ -2144,41 +2138,6 @@ static bool obj_stock_flush_required(struct memcg_stock_pcp *stock,
#endif
/*
- * Most kmem_cache_alloc() calls are from user context. The irq disable/enable
- * sequence used in this case to access content from object stock is slow.
- * To optimize for user context access, there are now two object stocks for
- * task context and interrupt context access respectively.
- *
- * The task context object stock can be accessed by disabling preemption only
- * which is cheap in non-preempt kernel. The interrupt context object stock
- * can only be accessed after disabling interrupt. User context code can
- * access interrupt object stock, but not vice versa.
- */
-static inline struct obj_stock *get_obj_stock(unsigned long *pflags)
-{
- struct memcg_stock_pcp *stock;
-
- if (likely(in_task())) {
- *pflags = 0UL;
- preempt_disable();
- stock = this_cpu_ptr(&memcg_stock);
- return &stock->task_obj;
- }
-
- local_irq_save(*pflags);
- stock = this_cpu_ptr(&memcg_stock);
- return &stock->irq_obj;
-}
-
-static inline void put_obj_stock(unsigned long flags)
-{
- if (likely(in_task()))
- preempt_enable();
- else
- local_irq_restore(flags);
-}
-
-/**
* consume_stock: Try to consume stocked charge on this cpu.
* @memcg: memcg to consume from.
* @nr_pages: how many pages to charge.
@@ -2245,9 +2204,7 @@ static void drain_local_stock(struct work_struct *dummy)
local_irq_save(flags);
stock = this_cpu_ptr(&memcg_stock);
- drain_obj_stock(&stock->irq_obj);
- if (in_task())
- drain_obj_stock(&stock->task_obj);
+ drain_obj_stock(stock);
drain_stock(stock);
clear_bit(FLUSHING_CACHED_CHARGE, &stock->flags);
@@ -3084,10 +3041,13 @@ void __memcg_kmem_uncharge_page(struct page *page, int order)
void mod_objcg_state(struct obj_cgroup *objcg, struct pglist_data *pgdat,
enum node_stat_item idx, int nr)
{
+ struct memcg_stock_pcp *stock;
unsigned long flags;
- struct obj_stock *stock = get_obj_stock(&flags);
int *bytes;
+ local_irq_save(flags);
+ stock = this_cpu_ptr(&memcg_stock);
+
/*
* Save vmstat data in stock and skip vmstat array update unless
* accumulating over a page of vmstat data or when pgdat or idx
@@ -3138,26 +3098,29 @@ void mod_objcg_state(struct obj_cgroup *objcg, struct pglist_data *pgdat,
if (nr)
mod_objcg_mlstate(objcg, pgdat, idx, nr);
- put_obj_stock(flags);
+ local_irq_restore(flags);
}
static bool consume_obj_stock(struct obj_cgroup *objcg, unsigned int nr_bytes)
{
+ struct memcg_stock_pcp *stock;
unsigned long flags;
- struct obj_stock *stock = get_obj_stock(&flags);
bool ret = false;
+ local_irq_save(flags);
+
+ stock = this_cpu_ptr(&memcg_stock);
if (objcg == stock->cached_objcg && stock->nr_bytes >= nr_bytes) {
stock->nr_bytes -= nr_bytes;
ret = true;
}
- put_obj_stock(flags);
+ local_irq_restore(flags);
return ret;
}
-static void drain_obj_stock(struct obj_stock *stock)
+static void drain_obj_stock(struct memcg_stock_pcp *stock)
{
struct obj_cgroup *old = stock->cached_objcg;
@@ -3213,13 +3176,8 @@ static bool obj_stock_flush_required(struct memcg_stock_pcp *stock,
{
struct mem_cgroup *memcg;
- if (in_task() && stock->task_obj.cached_objcg) {
- memcg = obj_cgroup_memcg(stock->task_obj.cached_objcg);
- if (memcg && mem_cgroup_is_descendant(memcg, root_memcg))
- return true;
- }
- if (stock->irq_obj.cached_objcg) {
- memcg = obj_cgroup_memcg(stock->irq_obj.cached_objcg);
+ if (stock->cached_objcg) {
+ memcg = obj_cgroup_memcg(stock->cached_objcg);
if (memcg && mem_cgroup_is_descendant(memcg, root_memcg))
return true;
}
@@ -3230,10 +3188,13 @@ static bool obj_stock_flush_required(struct memcg_stock_pcp *stock,
static void refill_obj_stock(struct obj_cgroup *objcg, unsigned int nr_bytes,
bool allow_uncharge)
{
+ struct memcg_stock_pcp *stock;
unsigned long flags;
- struct obj_stock *stock = get_obj_stock(&flags);
unsigned int nr_pages = 0;
+ local_irq_save(flags);
+
+ stock = this_cpu_ptr(&memcg_stock);
if (stock->cached_objcg != objcg) { /* reset if necessary */
drain_obj_stock(stock);
obj_cgroup_get(objcg);
@@ -3249,7 +3210,7 @@ static void refill_obj_stock(struct obj_cgroup *objcg, unsigned int nr_bytes,
stock->nr_bytes &= (PAGE_SIZE - 1);
}
- put_obj_stock(flags);
+ local_irq_restore(flags);
if (nr_pages)
obj_cgroup_uncharge_pages(objcg, nr_pages);
@@ -6874,7 +6835,6 @@ static void uncharge_page(struct page *page, struct uncharge_gather *ug)
unsigned long nr_pages;
struct mem_cgroup *memcg;
struct obj_cgroup *objcg;
- bool use_objcg = PageMemcgKmem(page);
VM_BUG_ON_PAGE(PageLRU(page), page);
@@ -6883,7 +6843,7 @@ static void uncharge_page(struct page *page, struct uncharge_gather *ug)
* page memcg or objcg at this point, we have fully
* exclusive access to the page.
*/
- if (use_objcg) {
+ if (PageMemcgKmem(page)) {
objcg = __page_objcg(page);
/*
* This get matches the put at the end of the function and
@@ -6911,7 +6871,7 @@ static void uncharge_page(struct page *page, struct uncharge_gather *ug)
nr_pages = compound_nr(page);
- if (use_objcg) {
+ if (PageMemcgKmem(page)) {
ug->nr_memory += nr_pages;
ug->nr_kmem += nr_pages;
--
2.37.1
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH v2 02/10] mm/memcg: Disable threshold event handlers on PREEMPT_RT
2022-08-08 12:55 [PATCH v2 00/10] Backport MEMCG changes from v5.17 David Oberhollenzer
2022-08-08 12:55 ` [PATCH v2 01/10] mm/memcg: Revert ("mm/memcg: optimize user context object stock access") David Oberhollenzer
@ 2022-08-08 12:55 ` David Oberhollenzer
2022-08-08 12:55 ` [PATCH v2 03/10] mm/memcg: Protect per-CPU counter by disabling preemption on PREEMPT_RT where needed David Oberhollenzer
` (8 subsequent siblings)
10 siblings, 0 replies; 12+ messages in thread
From: David Oberhollenzer @ 2022-08-08 12:55 UTC (permalink / raw)
To: linux-rt-users
Cc: williams, bigeasy, richard, joseph.salisbury, Michal Hocko,
Michal Koutný, Roman Gushchin, Johannes Weiner, Shakeel Butt,
Michal Hocko, David Oberhollenzer
From: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
During the integration of PREEMPT_RT support, the code flow around
memcg_check_events() resulted in `twisted code'. Moving the code around
and avoiding then would then lead to an additional local-irq-save
section within memcg_check_events(). While looking better, it adds a
local-irq-save section to code flow which is usually within an
local-irq-off block on non-PREEMPT_RT configurations.
The threshold event handler is a deprecated memcg v1 feature. Instead of
trying to get it to work under PREEMPT_RT just disable it. There should
be no users on PREEMPT_RT. From that perspective it makes even less
sense to get it to work under PREEMPT_RT while having zero users.
Make memory.soft_limit_in_bytes and cgroup.event_control return
-EOPNOTSUPP on PREEMPT_RT. Make an empty memcg_check_events() and
memcg_write_event_control() which return only -EOPNOTSUPP on PREEMPT_RT.
Document that the two knobs are disabled on PREEMPT_RT.
Suggested-by: Michal Hocko <mhocko@kernel.org>
Suggested-by: Michal Koutný <mkoutny@suse.com>
Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
Acked-by: Roman Gushchin <guro@fb.com>
Acked-by: Johannes Weiner <hannes@cmpxchg.org>
Reviewed-by: Shakeel Butt <shakeelb@google.com>
Acked-by: Michal Hocko <mhocko@suse.com>
[do: backported to v5.15]
Signed-off-by: David Oberhollenzer <goliath@infraroot.at>
---
Documentation/admin-guide/cgroup-v1/memory.rst | 2 ++
mm/memcontrol.c | 14 ++++++++++++--
2 files changed, 14 insertions(+), 2 deletions(-)
diff --git a/Documentation/admin-guide/cgroup-v1/memory.rst b/Documentation/admin-guide/cgroup-v1/memory.rst
index 41191b5fb69d..c45291ac9ffb 100644
--- a/Documentation/admin-guide/cgroup-v1/memory.rst
+++ b/Documentation/admin-guide/cgroup-v1/memory.rst
@@ -64,6 +64,7 @@ Brief summary of control files.
threads
cgroup.procs show list of processes
cgroup.event_control an interface for event_fd()
+ This knob is not available on CONFIG_PREEMPT_RT systems.
memory.usage_in_bytes show current usage for memory
(See 5.5 for details)
memory.memsw.usage_in_bytes show current usage for memory+Swap
@@ -75,6 +76,7 @@ Brief summary of control files.
memory.max_usage_in_bytes show max memory usage recorded
memory.memsw.max_usage_in_bytes show max memory+Swap usage recorded
memory.soft_limit_in_bytes set/show soft limit of memory usage
+ This knob is not available on CONFIG_PREEMPT_RT systems.
memory.stat show various statistics
memory.use_hierarchy set/show hierarchical account enabled
This knob is deprecated and shouldn't be
diff --git a/mm/memcontrol.c b/mm/memcontrol.c
index a07e068989b4..6078d57aee0f 100644
--- a/mm/memcontrol.c
+++ b/mm/memcontrol.c
@@ -909,6 +909,9 @@ static bool mem_cgroup_event_ratelimit(struct mem_cgroup *memcg,
*/
static void memcg_check_events(struct mem_cgroup *memcg, struct page *page)
{
+ if (IS_ENABLED(CONFIG_PREEMPT_RT))
+ return;
+
/* threshold event is triggered in finer grain than soft limit */
if (unlikely(mem_cgroup_event_ratelimit(memcg,
MEM_CGROUP_TARGET_THRESH))) {
@@ -3777,8 +3780,12 @@ static ssize_t mem_cgroup_write(struct kernfs_open_file *of,
}
break;
case RES_SOFT_LIMIT:
- memcg->soft_limit = nr_pages;
- ret = 0;
+ if (IS_ENABLED(CONFIG_PREEMPT_RT)) {
+ ret = -EOPNOTSUPP;
+ } else {
+ memcg->soft_limit = nr_pages;
+ ret = 0;
+ }
break;
}
return ret ?: nbytes;
@@ -4754,6 +4761,9 @@ static ssize_t memcg_write_event_control(struct kernfs_open_file *of,
char *endp;
int ret;
+ if (IS_ENABLED(CONFIG_PREEMPT_RT))
+ return -EOPNOTSUPP;
+
buf = strstrip(buf);
efd = simple_strtoul(buf, &endp, 10);
--
2.37.1
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH v2 03/10] mm/memcg: Protect per-CPU counter by disabling preemption on PREEMPT_RT where needed.
2022-08-08 12:55 [PATCH v2 00/10] Backport MEMCG changes from v5.17 David Oberhollenzer
2022-08-08 12:55 ` [PATCH v2 01/10] mm/memcg: Revert ("mm/memcg: optimize user context object stock access") David Oberhollenzer
2022-08-08 12:55 ` [PATCH v2 02/10] mm/memcg: Disable threshold event handlers on PREEMPT_RT David Oberhollenzer
@ 2022-08-08 12:55 ` David Oberhollenzer
2022-08-08 12:55 ` [PATCH v2 04/10] mm/memcg: Opencode the inner part of obj_cgroup_uncharge_pages() in drain_obj_stock() David Oberhollenzer
` (7 subsequent siblings)
10 siblings, 0 replies; 12+ messages in thread
From: David Oberhollenzer @ 2022-08-08 12:55 UTC (permalink / raw)
To: linux-rt-users
Cc: williams, bigeasy, richard, joseph.salisbury, Roman Gushchin,
David Oberhollenzer
From: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
The per-CPU counter are modified with the non-atomic modifier. The
consistency is ensured by disabling interrupts for the update.
On non PREEMPT_RT configuration this works because acquiring a
spinlock_t typed lock with the _irq() suffix disables interrupts. On
PREEMPT_RT configurations the RMW operation can be interrupted.
Another problem is that mem_cgroup_swapout() expects to be invoked with
disabled interrupts because the caller has to acquire a spinlock_t which
is acquired with disabled interrupts. Since spinlock_t never disables
interrupts on PREEMPT_RT the interrupts are never disabled at this
point.
The code is never called from in_irq() context on PREEMPT_RT therefore
disabling preemption during the update is sufficient on PREEMPT_RT.
The sections which explicitly disable interrupts can remain on
PREEMPT_RT because the sections remain short and they don't involve
sleeping locks (memcg_check_events() is doing nothing on PREEMPT_RT).
Disable preemption during update of the per-CPU variables which do not
explicitly disable interrupts.
Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
Acked-by: Roman Gushchin <guro@fb.com>
[do: backported to v5.15]
Signed-off-by: David Oberhollenzer <goliath@infraroot.at>
---
mm/memcontrol.c | 49 ++++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 48 insertions(+), 1 deletion(-)
diff --git a/mm/memcontrol.c b/mm/memcontrol.c
index 6078d57aee0f..e566c34466a1 100644
--- a/mm/memcontrol.c
+++ b/mm/memcontrol.c
@@ -654,6 +654,35 @@ static u64 flush_next_time;
#define FLUSH_TIME (2UL*HZ)
+/*
+ * Accessors to ensure that preemption is disabled on PREEMPT_RT because it can
+ * not rely on this as part of an acquired spinlock_t lock. These functions are
+ * never used in hardirq context on PREEMPT_RT and therefore disabling preemtion
+ * is sufficient.
+ */
+static void memcg_stats_lock(void)
+{
+#ifdef CONFIG_PREEMPT_RT
+ preempt_disable();
+#else
+ VM_BUG_ON(!irqs_disabled());
+#endif
+}
+
+static void __memcg_stats_lock(void)
+{
+#ifdef CONFIG_PREEMPT_RT
+ preempt_disable();
+#endif
+}
+
+static void memcg_stats_unlock(void)
+{
+#ifdef CONFIG_PREEMPT_RT
+ preempt_enable();
+#endif
+}
+
static inline void memcg_rstat_updated(struct mem_cgroup *memcg, int val)
{
unsigned int x;
@@ -737,6 +766,20 @@ void __mod_memcg_lruvec_state(struct lruvec *lruvec, enum node_stat_item idx,
pn = container_of(lruvec, struct mem_cgroup_per_node, lruvec);
memcg = pn->memcg;
+ /*
+ * The caller from rmap relay on disabled preemption becase they never
+ * update their counter from in-interrupt context. For these two
+ * counters we check that the update is never performed from an
+ * interrupt context while other caller need to have disabled interrupt.
+ */
+ __memcg_stats_lock();
+ if (IS_ENABLED(CONFIG_DEBUG_VM)) {
+ if (idx == NR_ANON_MAPPED || idx == NR_FILE_MAPPED)
+ WARN_ON_ONCE(!in_task());
+ else
+ WARN_ON_ONCE(!irqs_disabled());
+ }
+
/* Update memcg */
__this_cpu_add(memcg->vmstats_percpu->state[idx], val);
@@ -744,6 +787,7 @@ void __mod_memcg_lruvec_state(struct lruvec *lruvec, enum node_stat_item idx,
__this_cpu_add(pn->lruvec_stats_percpu->state[idx], val);
memcg_rstat_updated(memcg, val);
+ memcg_stats_unlock();
}
/**
@@ -844,8 +888,10 @@ void __count_memcg_events(struct mem_cgroup *memcg, enum vm_event_item idx,
if (mem_cgroup_disabled())
return;
+ memcg_stats_lock();
__this_cpu_add(memcg->vmstats_percpu->events[idx], count);
memcg_rstat_updated(memcg, count);
+ memcg_stats_unlock();
}
static unsigned long memcg_events(struct mem_cgroup *memcg, int event)
@@ -7211,8 +7257,9 @@ void mem_cgroup_swapout(struct page *page, swp_entry_t entry)
* important here to have the interrupts disabled because it is the
* only synchronisation we have for updating the per-CPU variables.
*/
- VM_BUG_ON(!irqs_disabled());
+ memcg_stats_lock();
mem_cgroup_charge_statistics(memcg, page, -nr_entries);
+ memcg_stats_unlock();
memcg_check_events(memcg, page);
css_put(&memcg->css);
--
2.37.1
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH v2 04/10] mm/memcg: Opencode the inner part of obj_cgroup_uncharge_pages() in drain_obj_stock()
2022-08-08 12:55 [PATCH v2 00/10] Backport MEMCG changes from v5.17 David Oberhollenzer
` (2 preceding siblings ...)
2022-08-08 12:55 ` [PATCH v2 03/10] mm/memcg: Protect per-CPU counter by disabling preemption on PREEMPT_RT where needed David Oberhollenzer
@ 2022-08-08 12:55 ` David Oberhollenzer
2022-08-08 12:55 ` [PATCH v2 05/10] mm/memcg: Protect memcg_stock with a local_lock_t David Oberhollenzer
` (6 subsequent siblings)
10 siblings, 0 replies; 12+ messages in thread
From: David Oberhollenzer @ 2022-08-08 12:55 UTC (permalink / raw)
To: linux-rt-users
Cc: williams, bigeasy, richard, joseph.salisbury, Johannes Weiner,
Shakeel Butt, Roman Gushchin, Michal Hocko, David Oberhollenzer
From: Johannes Weiner <hannes@cmpxchg.org>
Provide the inner part of refill_stock() as __refill_stock() without
disabling interrupts. This eases the integration of local_lock_t where
recursive locking must be avoided.
Open code obj_cgroup_uncharge_pages() in drain_obj_stock() and use
__refill_stock(). The caller of drain_obj_stock() already disables
interrupts.
[bigeasy: Patch body around Johannes' diff ]
Signed-off-by: Johannes Weiner <hannes@cmpxchg.org>
Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
Reviewed-by: Shakeel Butt <shakeelb@google.com>
Reviewed-by: Roman Gushchin <guro@fb.com>
Acked-by: Michal Hocko <mhocko@suse.com>
[do: backported to v5.15]
Signed-off-by: David Oberhollenzer <goliath@infraroot.at>
---
mm/memcontrol.c | 26 ++++++++++++++++++++------
1 file changed, 20 insertions(+), 6 deletions(-)
diff --git a/mm/memcontrol.c b/mm/memcontrol.c
index e566c34466a1..2cf55b3ab4b0 100644
--- a/mm/memcontrol.c
+++ b/mm/memcontrol.c
@@ -2264,12 +2264,9 @@ static void drain_local_stock(struct work_struct *dummy)
* Cache charges(val) to local per_cpu area.
* This will be consumed by consume_stock() function, later.
*/
-static void refill_stock(struct mem_cgroup *memcg, unsigned int nr_pages)
+static void __refill_stock(struct mem_cgroup *memcg, unsigned int nr_pages)
{
struct memcg_stock_pcp *stock;
- unsigned long flags;
-
- local_irq_save(flags);
stock = this_cpu_ptr(&memcg_stock);
if (stock->cached != memcg) { /* reset if necessary */
@@ -2281,7 +2278,14 @@ static void refill_stock(struct mem_cgroup *memcg, unsigned int nr_pages)
if (stock->nr_pages > MEMCG_CHARGE_BATCH)
drain_stock(stock);
+}
+static void refill_stock(struct mem_cgroup *memcg, unsigned int nr_pages)
+{
+ unsigned long flags;
+
+ local_irq_save(flags);
+ __refill_stock(memcg, nr_pages);
local_irq_restore(flags);
}
@@ -3180,8 +3184,18 @@ static void drain_obj_stock(struct memcg_stock_pcp *stock)
unsigned int nr_pages = stock->nr_bytes >> PAGE_SHIFT;
unsigned int nr_bytes = stock->nr_bytes & (PAGE_SIZE - 1);
- if (nr_pages)
- obj_cgroup_uncharge_pages(old, nr_pages);
+ if (nr_pages) {
+ struct mem_cgroup *memcg;
+
+ memcg = get_mem_cgroup_from_objcg(old);
+
+ if (!cgroup_subsys_on_dfl(memory_cgrp_subsys))
+ page_counter_uncharge(&memcg->kmem, nr_pages);
+
+ __refill_stock(memcg, nr_pages);
+
+ css_put(&memcg->css);
+ }
/*
* The leftover is flushed to the centralized per-memcg value.
--
2.37.1
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH v2 05/10] mm/memcg: Protect memcg_stock with a local_lock_t
2022-08-08 12:55 [PATCH v2 00/10] Backport MEMCG changes from v5.17 David Oberhollenzer
` (3 preceding siblings ...)
2022-08-08 12:55 ` [PATCH v2 04/10] mm/memcg: Opencode the inner part of obj_cgroup_uncharge_pages() in drain_obj_stock() David Oberhollenzer
@ 2022-08-08 12:55 ` David Oberhollenzer
2022-08-08 12:55 ` [PATCH v2 06/10] mm/memcg: Disable migration instead of preemption in drain_all_stock() David Oberhollenzer
` (5 subsequent siblings)
10 siblings, 0 replies; 12+ messages in thread
From: David Oberhollenzer @ 2022-08-08 12:55 UTC (permalink / raw)
To: linux-rt-users
Cc: williams, bigeasy, richard, joseph.salisbury, kernel test robot,
David Oberhollenzer
From: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
The members of the per-CPU structure memcg_stock_pcp are protected by
disabling interrupts. This is not working on PREEMPT_RT because it
creates atomic context in which actions are performed which require
preemptible context. One example is obj_cgroup_release().
The IRQ-disable sections can be replaced with local_lock_t which
preserves the explicit disabling of interrupts while keeps the code
preemptible on PREEMPT_RT.
drain_obj_stock() drops a reference on obj_cgroup which leads to an invocation
of obj_cgroup_release() if it is the last object. This in turn leads to
recursive locking of the local_lock_t. To avoid this, obj_cgroup_release() is
invoked outside of the locked section.
obj_cgroup_uncharge_pages() can be invoked with the local_lock_t acquired and
without it. This will lead later to a recursion in refill_stock(). To
avoid the locking recursion provide obj_cgroup_uncharge_pages_locked()
which uses the locked version of refill_stock().
- Replace disabling interrupts for memcg_stock with a local_lock_t.
- Let drain_obj_stock() return the old struct obj_cgroup which is passed
to obj_cgroup_put() outside of the locked section.
- Provide obj_cgroup_uncharge_pages_locked() which uses the locked
version of refill_stock() to avoid recursive locking in
drain_obj_stock().
Link: https://lkml.kernel.org/r/20220209014709.GA26885@xsang-OptiPlex-9020
Reported-by: kernel test robot <oliver.sang@intel.com>
Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
[do: backported to v5.15]
Signed-off-by: David Oberhollenzer <goliath@infraroot.at>
---
mm/memcontrol.c | 55 ++++++++++++++++++++++++++++++-------------------
1 file changed, 34 insertions(+), 21 deletions(-)
diff --git a/mm/memcontrol.c b/mm/memcontrol.c
index 2cf55b3ab4b0..20bce9682e8a 100644
--- a/mm/memcontrol.c
+++ b/mm/memcontrol.c
@@ -2152,6 +2152,7 @@ void unlock_page_memcg(struct page *page)
EXPORT_SYMBOL(unlock_page_memcg);
struct memcg_stock_pcp {
+ local_lock_t stock_lock;
struct mem_cgroup *cached; /* this never be root cgroup */
unsigned int nr_pages;
@@ -2167,17 +2168,20 @@ struct memcg_stock_pcp {
unsigned long flags;
#define FLUSHING_CACHED_CHARGE 0
};
-static DEFINE_PER_CPU(struct memcg_stock_pcp, memcg_stock);
+static DEFINE_PER_CPU(struct memcg_stock_pcp, memcg_stock) = {
+ .stock_lock = INIT_LOCAL_LOCK(stock_lock),
+};
static DEFINE_MUTEX(percpu_charge_mutex);
#ifdef CONFIG_MEMCG_KMEM
-static void drain_obj_stock(struct memcg_stock_pcp *stock);
+static struct obj_cgroup *drain_obj_stock(struct memcg_stock_pcp *stock);
static bool obj_stock_flush_required(struct memcg_stock_pcp *stock,
struct mem_cgroup *root_memcg);
#else
-static inline void drain_obj_stock(struct memcg_stock_pcp *stock)
+static inline struct obj_cgroup *drain_obj_stock(struct memcg_stock_pcp *stock)
{
+ return NULL;
}
static bool obj_stock_flush_required(struct memcg_stock_pcp *stock,
struct mem_cgroup *root_memcg)
@@ -2206,7 +2210,7 @@ static bool consume_stock(struct mem_cgroup *memcg, unsigned int nr_pages)
if (nr_pages > MEMCG_CHARGE_BATCH)
return ret;
- local_irq_save(flags);
+ local_lock_irqsave(&memcg_stock.stock_lock, flags);
stock = this_cpu_ptr(&memcg_stock);
if (memcg == stock->cached && stock->nr_pages >= nr_pages) {
@@ -2214,7 +2218,7 @@ static bool consume_stock(struct mem_cgroup *memcg, unsigned int nr_pages)
ret = true;
}
- local_irq_restore(flags);
+ local_unlock_irqrestore(&memcg_stock.stock_lock, flags);
return ret;
}
@@ -2243,6 +2247,7 @@ static void drain_stock(struct memcg_stock_pcp *stock)
static void drain_local_stock(struct work_struct *dummy)
{
struct memcg_stock_pcp *stock;
+ struct obj_cgroup *old = NULL;
unsigned long flags;
/*
@@ -2250,14 +2255,16 @@ static void drain_local_stock(struct work_struct *dummy)
* drain_stock races is that we always operate on local CPU stock
* here with IRQ disabled
*/
- local_irq_save(flags);
+ local_lock_irqsave(&memcg_stock.stock_lock, flags);
stock = this_cpu_ptr(&memcg_stock);
- drain_obj_stock(stock);
+ old = drain_obj_stock(stock);
drain_stock(stock);
clear_bit(FLUSHING_CACHED_CHARGE, &stock->flags);
- local_irq_restore(flags);
+ local_unlock_irqrestore(&memcg_stock.stock_lock, flags);
+ if (old)
+ obj_cgroup_put(old);
}
/*
@@ -2284,9 +2291,9 @@ static void refill_stock(struct mem_cgroup *memcg, unsigned int nr_pages)
{
unsigned long flags;
- local_irq_save(flags);
+ local_lock_irqsave(&memcg_stock.stock_lock, flags);
__refill_stock(memcg, nr_pages);
- local_irq_restore(flags);
+ local_unlock_irqrestore(&memcg_stock.stock_lock, flags);
}
/*
@@ -3095,10 +3102,11 @@ void mod_objcg_state(struct obj_cgroup *objcg, struct pglist_data *pgdat,
enum node_stat_item idx, int nr)
{
struct memcg_stock_pcp *stock;
+ struct obj_cgroup *old = NULL;
unsigned long flags;
int *bytes;
- local_irq_save(flags);
+ local_lock_irqsave(&memcg_stock.stock_lock, flags);
stock = this_cpu_ptr(&memcg_stock);
/*
@@ -3107,7 +3115,7 @@ void mod_objcg_state(struct obj_cgroup *objcg, struct pglist_data *pgdat,
* changes.
*/
if (stock->cached_objcg != objcg) {
- drain_obj_stock(stock);
+ old = drain_obj_stock(stock);
obj_cgroup_get(objcg);
stock->nr_bytes = atomic_read(&objcg->nr_charged_bytes)
? atomic_xchg(&objcg->nr_charged_bytes, 0) : 0;
@@ -3151,7 +3159,9 @@ void mod_objcg_state(struct obj_cgroup *objcg, struct pglist_data *pgdat,
if (nr)
mod_objcg_mlstate(objcg, pgdat, idx, nr);
- local_irq_restore(flags);
+ local_unlock_irqrestore(&memcg_stock.stock_lock, flags);
+ if (old)
+ obj_cgroup_put(old);
}
static bool consume_obj_stock(struct obj_cgroup *objcg, unsigned int nr_bytes)
@@ -3160,7 +3170,7 @@ static bool consume_obj_stock(struct obj_cgroup *objcg, unsigned int nr_bytes)
unsigned long flags;
bool ret = false;
- local_irq_save(flags);
+ local_lock_irqsave(&memcg_stock.stock_lock, flags);
stock = this_cpu_ptr(&memcg_stock);
if (objcg == stock->cached_objcg && stock->nr_bytes >= nr_bytes) {
@@ -3168,17 +3178,17 @@ static bool consume_obj_stock(struct obj_cgroup *objcg, unsigned int nr_bytes)
ret = true;
}
- local_irq_restore(flags);
+ local_unlock_irqrestore(&memcg_stock.stock_lock, flags);
return ret;
}
-static void drain_obj_stock(struct memcg_stock_pcp *stock)
+static struct obj_cgroup *drain_obj_stock(struct memcg_stock_pcp *stock)
{
struct obj_cgroup *old = stock->cached_objcg;
if (!old)
- return;
+ return NULL;
if (stock->nr_bytes) {
unsigned int nr_pages = stock->nr_bytes >> PAGE_SHIFT;
@@ -3230,8 +3240,8 @@ static void drain_obj_stock(struct memcg_stock_pcp *stock)
stock->cached_pgdat = NULL;
}
- obj_cgroup_put(old);
stock->cached_objcg = NULL;
+ return old;
}
static bool obj_stock_flush_required(struct memcg_stock_pcp *stock,
@@ -3252,14 +3262,15 @@ static void refill_obj_stock(struct obj_cgroup *objcg, unsigned int nr_bytes,
bool allow_uncharge)
{
struct memcg_stock_pcp *stock;
+ struct obj_cgroup *old = NULL;
unsigned long flags;
unsigned int nr_pages = 0;
- local_irq_save(flags);
+ local_lock_irqsave(&memcg_stock.stock_lock, flags);
stock = this_cpu_ptr(&memcg_stock);
if (stock->cached_objcg != objcg) { /* reset if necessary */
- drain_obj_stock(stock);
+ old = drain_obj_stock(stock);
obj_cgroup_get(objcg);
stock->cached_objcg = objcg;
stock->nr_bytes = atomic_read(&objcg->nr_charged_bytes)
@@ -3273,7 +3284,9 @@ static void refill_obj_stock(struct obj_cgroup *objcg, unsigned int nr_bytes,
stock->nr_bytes &= (PAGE_SIZE - 1);
}
- local_irq_restore(flags);
+ local_unlock_irqrestore(&memcg_stock.stock_lock, flags);
+ if (old)
+ obj_cgroup_put(old);
if (nr_pages)
obj_cgroup_uncharge_pages(objcg, nr_pages);
--
2.37.1
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH v2 06/10] mm/memcg: Disable migration instead of preemption in drain_all_stock().
2022-08-08 12:55 [PATCH v2 00/10] Backport MEMCG changes from v5.17 David Oberhollenzer
` (4 preceding siblings ...)
2022-08-08 12:55 ` [PATCH v2 05/10] mm/memcg: Protect memcg_stock with a local_lock_t David Oberhollenzer
@ 2022-08-08 12:55 ` David Oberhollenzer
2022-08-08 12:55 ` [PATCH v2 07/10] mm/memcg: Add missing counter index which are not update in interrupt David Oberhollenzer
` (4 subsequent siblings)
10 siblings, 0 replies; 12+ messages in thread
From: David Oberhollenzer @ 2022-08-08 12:55 UTC (permalink / raw)
To: linux-rt-users
Cc: williams, bigeasy, richard, joseph.salisbury, Michal Hocko,
David Oberhollenzer
From: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
Before the for-each-CPU loop, preemption is disabled so that so that
drain_local_stock() can be invoked directly instead of scheduling a
worker. Ensuring that drain_local_stock() completed on the local CPU is
not correctness problem. It _could_ be that the charging path will be
forced to reclaim memory because cached charges are still waiting for
their draining.
Disabling preemption before invoking drain_local_stock() is problematic
on PREEMPT_RT due to the sleeping locks involved. To ensure that no CPU
migrations happens across for_each_online_cpu() it is enouhg to use
migrate_disable() which disables migration and keeps context preemptible
to a sleeping lock can be acquired.
A race with CPU hotplug is not a problem because pcp data is not going away.
In the worst case we just schedule draining of an empty stock.
Use migrate_disable() instead of get_cpu() around the
for_each_online_cpu() loop.
Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
Acked-by: Michal Hocko <mhocko@suse.com>
[do: backported to v5.15]
Signed-off-by: David Oberhollenzer <goliath@infraroot.at>
---
mm/memcontrol.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/mm/memcontrol.c b/mm/memcontrol.c
index 20bce9682e8a..4b5888bf0a60 100644
--- a/mm/memcontrol.c
+++ b/mm/memcontrol.c
@@ -2313,7 +2313,8 @@ static void drain_all_stock(struct mem_cgroup *root_memcg)
* as well as workers from this path always operate on the local
* per-cpu data. CPU up doesn't touch memcg_stock at all.
*/
- curcpu = get_cpu();
+ migrate_disable();
+ curcpu = smp_processor_id();
for_each_online_cpu(cpu) {
struct memcg_stock_pcp *stock = &per_cpu(memcg_stock, cpu);
struct mem_cgroup *memcg;
@@ -2336,7 +2337,7 @@ static void drain_all_stock(struct mem_cgroup *root_memcg)
schedule_work_on(cpu, &stock->work);
}
}
- put_cpu();
+ migrate_enable();
mutex_unlock(&percpu_charge_mutex);
}
--
2.37.1
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH v2 07/10] mm/memcg: Add missing counter index which are not update in interrupt.
2022-08-08 12:55 [PATCH v2 00/10] Backport MEMCG changes from v5.17 David Oberhollenzer
` (5 preceding siblings ...)
2022-08-08 12:55 ` [PATCH v2 06/10] mm/memcg: Disable migration instead of preemption in drain_all_stock() David Oberhollenzer
@ 2022-08-08 12:55 ` David Oberhollenzer
2022-08-08 12:56 ` [PATCH v2 08/10] mm/memcg: Add a comment regarding the release `obj' David Oberhollenzer
` (3 subsequent siblings)
10 siblings, 0 replies; 12+ messages in thread
From: David Oberhollenzer @ 2022-08-08 12:55 UTC (permalink / raw)
To: linux-rt-users
Cc: williams, bigeasy, richard, joseph.salisbury, David Oberhollenzer
From: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
Shakeel Butt reported that I missed a few counters which are not updated
in-interrupt context and therefore disabling preemption is fine.
Please fold into:
"Protect per-CPU counter by disabling preemption on PREEMPT_RT"
Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
[do: backported to v5.15]
Signed-off-by: David Oberhollenzer <goliath@infraroot.at>
---
mm/memcontrol.c | 11 +++++++++--
1 file changed, 9 insertions(+), 2 deletions(-)
diff --git a/mm/memcontrol.c b/mm/memcontrol.c
index 4b5888bf0a60..50d2d5432018 100644
--- a/mm/memcontrol.c
+++ b/mm/memcontrol.c
@@ -774,10 +774,17 @@ void __mod_memcg_lruvec_state(struct lruvec *lruvec, enum node_stat_item idx,
*/
__memcg_stats_lock();
if (IS_ENABLED(CONFIG_DEBUG_VM)) {
- if (idx == NR_ANON_MAPPED || idx == NR_FILE_MAPPED)
+ switch (idx) {
+ case NR_ANON_MAPPED:
+ case NR_FILE_MAPPED:
+ case NR_ANON_THPS:
+ case NR_SHMEM_PMDMAPPED:
+ case NR_FILE_PMDMAPPED:
WARN_ON_ONCE(!in_task());
- else
+ break;
+ default:
WARN_ON_ONCE(!irqs_disabled());
+ }
}
/* Update memcg */
--
2.37.1
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH v2 08/10] mm/memcg: Add a comment regarding the release `obj'.
2022-08-08 12:55 [PATCH v2 00/10] Backport MEMCG changes from v5.17 David Oberhollenzer
` (6 preceding siblings ...)
2022-08-08 12:55 ` [PATCH v2 07/10] mm/memcg: Add missing counter index which are not update in interrupt David Oberhollenzer
@ 2022-08-08 12:56 ` David Oberhollenzer
2022-08-08 12:56 ` [PATCH v2 09/10] mm/memcg: Only perform the debug checks on !PREEMPT_RT David Oberhollenzer
` (2 subsequent siblings)
10 siblings, 0 replies; 12+ messages in thread
From: David Oberhollenzer @ 2022-08-08 12:56 UTC (permalink / raw)
To: linux-rt-users
Cc: williams, bigeasy, richard, joseph.salisbury, David Oberhollenzer
From: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
Please fold into
mm/memcg: Protect memcg_stock with a local_lock_t
Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
[do: backported to v5.15]
Signed-off-by: David Oberhollenzer <goliath@infraroot.at>
---
mm/memcontrol.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/mm/memcontrol.c b/mm/memcontrol.c
index 50d2d5432018..70c374761bb8 100644
--- a/mm/memcontrol.c
+++ b/mm/memcontrol.c
@@ -3249,6 +3249,10 @@ static struct obj_cgroup *drain_obj_stock(struct memcg_stock_pcp *stock)
}
stock->cached_objcg = NULL;
+ /*
+ * The `old' objects needs to be released by the caller via
+ * obj_cgroup_put() outside of memcg_stock_pcp::stock_lock.
+ */
return old;
}
--
2.37.1
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH v2 09/10] mm/memcg: Only perform the debug checks on !PREEMPT_RT
2022-08-08 12:55 [PATCH v2 00/10] Backport MEMCG changes from v5.17 David Oberhollenzer
` (7 preceding siblings ...)
2022-08-08 12:56 ` [PATCH v2 08/10] mm/memcg: Add a comment regarding the release `obj' David Oberhollenzer
@ 2022-08-08 12:56 ` David Oberhollenzer
2022-08-08 12:56 ` [PATCH v2 10/10] Allow MEMCG on PREEMPT_RT David Oberhollenzer
2022-08-18 15:55 ` [PATCH v2 00/10] Backport MEMCG changes from v5.17 Sebastian Andrzej Siewior
10 siblings, 0 replies; 12+ messages in thread
From: David Oberhollenzer @ 2022-08-08 12:56 UTC (permalink / raw)
To: linux-rt-users
Cc: williams, bigeasy, richard, joseph.salisbury, David Oberhollenzer
From: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
On PREEMPT_RT interrupts and preemption is always enabled. The locking
function __memcg_stats_lock() always disabled preemptions. The recently
added checks need to performed only on !PREEMPT_RT where preemption and
disabled interrupts are used.
Please fold into:
"Protect per-CPU counter by disabling preemption on PREEMPT_RT"
Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
[do: backported to v5.15]
Signed-off-by: David Oberhollenzer <goliath@infraroot.at>
---
mm/memcontrol.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/mm/memcontrol.c b/mm/memcontrol.c
index 70c374761bb8..74025c2e2bcc 100644
--- a/mm/memcontrol.c
+++ b/mm/memcontrol.c
@@ -773,7 +773,7 @@ void __mod_memcg_lruvec_state(struct lruvec *lruvec, enum node_stat_item idx,
* interrupt context while other caller need to have disabled interrupt.
*/
__memcg_stats_lock();
- if (IS_ENABLED(CONFIG_DEBUG_VM)) {
+ if (IS_ENABLED(CONFIG_DEBUG_VM) && !IS_ENABLED(CONFIG_PREEMPT_RT)) {
switch (idx) {
case NR_ANON_MAPPED:
case NR_FILE_MAPPED:
--
2.37.1
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH v2 10/10] Allow MEMCG on PREEMPT_RT
2022-08-08 12:55 [PATCH v2 00/10] Backport MEMCG changes from v5.17 David Oberhollenzer
` (8 preceding siblings ...)
2022-08-08 12:56 ` [PATCH v2 09/10] mm/memcg: Only perform the debug checks on !PREEMPT_RT David Oberhollenzer
@ 2022-08-08 12:56 ` David Oberhollenzer
2022-08-18 15:55 ` [PATCH v2 00/10] Backport MEMCG changes from v5.17 Sebastian Andrzej Siewior
10 siblings, 0 replies; 12+ messages in thread
From: David Oberhollenzer @ 2022-08-08 12:56 UTC (permalink / raw)
To: linux-rt-users
Cc: williams, bigeasy, richard, joseph.salisbury, David Oberhollenzer
With these backported, it is safe to use MEMCG again:
0001-mm-memcg-Revert-mm-memcg-optimize-user-context-objec.patch
0002-mm-memcg-Disable-threshold-event-handlers-on-PREEMPT.patch
0003-mm-memcg-Protect-per-CPU-counter-by-disabling-preemp.patch
0004-mm-memcg-Opencode-the-inner-part-of-obj_cgroup_uncha.patch
0005-mm-memcg-Protect-memcg_stock-with-a-local_lock_t.patch
0006-mm-memcg-Disable-migration-instead-of-preemption-in-.patch
0007-mm-memcg-Add-missing-counter-index-which-are-not-upd.patch
0008-mm-memcg-Add-a-comment-regarding-the-release-obj.patch
0009-mm-memcg-Only-perform-the-debug-checks-on-PREEMPT_RT.patch
Signed-off-by: David Oberhollenzer <goliath@infraroot.at>
---
init/Kconfig | 1 -
1 file changed, 1 deletion(-)
diff --git a/init/Kconfig b/init/Kconfig
index 160f836f81c7..1646c25f6ec5 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -943,7 +943,6 @@ config PAGE_COUNTER
config MEMCG
bool "Memory controller"
- depends on !PREEMPT_RT
select PAGE_COUNTER
select EVENTFD
help
--
2.37.1
^ permalink raw reply related [flat|nested] 12+ messages in thread
* Re: [PATCH v2 00/10] Backport MEMCG changes from v5.17
2022-08-08 12:55 [PATCH v2 00/10] Backport MEMCG changes from v5.17 David Oberhollenzer
` (9 preceding siblings ...)
2022-08-08 12:56 ` [PATCH v2 10/10] Allow MEMCG on PREEMPT_RT David Oberhollenzer
@ 2022-08-18 15:55 ` Sebastian Andrzej Siewior
10 siblings, 0 replies; 12+ messages in thread
From: Sebastian Andrzej Siewior @ 2022-08-18 15:55 UTC (permalink / raw)
To: David Oberhollenzer; +Cc: linux-rt-users, williams, richard, joseph.salisbury
On 2022-08-08 14:55:52 [+0200], David Oberhollenzer wrote:
> This is a backport of Sebastian's MEMCG changes to v5.15. With these
> patches applied, it is possible to use memory cgroups together
> with PREEMPT_RT on v5.15, just like on v5.17.
>
> The patch set was tested on my end by building an x86_64 kernel
> with PREEMPT_RT, cgroup debug and lockdep enabled. The kernel was
> run in Qemu, where a small number of child cgroups were created,
> with memory controller enabled for each and an instance of a small
> test program running.
This looks good, thank you.
Sebastian
^ permalink raw reply [flat|nested] 12+ messages in thread
end of thread, other threads:[~2022-08-18 15:56 UTC | newest]
Thread overview: 12+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2022-08-08 12:55 [PATCH v2 00/10] Backport MEMCG changes from v5.17 David Oberhollenzer
2022-08-08 12:55 ` [PATCH v2 01/10] mm/memcg: Revert ("mm/memcg: optimize user context object stock access") David Oberhollenzer
2022-08-08 12:55 ` [PATCH v2 02/10] mm/memcg: Disable threshold event handlers on PREEMPT_RT David Oberhollenzer
2022-08-08 12:55 ` [PATCH v2 03/10] mm/memcg: Protect per-CPU counter by disabling preemption on PREEMPT_RT where needed David Oberhollenzer
2022-08-08 12:55 ` [PATCH v2 04/10] mm/memcg: Opencode the inner part of obj_cgroup_uncharge_pages() in drain_obj_stock() David Oberhollenzer
2022-08-08 12:55 ` [PATCH v2 05/10] mm/memcg: Protect memcg_stock with a local_lock_t David Oberhollenzer
2022-08-08 12:55 ` [PATCH v2 06/10] mm/memcg: Disable migration instead of preemption in drain_all_stock() David Oberhollenzer
2022-08-08 12:55 ` [PATCH v2 07/10] mm/memcg: Add missing counter index which are not update in interrupt David Oberhollenzer
2022-08-08 12:56 ` [PATCH v2 08/10] mm/memcg: Add a comment regarding the release `obj' David Oberhollenzer
2022-08-08 12:56 ` [PATCH v2 09/10] mm/memcg: Only perform the debug checks on !PREEMPT_RT David Oberhollenzer
2022-08-08 12:56 ` [PATCH v2 10/10] Allow MEMCG on PREEMPT_RT David Oberhollenzer
2022-08-18 15:55 ` [PATCH v2 00/10] Backport MEMCG changes from v5.17 Sebastian Andrzej Siewior
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.