[ANNOUNCE] v5.16-rt15

From: Sebastian Andrzej Siewior
Date: Thu Jan 13 2022 - 04:12:56 EST


Dear RT folks!

I'm pleased to announce the v5.16-rt15 patch set.

Changes since v5.16-rt14:

- Backport a write_lock_nested() fix. Introduced by the zsmalloc
patches, leading to build failure in certain configurations.

- In memcg patch, pass a bool instead of a pointer.

Known issues
- netconsole triggers WARN.

- Valentin Schneider reported a few splats on ARM64, see
https://lkml.kernel.org/r/20210810134127.1394269-1-valentin.schneider@xxxxxxx

The delta patch against v5.16-rt14 is appended below and can be found here:

https://cdn.kernel.org/pub/linux/kernel/projects/rt/5.16/incr/patch-5.16-rt14-rt15.patch.xz

You can get this release via the git tree at:

git://git.kernel.org/pub/scm/linux/kernel/git/rt/linux-rt-devel.git v5.16-rt15

The RT patch against v5.16 can be found here:

https://cdn.kernel.org/pub/linux/kernel/projects/rt/5.16/older/patch-5.16-rt15.patch.xz

The split quilt queue is available at:

https://cdn.kernel.org/pub/linux/kernel/projects/rt/5.16/older/patches-5.16-rt15.tar.xz

Sebastian

diff --git a/include/linux/rwlock_api_smp.h b/include/linux/rwlock_api_smp.h
index f0c535ec4e654..dceb0a59b6927 100644
--- a/include/linux/rwlock_api_smp.h
+++ b/include/linux/rwlock_api_smp.h
@@ -47,7 +47,6 @@ _raw_write_unlock_irqrestore(rwlock_t *lock, unsigned long flags)

#ifdef CONFIG_INLINE_WRITE_LOCK
#define _raw_write_lock(lock) __raw_write_lock(lock)
-#define _raw_write_lock_nested(lock, subclass) __raw_write_lock_nested(lock, subclass)
#endif

#ifdef CONFIG_INLINE_READ_LOCK_BH
diff --git a/kernel/locking/spinlock.c b/kernel/locking/spinlock.c
index 996811efa6d6e..7f49baaa49793 100644
--- a/kernel/locking/spinlock.c
+++ b/kernel/locking/spinlock.c
@@ -301,6 +301,10 @@ void __lockfunc _raw_write_lock(rwlock_t *lock)
}
EXPORT_SYMBOL(_raw_write_lock);

+#ifndef CONFIG_DEBUG_LOCK_ALLOC
+#define __raw_write_lock_nested(lock, subclass) __raw_write_lock(((void)(subclass), (lock)))
+#endif
+
void __lockfunc _raw_write_lock_nested(rwlock_t *lock, int subclass)
{
__raw_write_lock_nested(lock, subclass);
diff --git a/localversion-rt b/localversion-rt
index 08b3e75841adc..18777ec0c27d4 100644
--- a/localversion-rt
+++ b/localversion-rt
@@ -1 +1 @@
--rt14
+-rt15
diff --git a/mm/memcontrol.c b/mm/memcontrol.c
index 92180f1aa9edc..bfb99225527fe 100644
--- a/mm/memcontrol.c
+++ b/mm/memcontrol.c
@@ -264,7 +264,7 @@ bool mem_cgroup_kmem_disabled(void)
struct memcg_stock_pcp;
static void obj_cgroup_uncharge_pages(struct obj_cgroup *objcg,
unsigned int nr_pages,
- struct memcg_stock_pcp *stock_pcp);
+ bool stock_lock_acquried);

static void obj_cgroup_release(struct percpu_ref *ref)
{
@@ -298,7 +298,7 @@ static void obj_cgroup_release(struct percpu_ref *ref)
nr_pages = nr_bytes >> PAGE_SHIFT;

if (nr_pages)
- obj_cgroup_uncharge_pages(objcg, nr_pages, NULL);
+ obj_cgroup_uncharge_pages(objcg, nr_pages, false);

spin_lock_irqsave(&css_set_lock, flags);
list_del(&objcg->list);
@@ -2147,13 +2147,13 @@ static DEFINE_MUTEX(percpu_charge_mutex);

#ifdef CONFIG_MEMCG_KMEM
static struct obj_cgroup *drain_obj_stock(struct obj_stock *stock,
- struct memcg_stock_pcp *stock_pcp);
+ bool stock_lock_acquried);
static bool obj_stock_flush_required(struct memcg_stock_pcp *stock,
struct mem_cgroup *root_memcg);

#else
static inline struct obj_cgroup *drain_obj_stock(struct obj_stock *stock,
- struct memcg_stock_pcp *stock_pcp)
+ bool stock_lock_acquried)
{
return NULL;
}
@@ -2252,11 +2252,11 @@ 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,
- struct memcg_stock_pcp *stock)
+static void __refill_stock(struct mem_cgroup *memcg, unsigned int nr_pages)
{
- lockdep_assert_held(&stock->stock_lock);
+ struct memcg_stock_pcp *stock = this_cpu_ptr(&memcg_stock);

+ lockdep_assert_held(&stock->stock_lock);
if (stock->cached != memcg) { /* reset if necessary */
drain_stock(stock);
css_get(&memcg->css);
@@ -2269,16 +2269,16 @@ 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_pcp)
+ bool stock_lock_acquried)
{
unsigned long flags;

- if (stock_pcp) {
- __refill_stock(memcg, nr_pages, stock_pcp);
+ if (stock_lock_acquried) {
+ __refill_stock(memcg, nr_pages);
return;
}
local_lock_irqsave(&memcg_stock.stock_lock, flags);
- __refill_stock(memcg, nr_pages, this_cpu_ptr(&memcg_stock));
+ __refill_stock(memcg, nr_pages);
local_unlock_irqrestore(&memcg_stock.stock_lock, flags);
}

@@ -2719,7 +2719,7 @@ static int try_charge_memcg(struct mem_cgroup *memcg, gfp_t gfp_mask,

done_restock:
if (batch > nr_pages)
- refill_stock(memcg, batch - nr_pages, NULL);
+ refill_stock(memcg, batch - nr_pages, false);

/*
* If the hierarchy is above the normal consumption range, schedule
@@ -2833,34 +2833,35 @@ static struct mem_cgroup *get_mem_cgroup_from_objcg(struct obj_cgroup *objcg)
* access interrupt object stock, but not vice versa.
*/
static inline struct obj_stock *get_obj_stock(unsigned long *pflags,
- struct memcg_stock_pcp **stock_pcp)
+ bool *stock_lock_acquried)
{
struct memcg_stock_pcp *stock;

#ifndef CONFIG_PREEMPTION
if (likely(in_task())) {
*pflags = 0UL;
- *stock_pcp = NULL;
+ *stock_lock_acquried = false;
local_lock(&memcg_stock.task_obj_lock);
stock = this_cpu_ptr(&memcg_stock);
return &stock->task_obj;
}
#endif
+ *stock_lock_acquried = true;
local_lock_irqsave(&memcg_stock.stock_lock, *pflags);
stock = this_cpu_ptr(&memcg_stock);
- *stock_pcp = stock;
return &stock->irq_obj;
}

static inline void put_obj_stock(unsigned long flags,
- struct memcg_stock_pcp *stock_pcp)
+ bool stock_lock_acquried)
{
#ifndef CONFIG_PREEMPTION
- if (likely(!stock_pcp))
+ if (likely(!stock_lock_acquried)) {
local_unlock(&memcg_stock.task_obj_lock);
- else
+ return;
+ }
#endif
- local_unlock_irqrestore(&memcg_stock.stock_lock, flags);
+ local_unlock_irqrestore(&memcg_stock.stock_lock, flags);
}

/*
@@ -3039,7 +3040,7 @@ static void memcg_free_cache_id(int id)
*/
static void obj_cgroup_uncharge_pages(struct obj_cgroup *objcg,
unsigned int nr_pages,
- struct memcg_stock_pcp *stock_pcp)
+ bool stock_lock_acquried)
{
struct mem_cgroup *memcg;

@@ -3047,7 +3048,7 @@ static void obj_cgroup_uncharge_pages(struct obj_cgroup *objcg,

if (!cgroup_subsys_on_dfl(memory_cgrp_subsys))
page_counter_uncharge(&memcg->kmem, nr_pages);
- refill_stock(memcg, nr_pages, stock_pcp);
+ refill_stock(memcg, nr_pages, stock_lock_acquried);

css_put(&memcg->css);
}
@@ -3121,7 +3122,7 @@ void __memcg_kmem_uncharge_page(struct page *page, int order)
return;

objcg = __folio_objcg(folio);
- obj_cgroup_uncharge_pages(objcg, nr_pages, NULL);
+ obj_cgroup_uncharge_pages(objcg, nr_pages, false);
folio->memcg_data = 0;
obj_cgroup_put(objcg);
}
@@ -3129,20 +3130,20 @@ 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_pcp;
+ bool stock_lock_acquried;
unsigned long flags;
struct obj_cgroup *old = NULL;
struct obj_stock *stock;
int *bytes;

- stock = get_obj_stock(&flags, &stock_pcp);
+ stock = get_obj_stock(&flags, &stock_lock_acquried);
/*
* Save vmstat data in stock and skip vmstat array update unless
* accumulating over a page of vmstat data or when pgdat or idx
* changes.
*/
if (stock->cached_objcg != objcg) {
- old = drain_obj_stock(stock, stock_pcp);
+ old = drain_obj_stock(stock, stock_lock_acquried);

obj_cgroup_get(objcg);
stock->nr_bytes = atomic_read(&objcg->nr_charged_bytes)
@@ -3187,31 +3188,31 @@ 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, stock_pcp);
+ put_obj_stock(flags, stock_lock_acquried);
if (old)
obj_cgroup_put(old);
}

static bool consume_obj_stock(struct obj_cgroup *objcg, unsigned int nr_bytes)
{
- struct memcg_stock_pcp *stock_pcp;
+ bool stock_lock_acquried;
unsigned long flags;
struct obj_stock *stock;
bool ret = false;

- stock = get_obj_stock(&flags, &stock_pcp);
+ stock = get_obj_stock(&flags, &stock_lock_acquried);
if (objcg == stock->cached_objcg && stock->nr_bytes >= nr_bytes) {
stock->nr_bytes -= nr_bytes;
ret = true;
}

- put_obj_stock(flags, stock_pcp);
+ put_obj_stock(flags, stock_lock_acquried);

return ret;
}

static struct obj_cgroup *drain_obj_stock(struct obj_stock *stock,
- struct memcg_stock_pcp *stock_pcp)
+ bool stock_lock_acquried)
{
struct obj_cgroup *old = stock->cached_objcg;

@@ -3223,7 +3224,7 @@ static struct obj_cgroup *drain_obj_stock(struct obj_stock *stock,
unsigned int nr_bytes = stock->nr_bytes & (PAGE_SIZE - 1);

if (nr_pages)
- obj_cgroup_uncharge_pages(old, nr_pages, stock_pcp);
+ obj_cgroup_uncharge_pages(old, nr_pages, stock_lock_acquried);

/*
* The leftover is flushed to the centralized per-memcg value.
@@ -3286,15 +3287,15 @@ 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_pcp;
+ bool stock_lock_acquried;
unsigned long flags;
struct obj_stock *stock;
unsigned int nr_pages = 0;
struct obj_cgroup *old = NULL;

- stock = get_obj_stock(&flags, &stock_pcp);
+ stock = get_obj_stock(&flags, &stock_lock_acquried);
if (stock->cached_objcg != objcg) { /* reset if necessary */
- old = drain_obj_stock(stock, stock_pcp);
+ old = drain_obj_stock(stock, stock_lock_acquried);
obj_cgroup_get(objcg);
stock->cached_objcg = objcg;
stock->nr_bytes = atomic_read(&objcg->nr_charged_bytes)
@@ -3308,12 +3309,12 @@ static void refill_obj_stock(struct obj_cgroup *objcg, unsigned int nr_bytes,
stock->nr_bytes &= (PAGE_SIZE - 1);
}

- put_obj_stock(flags, stock_pcp);
+ put_obj_stock(flags, stock_lock_acquried);
if (old)
obj_cgroup_put(old);

if (nr_pages)
- obj_cgroup_uncharge_pages(objcg, nr_pages, NULL);
+ obj_cgroup_uncharge_pages(objcg, nr_pages, false);
}

int obj_cgroup_charge(struct obj_cgroup *objcg, gfp_t gfp, size_t size)
@@ -7114,7 +7115,7 @@ void mem_cgroup_uncharge_skmem(struct mem_cgroup *memcg, unsigned int nr_pages)

mod_memcg_state(memcg, MEMCG_SOCK, -nr_pages);

- refill_stock(memcg, nr_pages, NULL);
+ refill_stock(memcg, nr_pages, false);
}

static int __init cgroup_memory(char *s)