* [PATCH v19 34/40] rcu/update: fix same dept key collision between various types of RCU
From: Byungchul Park @ 2026-07-06 6:19 UTC (permalink / raw)
To: linux-kernel
Cc: max.byungchul.park, kernel_team, torvalds, damien.lemoal,
linux-ide, adilger.kernel, linux-ext4, mingo, peterz, will, tglx,
rostedt, joel, sashal, daniel.vetter, duyuyang, johannes.berg, tj,
tytso, willy, david, amir73il, gregkh, kernel-team, linux-mm,
akpm, mhocko, minchan, hannes, vdavydov.dev, sj, jglisse, dennis,
cl, penberg, rientjes, vbabka, ngupta, linux-block, josef,
linux-fsdevel, jack, jlayton, dan.j.williams, hch, djwong,
dri-devel, rodrigosiqueiramelo, melissa.srw, hamohammed.sa,
harry.yoo, chris.p.wilson, gwan-gyeong.mun, boqun.feng, longman,
yunseong.kim, ysk, yeoreum.yun, netdev, matthew.brost, her0gyugyu,
corbet, catalin.marinas, bp, x86, hpa, luto, sumit.semwal,
gustavo, christian.koenig, andi.shyti, arnd, lorenzo.stoakes,
Liam.Howlett, rppt, surenb, mcgrof, petr.pavlu, da.gomez,
samitolvanen, paulmck, frederic, neeraj.upadhyay, joelagnelf,
josh, urezki, mathieu.desnoyers, jiangshanlai, qiang.zhang,
juri.lelli, vincent.guittot, dietmar.eggemann, bsegall, mgorman,
vschneid, chuck.lever, neil, okorniev, Dai.Ngo, tom, trondmy,
anna, kees, bigeasy, clrkwllms, mark.rutland, ada.coupriediaz,
kristina.martsenko, wangkefeng.wang, broonie, kevin.brodsky, dwmw,
shakeel.butt, ast, ziy, yuzhao, baolin.wang, usamaarif642,
joel.granados, richard.weiyang, geert+renesas, tim.c.chen, linux,
alexander.shishkin, lillian, chenhuacai, francesco,
guoweikang.kernel, link, jpoimboe, masahiroy, brauner,
thomas.weissschuh, oleg, mjguzik, andrii, wangfushuai, linux-doc,
linux-arm-kernel, linux-media, linaro-mm-sig, linux-i2c,
linux-arch, linux-modules, rcu, linux-nfs, linux-rt-devel,
2407018371, dakr, miguel.ojeda.sandonis, neilb, bagasdotme,
wsa+renesas, dave.hansen, geert, ojeda, alex.gaynor, gary,
bjorn3_gh, lossin, a.hindborg, aliceryhl, tmgross, rust-for-linux
In-Reply-To: <20260706061928.66713-1-byungchul@sk.com>
From: Yunseong Kim <ysk@kzalloc.com>
The current implementation shares the same dept key for multiple
synchronization points, which can lead to false positive reports in
dependency tracking and potential confusion in debugging. For example,
both normal RCU and tasks trace RCU synchronization points use the same
dept key. Specifically:
1. synchronize_rcu() uses a dept key embedded in __wait_rcu_gp():
synchronize_rcu()
synchronize_rcu_normal()
_wait_rcu_gp()
__wait_rcu_gp() <- the key as static variable
2. synchronize_rcu_tasks_trace() uses the dept key, too:
synchronize_rcu_tasks_trace()
synchronize_rcu_tasks_generic()
_wait_rcu_gp()
__wait_rcu_gp() <- the key as static variable
Since the both rely on the same dept key, dept may report false positive
circular dependency. To resolve this, separate dept keys and maps
should be assigned to each struct rcu_synchronize.
===================================================
DEPT: Circular dependency has been detected.
6.15.0-rc6-00042-ged94bafc6405 #2 Not tainted
---------------------------------------------------
summary
---------------------------------------------------
*** DEADLOCK ***
context A
[S] lock(cpu_hotplug_lock:0)
[W] __wait_rcu_gp(<sched>:0)
[E] unlock(cpu_hotplug_lock:0)
context B
[S] (unknown)(<sched>:0)
[W] lock(cpu_hotplug_lock:0)
[E] try_to_wake_up(<sched>:0)
[S]: start of the event context
[W]: the wait blocked
[E]: the event not reachable
---------------------------------------------------
context A's detail
---------------------------------------------------
context A
[S] lock(cpu_hotplug_lock:0)
[W] __wait_rcu_gp(<sched>:0)
[E] unlock(cpu_hotplug_lock:0)
[S] lock(cpu_hotplug_lock:0):
[<ffff8000802ce964>] cpus_read_lock+0x14/0x20
stacktrace:
percpu_down_read.constprop.0+0x88/0x2ec
cpus_read_lock+0x14/0x20
cgroup_procs_write_start+0x164/0x634
__cgroup_procs_write+0xdc/0x4d0
cgroup_procs_write+0x34/0x74
cgroup_file_write+0x25c/0x670
kernfs_fop_write_iter+0x2ec/0x498
vfs_write+0x574/0xc30
ksys_write+0x124/0x244
__arm64_sys_write+0x70/0xa4
invoke_syscall+0x88/0x2e0
el0_svc_common.constprop.0+0xe8/0x2e0
do_el0_svc+0x44/0x60
el0_svc+0x50/0x188
el0t_64_sync_handler+0x10c/0x140
el0t_64_sync+0x198/0x19c
[W] __wait_rcu_gp(<sched>:0):
[<ffff8000804ce88c>] __wait_rcu_gp+0x324/0x498
stacktrace:
schedule+0xcc/0x348
schedule_timeout+0x1a4/0x268
__wait_for_common+0x1c4/0x3f0
__wait_for_completion_state+0x20/0x38
__wait_rcu_gp+0x35c/0x498
synchronize_rcu_normal+0x200/0x218
synchronize_rcu+0x234/0x2a0
rcu_sync_enter+0x11c/0x300
percpu_down_write+0xb4/0x3e0
cgroup_procs_write_start+0x174/0x634
__cgroup_procs_write+0xdc/0x4d0
cgroup_procs_write+0x34/0x74
cgroup_file_write+0x25c/0x670
kernfs_fop_write_iter+0x2ec/0x498
vfs_write+0x574/0xc30
ksys_write+0x124/0x244
[E] unlock(cpu_hotplug_lock:0):
(N/A)
---------------------------------------------------
context B's detail
---------------------------------------------------
context B
[S] (unknown)(<sched>:0)
[W] lock(cpu_hotplug_lock:0)
[E] try_to_wake_up(<sched>:0)
[S] (unknown)(<sched>:0):
(N/A)
[W] lock(cpu_hotplug_lock:0):
[<ffff8000802ce964>] cpus_read_lock+0x14/0x20
stacktrace:
percpu_down_read.constprop.0+0x6c/0x2ec
cpus_read_lock+0x14/0x20
check_all_holdout_tasks_trace+0x90/0xa30
rcu_tasks_wait_gp+0x47c/0x938
rcu_tasks_one_gp+0x75c/0xef8
rcu_tasks_kthread+0x180/0x1dc
kthread+0x3ac/0x74c
ret_from_fork+0x10/0x20
[E] try_to_wake_up(<sched>:0):
[<ffff8000804233b8>] complete+0xb8/0x1e8
stacktrace:
try_to_wake_up+0x374/0x1164
complete+0xb8/0x1e8
wakeme_after_rcu+0x14/0x20
rcu_tasks_invoke_cbs+0x218/0xaa8
rcu_tasks_one_gp+0x834/0xef8
rcu_tasks_kthread+0x180/0x1dc
kthread+0x3ac/0x74c
ret_from_fork+0x10/0x20
(wait to wake up)
stacktrace:
__schedule+0xf64/0x3614
schedule+0xcc/0x348
schedule_timeout+0x1a4/0x268
__wait_for_common+0x1c4/0x3f0
__wait_for_completion_state+0x20/0x38
__wait_rcu_gp+0x35c/0x498
synchronize_rcu_tasks_generic+0x14c/0x220
synchronize_rcu_tasks_trace+0x24/0x8c
rcu_init_tasks_generic+0x168/0x194
do_one_initcall+0x174/0xa00
kernel_init_freeable+0x744/0x7dc
kernel_init+0x78/0x220
ret_from_fork+0x10/0x20
Separating the dept key and map for each of struct rcu_synchronize,
ensuring proper tracking for each execution context.
Signed-off-by: Yunseong Kim <ysk@kzalloc.com>
[ Rewrote the changelog. ]
Signed-off-by: Byungchul Park <byungchul@sk.com>
---
include/linux/rcupdate_wait.h | 13 ++++++++-----
kernel/rcu/rcu.h | 1 +
kernel/rcu/update.c | 5 +++--
3 files changed, 12 insertions(+), 7 deletions(-)
diff --git a/include/linux/rcupdate_wait.h b/include/linux/rcupdate_wait.h
index 4c92d4291cce..ee598e70b4bc 100644
--- a/include/linux/rcupdate_wait.h
+++ b/include/linux/rcupdate_wait.h
@@ -19,17 +19,20 @@ struct rcu_synchronize {
/* This is for debugging. */
struct rcu_gp_oldstate oldstate;
+ struct dept_map dmap;
+ struct dept_key dkey;
};
void wakeme_after_rcu(struct rcu_head *head);
void __wait_rcu_gp(bool checktiny, unsigned int state, int n, call_rcu_func_t *crcu_array,
- struct rcu_synchronize *rs_array);
+ struct rcu_synchronize *rs_array, struct dept_key *dkey);
#define _wait_rcu_gp(checktiny, state, ...) \
-do { \
- call_rcu_func_t __crcu_array[] = { __VA_ARGS__ }; \
- struct rcu_synchronize __rs_array[ARRAY_SIZE(__crcu_array)]; \
- __wait_rcu_gp(checktiny, state, ARRAY_SIZE(__crcu_array), __crcu_array, __rs_array); \
+do { \
+ call_rcu_func_t __crcu_array[] = { __VA_ARGS__ }; \
+ static struct dept_key __key; \
+ struct rcu_synchronize __rs_array[ARRAY_SIZE(__crcu_array)]; \
+ __wait_rcu_gp(checktiny, state, ARRAY_SIZE(__crcu_array), __crcu_array, __rs_array, &__key); \
} while (0)
#define wait_rcu_gp(...) _wait_rcu_gp(false, TASK_UNINTERRUPTIBLE, __VA_ARGS__)
diff --git a/kernel/rcu/rcu.h b/kernel/rcu/rcu.h
index 9b10b57b79ad..d30dfc345532 100644
--- a/kernel/rcu/rcu.h
+++ b/kernel/rcu/rcu.h
@@ -12,6 +12,7 @@
#include <linux/slab.h>
#include <trace/events/rcu.h>
+#include <linux/dept_sdt.h>
/*
* Grace-period counter management.
diff --git a/kernel/rcu/update.c b/kernel/rcu/update.c
index d98a5c38e19c..c2858650ccf5 100644
--- a/kernel/rcu/update.c
+++ b/kernel/rcu/update.c
@@ -409,7 +409,7 @@ void wakeme_after_rcu(struct rcu_head *head)
EXPORT_SYMBOL_GPL(wakeme_after_rcu);
void __wait_rcu_gp(bool checktiny, unsigned int state, int n, call_rcu_func_t *crcu_array,
- struct rcu_synchronize *rs_array)
+ struct rcu_synchronize *rs_array, struct dept_key *dkey)
{
int i;
int j;
@@ -426,7 +426,8 @@ void __wait_rcu_gp(bool checktiny, unsigned int state, int n, call_rcu_func_t *c
break;
if (j == i) {
init_rcu_head_on_stack(&rs_array[i].head);
- init_completion(&rs_array[i].completion);
+ sdt_map_init_key(&rs_array[i].dmap, dkey);
+ init_completion_dmap(&rs_array[i].completion, &rs_array[i].dmap);
(crcu_array[i])(&rs_array[i].head, wakeme_after_rcu);
}
}
--
2.17.1
^ permalink raw reply related
* [PATCH v19 35/40] dept: introduce APIs to set page usage and use subclasses_evt for the usage
From: Byungchul Park @ 2026-07-06 6:19 UTC (permalink / raw)
To: linux-kernel
Cc: max.byungchul.park, kernel_team, torvalds, damien.lemoal,
linux-ide, adilger.kernel, linux-ext4, mingo, peterz, will, tglx,
rostedt, joel, sashal, daniel.vetter, duyuyang, johannes.berg, tj,
tytso, willy, david, amir73il, gregkh, kernel-team, linux-mm,
akpm, mhocko, minchan, hannes, vdavydov.dev, sj, jglisse, dennis,
cl, penberg, rientjes, vbabka, ngupta, linux-block, josef,
linux-fsdevel, jack, jlayton, dan.j.williams, hch, djwong,
dri-devel, rodrigosiqueiramelo, melissa.srw, hamohammed.sa,
harry.yoo, chris.p.wilson, gwan-gyeong.mun, boqun.feng, longman,
yunseong.kim, ysk, yeoreum.yun, netdev, matthew.brost, her0gyugyu,
corbet, catalin.marinas, bp, x86, hpa, luto, sumit.semwal,
gustavo, christian.koenig, andi.shyti, arnd, lorenzo.stoakes,
Liam.Howlett, rppt, surenb, mcgrof, petr.pavlu, da.gomez,
samitolvanen, paulmck, frederic, neeraj.upadhyay, joelagnelf,
josh, urezki, mathieu.desnoyers, jiangshanlai, qiang.zhang,
juri.lelli, vincent.guittot, dietmar.eggemann, bsegall, mgorman,
vschneid, chuck.lever, neil, okorniev, Dai.Ngo, tom, trondmy,
anna, kees, bigeasy, clrkwllms, mark.rutland, ada.coupriediaz,
kristina.martsenko, wangkefeng.wang, broonie, kevin.brodsky, dwmw,
shakeel.butt, ast, ziy, yuzhao, baolin.wang, usamaarif642,
joel.granados, richard.weiyang, geert+renesas, tim.c.chen, linux,
alexander.shishkin, lillian, chenhuacai, francesco,
guoweikang.kernel, link, jpoimboe, masahiroy, brauner,
thomas.weissschuh, oleg, mjguzik, andrii, wangfushuai, linux-doc,
linux-arm-kernel, linux-media, linaro-mm-sig, linux-i2c,
linux-arch, linux-modules, rcu, linux-nfs, linux-rt-devel,
2407018371, dakr, miguel.ojeda.sandonis, neilb, bagasdotme,
wsa+renesas, dave.hansen, geert, ojeda, alex.gaynor, gary,
bjorn3_gh, lossin, a.hindborg, aliceryhl, tmgross, rust-for-linux
In-Reply-To: <20260706061928.66713-1-byungchul@sk.com>
False positive reports have been observed since dept assumes that all
the pages have the same dept class, but the class should be split since
the call paths are different depending on what the page is used for.
At least, ones for block device and ones for regular file have
exclusively different usages.
Define usage candidates like:
DEPT_PAGE_REGFILE_CACHE /* page in regular file's address_space */
DEPT_PAGE_BDEV_CACHE /* page in block device's address_space */
DEPT_PAGE_DEFAULT /* the others */
Introduce APIs to set each page usage properly and make sure not to
interact between DEPT_PAGE_REGFILE_CACHE and DEPT_PAGE_BDEV_CACHE.
Besides that, it allows the other cases:
interaction between DEPT_PAGE_DEFAULT and DEPT_PAGE_REGFILE_CACHE,
interaction between DEPT_PAGE_DEFAULT and DEPT_PAGE_BDEV_CACHE,
interaction between DEPT_PAGE_DEFAULT and DEPT_PAGE_DEFAULT.
Signed-off-by: Byungchul Park <byungchul@sk.com>
---
include/linux/dept.h | 34 ++++++++++++++-
include/linux/mm_types.h | 1 +
include/linux/page-flags.h | 89 +++++++++++++++++++++++++++++++++++++-
3 files changed, 120 insertions(+), 4 deletions(-)
diff --git a/include/linux/dept.h b/include/linux/dept.h
index 236e57befb13..3b8faf5f04cf 100644
--- a/include/linux/dept.h
+++ b/include/linux/dept.h
@@ -19,8 +19,8 @@ struct task_struct;
#define DEPT_MAX_WAIT_HIST 64
#define DEPT_MAX_ECXT_HELD 48
-#define DEPT_MAX_SUBCLASSES 16
-#define DEPT_MAX_SUBCLASSES_EVT 2
+#define DEPT_MAX_SUBCLASSES 24
+#define DEPT_MAX_SUBCLASSES_EVT 3
#define DEPT_MAX_SUBCLASSES_USR (DEPT_MAX_SUBCLASSES / DEPT_MAX_SUBCLASSES_EVT)
#define DEPT_MAX_SUBCLASSES_CACHE 2
@@ -142,6 +142,35 @@ struct dept_ext_wgen {
unsigned int wgen;
};
+enum {
+ DEPT_PAGE_DEFAULT = 0,
+ DEPT_PAGE_REGFILE_CACHE, /* regular file page cache */
+ DEPT_PAGE_BDEV_CACHE, /* block device cache */
+ DEPT_PAGE_USAGE_NR, /* nr of usages options */
+};
+
+#define DEPT_PAGE_USAGE_SHIFT 16
+#define DEPT_PAGE_USAGE_MASK ((1U << DEPT_PAGE_USAGE_SHIFT) - 1)
+#define DEPT_PAGE_USAGE_PENDING_MASK (DEPT_PAGE_USAGE_MASK << DEPT_PAGE_USAGE_SHIFT)
+
+/*
+ * Identify each page's usage type
+ */
+struct dept_page_usage {
+ /*
+ * low 16 bits : the current usage type
+ * high 16 bits : usage type requested to be set
+ *
+ * Do not apply usage type on request immediately but postpone
+ * it until the next use of PG flags. For example, if the page
+ * is already within a PG_locked critical section, regard it as
+ * DEPT_PAGE_DEFAULT temporarily at least until the section ends
+ * e.g. folio_unlock() since it's still unclear which usage type
+ * the page acts within the section.
+ */
+ atomic_t type; /* Update and read atomically */
+};
+
void dept_stop_emerg(void);
void dept_on(void);
void dept_off(void);
@@ -192,6 +221,7 @@ void dept_hardirqs_off(void);
struct dept_key { };
struct dept_map { };
struct dept_ext_wgen { };
+struct dept_page_usage { };
#define DEPT_MAP_INITIALIZER(n, k) { }
diff --git a/include/linux/mm_types.h b/include/linux/mm_types.h
index 5b3f54ee0d38..e25d09f3dfa9 100644
--- a/include/linux/mm_types.h
+++ b/include/linux/mm_types.h
@@ -220,6 +220,7 @@ struct page {
struct page *kmsan_shadow;
struct page *kmsan_origin;
#endif
+ struct dept_page_usage usage;
struct dept_ext_wgen pg_locked_wgen;
} _struct_page_alignment;
diff --git a/include/linux/page-flags.h b/include/linux/page-flags.h
index 8ab39823ea31..0b0655354b08 100644
--- a/include/linux/page-flags.h
+++ b/include/linux/page-flags.h
@@ -204,6 +204,80 @@ enum pageflags {
extern struct dept_map pg_locked_map;
+static inline void dept_set_page_usage(struct page *p,
+ unsigned int new_type)
+{
+ /*
+ * Consider the page as DEPT_PAGE_DEFAULT until the next use of
+ * PG flags e.g. folio_lock().
+ */
+ unsigned int type = DEPT_PAGE_DEFAULT;
+
+ if (WARN_ON_ONCE(new_type >= DEPT_PAGE_USAGE_NR))
+ return;
+
+ new_type <<= DEPT_PAGE_USAGE_SHIFT;
+ new_type |= type & DEPT_PAGE_USAGE_MASK;
+ atomic_set(&p->usage.type, new_type);
+}
+
+static inline void dept_set_folio_usage(struct folio *f,
+ unsigned int new_type)
+{
+ dept_set_page_usage(&f->page, new_type);
+}
+
+static inline void dept_reset_page_usage(struct page *p)
+{
+ dept_set_page_usage(p, DEPT_PAGE_DEFAULT);
+}
+
+static inline void dept_reset_folio_usage(struct folio *f)
+{
+ dept_reset_page_usage(&f->page);
+}
+
+static inline void dept_update_page_usage(struct page *p)
+{
+ unsigned int type = atomic_read(&p->usage.type);
+ unsigned int new_type;
+
+retry:
+ new_type = type & DEPT_PAGE_USAGE_PENDING_MASK;
+ new_type >>= DEPT_PAGE_USAGE_SHIFT;
+ new_type |= type & DEPT_PAGE_USAGE_PENDING_MASK;
+
+ /*
+ * Already updated by others.
+ */
+ if (type == new_type)
+ return;
+
+ if (!atomic_try_cmpxchg(&p->usage.type, &type, new_type))
+ goto retry;
+}
+
+static inline unsigned long dept_event_flags(struct page *p, bool wait)
+{
+ unsigned int type;
+
+ type = atomic_read(&p->usage.type) & DEPT_PAGE_USAGE_MASK;
+
+ if (WARN_ON_ONCE(type >= DEPT_PAGE_USAGE_NR))
+ return 0;
+
+ /*
+ * wait
+ */
+ if (wait)
+ return (1UL << DEPT_PAGE_DEFAULT) | (1UL << type);
+
+ /*
+ * event
+ */
+ return 1UL << type;
+}
+
/*
* Place the following annotations in its suitable point in code:
*
@@ -214,20 +288,29 @@ extern struct dept_map pg_locked_map;
static inline void dept_page_set_bit(struct page *p, int bit_nr)
{
+ dept_update_page_usage(p);
+
if (bit_nr == PG_locked)
dept_request_event(&pg_locked_map, &p->pg_locked_wgen);
}
static inline void dept_page_clear_bit(struct page *p, int bit_nr)
{
+ unsigned long evt_f = dept_event_flags(p, false);
+
if (bit_nr == PG_locked)
- dept_event(&pg_locked_map, 1UL, _RET_IP_, __func__, &p->pg_locked_wgen);
+ dept_event(&pg_locked_map, evt_f, _RET_IP_, __func__, &p->pg_locked_wgen);
}
static inline void dept_page_wait_on_bit(struct page *p, int bit_nr)
{
+ unsigned long evt_f;
+
+ dept_update_page_usage(p);
+ evt_f = dept_event_flags(p, true);
+
if (bit_nr == PG_locked)
- dept_wait(&pg_locked_map, 1UL, _RET_IP_, __func__, 0, -1L);
+ dept_wait(&pg_locked_map, evt_f, _RET_IP_, __func__, 0, -1L);
}
static inline void dept_folio_set_bit(struct folio *f, int bit_nr)
@@ -245,6 +328,8 @@ static inline void dept_folio_wait_on_bit(struct folio *f, int bit_nr)
dept_page_wait_on_bit(&f->page, bit_nr);
}
#else
+#define dept_set_page_usage(p, t) do { } while (0)
+#define dept_reset_page_usage(p) do { } while (0)
#define dept_page_set_bit(p, bit_nr) do { } while (0)
#define dept_page_clear_bit(p, bit_nr) do { } while (0)
#define dept_page_wait_on_bit(p, bit_nr) do { } while (0)
--
2.17.1
^ permalink raw reply related
* [PATCH v19 36/40] dept: track PG_writeback with dept
From: Byungchul Park @ 2026-07-06 6:19 UTC (permalink / raw)
To: linux-kernel
Cc: max.byungchul.park, kernel_team, torvalds, damien.lemoal,
linux-ide, adilger.kernel, linux-ext4, mingo, peterz, will, tglx,
rostedt, joel, sashal, daniel.vetter, duyuyang, johannes.berg, tj,
tytso, willy, david, amir73il, gregkh, kernel-team, linux-mm,
akpm, mhocko, minchan, hannes, vdavydov.dev, sj, jglisse, dennis,
cl, penberg, rientjes, vbabka, ngupta, linux-block, josef,
linux-fsdevel, jack, jlayton, dan.j.williams, hch, djwong,
dri-devel, rodrigosiqueiramelo, melissa.srw, hamohammed.sa,
harry.yoo, chris.p.wilson, gwan-gyeong.mun, boqun.feng, longman,
yunseong.kim, ysk, yeoreum.yun, netdev, matthew.brost, her0gyugyu,
corbet, catalin.marinas, bp, x86, hpa, luto, sumit.semwal,
gustavo, christian.koenig, andi.shyti, arnd, lorenzo.stoakes,
Liam.Howlett, rppt, surenb, mcgrof, petr.pavlu, da.gomez,
samitolvanen, paulmck, frederic, neeraj.upadhyay, joelagnelf,
josh, urezki, mathieu.desnoyers, jiangshanlai, qiang.zhang,
juri.lelli, vincent.guittot, dietmar.eggemann, bsegall, mgorman,
vschneid, chuck.lever, neil, okorniev, Dai.Ngo, tom, trondmy,
anna, kees, bigeasy, clrkwllms, mark.rutland, ada.coupriediaz,
kristina.martsenko, wangkefeng.wang, broonie, kevin.brodsky, dwmw,
shakeel.butt, ast, ziy, yuzhao, baolin.wang, usamaarif642,
joel.granados, richard.weiyang, geert+renesas, tim.c.chen, linux,
alexander.shishkin, lillian, chenhuacai, francesco,
guoweikang.kernel, link, jpoimboe, masahiroy, brauner,
thomas.weissschuh, oleg, mjguzik, andrii, wangfushuai, linux-doc,
linux-arm-kernel, linux-media, linaro-mm-sig, linux-i2c,
linux-arch, linux-modules, rcu, linux-nfs, linux-rt-devel,
2407018371, dakr, miguel.ojeda.sandonis, neilb, bagasdotme,
wsa+renesas, dave.hansen, geert, ojeda, alex.gaynor, gary,
bjorn3_gh, lossin, a.hindborg, aliceryhl, tmgross, rust-for-linux
In-Reply-To: <20260706061928.66713-1-byungchul@sk.com>
Makes dept able to track PG_writeback waits and events, which will be
useful in practice.
Signed-off-by: Byungchul Park <byungchul@sk.com>
---
include/linux/mm_types.h | 1 +
include/linux/page-flags.h | 7 +++++++
mm/filemap.c | 6 +++++-
mm/mm_init.c | 1 +
4 files changed, 14 insertions(+), 1 deletion(-)
diff --git a/include/linux/mm_types.h b/include/linux/mm_types.h
index e25d09f3dfa9..81dc9999090a 100644
--- a/include/linux/mm_types.h
+++ b/include/linux/mm_types.h
@@ -222,6 +222,7 @@ struct page {
#endif
struct dept_page_usage usage;
struct dept_ext_wgen pg_locked_wgen;
+ struct dept_ext_wgen pg_writeback_wgen;
} _struct_page_alignment;
/*
diff --git a/include/linux/page-flags.h b/include/linux/page-flags.h
index 0b0655354b08..ec736811a2c6 100644
--- a/include/linux/page-flags.h
+++ b/include/linux/page-flags.h
@@ -203,6 +203,7 @@ enum pageflags {
#include <linux/dept.h>
extern struct dept_map pg_locked_map;
+extern struct dept_map pg_writeback_map;
static inline void dept_set_page_usage(struct page *p,
unsigned int new_type)
@@ -292,6 +293,8 @@ static inline void dept_page_set_bit(struct page *p, int bit_nr)
if (bit_nr == PG_locked)
dept_request_event(&pg_locked_map, &p->pg_locked_wgen);
+ else if (bit_nr == PG_writeback)
+ dept_request_event(&pg_writeback_map, &p->pg_writeback_wgen);
}
static inline void dept_page_clear_bit(struct page *p, int bit_nr)
@@ -300,6 +303,8 @@ static inline void dept_page_clear_bit(struct page *p, int bit_nr)
if (bit_nr == PG_locked)
dept_event(&pg_locked_map, evt_f, _RET_IP_, __func__, &p->pg_locked_wgen);
+ else if (bit_nr == PG_writeback)
+ dept_event(&pg_writeback_map, evt_f, _RET_IP_, __func__, &p->pg_writeback_wgen);
}
static inline void dept_page_wait_on_bit(struct page *p, int bit_nr)
@@ -311,6 +316,8 @@ static inline void dept_page_wait_on_bit(struct page *p, int bit_nr)
if (bit_nr == PG_locked)
dept_wait(&pg_locked_map, evt_f, _RET_IP_, __func__, 0, -1L);
+ else if (bit_nr == PG_writeback)
+ dept_wait(&pg_writeback_map, evt_f, _RET_IP_, __func__, 0, -1L);
}
static inline void dept_folio_set_bit(struct folio *f, int bit_nr)
diff --git a/mm/filemap.c b/mm/filemap.c
index c0bff1e08a28..e3aa2754da3f 100644
--- a/mm/filemap.c
+++ b/mm/filemap.c
@@ -1197,7 +1197,7 @@ static void folio_wake_bit(struct folio *folio, int bit_nr)
* dept_page_clear_bit() being called multiple times is harmless.
* The worst case is to miss some dependencies but it's okay.
*/
- if (bit_nr == PG_locked)
+ if (bit_nr == PG_locked || bit_nr == PG_writeback)
dept_page_clear_bit(&folio->page, bit_nr);
spin_lock_irqsave(&q->lock, flags);
@@ -1254,6 +1254,9 @@ static inline bool folio_trylock_flag(struct folio *folio, int bit_nr,
struct dept_map __maybe_unused pg_locked_map = DEPT_MAP_INITIALIZER(pg_locked_map, NULL);
EXPORT_SYMBOL(pg_locked_map);
+struct dept_map __maybe_unused pg_writeback_map = DEPT_MAP_INITIALIZER(pg_writeback_map, NULL);
+EXPORT_SYMBOL(pg_writeback_map);
+
static inline int folio_wait_bit_common(struct folio *folio, int bit_nr,
int state, enum behavior behavior)
{
@@ -1697,6 +1700,7 @@ void folio_end_writeback_no_dropbehind(struct folio *folio)
folio_rotate_reclaimable(folio);
}
+ dept_page_clear_bit(&folio->page, PG_writeback);
if (__folio_end_writeback(folio))
folio_wake_bit(folio, PG_writeback);
diff --git a/mm/mm_init.c b/mm/mm_init.c
index 66b68c02d8d4..2695d7b3b089 100644
--- a/mm/mm_init.c
+++ b/mm/mm_init.c
@@ -589,6 +589,7 @@ void __meminit __init_single_page(struct page *page, unsigned long pfn,
page_cpupid_reset_last(page);
page_kasan_tag_reset(page);
dept_ext_wgen_init(&page->pg_locked_wgen);
+ dept_ext_wgen_init(&page->pg_writeback_wgen);
INIT_LIST_HEAD(&page->lru);
#ifdef WANT_PAGE_VIRTUAL
--
2.17.1
^ permalink raw reply related
* [PATCH v19 37/40] SUNRPC: relocate struct rcu_head to the first field of struct rpc_xprt
From: Byungchul Park @ 2026-07-06 6:19 UTC (permalink / raw)
To: linux-kernel
Cc: max.byungchul.park, kernel_team, torvalds, damien.lemoal,
linux-ide, adilger.kernel, linux-ext4, mingo, peterz, will, tglx,
rostedt, joel, sashal, daniel.vetter, duyuyang, johannes.berg, tj,
tytso, willy, david, amir73il, gregkh, kernel-team, linux-mm,
akpm, mhocko, minchan, hannes, vdavydov.dev, sj, jglisse, dennis,
cl, penberg, rientjes, vbabka, ngupta, linux-block, josef,
linux-fsdevel, jack, jlayton, dan.j.williams, hch, djwong,
dri-devel, rodrigosiqueiramelo, melissa.srw, hamohammed.sa,
harry.yoo, chris.p.wilson, gwan-gyeong.mun, boqun.feng, longman,
yunseong.kim, ysk, yeoreum.yun, netdev, matthew.brost, her0gyugyu,
corbet, catalin.marinas, bp, x86, hpa, luto, sumit.semwal,
gustavo, christian.koenig, andi.shyti, arnd, lorenzo.stoakes,
Liam.Howlett, rppt, surenb, mcgrof, petr.pavlu, da.gomez,
samitolvanen, paulmck, frederic, neeraj.upadhyay, joelagnelf,
josh, urezki, mathieu.desnoyers, jiangshanlai, qiang.zhang,
juri.lelli, vincent.guittot, dietmar.eggemann, bsegall, mgorman,
vschneid, chuck.lever, neil, okorniev, Dai.Ngo, tom, trondmy,
anna, kees, bigeasy, clrkwllms, mark.rutland, ada.coupriediaz,
kristina.martsenko, wangkefeng.wang, broonie, kevin.brodsky, dwmw,
shakeel.butt, ast, ziy, yuzhao, baolin.wang, usamaarif642,
joel.granados, richard.weiyang, geert+renesas, tim.c.chen, linux,
alexander.shishkin, lillian, chenhuacai, francesco,
guoweikang.kernel, link, jpoimboe, masahiroy, brauner,
thomas.weissschuh, oleg, mjguzik, andrii, wangfushuai, linux-doc,
linux-arm-kernel, linux-media, linaro-mm-sig, linux-i2c,
linux-arch, linux-modules, rcu, linux-nfs, linux-rt-devel,
2407018371, dakr, miguel.ojeda.sandonis, neilb, bagasdotme,
wsa+renesas, dave.hansen, geert, ojeda, alex.gaynor, gary,
bjorn3_gh, lossin, a.hindborg, aliceryhl, tmgross, rust-for-linux
In-Reply-To: <20260706061928.66713-1-byungchul@sk.com>
While compiling Linux kernel with DEPT on, the following error was
observed:
./include/linux/rcupdate.h:1084:17: note: in expansion of macro
‘BUILD_BUG_ON’
1084 | BUILD_BUG_ON(offsetof(typeof(*(ptr)), rhf) >= 4096); \
| ^~~~~~~~~~~~
./include/linux/rcupdate.h:1047:29: note: in expansion of macro
'kvfree_rcu_arg_2'
1047 | #define kfree_rcu(ptr, rhf) kvfree_rcu_arg_2(ptr, rhf)
| ^~~~~~~~~~~~~~~~
net/sunrpc/xprt.c:1856:9: note: in expansion of macro 'kfree_rcu'
1856 | kfree_rcu(xprt, rcu);
| ^~~~~~~~~
CC net/kcm/kcmproc.o
make[4]: *** [scripts/Makefile.build:203: net/sunrpc/xprt.o] Error 1
Since kfree_rcu() assumes 'offset of struct rcu_head in a rcu-managed
struct < 4096', the offest of struct rcu_head in struct rpc_xprt should
not exceed 4096 but does, due to the debug information added by DEPT.
Relocate struct rcu_head to the first field of struct rpc_xprt from an
arbitrary location to avoid the issue and meet the assumption.
Reported-by: Yunseong Kim <ysk@kzalloc.com>
Signed-off-by: Byungchul Park <byungchul@sk.com>
Reviewed-by: Jeff Layton <jlayton@kernel.org>
---
include/linux/sunrpc/xprt.h | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)
diff --git a/include/linux/sunrpc/xprt.h b/include/linux/sunrpc/xprt.h
index f46d1fb8f71a..666e42a17a31 100644
--- a/include/linux/sunrpc/xprt.h
+++ b/include/linux/sunrpc/xprt.h
@@ -211,6 +211,14 @@ enum xprt_transports {
struct rpc_sysfs_xprt;
struct rpc_xprt {
+ /*
+ * Place struct rcu_head within the first 4096 bytes of struct
+ * rpc_xprt if sizeof(struct rpc_xprt) > 4096, so that
+ * kfree_rcu() can simply work assuming that. See the comment
+ * in kfree_rcu().
+ */
+ struct rcu_head rcu;
+
struct kref kref; /* Reference count */
const struct rpc_xprt_ops *ops; /* transport methods */
unsigned int id; /* transport id */
@@ -317,7 +325,6 @@ struct rpc_xprt {
#if IS_ENABLED(CONFIG_SUNRPC_DEBUG)
struct dentry *debugfs; /* debugfs directory */
#endif
- struct rcu_head rcu;
const struct xprt_class *xprt_class;
struct rpc_sysfs_xprt *xprt_sysfs;
bool main; /*mark if this is the 1st transport */
--
2.17.1
^ permalink raw reply related
* [PATCH v19 38/40] mm: percpu: increase PERCPU_DYNAMIC_SIZE_SHIFT on DEPT and large PAGE_SIZE
From: Byungchul Park @ 2026-07-06 6:19 UTC (permalink / raw)
To: linux-kernel
Cc: max.byungchul.park, kernel_team, torvalds, damien.lemoal,
linux-ide, adilger.kernel, linux-ext4, mingo, peterz, will, tglx,
rostedt, joel, sashal, daniel.vetter, duyuyang, johannes.berg, tj,
tytso, willy, david, amir73il, gregkh, kernel-team, linux-mm,
akpm, mhocko, minchan, hannes, vdavydov.dev, sj, jglisse, dennis,
cl, penberg, rientjes, vbabka, ngupta, linux-block, josef,
linux-fsdevel, jack, jlayton, dan.j.williams, hch, djwong,
dri-devel, rodrigosiqueiramelo, melissa.srw, hamohammed.sa,
harry.yoo, chris.p.wilson, gwan-gyeong.mun, boqun.feng, longman,
yunseong.kim, ysk, yeoreum.yun, netdev, matthew.brost, her0gyugyu,
corbet, catalin.marinas, bp, x86, hpa, luto, sumit.semwal,
gustavo, christian.koenig, andi.shyti, arnd, lorenzo.stoakes,
Liam.Howlett, rppt, surenb, mcgrof, petr.pavlu, da.gomez,
samitolvanen, paulmck, frederic, neeraj.upadhyay, joelagnelf,
josh, urezki, mathieu.desnoyers, jiangshanlai, qiang.zhang,
juri.lelli, vincent.guittot, dietmar.eggemann, bsegall, mgorman,
vschneid, chuck.lever, neil, okorniev, Dai.Ngo, tom, trondmy,
anna, kees, bigeasy, clrkwllms, mark.rutland, ada.coupriediaz,
kristina.martsenko, wangkefeng.wang, broonie, kevin.brodsky, dwmw,
shakeel.butt, ast, ziy, yuzhao, baolin.wang, usamaarif642,
joel.granados, richard.weiyang, geert+renesas, tim.c.chen, linux,
alexander.shishkin, lillian, chenhuacai, francesco,
guoweikang.kernel, link, jpoimboe, masahiroy, brauner,
thomas.weissschuh, oleg, mjguzik, andrii, wangfushuai, linux-doc,
linux-arm-kernel, linux-media, linaro-mm-sig, linux-i2c,
linux-arch, linux-modules, rcu, linux-nfs, linux-rt-devel,
2407018371, dakr, miguel.ojeda.sandonis, neilb, bagasdotme,
wsa+renesas, dave.hansen, geert, ojeda, alex.gaynor, gary,
bjorn3_gh, lossin, a.hindborg, aliceryhl, tmgross, rust-for-linux
In-Reply-To: <20260706061928.66713-1-byungchul@sk.com>
Yunseong reported a build failure due to the BUILD_BUG_ON() statement in
alloc_kmem_cache_cpus(). In the following test:
PERCPU_DYNAMIC_EARLY_SIZE < NR_KMALLOC_TYPES * KMALLOC_SHIFT_HIGH * sizeof(struct kmem_cache_cpu)
The following factors increase the right side of the equation:
1. PAGE_SIZE > 4KiB increases KMALLOC_SHIFT_HIGH.
2. DEPT increases the size of the local_lock_t in kmem_cache_cpu.
Increase PERCPU_DYNAMIC_SIZE_SHIFT to 11 on configs with PAGE_SIZE
larger than 4KiB and DEPT enabled.
Reported-by: Yunseong Kim <ysk@kzalloc.com>
Signed-off-by: Byungchul Park <byungchul@sk.com>
---
include/linux/percpu.h | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/include/linux/percpu.h b/include/linux/percpu.h
index 85bf8dd9f087..dd74321d4bbd 100644
--- a/include/linux/percpu.h
+++ b/include/linux/percpu.h
@@ -43,7 +43,11 @@
# define PERCPU_DYNAMIC_SIZE_SHIFT 12
#endif /* LOCKDEP and PAGE_SIZE > 4KiB */
#else
+#if defined(CONFIG_DEPT) && !defined(CONFIG_PAGE_SIZE_4KB)
+#define PERCPU_DYNAMIC_SIZE_SHIFT 11
+#else
#define PERCPU_DYNAMIC_SIZE_SHIFT 10
+#endif /* DEPT and PAGE_SIZE > 4KiB */
#endif
/*
--
2.17.1
^ permalink raw reply related
* [PATCH v19 39/40] rust: completion: Add __rust_helper to rust_helper_wait_for_completion()
From: Byungchul Park @ 2026-07-06 6:19 UTC (permalink / raw)
To: linux-kernel
Cc: max.byungchul.park, kernel_team, torvalds, damien.lemoal,
linux-ide, adilger.kernel, linux-ext4, mingo, peterz, will, tglx,
rostedt, joel, sashal, daniel.vetter, duyuyang, johannes.berg, tj,
tytso, willy, david, amir73il, gregkh, kernel-team, linux-mm,
akpm, mhocko, minchan, hannes, vdavydov.dev, sj, jglisse, dennis,
cl, penberg, rientjes, vbabka, ngupta, linux-block, josef,
linux-fsdevel, jack, jlayton, dan.j.williams, hch, djwong,
dri-devel, rodrigosiqueiramelo, melissa.srw, hamohammed.sa,
harry.yoo, chris.p.wilson, gwan-gyeong.mun, boqun.feng, longman,
yunseong.kim, ysk, yeoreum.yun, netdev, matthew.brost, her0gyugyu,
corbet, catalin.marinas, bp, x86, hpa, luto, sumit.semwal,
gustavo, christian.koenig, andi.shyti, arnd, lorenzo.stoakes,
Liam.Howlett, rppt, surenb, mcgrof, petr.pavlu, da.gomez,
samitolvanen, paulmck, frederic, neeraj.upadhyay, joelagnelf,
josh, urezki, mathieu.desnoyers, jiangshanlai, qiang.zhang,
juri.lelli, vincent.guittot, dietmar.eggemann, bsegall, mgorman,
vschneid, chuck.lever, neil, okorniev, Dai.Ngo, tom, trondmy,
anna, kees, bigeasy, clrkwllms, mark.rutland, ada.coupriediaz,
kristina.martsenko, wangkefeng.wang, broonie, kevin.brodsky, dwmw,
shakeel.butt, ast, ziy, yuzhao, baolin.wang, usamaarif642,
joel.granados, richard.weiyang, geert+renesas, tim.c.chen, linux,
alexander.shishkin, lillian, chenhuacai, francesco,
guoweikang.kernel, link, jpoimboe, masahiroy, brauner,
thomas.weissschuh, oleg, mjguzik, andrii, wangfushuai, linux-doc,
linux-arm-kernel, linux-media, linaro-mm-sig, linux-i2c,
linux-arch, linux-modules, rcu, linux-nfs, linux-rt-devel,
2407018371, dakr, miguel.ojeda.sandonis, neilb, bagasdotme,
wsa+renesas, dave.hansen, geert, ojeda, alex.gaynor, gary,
bjorn3_gh, lossin, a.hindborg, aliceryhl, tmgross, rust-for-linux
In-Reply-To: <20260706061928.66713-1-byungchul@sk.com>
This is needed to inline these helpers into Rust code, which is required
for DEPT to play with wait_for_completion().
Signed-off-by: Byungchul Park <byungchul@sk.com>
---
rust/helpers/completion.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/rust/helpers/completion.c b/rust/helpers/completion.c
index 5ea2eef74abc..7b55c960fe22 100644
--- a/rust/helpers/completion.c
+++ b/rust/helpers/completion.c
@@ -7,7 +7,7 @@ __rust_helper void rust_helper_init_completion(struct completion *x)
init_completion(x);
}
-void rust_helper_wait_for_completion(struct completion *x)
+__rust_helper void rust_helper_wait_for_completion(struct completion *x)
{
wait_for_completion(x);
}
--
2.17.1
^ permalink raw reply related
* [PATCH v19 40/40] dept: implement a basic unit test for dept
From: Byungchul Park @ 2026-07-06 6:19 UTC (permalink / raw)
To: linux-kernel
Cc: max.byungchul.park, kernel_team, torvalds, damien.lemoal,
linux-ide, adilger.kernel, linux-ext4, mingo, peterz, will, tglx,
rostedt, joel, sashal, daniel.vetter, duyuyang, johannes.berg, tj,
tytso, willy, david, amir73il, gregkh, kernel-team, linux-mm,
akpm, mhocko, minchan, hannes, vdavydov.dev, sj, jglisse, dennis,
cl, penberg, rientjes, vbabka, ngupta, linux-block, josef,
linux-fsdevel, jack, jlayton, dan.j.williams, hch, djwong,
dri-devel, rodrigosiqueiramelo, melissa.srw, hamohammed.sa,
harry.yoo, chris.p.wilson, gwan-gyeong.mun, boqun.feng, longman,
yunseong.kim, ysk, yeoreum.yun, netdev, matthew.brost, her0gyugyu,
corbet, catalin.marinas, bp, x86, hpa, luto, sumit.semwal,
gustavo, christian.koenig, andi.shyti, arnd, lorenzo.stoakes,
Liam.Howlett, rppt, surenb, mcgrof, petr.pavlu, da.gomez,
samitolvanen, paulmck, frederic, neeraj.upadhyay, joelagnelf,
josh, urezki, mathieu.desnoyers, jiangshanlai, qiang.zhang,
juri.lelli, vincent.guittot, dietmar.eggemann, bsegall, mgorman,
vschneid, chuck.lever, neil, okorniev, Dai.Ngo, tom, trondmy,
anna, kees, bigeasy, clrkwllms, mark.rutland, ada.coupriediaz,
kristina.martsenko, wangkefeng.wang, broonie, kevin.brodsky, dwmw,
shakeel.butt, ast, ziy, yuzhao, baolin.wang, usamaarif642,
joel.granados, richard.weiyang, geert+renesas, tim.c.chen, linux,
alexander.shishkin, lillian, chenhuacai, francesco,
guoweikang.kernel, link, jpoimboe, masahiroy, brauner,
thomas.weissschuh, oleg, mjguzik, andrii, wangfushuai, linux-doc,
linux-arm-kernel, linux-media, linaro-mm-sig, linux-i2c,
linux-arch, linux-modules, rcu, linux-nfs, linux-rt-devel,
2407018371, dakr, miguel.ojeda.sandonis, neilb, bagasdotme,
wsa+renesas, dave.hansen, geert, ojeda, alex.gaynor, gary,
bjorn3_gh, lossin, a.hindborg, aliceryhl, tmgross, rust-for-linux
In-Reply-To: <20260706061928.66713-1-byungchul@sk.com>
Implement CONFIG_DEPT_UNIT_TEST introducing a kernel module that runs
basic unit test for dept.
Signed-off-by: Byungchul Park <byungchul@sk.com>
---
include/linux/dept_unit_test.h | 61 ++++++++++++
kernel/dependency/Makefile | 1 +
kernel/dependency/dept.c | 10 ++
kernel/dependency/dept_unit_test.c | 149 +++++++++++++++++++++++++++++
lib/Kconfig.debug | 12 +++
5 files changed, 233 insertions(+)
create mode 100644 include/linux/dept_unit_test.h
create mode 100644 kernel/dependency/dept_unit_test.c
diff --git a/include/linux/dept_unit_test.h b/include/linux/dept_unit_test.h
new file mode 100644
index 000000000000..753ac9ac727c
--- /dev/null
+++ b/include/linux/dept_unit_test.h
@@ -0,0 +1,61 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * DEPT unit test
+ *
+ * Started by Byungchul Park <max.byungchul.park@gmail.com>:
+ *
+ * Copyright (c) 2025 SK hynix, Inc., Byungchul Park
+ */
+
+#ifndef __LINUX_DEPT_UNIT_TEST_H
+#define __LINUX_DEPT_UNIT_TEST_H
+
+#if defined(CONFIG_DEPT_UNIT_TEST) || defined(CONFIG_DEPT_UNIT_TEST_MODULE)
+struct dept_ut {
+ bool circle_detected;
+
+ int ecxt_stack_total_cnt;
+ int wait_stack_total_cnt;
+ int evnt_stack_total_cnt;
+ int ecxt_stack_valid_cnt;
+ int wait_stack_valid_cnt;
+ int evnt_stack_valid_cnt;
+};
+
+extern struct dept_ut dept_ut_results;
+
+static inline void dept_ut_circle_detect(void)
+{
+ dept_ut_results.circle_detected = true;
+}
+static inline void dept_ut_ecxt_stack_account(bool valid)
+{
+ dept_ut_results.ecxt_stack_total_cnt++;
+
+ if (valid)
+ dept_ut_results.ecxt_stack_valid_cnt++;
+}
+static inline void dept_ut_wait_stack_account(bool valid)
+{
+ dept_ut_results.wait_stack_total_cnt++;
+
+ if (valid)
+ dept_ut_results.wait_stack_valid_cnt++;
+}
+static inline void dept_ut_evnt_stack_account(bool valid)
+{
+ dept_ut_results.evnt_stack_total_cnt++;
+
+ if (valid)
+ dept_ut_results.evnt_stack_valid_cnt++;
+}
+#else
+struct dept_ut {};
+
+#define dept_ut_circle_detect() do { } while (0)
+#define dept_ut_ecxt_stack_account(v) do { } while (0)
+#define dept_ut_wait_stack_account(v) do { } while (0)
+#define dept_ut_evnt_stack_account(v) do { } while (0)
+
+#endif
+#endif /* __LINUX_DEPT_UNIT_TEST_H */
diff --git a/kernel/dependency/Makefile b/kernel/dependency/Makefile
index 92f165400187..fc584ca87124 100644
--- a/kernel/dependency/Makefile
+++ b/kernel/dependency/Makefile
@@ -2,3 +2,4 @@
obj-$(CONFIG_DEPT) += dept.o
obj-$(CONFIG_DEPT) += dept_proc.o
+obj-$(CONFIG_DEPT_UNIT_TEST) += dept_unit_test.o
diff --git a/kernel/dependency/dept.c b/kernel/dependency/dept.c
index 35a3667ac8b3..bcff14f20046 100644
--- a/kernel/dependency/dept.c
+++ b/kernel/dependency/dept.c
@@ -78,8 +78,12 @@
#include <linux/workqueue.h>
#include <linux/irq_work.h>
#include <linux/vmalloc.h>
+#include <linux/dept_unit_test.h>
#include "dept_internal.h"
+struct dept_ut dept_ut_results;
+EXPORT_SYMBOL_GPL(dept_ut_results);
+
static int dept_stop;
static int dept_per_cpu_ready;
@@ -826,6 +830,10 @@ static void print_dep(struct dept_dep *d)
pr_warn("(wait to wake up)\n");
print_ip_stack(0, e->ewait_stack);
}
+
+ dept_ut_ecxt_stack_account(valid_stack(e->ecxt_stack));
+ dept_ut_wait_stack_account(valid_stack(w->wait_stack));
+ dept_ut_evnt_stack_account(valid_stack(e->event_stack));
}
}
@@ -920,6 +928,8 @@ static void print_circle(struct dept_class *c)
dump_stack();
dept_outworld_exit();
+
+ dept_ut_circle_detect();
}
/*
diff --git a/kernel/dependency/dept_unit_test.c b/kernel/dependency/dept_unit_test.c
new file mode 100644
index 000000000000..e8dada2e3dfb
--- /dev/null
+++ b/kernel/dependency/dept_unit_test.c
@@ -0,0 +1,149 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * DEPT unit test
+ *
+ * Started by Byungchul Park <max.byungchul.park@gmail.com>:
+ *
+ * Copyright (c) 2025 SK hynix, Inc., Byungchul Park
+ */
+
+#include <linux/module.h>
+#include <linux/spinlock.h>
+#include <linux/mutex.h>
+#include <linux/dept.h>
+#include <linux/dept_unit_test.h>
+
+MODULE_DESCRIPTION("DEPT unit test");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Byungchul Park <max.byungchul.park@sk.com>");
+
+struct unit {
+ const char *name;
+ bool (*func)(void);
+ bool result;
+};
+
+static DEFINE_SPINLOCK(s1);
+static DEFINE_SPINLOCK(s2);
+static bool test_spin_lock_deadlock(void)
+{
+ dept_ut_results.circle_detected = false;
+
+ spin_lock(&s1);
+ spin_lock(&s2);
+ spin_unlock(&s2);
+ spin_unlock(&s1);
+
+ spin_lock(&s2);
+ spin_lock(&s1);
+ spin_unlock(&s1);
+ spin_unlock(&s2);
+
+ return dept_ut_results.circle_detected;
+}
+
+static DEFINE_MUTEX(m1);
+static DEFINE_MUTEX(m2);
+static bool test_mutex_lock_deadlock(void)
+{
+ dept_ut_results.circle_detected = false;
+
+ mutex_lock(&m1);
+ mutex_lock(&m2);
+ mutex_unlock(&m2);
+ mutex_unlock(&m1);
+
+ mutex_lock(&m2);
+ mutex_lock(&m1);
+ mutex_unlock(&m1);
+ mutex_unlock(&m2);
+
+ return dept_ut_results.circle_detected;
+}
+
+static bool test_wait_event_deadlock(void)
+{
+ struct dept_map dmap1;
+ struct dept_map dmap2;
+
+ sdt_map_init(&dmap1);
+ sdt_map_init(&dmap2);
+
+ dept_ut_results.circle_detected = false;
+
+ sdt_request_event(&dmap1); /* [S] */
+ sdt_wait(&dmap2); /* [W] */
+ sdt_event(&dmap1); /* [E] */
+
+ sdt_request_event(&dmap2); /* [S] */
+ sdt_wait(&dmap1); /* [W] */
+ sdt_event(&dmap2); /* [E] */
+
+ return dept_ut_results.circle_detected;
+}
+
+static struct unit units[] = {
+ {
+ .name = "spin lock deadlock test",
+ .func = test_spin_lock_deadlock,
+ },
+ {
+ .name = "mutex lock deadlock test",
+ .func = test_mutex_lock_deadlock,
+ },
+ {
+ .name = "wait event deadlock test",
+ .func = test_wait_event_deadlock,
+ },
+};
+
+static int __init dept_ut_init(void)
+{
+ int i;
+
+ lockdep_off();
+
+ dept_ut_results.ecxt_stack_valid_cnt = 0;
+ dept_ut_results.ecxt_stack_total_cnt = 0;
+ dept_ut_results.wait_stack_valid_cnt = 0;
+ dept_ut_results.wait_stack_total_cnt = 0;
+ dept_ut_results.evnt_stack_valid_cnt = 0;
+ dept_ut_results.evnt_stack_total_cnt = 0;
+
+ for (i = 0; i < ARRAY_SIZE(units); i++)
+ units[i].result = units[i].func();
+
+ pr_info("\n");
+ pr_info("******************************************\n");
+ pr_info("DEPT unit test results\n");
+ pr_info("******************************************\n");
+ for (i = 0; i < ARRAY_SIZE(units); i++) {
+ pr_info("(%s) %s\n", units[i].result ? "pass" : "fail",
+ units[i].name);
+ }
+ pr_info("ecxt stack valid count = %d/%d\n",
+ dept_ut_results.ecxt_stack_valid_cnt,
+ dept_ut_results.ecxt_stack_total_cnt);
+ pr_info("wait stack valid count = %d/%d\n",
+ dept_ut_results.wait_stack_valid_cnt,
+ dept_ut_results.wait_stack_total_cnt);
+ pr_info("event stack valid count = %d/%d\n",
+ dept_ut_results.evnt_stack_valid_cnt,
+ dept_ut_results.evnt_stack_total_cnt);
+ pr_info("******************************************\n");
+ pr_info("\n");
+
+ lockdep_on();
+
+ return 0;
+}
+
+static void dept_ut_cleanup(void)
+{
+ /*
+ * Do nothing for now.
+ */
+}
+
+module_init(dept_ut_init);
+module_exit(dept_ut_cleanup);
diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
index 5c7f22ba253e..41c822f7b75a 100644
--- a/lib/Kconfig.debug
+++ b/lib/Kconfig.debug
@@ -1477,6 +1477,18 @@ config DEPT_AGGRESSIVE_TIMEOUT_WAIT
that timeout is used to avoid a deadlock. Say N if you'd like
to avoid verbose reports.
+config DEPT_UNIT_TEST
+ tristate "unit test for DEPT"
+ depends on DEBUG_KERNEL && DEPT
+ default n
+ help
+ This option provides a kernel module that runs unit test for
+ DEPT.
+
+ Say Y if you want DEPT unit test to be built into the kernel.
+ Say M if you want DEPT unit test to build as a module.
+ Say N if you are unsure.
+
config LOCK_DEBUGGING_SUPPORT
bool
depends on TRACE_IRQFLAGS_SUPPORT && STACKTRACE_SUPPORT && LOCKDEP_SUPPORT
--
2.17.1
^ permalink raw reply related
* Re: [PATCH] iomap: Remove FGP_NOFS from iomap_get_folio()
From: Shin'ichiro Kawasaki @ 2026-07-06 6:29 UTC (permalink / raw)
To: Matthew Wilcox (Oracle)
Cc: Christian Brauner, Darrick J. Wong, Jens Axboe, Namjae Jeon,
Sungjong Seo, Yuezhang Mo, Miklos Szeredi, Andreas Gruenbacher,
Hyunchul Lee, Konstantin Komarov, Carlos Maiolino, Damien Le Moal,
Naohiro Aota, Johannes Thumshirn, linux-xfs, linux-fsdevel,
linux-block, fuse-devel, gfs2, ntfs3
In-Reply-To: <20260624174228.2015893-1-willy@infradead.org>
On Jun 24, 2026 / 18:42, Matthew Wilcox (Oracle) wrote:
> FGP_NOFS is legacy; filesystems should be using memalloc_nofs_save/restore
> instead. We have it here in iomap because it was buried in
> grab_cache_page_write_begin() and we didn't want to change this behaviour
> as part of the folio transition.
>
> I have tested this with XFS and see no issues. Other filesystems (cc'd)
> may need to make adjustments. Please test with lockdep enabled.
I applied this patch on top of v7.2-rc1 kernel, and ran my zonefs test set.
I observed no failure. Good from zonefs point of view:
Tested-by: Shin'ichiro Kawasaki <shinichiro.kawasaki@wdc.com>
^ permalink raw reply
* Re: [PATCH] block: split out a new blk_plug.h helper
From: Johannes Thumshirn @ 2026-07-06 6:38 UTC (permalink / raw)
To: Christoph Hellwig, axboe
Cc: linux-block, linux-fsdevel, linux-aio, linux-kernel, io-uring,
linux-mm
In-Reply-To: <20260706041125.642097-1-hch@lst.de>
On 7/6/26 6:11 AM, Christoph Hellwig wrote:
> diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h
> index 9213a5716f95..20cb8ed7d987 100644
> --- a/include/linux/blkdev.h
> +++ b/include/linux/blkdev.h
> @@ -7,6 +7,7 @@
>
> #include <linux/types.h>
> #include <linux/blk_types.h>
> +#include <linux/blk_plug.h>
> #include <linux/device.h>
> #include <linux/list.h>
> #include <linux/llist.h>
>
I know it's a lot of cross subsystem churn, but wouldn't it be cleaner
to not include blk_plug.h in blkdev.h, but patch the update the
consumers? A quick grep shows 68 files that would need updating and some
you already have updated.
^ permalink raw reply
* Re: [PATCH] block: split out a new blk_plug.h helper
From: Christoph Hellwig @ 2026-07-06 6:45 UTC (permalink / raw)
To: Johannes Thumshirn
Cc: Christoph Hellwig, axboe, linux-block, linux-fsdevel, linux-aio,
linux-kernel, io-uring, linux-mm
In-Reply-To: <8583b332-0d24-4f6f-8831-69e3aad936fd@wdc.com>
On Mon, Jul 06, 2026 at 08:38:12AM +0200, Johannes Thumshirn wrote:
> On 7/6/26 6:11 AM, Christoph Hellwig wrote:
>> diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h
>> index 9213a5716f95..20cb8ed7d987 100644
>> --- a/include/linux/blkdev.h
>> +++ b/include/linux/blkdev.h
>> @@ -7,6 +7,7 @@
>> #include <linux/types.h>
>> #include <linux/blk_types.h>
>> +#include <linux/blk_plug.h>
>> #include <linux/device.h>
>> #include <linux/list.h>
>> #include <linux/llist.h>
>>
> I know it's a lot of cross subsystem churn, but wouldn't it be cleaner to
> not include blk_plug.h in blkdev.h, but patch the update the consumers? A
> quick grep shows 68 files that would need updating and some you already
> have updated.
Right now blkdev.h needs the rq_list from it. So we'd need to move
that to linux/types.h or something first, which feels a bit iffy.
And no, including blk_types.h in blk_plug.h is not a solution,
as that is still touched far too often.
^ permalink raw reply
* Re: [PATCH] block: split out a new blk_plug.h helper
From: Johannes Thumshirn @ 2026-07-06 6:47 UTC (permalink / raw)
To: Christoph Hellwig
Cc: axboe, linux-block, linux-fsdevel, linux-aio, linux-kernel,
io-uring, linux-mm
In-Reply-To: <20260706064547.GA25268@lst.de>
On 7/6/26 8:45 AM, Christoph Hellwig wrote:
> On Mon, Jul 06, 2026 at 08:38:12AM +0200, Johannes Thumshirn wrote:
>> On 7/6/26 6:11 AM, Christoph Hellwig wrote:
>>> diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h
>>> index 9213a5716f95..20cb8ed7d987 100644
>>> --- a/include/linux/blkdev.h
>>> +++ b/include/linux/blkdev.h
>>> @@ -7,6 +7,7 @@
>>> #include <linux/types.h>
>>> #include <linux/blk_types.h>
>>> +#include <linux/blk_plug.h>
>>> #include <linux/device.h>
>>> #include <linux/list.h>
>>> #include <linux/llist.h>
>>>
>> I know it's a lot of cross subsystem churn, but wouldn't it be cleaner to
>> not include blk_plug.h in blkdev.h, but patch the update the consumers? A
>> quick grep shows 68 files that would need updating and some you already
>> have updated.
> Right now blkdev.h needs the rq_list from it. So we'd need to move
> that to linux/types.h or something first, which feels a bit iffy.
>
> And no, including blk_types.h in blk_plug.h is not a solution,
> as that is still touched far too often.
Ah sh*t I did miss rq_list. Fair enough.
Reviewed-by: Johannes Thumshirn <johannes.thumshirn@wdc.com>
^ permalink raw reply
* Re: [PATCH] block: split out a new blk_plug.h helper
From: Damien Le Moal @ 2026-07-06 7:04 UTC (permalink / raw)
To: Christoph Hellwig, axboe
Cc: linux-block, linux-fsdevel, linux-aio, linux-kernel, io-uring,
linux-mm
In-Reply-To: <20260706041125.642097-1-hch@lst.de>
On 7/6/26 1:11 PM, Christoph Hellwig wrote:
> blkdev.h gets included in various places outside the block layer just
> for struct blk_plug and related plugging functions.
>
> Split blk_plug into a separate helper to reduce the amount of code
> that needs to get rebuilt when blkdev.h changes and to slightly
> reduce compile times.
>
> In io_uring this requires pulling in a few other headers explicitly that
> previously were implicitly included through blkdev.h.
>
> Signed-off-by: Christoph Hellwig <hch@lst.de>
A couple of nits below (not entirely sure if they make sense).
But otherwise looks OK to me.
Reviewed-by: Damien Le Moal <dlemoal@kernel.org>
> diff --git a/include/linux/blk_plug.h b/include/linux/blk_plug.h
> new file mode 100644
> index 000000000000..2ac1265662ad
> --- /dev/null
> +++ b/include/linux/blk_plug.h
> @@ -0,0 +1,95 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +#ifndef _LINUX_BLK_PLUG_H
> +#define _LINUX_BLK_PLUG_H
> +
> +#include <linux/sched.h>
struct blk_plug_cb has a list_head. So maybe also add
#include <linux/types.h>
?
> +
> +struct blk_plug_cb;
Maybe add "struct request;" here too ?
> +typedef void (*blk_plug_cb_fn)(struct blk_plug_cb *cb, bool from_schedule);
> +
> +struct rq_list {
> + struct request *head;
> + struct request *tail;
> +};
--
Damien Le Moal
Western Digital Research
^ permalink raw reply
* Re: [PATCH] block: split out a new blk_plug.h helper
From: Christoph Hellwig @ 2026-07-06 9:54 UTC (permalink / raw)
To: Damien Le Moal
Cc: Christoph Hellwig, axboe, linux-block, linux-fsdevel, linux-aio,
linux-kernel, io-uring, linux-mm
In-Reply-To: <f389a101-2af1-4b18-a74b-031e6c1899bd@kernel.org>
On Mon, Jul 06, 2026 at 04:04:48PM +0900, Damien Le Moal wrote:
> > +#include <linux/sched.h>
>
> struct blk_plug_cb has a list_head. So maybe also add
>
> #include <linux/types.h>
>
> ?
That already gets pulled in.
> > +
> > +struct blk_plug_cb;
>
> Maybe add "struct request;" here too ?
No need for type forward declarations when the types are only used
for pointers in structs (or as pointer variables). They are needed
only when pointers to the type are used in prototypes.
^ permalink raw reply
* [PATCH 2/3] null_blk: give the file-scope mutex a descriptive name
From: Zizhi Wo @ 2026-07-06 12:35 UTC (permalink / raw)
To: axboe, dlemoal, nilay, linux-block, kch, johannes.thumshirn,
kbusch, bvanassche
Cc: linux-kernel, yangerkun, chengzhihao1, wozizhi
In-Reply-To: <20260706123507.3809871-1-wozizhi@huaweicloud.com>
From: Zizhi Wo <wozizhi@huawei.com>
The file-scope lock mutex mainly serializes access to the global nullb_list
and related device setup. Rename it to "nullb_list_lock" to make its
purpose clear. No functional change.
Suggested-by: Bart Van Assche <bvanassche@acm.org>
Signed-off-by: Zizhi Wo <wozizhi@huawei.com>
---
drivers/block/null_blk/main.c | 32 ++++++++++++++++----------------
1 file changed, 16 insertions(+), 16 deletions(-)
diff --git a/drivers/block/null_blk/main.c b/drivers/block/null_blk/main.c
index eba204b27785..a775e70e16fc 100644
--- a/drivers/block/null_blk/main.c
+++ b/drivers/block/null_blk/main.c
@@ -66,7 +66,7 @@ struct nullb_page {
#define NULLB_PAGE_FREE (MAP_SZ - 2)
static LIST_HEAD(nullb_list);
-static DEFINE_MUTEX(lock);
+static DEFINE_MUTEX(nullb_list_lock);
static int null_major;
static DEFINE_IDA(nullb_indexes);
static struct blk_mq_tag_set tag_set;
@@ -423,9 +423,9 @@ static int nullb_apply_submit_queues(struct nullb_device *dev,
{
int ret;
- mutex_lock(&lock);
+ mutex_lock(&nullb_list_lock);
ret = nullb_update_nr_hw_queues(dev, submit_queues, dev->poll_queues);
- mutex_unlock(&lock);
+ mutex_unlock(&nullb_list_lock);
return ret;
}
@@ -435,9 +435,9 @@ static int nullb_apply_poll_queues(struct nullb_device *dev,
{
int ret;
- mutex_lock(&lock);
+ mutex_lock(&nullb_list_lock);
ret = nullb_update_nr_hw_queues(dev, dev->submit_queues, poll_queues);
- mutex_unlock(&lock);
+ mutex_unlock(&nullb_list_lock);
return ret;
}
@@ -493,7 +493,7 @@ static ssize_t nullb_device_power_store(struct config_item *item,
return ret;
ret = count;
- mutex_lock(&lock);
+ mutex_lock(&nullb_list_lock);
if (!dev->power && newp) {
if (test_and_set_bit(NULLB_DEV_FL_UP, &dev->flags))
goto out;
@@ -516,7 +516,7 @@ static ssize_t nullb_device_power_store(struct config_item *item,
}
out:
- mutex_unlock(&lock);
+ mutex_unlock(&nullb_list_lock);
return ret;
}
@@ -707,10 +707,10 @@ nullb_group_drop_item(struct config_group *group, struct config_item *item)
struct nullb_device *dev = to_nullb_device(item);
if (test_and_clear_bit(NULLB_DEV_FL_UP, &dev->flags)) {
- mutex_lock(&lock);
+ mutex_lock(&nullb_list_lock);
dev->power = false;
null_del_dev(dev->nullb);
- mutex_unlock(&lock);
+ mutex_unlock(&nullb_list_lock);
}
nullb_del_fault_config(dev);
config_item_put(item);
@@ -2081,14 +2081,14 @@ static struct nullb *null_find_dev_by_name(const char *name)
{
struct nullb *nullb = NULL, *nb;
- mutex_lock(&lock);
+ mutex_lock(&nullb_list_lock);
list_for_each_entry(nb, &nullb_list, list) {
if (strcmp(nb->disk_name, name) == 0) {
nullb = nb;
break;
}
}
- mutex_unlock(&lock);
+ mutex_unlock(&nullb_list_lock);
return nullb;
}
@@ -2102,9 +2102,9 @@ static int null_create_dev(void)
if (!dev)
return -ENOMEM;
- mutex_lock(&lock);
+ mutex_lock(&nullb_list_lock);
ret = null_add_dev(dev);
- mutex_unlock(&lock);
+ mutex_unlock(&nullb_list_lock);
if (ret) {
null_free_dev(dev);
return ret;
@@ -2200,17 +2200,17 @@ static void __exit null_exit(void)
unregister_blkdev(null_major, "nullb");
- mutex_lock(&lock);
+ mutex_lock(&nullb_list_lock);
while (!list_empty(&nullb_list)) {
nullb = list_entry(nullb_list.next, struct nullb, list);
null_destroy_dev(nullb);
}
- mutex_unlock(&lock);
+ mutex_unlock(&nullb_list_lock);
if (tag_set.ops)
blk_mq_free_tag_set(&tag_set);
- mutex_destroy(&lock);
+ mutex_destroy(&nullb_list_lock);
}
module_init(null_init);
--
2.52.0
^ permalink raw reply related
* [PATCH 0/3] null_blk: fix mutex initialization and configfs teardown race
From: Zizhi Wo @ 2026-07-06 12:35 UTC (permalink / raw)
To: axboe, dlemoal, nilay, linux-block, kch, johannes.thumshirn,
kbusch, bvanassche
Cc: linux-kernel, yangerkun, chengzhihao1, wozizhi
This series fixes a few simple issues in null_blk.
Patches 1-2 fix a problem where the null_blk mutex was left uninitialized.
The fix for the first issue was originally sent as a separate patch[1].
Following Bart's suggestion, it now use DEFINE_MUTEX() and the lock has
been renamed to a more descriptive name.
Patch 3 fixes concurrency issues around configfs registration.
See the individual patch descriptions for details.
[1] https://lore.kernel.org/all/20260704092323.748772-1-wozizhi@huaweicloud.com/
Zizhi Wo (3):
null_blk: use DEFINE_MUTEX for the file-scope mutex
null_blk: give the file-scope mutex a descriptive name
null_blk: register configfs subsystem after creating default devices
drivers/block/null_blk/main.c | 50 +++++++++++++++--------------------
1 file changed, 22 insertions(+), 28 deletions(-)
--
2.52.0
^ permalink raw reply
* [PATCH 1/3] null_blk: use DEFINE_MUTEX for the file-scope mutex
From: Zizhi Wo @ 2026-07-06 12:35 UTC (permalink / raw)
To: axboe, dlemoal, nilay, linux-block, kch, johannes.thumshirn,
kbusch, bvanassche
Cc: linux-kernel, yangerkun, chengzhihao1, wozizhi
In-Reply-To: <20260706123507.3809871-1-wozizhi@huaweicloud.com>
From: Zizhi Wo <wozizhi@huawei.com>
In null_init(), mutex_init(&lock) currently happens after
configfs_register_subsystem(), which exposes the nullb subsystem to
userspace. A racing mkdir() into /sys/kernel/config/nullb/ can reach
null_find_dev_by_name() -> mutex_lock(&lock) before the mutex is
initialized, trigger warning:
[ 123.137788] DEBUG_LOCKS_WARN_ON(lock->magic != lock)
[ 123.137796] WARNING: kernel/locking/mutex.c:159 at mutex_lock+0x171/0x1c0, CPU#13: mkdir/1301
[ 123.140090] Modules linked in: null_blk(+) nft_fib_inet nft_fib_ipv4
......
[ 123.154926] Call Trace:
[ 123.155172] <TASK>
[ 123.155419] ? __pfx_mutex_lock+0x10/0x10
[ 123.156181] ? __pfx__raw_spin_lock+0x10/0x10
[ 123.156571] nullb_group_make_group+0x20/0x100 [null_blk]
[ 123.157011] configfs_mkdir+0x47b/0xc70
[ 123.157337] ? __pfx_configfs_mkdir+0x10/0x10
[ 123.157719] ? may_create_dentry+0x242/0x2e0
[ 123.158061] vfs_mkdir+0x2a9/0x6c0
[ 123.158352] filename_mkdirat+0x3dc/0x500
[ 123.158710] ? __pfx_filename_mkdirat+0x10/0x10
[ 123.159070] ? strncpy_from_user+0x3a/0x1d0
[ 123.159413] __x64_sys_mkdir+0x6b/0x90
[ 123.159760] do_syscall_64+0xea/0x600
Replace the runtime mutex_init(&lock) with a static DEFINE_MUTEX(lock)
declaration to fix this issue.
Fixes: 49c3b9266a71 ("block: null_blk: Improve device creation with configfs")
Suggested-by: Bart Van Assche <bvanassche@acm.org>
Signed-off-by: Zizhi Wo <wozizhi@huawei.com>
---
drivers/block/null_blk/main.c | 4 +---
1 file changed, 1 insertion(+), 3 deletions(-)
diff --git a/drivers/block/null_blk/main.c b/drivers/block/null_blk/main.c
index f8c0fd57e041..eba204b27785 100644
--- a/drivers/block/null_blk/main.c
+++ b/drivers/block/null_blk/main.c
@@ -66,7 +66,7 @@ struct nullb_page {
#define NULLB_PAGE_FREE (MAP_SZ - 2)
static LIST_HEAD(nullb_list);
-static struct mutex lock;
+static DEFINE_MUTEX(lock);
static int null_major;
static DEFINE_IDA(nullb_indexes);
static struct blk_mq_tag_set tag_set;
@@ -2166,8 +2166,6 @@ static int __init null_init(void)
if (ret)
return ret;
- mutex_init(&lock);
-
null_major = register_blkdev(0, "nullb");
if (null_major < 0) {
ret = null_major;
--
2.52.0
^ permalink raw reply related
* [PATCH 3/3] null_blk: register configfs subsystem after creating default devices
From: Zizhi Wo @ 2026-07-06 12:35 UTC (permalink / raw)
To: axboe, dlemoal, nilay, linux-block, kch, johannes.thumshirn,
kbusch, bvanassche
Cc: linux-kernel, yangerkun, chengzhihao1, wozizhi
In-Reply-To: <20260706123507.3809871-1-wozizhi@huaweicloud.com>
From: Zizhi Wo <wozizhi@huawei.com>
In null_init(), configfs_register_subsystem() currently runs before
register_blkdev(), so when null_blk is built as a module, a racing mkdir()
+ poweron from userspace can reach null_add_dev() while null_major is still
0. __add_disk() then hits WARN_ON(disk->minors) (major=0 with minors!=0)
and fails:
[root@fedora ~]# [ 2366.521436] WARNING: block/genhd.c:476 at __add_disk+0x8a7/0xde0,
[ 2366.523552] Modules linked in: null_blk(+) nft_fib_inet nft_fib_ipv4 nft_fib_ipv6 nft_fib
[ 2366.529081] CPU: 26 UID: 0 PID: 1600 Comm: sh Not tainted 7.2.0-rc1+ #66 PREEMPT(full)
......
[ 2366.547251] Call Trace:
[ 2366.547575] <TASK>
[ 2366.547831] ? _raw_spin_lock+0x84/0xe0
[ 2366.548260] add_disk_fwnode+0x114/0x560
[ 2366.548739] null_add_dev+0x102d/0x1b80 [null_blk]
[ 2366.549310] ? __pfx_null_add_dev+0x10/0x10 [null_blk]
[ 2366.549906] ? mutex_lock+0xde/0x1c0
[ 2366.550361] ? __pfx_mutex_lock+0x10/0x10
[ 2366.550827] nullb_device_power_store+0x1e7/0x280 [null_blk]
[ 2366.551499] ? __pfx_nullb_device_power_store+0x10/0x10 [null_blk]
[ 2366.552177] ? __kmalloc_cache_noprof+0x1f5/0x470
[ 2366.552748] ? configfs_write_iter+0x35c/0x4e0
[ 2366.553242] configfs_write_iter+0x286/0x4e0
[ 2366.553787] vfs_write+0x52d/0xd00
[ 2366.554169] ? __pfx_vfs_write+0x10/0x10
[ 2366.554679] ? __pfx___css_rstat_updated+0x10/0x10
[ 2366.555196] ? fdget_pos+0x1cf/0x4c0
[ 2366.555649] ksys_write+0xfc/0x1d0
......
Additionally, the err_dev path destroys all devices on nullb_list while
configfs is still registered. If a racing mkdir() + poweron puts a user
device on the list, null_destroy_dev()->null_free_dev() kfrees the user
device's nullb_device but /sys/kernel/config/nullb/<name> is still
reachable. Any userspace access to the item will trigger a UAF.
For simplicity, move configfs_register_subsystem() to the end to solve
the problems above. This also mirrors null_exit().
Fixes: 3bf2bd20734e ("nullb: add configfs interface")
Signed-off-by: Zizhi Wo <wozizhi@huawei.com>
---
drivers/block/null_blk/main.c | 16 ++++++----------
1 file changed, 6 insertions(+), 10 deletions(-)
diff --git a/drivers/block/null_blk/main.c b/drivers/block/null_blk/main.c
index a775e70e16fc..9800049b3c3f 100644
--- a/drivers/block/null_blk/main.c
+++ b/drivers/block/null_blk/main.c
@@ -2162,15 +2162,9 @@ static int __init null_init(void)
config_group_init(&nullb_subsys.su_group);
mutex_init(&nullb_subsys.su_mutex);
- ret = configfs_register_subsystem(&nullb_subsys);
- if (ret)
- return ret;
-
null_major = register_blkdev(0, "nullb");
- if (null_major < 0) {
- ret = null_major;
- goto err_conf;
- }
+ if (null_major < 0)
+ return null_major;
for (i = 0; i < nr_devices; i++) {
ret = null_create_dev();
@@ -2178,6 +2172,10 @@ static int __init null_init(void)
goto err_dev;
}
+ ret = configfs_register_subsystem(&nullb_subsys);
+ if (ret)
+ goto err_dev;
+
pr_info("module loaded\n");
return 0;
@@ -2187,8 +2185,6 @@ static int __init null_init(void)
null_destroy_dev(nullb);
}
unregister_blkdev(null_major, "nullb");
-err_conf:
- configfs_unregister_subsystem(&nullb_subsys);
return ret;
}
--
2.52.0
^ permalink raw reply related
* Re: [PATCH] block: split out a new blk_plug.h helper
From: Christian Brauner @ 2026-07-06 13:09 UTC (permalink / raw)
To: Christoph Hellwig
Cc: axboe, linux-block, linux-fsdevel, linux-aio, linux-kernel,
io-uring, linux-mm
In-Reply-To: <20260706041125.642097-1-hch@lst.de>
> blkdev.h gets included in various places outside the block layer just
> for struct blk_plug and related plugging functions.
>
> Split blk_plug into a separate helper to reduce the amount of code
> that needs to get rebuilt when blkdev.h changes and to slightly
> reduce compile times.
>
> In io_uring this requires pulling in a few other headers explicitly that
> previously were implicitly included through blkdev.h.
>
> Signed-off-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Christian Brauner (Amutable) <brauner@kernel.org>
--
Christian Brauner <brauner@kernel.org>
^ permalink raw reply
* Re: [PATCH 2/3] null_blk: give the file-scope mutex a descriptive name
From: Bart Van Assche @ 2026-07-06 13:12 UTC (permalink / raw)
To: Zizhi Wo, axboe, dlemoal, nilay, linux-block, kch,
johannes.thumshirn, kbusch
Cc: linux-kernel, yangerkun, chengzhihao1, wozizhi
In-Reply-To: <20260706123507.3809871-3-wozizhi@huaweicloud.com>
On 7/6/26 5:35 AM, Zizhi Wo wrote:
> The file-scope lock mutex mainly serializes access to the global nullb_list
> and related device setup. Rename it to "nullb_list_lock" to make its
> purpose clear. No functional change.
From commit a2db328b0839 ("null_blk: fix null-ptr-dereference while
configuring 'power' and 'submit_queues'"):
Writing 'power' and 'submit_queues' concurrently will trigger kernel
panic:
[ ... ]
Fix this problem by resuing the global mutex to protect
nullb_device_power_store() and nullb_update_nr_hw_queues() from
configfs.
This makes it clear that the "lock" mutex has a broader purpose than
only protecting nullb_list. Hence, the name nullb_list_lock is
confusing. How about using the name "nullb_lock"?
Thanks,
Bart.
^ permalink raw reply
* Re: [PATCH 1/3] null_blk: use DEFINE_MUTEX for the file-scope mutex
From: Bart Van Assche @ 2026-07-06 13:13 UTC (permalink / raw)
To: Zizhi Wo, axboe, dlemoal, nilay, linux-block, kch,
johannes.thumshirn, kbusch
Cc: linux-kernel, yangerkun, chengzhihao1, wozizhi
In-Reply-To: <20260706123507.3809871-2-wozizhi@huaweicloud.com>
On 7/6/26 5:35 AM, Zizhi Wo wrote:
> [ ... ]
Reviewed-by: Bart Van Assche <bvanassche@acm.org>
^ permalink raw reply
* Re: [PATCH 3/3] null_blk: register configfs subsystem after creating default devices
From: Bart Van Assche @ 2026-07-06 13:17 UTC (permalink / raw)
To: Zizhi Wo, axboe, dlemoal, nilay, linux-block, kch,
johannes.thumshirn, kbusch
Cc: linux-kernel, yangerkun, chengzhihao1, wozizhi
In-Reply-To: <20260706123507.3809871-4-wozizhi@huaweicloud.com>
On 7/6/26 5:35 AM, Zizhi Wo wrote:
> @@ -2187,8 +2185,6 @@ static int __init null_init(void)
> null_destroy_dev(nullb);
> }
> unregister_blkdev(null_major, "nullb");
> -err_conf:
> - configfs_unregister_subsystem(&nullb_subsys);
> return ret;
> }
Please make null_exit() consistent with the cleanup path in null_init().
null_exit() calls unregister_blkdev() before it destroys the null_blk
instances. That doesn't look right to me.
Thanks,
Bart.
^ permalink raw reply
* Re: [PATCH 2/3] null_blk: give the file-scope mutex a descriptive name
From: Zizhi Wo @ 2026-07-06 13:21 UTC (permalink / raw)
To: Bart Van Assche, axboe, dlemoal, nilay, linux-block, kch,
johannes.thumshirn, kbusch
Cc: linux-kernel, yangerkun, chengzhihao1, wozizhi
In-Reply-To: <9004743e-f522-424e-a1ab-8779ecc6da02@acm.org>
在 2026/7/6 21:12, Bart Van Assche 写道:
> On 7/6/26 5:35 AM, Zizhi Wo wrote:
>> The file-scope lock mutex mainly serializes access to the global
>> nullb_list
>> and related device setup. Rename it to "nullb_list_lock" to make its
>> purpose clear. No functional change.
>
> From commit a2db328b0839 ("null_blk: fix null-ptr-dereference while
> configuring 'power' and 'submit_queues'"):
>
> Writing 'power' and 'submit_queues' concurrently will trigger kernel
> panic:
> [ ... ]
> Fix this problem by resuing the global mutex to protect
> nullb_device_power_store() and nullb_update_nr_hw_queues() from
> configfs.
>
> This makes it clear that the "lock" mutex has a broader purpose than
> only protecting nullb_list. Hence, the name nullb_list_lock is
> confusing. How about using the name "nullb_lock"?
>
> Thanks,
>
> Bart.
Thanks for the reminder! Agreed that "nullb_list_lock" is too narrow
since it also serializes nullb_device_power_store() and
nullb_update_nr_hw_queues().
However, I'm a bit worried that "nullb_lock" is easy to confuse with the
per-device spinlock "nullb->lock"... They are only one "->" apart?
Would "nullb_global_lock" (or "nullb_config_lock") work better? It
reflects the broader purpose and avoids clashing with nullb->lock.
Thanks,
Zizhi Wo
^ permalink raw reply
* Re: [PATCH 3/3] null_blk: register configfs subsystem after creating default devices
From: Zizhi Wo @ 2026-07-06 13:34 UTC (permalink / raw)
To: Bart Van Assche, axboe, dlemoal, nilay, linux-block, kch,
johannes.thumshirn, kbusch
Cc: linux-kernel, yangerkun, chengzhihao1, wozizhi
In-Reply-To: <490008e2-2345-48ea-bd8e-c078d828a43f@acm.org>
在 2026/7/6 21:17, Bart Van Assche 写道:
> On 7/6/26 5:35 AM, Zizhi Wo wrote:
>> @@ -2187,8 +2185,6 @@ static int __init null_init(void)
>> null_destroy_dev(nullb);
>> }
>> unregister_blkdev(null_major, "nullb");
>> -err_conf:
>> - configfs_unregister_subsystem(&nullb_subsys);
>> return ret;
>> }
>
> Please make null_exit() consistent with the cleanup path in null_init().
> null_exit() calls unregister_blkdev() before it destroys the null_blk
> instances. That doesn't look right to me.
>
> Thanks,
>
> Bart.
>
>
Thanks for pointing this out, I hadn't noticed that. I'll add this
change in the next version.
Thanks,
Zizhi Wo
^ permalink raw reply
* Re: [PATCH 2/3] null_blk: give the file-scope mutex a descriptive name
From: Bart Van Assche @ 2026-07-06 14:45 UTC (permalink / raw)
To: Zizhi Wo, axboe, dlemoal, nilay, linux-block, kch,
johannes.thumshirn, kbusch
Cc: linux-kernel, yangerkun, chengzhihao1, wozizhi
In-Reply-To: <5f99b2f3-05c1-4754-9827-d55528861ecc@huaweicloud.com>
On 7/6/26 6:21 AM, Zizhi Wo wrote:
> Thanks for the reminder! Agreed that "nullb_list_lock" is too narrow
> since it also serializes nullb_device_power_store() and
> nullb_update_nr_hw_queues().
>
> However, I'm a bit worried that "nullb_lock" is easy to confuse with the
> per-device spinlock "nullb->lock"... They are only one "->" apart?
>
> Would "nullb_global_lock" (or "nullb_config_lock") work better? It
> reflects the broader purpose and avoids clashing with nullb->lock.
Not sure what others prefer but nullb_global_lock sounds good to me.
Thanks,
Bart.
^ permalink raw reply
* [PATCH v5 03/21] Add a function to kmap one page of a multipage bio_vec
From: David Howells @ 2026-07-06 15:27 UTC (permalink / raw)
To: Christian Brauner, Matthew Wilcox, Christoph Hellwig
Cc: David Howells, Paulo Alcantara, Jens Axboe, Leon Romanovsky,
Steve French, ChenXiaoSong, Marc Dionne, Stefan Metzmacher,
Eric Van Hensbergen, Dominique Martinet, Ilya Dryomov, netfs,
linux-afs, linux-cifs, linux-nfs, ceph-devel, v9fs, linux-erofs,
linux-fsdevel, linux-kernel, linux-block
In-Reply-To: <20260706152737.1231312-1-dhowells@redhat.com>
Add a function to kmap one page of a multipage bio_vec by offset (which is
added to the offset in the bio_vec internally). The caller is responsible
for calculating how much of the page is then available.
Signed-off-by: David Howells <dhowells@redhat.com>
Acked-by: Paulo Alcantara (Red Hat) <pc@manguebit.org>
cc: Matthew Wilcox <willy@infradead.org>
cc: Christoph Hellwig <hch@infradead.org>
cc: Jens Axboe <axboe@kernel.dk>
cc: linux-block@vger.kernel.org
cc: netfs@lists.linux.dev
cc: linux-fsdevel@vger.kernel.org
---
include/linux/bvec.h | 18 ++++++++++++++++++
1 file changed, 18 insertions(+)
diff --git a/include/linux/bvec.h b/include/linux/bvec.h
index 92837e2743f1..53cf36e73967 100644
--- a/include/linux/bvec.h
+++ b/include/linux/bvec.h
@@ -343,4 +343,22 @@ static inline phys_addr_t bvec_phys(const struct bio_vec *bvec)
return page_to_phys(bvec->bv_page) + bvec->bv_offset;
}
+/**
+ * bvec_kmap_partial - Map part of a bvec into the kernel virtual address space
+ * @bvec: bvec to map
+ * @offset: Offset into bvec
+ *
+ * Map the page containing the byte at @offset into the kernel virtual address
+ * space. The caller is responsible for making sure this doesn't overrun.
+ *
+ * Call kunmap_local on the returned address to unmap.
+ */
+static inline void *bvec_kmap_partial(struct bio_vec *bvec, size_t offset)
+{
+ offset += bvec->bv_offset;
+
+ return kmap_local_page(bvec->bv_page + (offset >> PAGE_SHIFT)) +
+ (offset & ~PAGE_MASK);
+}
+
#endif /* __LINUX_BVEC_H */
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox