* [PATCH v19 31/40] dept: assign unique dept_key to each distinct wait_for_completion() caller
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>
wait_for_completion() can be used at various points in the code and it's
very hard to distinguish wait_for_completion()s between different usages.
Using a single dept_key for all the wait_for_completion()s could trigger
false positive reports.
Assign unique dept_key to each distinct wait_for_completion() caller to
avoid false positive reports.
While at it, add a rust helper for wait_for_completion() to avoid build
errors.
Signed-off-by: Byungchul Park <byungchul@sk.com>
---
include/linux/completion.h | 100 +++++++++++++++++++++++++++++++------
kernel/sched/completion.c | 60 +++++++++++-----------
rust/helpers/completion.c | 5 ++
3 files changed, 120 insertions(+), 45 deletions(-)
diff --git a/include/linux/completion.h b/include/linux/completion.h
index 3200b741de28..4d8fb1d95c0a 100644
--- a/include/linux/completion.h
+++ b/include/linux/completion.h
@@ -27,12 +27,10 @@
struct completion {
unsigned int done;
struct swait_queue_head wait;
- struct dept_map dmap;
};
#define init_completion(x) \
do { \
- sdt_map_init(&(x)->dmap); \
__init_completion(x); \
} while (0)
@@ -43,17 +41,14 @@ do { \
static inline void complete_acquire(struct completion *x, long timeout)
{
- sdt_might_sleep_start_timeout(&x->dmap, timeout);
}
static inline void complete_release(struct completion *x)
{
- sdt_might_sleep_end();
}
#define COMPLETION_INITIALIZER(work) \
- { 0, __SWAIT_QUEUE_HEAD_INITIALIZER((work).wait), \
- .dmap = DEPT_MAP_INITIALIZER(work, NULL), }
+ { 0, __SWAIT_QUEUE_HEAD_INITIALIZER((work).wait), }
#define COMPLETION_INITIALIZER_ONSTACK_MAP(work, map) \
(*({ init_completion_map(&(work), &(map)); &(work); }))
@@ -119,18 +114,18 @@ static inline void reinit_completion(struct completion *x)
x->done = 0;
}
-extern void wait_for_completion(struct completion *);
-extern void wait_for_completion_io(struct completion *);
-extern int wait_for_completion_interruptible(struct completion *x);
-extern int wait_for_completion_killable(struct completion *x);
-extern int wait_for_completion_state(struct completion *x, unsigned int state);
-extern unsigned long wait_for_completion_timeout(struct completion *x,
+extern void __wait_for_completion(struct completion *);
+extern void __wait_for_completion_io(struct completion *);
+extern int __wait_for_completion_interruptible(struct completion *x);
+extern int __wait_for_completion_killable(struct completion *x);
+extern int __wait_for_completion_state(struct completion *x, unsigned int state);
+extern unsigned long __wait_for_completion_timeout(struct completion *x,
unsigned long timeout);
-extern unsigned long wait_for_completion_io_timeout(struct completion *x,
+extern unsigned long __wait_for_completion_io_timeout(struct completion *x,
unsigned long timeout);
-extern long wait_for_completion_interruptible_timeout(
+extern long __wait_for_completion_interruptible_timeout(
struct completion *x, unsigned long timeout);
-extern long wait_for_completion_killable_timeout(
+extern long __wait_for_completion_killable_timeout(
struct completion *x, unsigned long timeout);
extern bool try_wait_for_completion(struct completion *x);
extern bool completion_done(struct completion *x);
@@ -139,4 +134,79 @@ extern void complete(struct completion *);
extern void complete_on_current_cpu(struct completion *x);
extern void complete_all(struct completion *);
+#define wait_for_completion(x) \
+({ \
+ sdt_might_sleep_start_timeout(NULL, -1L); \
+ __wait_for_completion(x); \
+ sdt_might_sleep_end(); \
+})
+#define wait_for_completion_io(x) \
+({ \
+ sdt_might_sleep_start_timeout(NULL, -1L); \
+ __wait_for_completion_io(x); \
+ sdt_might_sleep_end(); \
+})
+#define wait_for_completion_interruptible(x) \
+({ \
+ int __ret; \
+ \
+ sdt_might_sleep_start_timeout(NULL, -1L); \
+ __ret = __wait_for_completion_interruptible(x); \
+ sdt_might_sleep_end(); \
+ __ret; \
+})
+#define wait_for_completion_killable(x) \
+({ \
+ int __ret; \
+ \
+ sdt_might_sleep_start_timeout(NULL, -1L); \
+ __ret = __wait_for_completion_killable(x); \
+ sdt_might_sleep_end(); \
+ __ret; \
+})
+#define wait_for_completion_state(x, s) \
+({ \
+ int __ret; \
+ \
+ sdt_might_sleep_start_timeout(NULL, -1L); \
+ __ret = __wait_for_completion_state(x, s); \
+ sdt_might_sleep_end(); \
+ __ret; \
+})
+#define wait_for_completion_timeout(x, t) \
+({ \
+ unsigned long __ret; \
+ \
+ sdt_might_sleep_start_timeout(NULL, t); \
+ __ret = __wait_for_completion_timeout(x, t); \
+ sdt_might_sleep_end(); \
+ __ret; \
+})
+#define wait_for_completion_io_timeout(x, t) \
+({ \
+ unsigned long __ret; \
+ \
+ sdt_might_sleep_start_timeout(NULL, t); \
+ __ret = __wait_for_completion_io_timeout(x, t); \
+ sdt_might_sleep_end(); \
+ __ret; \
+})
+#define wait_for_completion_interruptible_timeout(x, t) \
+({ \
+ long __ret; \
+ \
+ sdt_might_sleep_start_timeout(NULL, t); \
+ __ret = __wait_for_completion_interruptible_timeout(x, t); \
+ sdt_might_sleep_end(); \
+ __ret; \
+})
+#define wait_for_completion_killable_timeout(x, t) \
+({ \
+ long __ret; \
+ \
+ sdt_might_sleep_start_timeout(NULL, t); \
+ __ret = __wait_for_completion_killable_timeout(x, t); \
+ sdt_might_sleep_end(); \
+ __ret; \
+})
#endif
diff --git a/kernel/sched/completion.c b/kernel/sched/completion.c
index 5e45a60ff7b3..7262000db114 100644
--- a/kernel/sched/completion.c
+++ b/kernel/sched/completion.c
@@ -4,7 +4,7 @@
* Generic wait-for-completion handler;
*
* It differs from semaphores in that their default case is the opposite,
- * wait_for_completion default blocks whereas semaphore default non-block. The
+ * __wait_for_completion default blocks whereas semaphore default non-block. The
* interface also makes it easy to 'complete' multiple waiting threads,
* something which isn't entirely natural for semaphores.
*
@@ -42,7 +42,7 @@ void complete_on_current_cpu(struct completion *x)
* This will wake up a single thread waiting on this completion. Threads will be
* awakened in the same order in which they were queued.
*
- * See also complete_all(), wait_for_completion() and related routines.
+ * See also complete_all(), __wait_for_completion() and related routines.
*
* If this function wakes up a task, it executes a full memory barrier before
* accessing the task state.
@@ -139,23 +139,23 @@ wait_for_common_io(struct completion *x, long timeout, int state)
}
/**
- * wait_for_completion: - waits for completion of a task
+ * __wait_for_completion: - waits for completion of a task
* @x: holds the state of this particular completion
*
* This waits to be signaled for completion of a specific task. It is NOT
* interruptible and there is no timeout.
*
- * See also similar routines (i.e. wait_for_completion_timeout()) with timeout
+ * See also similar routines (i.e. __wait_for_completion_timeout()) with timeout
* and interrupt capability. Also see complete().
*/
-void __sched wait_for_completion(struct completion *x)
+void __sched __wait_for_completion(struct completion *x)
{
wait_for_common(x, MAX_SCHEDULE_TIMEOUT, TASK_UNINTERRUPTIBLE);
}
-EXPORT_SYMBOL(wait_for_completion);
+EXPORT_SYMBOL(__wait_for_completion);
/**
- * wait_for_completion_timeout: - waits for completion of a task (w/timeout)
+ * __wait_for_completion_timeout: - waits for completion of a task (w/timeout)
* @x: holds the state of this particular completion
* @timeout: timeout value in jiffies
*
@@ -167,28 +167,28 @@ EXPORT_SYMBOL(wait_for_completion);
* till timeout) if completed.
*/
unsigned long __sched
-wait_for_completion_timeout(struct completion *x, unsigned long timeout)
+__wait_for_completion_timeout(struct completion *x, unsigned long timeout)
{
return wait_for_common(x, timeout, TASK_UNINTERRUPTIBLE);
}
-EXPORT_SYMBOL(wait_for_completion_timeout);
+EXPORT_SYMBOL(__wait_for_completion_timeout);
/**
- * wait_for_completion_io: - waits for completion of a task
+ * __wait_for_completion_io: - waits for completion of a task
* @x: holds the state of this particular completion
*
* This waits to be signaled for completion of a specific task. It is NOT
* interruptible and there is no timeout. The caller is accounted as waiting
* for IO (which traditionally means blkio only).
*/
-void __sched wait_for_completion_io(struct completion *x)
+void __sched __wait_for_completion_io(struct completion *x)
{
wait_for_common_io(x, MAX_SCHEDULE_TIMEOUT, TASK_UNINTERRUPTIBLE);
}
-EXPORT_SYMBOL(wait_for_completion_io);
+EXPORT_SYMBOL(__wait_for_completion_io);
/**
- * wait_for_completion_io_timeout: - waits for completion of a task (w/timeout)
+ * __wait_for_completion_io_timeout: - waits for completion of a task (w/timeout)
* @x: holds the state of this particular completion
* @timeout: timeout value in jiffies
*
@@ -201,14 +201,14 @@ EXPORT_SYMBOL(wait_for_completion_io);
* till timeout) if completed.
*/
unsigned long __sched
-wait_for_completion_io_timeout(struct completion *x, unsigned long timeout)
+__wait_for_completion_io_timeout(struct completion *x, unsigned long timeout)
{
return wait_for_common_io(x, timeout, TASK_UNINTERRUPTIBLE);
}
-EXPORT_SYMBOL(wait_for_completion_io_timeout);
+EXPORT_SYMBOL(__wait_for_completion_io_timeout);
/**
- * wait_for_completion_interruptible: - waits for completion of a task (w/intr)
+ * __wait_for_completion_interruptible: - waits for completion of a task (w/intr)
* @x: holds the state of this particular completion
*
* This waits for completion of a specific task to be signaled. It is
@@ -216,7 +216,7 @@ EXPORT_SYMBOL(wait_for_completion_io_timeout);
*
* Return: -ERESTARTSYS if interrupted, 0 if completed.
*/
-int __sched wait_for_completion_interruptible(struct completion *x)
+int __sched __wait_for_completion_interruptible(struct completion *x)
{
long t = wait_for_common(x, MAX_SCHEDULE_TIMEOUT, TASK_INTERRUPTIBLE);
@@ -224,10 +224,10 @@ int __sched wait_for_completion_interruptible(struct completion *x)
return t;
return 0;
}
-EXPORT_SYMBOL(wait_for_completion_interruptible);
+EXPORT_SYMBOL(__wait_for_completion_interruptible);
/**
- * wait_for_completion_interruptible_timeout: - waits for completion (w/(to,intr))
+ * __wait_for_completion_interruptible_timeout: - waits for completion (w/(to,intr))
* @x: holds the state of this particular completion
* @timeout: timeout value in jiffies
*
@@ -238,15 +238,15 @@ EXPORT_SYMBOL(wait_for_completion_interruptible);
* or number of jiffies left till timeout) if completed.
*/
long __sched
-wait_for_completion_interruptible_timeout(struct completion *x,
+__wait_for_completion_interruptible_timeout(struct completion *x,
unsigned long timeout)
{
return wait_for_common(x, timeout, TASK_INTERRUPTIBLE);
}
-EXPORT_SYMBOL(wait_for_completion_interruptible_timeout);
+EXPORT_SYMBOL(__wait_for_completion_interruptible_timeout);
/**
- * wait_for_completion_killable: - waits for completion of a task (killable)
+ * __wait_for_completion_killable: - waits for completion of a task (killable)
* @x: holds the state of this particular completion
*
* This waits to be signaled for completion of a specific task. It can be
@@ -254,7 +254,7 @@ EXPORT_SYMBOL(wait_for_completion_interruptible_timeout);
*
* Return: -ERESTARTSYS if interrupted, 0 if completed.
*/
-int __sched wait_for_completion_killable(struct completion *x)
+int __sched __wait_for_completion_killable(struct completion *x)
{
long t = wait_for_common(x, MAX_SCHEDULE_TIMEOUT, TASK_KILLABLE);
@@ -262,9 +262,9 @@ int __sched wait_for_completion_killable(struct completion *x)
return t;
return 0;
}
-EXPORT_SYMBOL(wait_for_completion_killable);
+EXPORT_SYMBOL(__wait_for_completion_killable);
-int __sched wait_for_completion_state(struct completion *x, unsigned int state)
+int __sched __wait_for_completion_state(struct completion *x, unsigned int state)
{
long t = wait_for_common(x, MAX_SCHEDULE_TIMEOUT, state);
@@ -272,10 +272,10 @@ int __sched wait_for_completion_state(struct completion *x, unsigned int state)
return t;
return 0;
}
-EXPORT_SYMBOL(wait_for_completion_state);
+EXPORT_SYMBOL(__wait_for_completion_state);
/**
- * wait_for_completion_killable_timeout: - waits for completion of a task (w/(to,killable))
+ * __wait_for_completion_killable_timeout: - waits for completion of a task (w/(to,killable))
* @x: holds the state of this particular completion
* @timeout: timeout value in jiffies
*
@@ -287,12 +287,12 @@ EXPORT_SYMBOL(wait_for_completion_state);
* or number of jiffies left till timeout) if completed.
*/
long __sched
-wait_for_completion_killable_timeout(struct completion *x,
+__wait_for_completion_killable_timeout(struct completion *x,
unsigned long timeout)
{
return wait_for_common(x, timeout, TASK_KILLABLE);
}
-EXPORT_SYMBOL(wait_for_completion_killable_timeout);
+EXPORT_SYMBOL(__wait_for_completion_killable_timeout);
/**
* try_wait_for_completion - try to decrement a completion without blocking
@@ -334,7 +334,7 @@ EXPORT_SYMBOL(try_wait_for_completion);
* completion_done - Test to see if a completion has any waiters
* @x: completion structure
*
- * Return: 0 if there are waiters (wait_for_completion() in progress)
+ * Return: 0 if there are waiters (__wait_for_completion() in progress)
* 1 if there are no waiters.
*
* Note, this will always return true if complete_all() was called on @X.
diff --git a/rust/helpers/completion.c b/rust/helpers/completion.c
index 0126767cc3be..5ea2eef74abc 100644
--- a/rust/helpers/completion.c
+++ b/rust/helpers/completion.c
@@ -6,3 +6,8 @@ __rust_helper void rust_helper_init_completion(struct completion *x)
{
init_completion(x);
}
+
+void rust_helper_wait_for_completion(struct completion *x)
+{
+ wait_for_completion(x);
+}
--
2.17.1
^ permalink raw reply related
* [PATCH v19 33/40] dept: call dept_hardirqs_off() in local_irq_*() regardless of irq state
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>
For dept to function properly, dept_task()->hardirqs_enabled must be set
correctly. If it fails to set this value to false, for example, dept
may mistakenly think irq is still enabled even when it's not.
Do dept_hardirqs_off() regardless of irq state not to miss any
unexpected cases by any chance e.g. changes of the state by asm code.
Signed-off-by: Byungchul Park <byungchul@sk.com>
---
include/linux/irqflags.h | 14 ++++++++++++++
kernel/dependency/dept.c | 1 +
2 files changed, 15 insertions(+)
diff --git a/include/linux/irqflags.h b/include/linux/irqflags.h
index d8b9cf093f83..586f5bad4da7 100644
--- a/include/linux/irqflags.h
+++ b/include/linux/irqflags.h
@@ -214,6 +214,13 @@ extern void warn_bogus_irq_restore(void);
raw_local_irq_disable(); \
if (!was_disabled) \
trace_hardirqs_off(); \
+ /* \
+ * Just in case that C code has missed \
+ * trace_hardirqs_off() at the first \
+ * place e.g. disabling irq at asm code.\
+ */ \
+ else \
+ dept_hardirqs_off(); \
} while (0)
#define local_irq_save(flags) \
@@ -221,6 +228,13 @@ extern void warn_bogus_irq_restore(void);
raw_local_irq_save(flags); \
if (!raw_irqs_disabled_flags(flags)) \
trace_hardirqs_off(); \
+ /* \
+ * Just in case that C code has missed \
+ * trace_hardirqs_off() at the first \
+ * place e.g. disabling irq at asm code.\
+ */ \
+ else \
+ dept_hardirqs_off(); \
} while (0)
#define local_irq_restore(flags) \
diff --git a/kernel/dependency/dept.c b/kernel/dependency/dept.c
index 007e1bc7d201..35a3667ac8b3 100644
--- a/kernel/dependency/dept.c
+++ b/kernel/dependency/dept.c
@@ -2095,6 +2095,7 @@ void noinstr dept_hardirqs_off(void)
*/
dept_task()->hardirqs_enabled = false;
}
+EXPORT_SYMBOL_GPL(dept_hardirqs_off);
void noinstr dept_update_cxt(void)
{
--
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 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 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 5/9] ax88179_178a: Add support for ethtool pause parameter configuration
From: Birger Koblitz @ 2026-07-06 6:28 UTC (permalink / raw)
To: Andrew Lunn
Cc: Maxime Chevallier, Andrew Lunn, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, linux-usb, netdev, linux-kernel
In-Reply-To: <46553470-9be3-4ae0-824d-ae85441c920d@lunn.ch>
On 7/1/26 19:05, Andrew Lunn wrote:
> On Wed, Jul 01, 2026 at 06:22:31PM +0200, Birger Koblitz wrote:
>> Hi Andrew,
>>
>> thanks for reviewing this patch-series! I will answer to the other questions later,
>> so that the answers stay together. But it is probably best if I give this answer
>> immediately:
>> On 7/1/26 17:08, Andrew Lunn wrote:
>>>>> +static void ax88179a_get_pauseparam(struct net_device *net, struct ethtool_pauseparam *pause)
>>>>> + if (!(bmcr & BMCR_ANENABLE)) {
>>>>> + pause->autoneg = 0;
>>>>> + pause->rx_pause = 0;
>>>>> + pause->tx_pause = 0;
>>>> The best way to have this correct is to use phylink, but for that you'd need to
>>>> have a proper PHY driver instead of using the mii_ API here.
>>>
>>> I said the some to one of the other patches.
>>>
>>> Do we know what PHYs are being used? Can register 2 and 3 be read to
>>> get the PHY IDs?
>>>
>>> Andrew
>>
>> I tested
>> id1 = ax88179_mdio_read(dev->net, dev->mii.phy_id, MII_PHYSID1);
>> id2 = ax88179_mdio_read(dev->net, dev->mii.phy_id, MII_PHYSID2);
>>
>> and got:
>
> Thanks for these numbers.
>
>> Renkforce AX88179A: ID1 7c9f, ID2 7061
>> Delock AX88279 ID1 03a2, ID2 a411
>
> air_en8811h.c:#define EN8811H_PHY_ID 0x03a2a411
>
>> UGreen AX88772D ID1 e65b, ID2 2c61
>> TP-Link AX88179A ID1 e65b, ID2 2c61
>
> The two ID registers contain part of an OUI, but it has some bits
> missing. So it is not so easy to look it up.
>
> However, anything using the MII framework basically assumes a very
> simple PHY and only looks at the 802.3 defined registers. So the
> genphy generic PHY driver might be sufficient for when there is not a
> specific driver. At lot depends on how much extra code there is
> accessing the PHY registers in the driver.
I started converting the driver to phylink, but hit rock-bottom. There definitely is
an Airoha EN8811H as IP-core in the AX88279, which is clear from the PHY-ID and quirks
such as only Full-Duplex and ANEG being supported by the phy, but the firmware is
completely different, leading to different register content. The most striking example
is that the 2.5GBit advertising bit in the firmware for the AX88279 abuses the
ADVERTISE_RESV bit of the MII_ADVERTISE register, but in the EN8811H this is the
standard bit in the 10GBit advertising register. There is no firmware needed for the
PHY in the AX88279. The EN8811H mechanism for vendor register access is using a so-called
buckpbus using phy-register reads/writes for access, whereas similar vendor registers
of the AX88279 are just standard AX88279 registers, also to avoid USB-transfers.
The pbuckbus logic is not implemented in the AX88279 firmware, but in any case a
vendor register read for the EN8811H would need 5 URBs, where as the AX88279 just needs
1. The vendor registers also have very different content, for example the WoL bits
are entirely different.
I am also relatively sure that the PHY in the AX88179a/b is an Airoha AN8801, but
again the firmware is so different it looks like a completely different chip with
regards to registers. Again it uses the pbuckbus to access the vendor registers,
which is not implemented in the AX88179a firmware.
Changing the behaviour of the EN8811H driver to also accept the firmware of the
AX88279 IP-core implementation does not appear to make sense, it would be cleaner
to add a separate driver, but that would not work from the phylink-logic as it would
grab the same PHY-IDs.
I could simulate the EN8811H firmware in the ax88179_178a.c driver, but I guess that
would beat the purpose, plus it would cost quite an overhead in URBs.
For me the way ahead is to stick with the simple MII-driver and just make sure that
features such as pause configuration are properly implemented. Please tell me if that
makes sense or there are better ways.
Birger
^ permalink raw reply
* RE: [PATCH net-next] net: rmnet: annotate endpoint lookup under RTNL
From: subash.a.kasiviswanathan @ 2026-07-06 6:31 UTC (permalink / raw)
To: 'Runyu Xiao', sean.tranchetti
Cc: andrew+netdev, davem, edumazet, kuba, pabeni, netdev,
linux-kernel, jianhao.xu
In-Reply-To: <20260701124017.3205729-1-runyu.xiao@seu.edu.cn>
> -----Original Message-----
> From: Runyu Xiao <runyu.xiao@seu.edu.cn>
> Sent: Wednesday, July 1, 2026 6:40 AM
> To: subash.a.kasiviswanathan@oss.qualcomm.com;
> sean.tranchetti@oss.qualcomm.com
> Cc: andrew+netdev@lunn.ch; davem@davemloft.net;
> edumazet@google.com; kuba@kernel.org; pabeni@redhat.com;
> netdev@vger.kernel.org; linux-kernel@vger.kernel.org;
> runyu.xiao@seu.edu.cn; jianhao.xu@seu.edu.cn
> Subject: [PATCH net-next] net: rmnet: annotate endpoint lookup under RTNL
>
> rmnet_get_endpoint() is shared by packet receive paths and RTNL-protected
> control paths. The receive paths already run under RCU/BH context through
> the RX handler, while the control paths reach
> rmnet_get_endpoint() after obtaining the rmnet port with
> rmnet_get_port_rtnl().
>
> The helper walks port->muxed_ep[] with hlist_for_each_entry_rcu(). Pass
> lockdep_rtnl_is_held() as the non-RCU protection condition so
> CONFIG_PROVE_RCU_LIST can see the RTNL-protected control-path calls
> while preserving the existing RCU-reader behavior for data paths.
>
> This was found by our static analysis tool and then manually reviewed
against
> the current tree. The dynamic triage evidence is a target-matched
> CONFIG_PROVE_RCU_LIST warning; the change is limited to documenting the
> existing protection contract.
>
> This is a lockdep annotation cleanup. It does not change endpoint lifetime
or
> hash updates.
>
> Signed-off-by: Runyu Xiao <runyu.xiao@seu.edu.cn>
> ---
> drivers/net/ethernet/qualcomm/rmnet/rmnet_config.c | 3 ++-
> 1 file changed, 2 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.c
> b/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.c
> index ba8763cac9d9..977fb80d8bf8 100644
> --- a/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.c
> +++ b/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.c
> @@ -423,7 +423,8 @@ struct rmnet_endpoint *rmnet_get_endpoint(struct
> rmnet_port *port, u8 mux_id) {
> struct rmnet_endpoint *ep;
>
> - hlist_for_each_entry_rcu(ep, &port->muxed_ep[mux_id], hlnode) {
> + hlist_for_each_entry_rcu(ep, &port->muxed_ep[mux_id], hlnode,
> + lockdep_rtnl_is_held()) {
> if (ep->mux_id == mux_id)
> return ep;
> }
> --
> 2.34.1
Reviewed-by: Subash Abhinov Kasiviswanathan
<subash.a.kasiviswanathan@oss.qualcomm.com>
^ permalink raw reply
* Re: [PATCH net] tun/tap & vhost-net: make qdisc backpressure opt-in via IFF_BACKPRESSURE
From: Simon Schippers @ 2026-07-06 6:46 UTC (permalink / raw)
To: Willem de Bruijn, Jason Wang, David S . Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Michael S . Tsirkin, netdev
Cc: Simon Horman, Jonathan Corbet, Shuah Khan, Andrew Lunn,
Tim Gebauer, Brett Sheffield, linux-doc, linux-kernel
In-Reply-To: <20260704112058.95421-1-simon.schippers@tu-dortmund.de>
On 7/4/26 13:20, Simon Schippers wrote:
> @@ -2893,8 +2899,19 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr)
> /* Make sure persistent devices do not get stuck in
> * xoff state.
> */
> - if (netif_running(tun->dev))
> - netif_tx_wake_all_queues(tun->dev);
> + if (netif_running(tun->dev)) {
> + for (int i = 0; i < tun->numqueues; i++) {
> + struct tun_file *i_tfile;
> +
> + i_tfile = rtnl_dereference(tun->tfiles[i]);
> + spin_lock_bh(&i_tfile->tx_ring.consumer_lock);
> + spin_lock(&i_tfile->tx_ring.producer_lock);
> + netif_wake_subqueue(tun->dev, i_tfile->queue_index);
> + i_tfile->cons_cnt = 0;
> + spin_unlock(&i_tfile->tx_ring.producer_lock);
> + spin_unlock_bh(&i_tfile->tx_ring.consumer_lock);
> + }
> + }
I think Sashiko [1] is right. I forgot to wake the disabled queues.
I will post a v2.
[1] Link: https://sashiko.dev/#/patchset/20260704112058.95421-1-simon.schippers%40tu-dortmund.de
^ permalink raw reply
* Re: [PATCH net] selftests: netfilter: conntrack_resize.sh: fix skip exit code
From: Florian Westphal @ 2026-07-06 6:53 UTC (permalink / raw)
To: Dharmik Parmar; +Cc: netdev
In-Reply-To: <20260705204252.630729-1-dharmikparmar2004@yahoo.com>
Dharmik Parmar <dharmikparmar2004@yahoo.com> wrote:
> When conntrack sysctls are unavailable, the test prints SKIP but exits
> with $KSFT_SKIP. lib.sh defines ksft_skip instead, so the kselftest
> runner did not see a proper skip.
Acked-by: Florian Westphal <fw@strlen.de>
^ permalink raw reply
* [PATCH net] net: airoha: fix HTB class modification offload
From: Wayen Yan @ 2026-07-06 6:18 UTC (permalink / raw)
To: netdev
Cc: lorenzo, horms, pabeni, kuba, edumazet, andrew+netdev,
angelogioacchino.delregno, matthias.bgg, linux-arm-kernel,
linux-mediatek
HTB core does not populate parent_classid for TC_HTB_NODE_MODIFY.
Airoha currently checks parent_classid against TC_HTB_CLASSID_ROOT
in a helper shared by both TC_HTB_LEAF_ALLOC_QUEUE and
TC_HTB_NODE_MODIFY. Since the modify path leaves parent_classid as
zero, the check always fails and changing parameters of an already
offloaded HTB class is rejected with -EINVAL.
Move the root-parent check into the allocation path and validate
modify requests using the per-netdev QoS channel bitmap, consistent
with the delete and query paths.
Fixes: ef1ca9271313 ("net: airoha: Add sched HTB offload support")
Signed-off-by: Wayen Yan <win847@gmail.com>
---
drivers/net/ethernet/airoha/airoha_eth.c | 32 +++++++++++++++++-------
1 file changed, 23 insertions(+), 9 deletions(-)
diff --git a/drivers/net/ethernet/airoha/airoha_eth.c b/drivers/net/ethernet/airoha/airoha_eth.c
index 59001fd4b6f7..8e4e79c1e4c2 100644
--- a/drivers/net/ethernet/airoha/airoha_eth.c
+++ b/drivers/net/ethernet/airoha/airoha_eth.c
@@ -2766,18 +2766,13 @@ static int airoha_qdma_set_tx_rate_limit(struct net_device *netdev,
return 0;
}
-static int airoha_tc_htb_modify_queue(struct net_device *dev,
- struct tc_htb_qopt_offload *opt)
+static int airoha_tc_htb_set_rate(struct net_device *dev,
+ struct tc_htb_qopt_offload *opt,
+ u32 channel)
{
- u32 channel = TC_H_MIN(opt->classid) % AIROHA_NUM_QOS_CHANNELS;
u32 rate = div_u64(opt->rate, 1000) << 3; /* kbps */
int err;
- if (opt->parent_classid != TC_HTB_CLASSID_ROOT) {
- NL_SET_ERR_MSG_MOD(opt->extack, "invalid parent classid");
- return -EINVAL;
- }
-
err = airoha_qdma_set_tx_rate_limit(dev, channel, rate, opt->quantum);
if (err)
NL_SET_ERR_MSG_MOD(opt->extack,
@@ -2786,6 +2781,20 @@ static int airoha_tc_htb_modify_queue(struct net_device *dev,
return err;
}
+static int airoha_tc_htb_modify_queue(struct net_device *netdev,
+ struct tc_htb_qopt_offload *opt)
+{
+ u32 channel = TC_H_MIN(opt->classid) % AIROHA_NUM_QOS_CHANNELS;
+ struct airoha_gdm_dev *dev = netdev_priv(netdev);
+
+ if (!test_bit(channel, dev->qos_sq_bmap)) {
+ NL_SET_ERR_MSG_MOD(opt->extack, "invalid queue id");
+ return -EINVAL;
+ }
+
+ return airoha_tc_htb_set_rate(netdev, opt, channel);
+}
+
static int airoha_tc_htb_alloc_leaf_queue(struct net_device *netdev,
struct tc_htb_qopt_offload *opt)
{
@@ -2794,6 +2803,11 @@ static int airoha_tc_htb_alloc_leaf_queue(struct net_device *netdev,
struct airoha_gdm_dev *dev = netdev_priv(netdev);
struct airoha_qdma *qdma = dev->qdma;
+ if (opt->parent_classid != TC_HTB_CLASSID_ROOT) {
+ NL_SET_ERR_MSG_MOD(opt->extack, "invalid parent classid");
+ return -EINVAL;
+ }
+
/* Here we need to check the requested QDMA channel is not already
* in use by another net_device running on the same QDMA block.
*/
@@ -2803,7 +2817,7 @@ static int airoha_tc_htb_alloc_leaf_queue(struct net_device *netdev,
return -EBUSY;
}
- err = airoha_tc_htb_modify_queue(netdev, opt);
+ err = airoha_tc_htb_set_rate(netdev, opt, channel);
if (err)
goto error;
--
2.51.0
^ permalink raw reply related
* [PATCH v2 net-next] net: neigh: avoid calling neigh_forced_gc on every alloc when table is full
From: Vimal Agrawal @ 2026-07-06 6:58 UTC (permalink / raw)
To: netdev; +Cc: kuba, kuniyu, edumazet, vimal.agrawal, avimalin
In-Reply-To: <20260625084213.4e0b70c4@kernel.org>
Once the neighbour table exceeds gc_thresh3, neigh_forced_gc() is called
on every allocation attempt with no rate limiting. In workloads with mostly
active/reachable entries, the GC walk traverses a large portion of the
neighbour table without reclaiming entries, holding tbl->lock for an
extended period. This causes severe lock contention and allocation
latencies exceeding 16ms under sustained neighbour creation.
Add a pre-lock check in neigh_forced_gc() to skip the GC run if one was
performed within the last 50 ms, avoiding repeated full table scans and
lock acquisitions on the hot allocation path.
Profiling of neigh_create() shows ~3 orders of magnitude latency
improvement with this change.
Link: https://lore.kernel.org/netdev/CALkUMdSCpx_ywYCx_ePLdm6yioO1nQWx7sSM=AEgsq0kywHxTw@mail.gmail.com/
Signed-off-by: Vimal Agrawal <vimal.agrawal@sophos.com>
---
v2: Changed threshold from 1s (HZ) to 50ms (msecs_to_jiffies(50))
based on profiling data showing 44% -> 2.56% CPU reduction
net/core/neighbour.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/net/core/neighbour.c b/net/core/neighbour.c
index 1349c0eedb64..a83535d32da3 100644
--- a/net/core/neighbour.c
+++ b/net/core/neighbour.c
@@ -260,6 +260,9 @@ static int neigh_forced_gc(struct neigh_table *tbl)
int shrunk = 0;
int loop = 0;
+ if (!time_after(jiffies, READ_ONCE(tbl->last_flush) + msecs_to_jiffies(50)))
+ return 0;
+
NEIGH_CACHE_STAT_INC(tbl, forced_gc_runs);
spin_lock_bh(&tbl->lock);
--
2.17.1
^ permalink raw reply related
* RE: [PATCH net-next 11/17] net: dsa: mv88e6xxx: Move available stats into info structure
From: Jagielski, Jedrzej @ 2026-07-06 7:17 UTC (permalink / raw)
To: Luke Howard, Andrew Lunn, Vladimir Oltean, David S. Miller,
Eric Dumazet, Jakub Kicinski, Paolo Abeni, Simon Horman,
Russell King, Richard Cochran, Florian Fainelli
Cc: Cedric Jehasse, Max Holtmann, Max Hunter, Tyrrell, Kieran,
Ryan Wilkins, Mattias Forsblad, netdev@vger.kernel.org,
linux-kernel@vger.kernel.org
In-Reply-To: <20260703-net-next-mv88e6xxx-rmu-v1-11-991a27d78bca@padl.com>
From: Luke Howard <lukeh@padl.com>
Sent: Friday, July 3, 2026 9:47 AM
>From: Andrew Lunn <andrew@lunn.ch>
>
>Different families of switches have different statistics available.
>This information is current hard coded into functions, however this
>information will also soon be needed when getting statistics from the
>RMU. Move it into the info structure.
>
>Signed-off-by: Andrew Lunn <andrew@lunn.ch>
>---
> drivers/net/dsa/mv88e6xxx/chip.c | 12 ++++++++++++
> 1 file changed, 12 insertions(+)
>
>diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c
>index 6431d25f3cfa2..5c0a1e2b0507d 100644
>--- a/drivers/net/dsa/mv88e6xxx/chip.c
>+++ b/drivers/net/dsa/mv88e6xxx/chip.c
>@@ -1303,6 +1303,9 @@ static size_t mv88e6095_stats_get_stat(struct mv88e6xxx_chip *chip, int port,
> const struct mv88e6xxx_hw_stat *stat,
> uint64_t *data)
> {
>+ if (!(stat->type & chip->info->stats_type))
>+ return 0;
>+
Is everything fine with this patch?
There's nothing beside adding checks to some of the functions
(which is reverted in the upcoming patch) what does not
seem to be corresponding to the commit msg
> *data = _mv88e6xxx_get_ethtool_stat(chip, stat, port, 0,
> MV88E6XXX_G1_STATS_OP_HIST_RX);
> return 1;
>@@ -1312,6 +1315,9 @@ static size_t mv88e6250_stats_get_stat(struct mv88e6xxx_chip *chip, int port,
> const struct mv88e6xxx_hw_stat *stat,
> uint64_t *data)
> {
>+ if (!(stat->type & chip->info->stats_type))
>+ return 0;
>+
> *data = _mv88e6xxx_get_ethtool_stat(chip, stat, port, 0,
> MV88E6XXX_G1_STATS_OP_HIST_RX);
> return 1;
>@@ -1321,6 +1327,9 @@ static size_t mv88e6320_stats_get_stat(struct mv88e6xxx_chip *chip, int port,
> const struct mv88e6xxx_hw_stat *stat,
> uint64_t *data)
> {
>+ if (!(stat->type & chip->info->stats_type))
>+ return 0;
>+
> *data = _mv88e6xxx_get_ethtool_stat(chip, stat, port,
> MV88E6XXX_G1_STATS_OP_BANK_1_BIT_9,
> MV88E6XXX_G1_STATS_OP_HIST_RX);
>@@ -1331,6 +1340,9 @@ static size_t mv88e6390_stats_get_stat(struct mv88e6xxx_chip *chip, int port,
> const struct mv88e6xxx_hw_stat *stat,
> uint64_t *data)
> {
>+ if (!(stat->type & chip->info->stats_type))
>+ return 0;
>+
> *data = _mv88e6xxx_get_ethtool_stat(chip, stat, port,
> MV88E6XXX_G1_STATS_OP_BANK_1_BIT_10,
> 0);
>
>--
>2.43.0
^ permalink raw reply
* Re: [PATCH net v2] ppp: defer channel free to an RCU grace period to fix pppol2tp RX UAF
From: Norbert Szetei @ 2026-07-06 7:22 UTC (permalink / raw)
To: Qingfang Deng
Cc: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Sebastian Andrzej Siewior, Breno Leitao, Taegu Ha,
Kees Cook, linux-ppp, linux-kernel, Guillaume Nault, netdev
In-Reply-To: <de2616b3-6edf-4255-ba77-0674e225ab27@linux.dev>
Hi,
> On Jul 3, 2026, at 09:27, Qingfang Deng <qingfang.deng@linux.dev> wrote:
>
> Hi,
>
> On 2026/7/2 2:12, Norbert Szetei wrote:
>> +/* Purge after the grace period: a late ppp_input() may still queue an
>> + * skb on pch->file.rq before the last RCU reader drains.
>> + */
>> +static void ppp_release_channel_free(struct rcu_head *rcu)
>> +{
>> + struct channel *pch = container_of(rcu, struct channel, rcu);
>> +
>> + skb_queue_purge(&pch->file.xq);
>> + skb_queue_purge(&pch->file.rq);
>> + kfree(pch);
>> +}
>> +
>> /*
>> * Drop a reference to a ppp channel and free its memory if the refcount reaches
>> * zero.
>> @@ -3581,9 +3594,7 @@ static void ppp_release_channel(struct channel *pch)
>> pr_err("ppp: destroying undead channel %p !\n", pch);
>> return;
>> }
>> - skb_queue_purge(&pch->file.xq);
>> - skb_queue_purge(&pch->file.rq);
>> - kfree(pch);
>> + call_rcu(&pch->rcu, ppp_release_channel_free);
>> }
>> static void __exit ppp_cleanup(void)
>
> AI-review found an issue: https://sashiko.dev/#/patchset/D9C0245B-608B-4884-8A09-F55BA4A9F948%40doyensec.com
>
> An rcu_barrier() call is needed at the end of ppp_cleanup().
Thanks for reviewing. I'll add it and send out a v3.
N.
>
> Regards,
>
> Qingfang
>
^ permalink raw reply
* Re: [PATCH net-next 1/2] net: sfp: allow prefix matching in quirk lookup
From: Maxime Chevallier @ 2026-07-06 7:28 UTC (permalink / raw)
To: Martino Dell'Ambrogio, netdev
Cc: Russell King, Andrew Lunn, Heiner Kallweit, David S . Miller,
Eric Dumazet, Jakub Kicinski, Paolo Abeni, linux-kernel
In-Reply-To: <20260705185440.136496-2-tillo@tillo.ch>
Hi,
On 7/5/26 20:54, Martino Dell'Ambrogio wrote:
> Some clone SFP modules (notably XGS-PON ONT sticks) ship malformed
> EEPROMs where the vendor PN field is filled with non-printable garbage
> past the trailing legitimate characters instead of SFF-8472 mandated
> space padding.
:(
> The current sfp_match() requires an exact full-field
> length match: sfp_strlen() returns 16 (no trailing spaces or NULs to
> strip), but strlen() of the quirk string is shorter, so the length
> comparison rejects the entry before strncmp() is even called and the
> quirk silently never applies. The kernel then honors the module's
> spurious TX_FAULT signal and the SFP state machine eventually disables
> the module.
>
> Add a prefix_match flag to struct sfp_quirk and a SFP_QUIRK_F_PREFIX
> macro. When set, sfp_match() compares only strlen() leading bytes of
> the quirk string, ignoring trailing field bytes. Existing exact-match
> quirks are unaffected (prefix_match defaults to false via zero-init in
> the existing SFP_QUIRK macros).
>
> Signed-off-by: Martino Dell'Ambrogio <tillo@tillo.ch>
> ---
> drivers/net/phy/sfp.c | 22 +++++++++++++++++-----
> drivers/net/phy/sfp.h | 1 +
> 2 files changed, 18 insertions(+), 5 deletions(-)
>
> diff --git a/drivers/net/phy/sfp.c b/drivers/net/phy/sfp.c
> index f520206..e7ba642 100644
> --- a/drivers/net/phy/sfp.c
> +++ b/drivers/net/phy/sfp.c
> @@ -516,6 +516,13 @@ static void sfp_quirk_ubnt_uf_instant(const struct sfp_eeprom_id *id,
> { .vendor = _v, .part = _p, .support = _s, .fixup = _f, }
> #define SFP_QUIRK_S(_v, _p, _s) SFP_QUIRK(_v, _p, _s, NULL)
> #define SFP_QUIRK_F(_v, _p, _f) SFP_QUIRK(_v, _p, NULL, _f)
> +/* Like SFP_QUIRK_F, but matches as a prefix. Use for clone modules
> + * that fill EEPROM trailing bytes with garbage instead of the
> + * SFF-8472-mandated space padding, so sfp_strlen can't trim the
> + * field down to the legitimate length.
> + */
> +#define SFP_QUIRK_F_PREFIX(_v, _p, _f) \
> + { .vendor = _v, .part = _p, .support = NULL, .fixup = _f, .prefix_match = true }
>
> static const struct sfp_quirk sfp_quirks[] = {
> // Alcatel Lucent G-010S-P can operate at 2500base-X, but incorrectly
> @@ -626,13 +633,16 @@ static size_t sfp_strlen(const char *str, size_t maxlen)
> return size;
> }
>
> -static bool sfp_match(const char *qs, const char *str, size_t len)
> +static bool sfp_match(const char *qs, const char *str, size_t len, bool prefix)
> {
> + size_t qs_len;
> +
> if (!qs)
> return true;
> - if (strlen(qs) != len)
> + qs_len = strlen(qs);
> + if (prefix ? qs_len > len : qs_len != len)
> return false;
> - return !strncmp(qs, str, len);
> + return !strncmp(qs, str, qs_len);
> }
The variable naming qs_len and the "if(<ternary operator>)" aren't very easy
to process. It's correct but could use a few comments to explain that for
prefix match, we only compare up to the PN/Vendor string length.
But there's already a good comment on the macro definition, I'm personally
OK with this.
>
> static const struct sfp_quirk *sfp_lookup_quirk(const struct sfp_eeprom_id *id)
> @@ -645,8 +655,10 @@ static const struct sfp_quirk *sfp_lookup_quirk(const struct sfp_eeprom_id *id)
> ps = sfp_strlen(id->base.vendor_pn, ARRAY_SIZE(id->base.vendor_pn));
>
> for (i = 0, q = sfp_quirks; i < ARRAY_SIZE(sfp_quirks); i++, q++)
> - if (sfp_match(q->vendor, id->base.vendor_name, vs) &&
> - sfp_match(q->part, id->base.vendor_pn, ps))
> + if (sfp_match(q->vendor, id->base.vendor_name, vs,
> + q->prefix_match) &&
> + sfp_match(q->part, id->base.vendor_pn, ps,
> + q->prefix_match))
> return q;
>
> return NULL;
> diff --git a/drivers/net/phy/sfp.h b/drivers/net/phy/sfp.h
> index 879dff7..867e45e 100644
> --- a/drivers/net/phy/sfp.h
> +++ b/drivers/net/phy/sfp.h
> @@ -12,6 +12,7 @@ struct sfp_quirk {
> void (*support)(const struct sfp_eeprom_id *id,
> struct sfp_module_caps *caps);
> void (*fixup)(struct sfp *sfp);
> + bool prefix_match;
> };
>
> struct sfp_socket_ops {
Reviewed-by: Maxime Chevallier <maxime.chevallier@bootlin.com>
Maxime
^ permalink raw reply
* Re: [PATCH net-next 2/2] net: sfp: add quirks for OEM XGSPONST2001 and FS XGS-SFP-ONT-MACI
From: Maxime Chevallier @ 2026-07-06 7:29 UTC (permalink / raw)
To: Martino Dell'Ambrogio, netdev
Cc: Russell King, Andrew Lunn, Heiner Kallweit, David S . Miller,
Eric Dumazet, Jakub Kicinski, Paolo Abeni, linux-kernel
In-Reply-To: <20260705185440.136496-3-tillo@tillo.ch>
Hi
On 7/5/26 20:54, Martino Dell'Ambrogio wrote:
> Cheap XGS-PON ONT sticks identifying as vendor "OEM", PN "XGSPONST2001"
> have broken TX_FAULT and LOS indicators (driven by the ONU serial
> passthrough wires) and need a longer T_START_UP than the SFF-8472
> default. The Fiberstore XGS-SFP-ONT-MACI MAC-mode ONT stick has the
> same ONT-class TX_FAULT/LOS wiring and startup behaviour. Apply the
> existing sfp_fixup_potron handler to both, which masks both signals
> and bumps T_START_UP to T_START_UP_BAD_GPON.
>
> Both modules fail to space-pad the EEPROM vendor PN field past the
> legitimate string as SFF-8472 mandates (the XGSPONST2001 fills it with
> non-printable garbage), which defeats exact-length matching:
> sfp_strlen() cannot trim the field, so a plain SFP_QUIRK_F entry would
> silently never apply and the kernel would honor the spurious TX_FAULT
> and eventually disable the module. Match both entries as prefixes
> using SFP_QUIRK_F_PREFIX.
>
> Signed-off-by: Martino Dell'Ambrogio <tillo@tillo.ch>
Reviewed-by: Maxime Chevallier <maxime.chevallier@bootlin.com>
Maxime
^ permalink raw reply
* Re: [PATCH net v3] net: usb: lan78xx: disable VLAN filter in promiscuous mode
From: Nicolai Buchwitz @ 2026-07-06 7:37 UTC (permalink / raw)
To: enrico.pozzobon
Cc: Thangaraj Samynathan, Rengarajan Sundararajan, UNGLinuxDriver,
Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Woojung.Huh, netdev, linux-usb, linux-kernel
In-Reply-To: <20260701-lan78xx-vlan-promisc-v3-1-232266d32743@dissecto.com>
On 1.7.2026 16:47, Enrico Pozzobon via B4 Relay wrote:
> From: Enrico Pozzobon <enrico.pozzobon@dissecto.com>
>
> The hardware VLAN filter (RFE_CTL_VLAN_FILTER_) drops VLAN-tagged
> frames
> whose VID has not been registered via lan78xx_vlan_rx_add_vid(). It is
> left enabled in promiscuous mode, so packet capture (e.g. tcpdump or
> Wireshark) does not see tagged frames for unregistered VIDs.
>
> Clear the filter while the interface is promiscuous and restore it from
> NETIF_F_HW_VLAN_CTAG_FILTER otherwise. Enforce the same condition in
> lan78xx_set_features() so netdev_update_features() cannot re-enable the
> filter while promiscuous.
>
> Fixes: 55d7de9de6c3 ("Microchip's LAN7800 family USB 2/3 to 10/100/1000
> Ethernet device driver")
> Signed-off-by: Enrico Pozzobon <enrico.pozzobon@dissecto.com>
> ---
> Currently, on microchip lan7801, enabling promiscuous mode does not
> result in VLAN tagged packets being captured. This patch fixes this,
> forcing the RFE_CTL_VLAN_FILTER_ flag to be off when promiscuous mode
> is
> enabled.
> ---
> Changes in v3:
> - EDITME: describe what is new in this series revision.
> - EDITME: use bulletpoints and terse descriptions.
> - Link to v2:
> https://patch.msgid.link/20260701-lan78xx-vlan-promisc-v2-1-fe3b18066728@dissecto.com
>
> Changes in v2:
> - moved VLAN filter logic into lan78xx_update_vlan_filter()
> - Link to v1:
> https://patch.msgid.link/20260630-lan78xx-vlan-promisc-v1-1-fbf0f903bd8f@dissecto.com
>
> To: Thangaraj Samynathan <Thangaraj.S@microchip.com>
> To: Rengarajan Sundararajan <Rengarajan.S@microchip.com>
> To: UNGLinuxDriver@microchip.com
> To: Andrew Lunn <andrew+netdev@lunn.ch>
> To: "David S. Miller" <davem@davemloft.net>
> To: Eric Dumazet <edumazet@google.com>
> To: Jakub Kicinski <kuba@kernel.org>
> To: Paolo Abeni <pabeni@redhat.com>
> To: Woojung.Huh@microchip.com
> Cc: netdev@vger.kernel.org
> Cc: linux-usb@vger.kernel.org
> Cc: linux-kernel@vger.kernel.org
> ---
> drivers/net/usb/lan78xx.c | 18 ++++++++++++++----
> 1 file changed, 14 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/net/usb/lan78xx.c b/drivers/net/usb/lan78xx.c
> index c4cebacabcb5..cb782d81d84f 100644
> --- a/drivers/net/usb/lan78xx.c
> +++ b/drivers/net/usb/lan78xx.c
> @@ -1499,6 +1499,17 @@ static void
> lan78xx_deferred_multicast_write(struct work_struct *param)
> return;
> }
>
> +static void lan78xx_update_vlan_filter(struct lan78xx_priv *pdata,
> + struct net_device *netdev,
> + netdev_features_t features)
> +{
> + if ((features & NETIF_F_HW_VLAN_CTAG_FILTER) &&
> + !(netdev->flags & IFF_PROMISC))
> + pdata->rfe_ctl |= RFE_CTL_VLAN_FILTER_;
> + else
> + pdata->rfe_ctl &= ~RFE_CTL_VLAN_FILTER_;
> +}
> +
> static void lan78xx_set_multicast(struct net_device *netdev)
> {
> struct lan78xx_net *dev = netdev_priv(netdev);
> @@ -1533,6 +1544,8 @@ static void lan78xx_set_multicast(struct
> net_device *netdev)
> }
> }
>
> + lan78xx_update_vlan_filter(pdata, dev->net, dev->net->features);
> +
> if (netdev_mc_count(dev->net)) {
> struct netdev_hw_addr *ha;
> int i;
> @@ -3074,10 +3087,7 @@ static int lan78xx_set_features(struct
> net_device *netdev,
> else
> pdata->rfe_ctl &= ~RFE_CTL_VLAN_STRIP_;
>
> - if (features & NETIF_F_HW_VLAN_CTAG_FILTER)
> - pdata->rfe_ctl |= RFE_CTL_VLAN_FILTER_;
> - else
> - pdata->rfe_ctl &= ~RFE_CTL_VLAN_FILTER_;
> + lan78xx_update_vlan_filter(pdata, netdev, features);
>
> spin_unlock_irqrestore(&pdata->rfe_ctl_lock, flags);
>
>
> ---
> base-commit: dc59e4fea9d83f03bad6bddf3fa2e52491777482
> change-id: 20260623-lan78xx-vlan-promisc-83af8a48a7ec
>
> Best regards,
> --
> Enrico Pozzobon <enrico.pozzobon@dissecto.com>
v2 is marked superseded in patchwork, so FWIW
Reviewed-by: Nicolai Buchwitz <nb@tipi-net.de>
Thanks
Nicolai
^ permalink raw reply
* [PATCH net-next] net: Convert %pK back to %p
From: Sebastian Andrzej Siewior @ 2026-07-06 7:38 UTC (permalink / raw)
To: linux-atm-general, linux-can, linux-sctp, netdev
Cc: David S. Miller, Eric Dumazet, Herbert Xu, Jakub Kicinski,
Kuniyuki Iwashima, Marc Kleine-Budde, Marcelo Ricardo Leitner,
Neal Cardwell, Oliver Hartkopp, Paolo Abeni, Remi Denis-Courmont,
Simon Horman, Steffen Klassert, Willem de Bruijn, Xin Long,
Petr Mladek, Thomas Weißschuh, Kees Cook
This is a revert of commit 71338aa7d050c ("net: convert %p usage to
%pK") which is from 2011. Back then the default behaviour for %p was to
print the pointer. The %pK modifier was introduced to be able to control
the behaviour of specific pointer output without changing the behaviour
of %p for everyone. It was dedicated to avoid leaking pointers via
/proc.
There was also the idea to remove the check from formatting the string
and move to the open callback (of the /proc file) with some helpers but
this did not happen.
Things changed over time. The default behaviour for %p is now to print a
hash pointer which does not leak the address but allows to
correlate if two pointers are equal. The pointer to hash value mapping
is not stable across reboots so one can not precompute the values and
have a lookup table. There is also the `hash_pointers' boot argument
which allows to disable it and print real pointers if needed. The
default behaviour of %pK (kptr_restrict==0) is already %p (hashed
pointer).
The %pK modifier brings hardly and value over %p. Removing it allows to
remove the policy checks from pointer formatting.
Switch back to the %p modifier.
Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
---
My long term goal is remove the restricted_pointer() handling from
vsprintf. I don't see any benefit in having it and case kptr_restrict==1
caused problems in terms of locking. Instead of attempting to get the
debug/ warn infrastructure right I am for removing it.
net/atm/proc.c | 2 +-
net/can/bcm.c | 6 +++---
net/can/proc.c | 4 ++--
net/ipv4/ping.c | 2 +-
net/ipv4/raw.c | 2 +-
net/ipv4/tcp_ipv4.c | 6 +++---
net/ipv4/udp.c | 2 +-
net/ipv6/datagram.c | 2 +-
net/ipv6/tcp_ipv6.c | 6 +++---
net/key/af_key.c | 2 +-
net/netlink/af_netlink.c | 2 +-
net/packet/af_packet.c | 2 +-
net/phonet/socket.c | 2 +-
net/sctp/proc.c | 4 ++--
net/unix/af_unix.c | 2 +-
15 files changed, 23 insertions(+), 23 deletions(-)
diff --git a/net/atm/proc.c b/net/atm/proc.c
index 8f20b49b9c02a..2c39364edf929 100644
--- a/net/atm/proc.c
+++ b/net/atm/proc.c
@@ -159,7 +159,7 @@ static void vcc_info(struct seq_file *seq, struct atm_vcc *vcc)
{
struct sock *sk = sk_atm(vcc);
- seq_printf(seq, "%pK ", vcc);
+ seq_printf(seq, "%p ", vcc);
if (!vcc->dev)
seq_printf(seq, "Unassigned ");
else
diff --git a/net/can/bcm.c b/net/can/bcm.c
index a4bef2c48a559..ce3650932d5cd 100644
--- a/net/can/bcm.c
+++ b/net/can/bcm.c
@@ -213,9 +213,9 @@ static int bcm_proc_show(struct seq_file *m, void *v)
struct bcm_sock *bo = bcm_sk(sk);
struct bcm_op *op;
- seq_printf(m, ">>> socket %pK", sk->sk_socket);
- seq_printf(m, " / sk %pK", sk);
- seq_printf(m, " / bo %pK", bo);
+ seq_printf(m, ">>> socket %p", sk->sk_socket);
+ seq_printf(m, " / sk %p", sk);
+ seq_printf(m, " / bo %p", bo);
seq_printf(m, " / dropped %lu", bo->dropped_usr_msgs);
seq_printf(m, " / bound %s", bcm_proc_getifname(net, ifname, bo->ifindex));
seq_printf(m, " <<<\n");
diff --git a/net/can/proc.c b/net/can/proc.c
index de4d05ae34597..1f2611b0ccfc1 100644
--- a/net/can/proc.c
+++ b/net/can/proc.c
@@ -192,8 +192,8 @@ static void can_print_rcvlist(struct seq_file *m, struct hlist_head *rx_list,
hlist_for_each_entry_rcu(r, rx_list, list) {
char *fmt = (r->can_id & CAN_EFF_FLAG)?
- " %-5s %08x %08x %pK %pK %8ld %s\n" :
- " %-5s %03x %08x %pK %pK %8ld %s\n";
+ " %-5s %08x %08x %p %p %8ld %s\n" :
+ " %-5s %03x %08x %p %p %8ld %s\n";
seq_printf(m, fmt, DNAME(dev), r->can_id, r->mask,
r->func, r->data, atomic_long_read(&r->matches),
diff --git a/net/ipv4/ping.c b/net/ipv4/ping.c
index d36f1e273fde4..d66811d825eba 100644
--- a/net/ipv4/ping.c
+++ b/net/ipv4/ping.c
@@ -1095,7 +1095,7 @@ static void ping_v4_format_sock(struct sock *sp, struct seq_file *f,
__u16 srcp = ntohs(inet->inet_sport);
seq_printf(f, "%5d: %08X:%04X %08X:%04X"
- " %02X %08X:%08X %02X:%08lX %08X %5u %8d %llu %d %pK %u",
+ " %02X %08X:%08X %02X:%08lX %08X %5u %8d %llu %d %p %u",
bucket, src, srcp, dest, destp, sp->sk_state,
sk_wmem_alloc_get(sp),
sk_rmem_alloc_get(sp),
diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c
index 2aebaf8297e04..c7ef95f8eb2c6 100644
--- a/net/ipv4/raw.c
+++ b/net/ipv4/raw.c
@@ -1045,7 +1045,7 @@ static void raw_sock_seq_show(struct seq_file *seq, struct sock *sp, int i)
srcp = inet->inet_num;
seq_printf(seq, "%4d: %08X:%04X %08X:%04X"
- " %02X %08X:%08X %02X:%08lX %08X %5u %8d %llu %d %pK %u\n",
+ " %02X %08X:%08X %02X:%08lX %08X %5u %8d %llu %d %p %u\n",
i, src, srcp, dest, destp, sp->sk_state,
sk_wmem_alloc_get(sp),
sk_rmem_alloc_get(sp),
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
index 209ef7522508f..aa31af06e5e3b 100644
--- a/net/ipv4/tcp_ipv4.c
+++ b/net/ipv4/tcp_ipv4.c
@@ -2743,7 +2743,7 @@ static void get_openreq4(const struct request_sock *req,
long delta = req->rsk_timer.expires - jiffies;
seq_printf(f, "%4d: %08X:%04X %08X:%04X"
- " %02X %08X:%08X %02X:%08lX %08X %5u %8d %u %d %pK",
+ " %02X %08X:%08X %02X:%08lX %08X %5u %8d %u %d %p",
i,
ireq->ir_loc_addr,
ireq->ir_num,
@@ -2806,7 +2806,7 @@ static void get_tcp4_sock(struct sock *sk, struct seq_file *f, int i)
READ_ONCE(tp->copied_seq), 0);
seq_printf(f, "%4d: %08X:%04X %08X:%04X %02X %08X:%08X %02X:%08lX "
- "%08X %5u %8d %llu %d %pK %lu %lu %u %u %d",
+ "%08X %5u %8d %llu %d %p %lu %lu %u %u %d",
i, src, srcp, dest, destp, state,
READ_ONCE(tp->write_seq) - tp->snd_una,
rx_queue,
@@ -2839,7 +2839,7 @@ static void get_timewait4_sock(const struct inet_timewait_sock *tw,
srcp = ntohs(tw->tw_sport);
seq_printf(f, "%4d: %08X:%04X %08X:%04X"
- " %02X %08X:%08X %02X:%08lX %08X %5d %8d %d %d %pK",
+ " %02X %08X:%08X %02X:%08lX %08X %5d %8d %d %d %p",
i, src, srcp, dest, destp, READ_ONCE(tw->tw_substate), 0, 0,
3, jiffies_delta_to_clock_t(delta), 0, 0, 0, 0,
refcount_read(&tw->tw_refcnt), tw);
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c
index 59248a59358ca..db3c90f9a56de 100644
--- a/net/ipv4/udp.c
+++ b/net/ipv4/udp.c
@@ -3280,7 +3280,7 @@ static void udp4_format_sock(struct sock *sp, struct seq_file *f,
__u16 srcp = ntohs(inet->inet_sport);
seq_printf(f, "%5d: %08X:%04X %08X:%04X"
- " %02X %08X:%08X %02X:%08lX %08X %5u %8d %llu %d %pK %u",
+ " %02X %08X:%08X %02X:%08lX %08X %5u %8d %llu %d %p %u",
bucket, src, srcp, dest, destp, sp->sk_state,
sk_wmem_alloc_get(sp),
udp_rqueue_get(sp),
diff --git a/net/ipv6/datagram.c b/net/ipv6/datagram.c
index 38d7b48452817..7cfacc06a331c 100644
--- a/net/ipv6/datagram.c
+++ b/net/ipv6/datagram.c
@@ -1102,7 +1102,7 @@ void __ip6_dgram_sock_seq_show(struct seq_file *seq, struct sock *sp,
src = &sp->sk_v6_rcv_saddr;
seq_printf(seq,
"%5d: %08X%08X%08X%08X:%04X %08X%08X%08X%08X:%04X "
- "%02X %08X:%08X %02X:%08lX %08X %5u %8d %llu %d %pK %u\n",
+ "%02X %08X:%08X %02X:%08lX %08X %5u %8d %llu %d %p %u\n",
bucket,
src->s6_addr32[0], src->s6_addr32[1],
src->s6_addr32[2], src->s6_addr32[3], srcp,
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c
index ebe161d72fbd0..e370b47171ce8 100644
--- a/net/ipv6/tcp_ipv6.c
+++ b/net/ipv6/tcp_ipv6.c
@@ -2099,7 +2099,7 @@ static void get_openreq6(struct seq_file *seq,
seq_printf(seq,
"%4d: %08X%08X%08X%08X:%04X %08X%08X%08X%08X:%04X "
- "%02X %08X:%08X %02X:%08lX %08X %5u %8d %d %d %pK\n",
+ "%02X %08X:%08X %02X:%08lX %08X %5u %8d %d %d %p\n",
i,
src->s6_addr32[0], src->s6_addr32[1],
src->s6_addr32[2], src->s6_addr32[3],
@@ -2167,7 +2167,7 @@ static void get_tcp6_sock(struct seq_file *seq, struct sock *sp, int i)
seq_printf(seq,
"%4d: %08X%08X%08X%08X:%04X %08X%08X%08X%08X:%04X "
- "%02X %08X:%08X %02X:%08lX %08X %5u %8d %llu %d %pK %lu %lu %u %u %d\n",
+ "%02X %08X:%08X %02X:%08lX %08X %5u %8d %llu %d %p %lu %lu %u %u %d\n",
i,
src->s6_addr32[0], src->s6_addr32[1],
src->s6_addr32[2], src->s6_addr32[3], srcp,
@@ -2207,7 +2207,7 @@ static void get_timewait6_sock(struct seq_file *seq,
seq_printf(seq,
"%4d: %08X%08X%08X%08X:%04X %08X%08X%08X%08X:%04X "
- "%02X %08X:%08X %02X:%08lX %08X %5d %8d %d %d %pK\n",
+ "%02X %08X:%08X %02X:%08lX %08X %5d %8d %d %d %p\n",
i,
src->s6_addr32[0], src->s6_addr32[1],
src->s6_addr32[2], src->s6_addr32[3], srcp,
diff --git a/net/key/af_key.c b/net/key/af_key.c
index 1d8965d7f4f3c..4df706789280f 100644
--- a/net/key/af_key.c
+++ b/net/key/af_key.c
@@ -3805,7 +3805,7 @@ static int pfkey_seq_show(struct seq_file *f, void *v)
if (v == SEQ_START_TOKEN)
seq_printf(f ,"sk RefCnt Rmem Wmem User Inode\n");
else
- seq_printf(f, "%pK %-6d %-6u %-6u %-6u %-6llu\n",
+ seq_printf(f, "%p %-6d %-6u %-6u %-6u %-6llu\n",
s,
refcount_read(&s->sk_refcnt),
sk_rmem_alloc_get(s),
diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c
index 5202fe0b08671..48a1996f897b9 100644
--- a/net/netlink/af_netlink.c
+++ b/net/netlink/af_netlink.c
@@ -2706,7 +2706,7 @@ static int netlink_native_seq_show(struct seq_file *seq, void *v)
struct sock *s = v;
struct netlink_sock *nlk = nlk_sk(s);
- seq_printf(seq, "%pK %-3d %-10u %08x %-8d %-8d %-5d %-8d %-8u %-8llu\n",
+ seq_printf(seq, "%p %-3d %-10u %08x %-8d %-8d %-5d %-8d %-8u %-8llu\n",
s,
s->sk_protocol,
nlk->portid,
diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c
index 8e6f3a734ba0b..fd22ff5677ebc 100644
--- a/net/packet/af_packet.c
+++ b/net/packet/af_packet.c
@@ -4726,7 +4726,7 @@ static int packet_seq_show(struct seq_file *seq, void *v)
const struct packet_sock *po = pkt_sk(s);
seq_printf(seq,
- "%pK %-6d %-4d %04x %-5d %1d %-6u %-6u %-6llu\n",
+ "%p %-6d %-4d %04x %-5d %1d %-6u %-6u %-6llu\n",
s,
refcount_read(&s->sk_refcnt),
s->sk_type,
diff --git a/net/phonet/socket.c b/net/phonet/socket.c
index 631a99cdbd006..eefdb788be592 100644
--- a/net/phonet/socket.c
+++ b/net/phonet/socket.c
@@ -586,7 +586,7 @@ static int pn_sock_seq_show(struct seq_file *seq, void *v)
struct pn_sock *pn = pn_sk(sk);
seq_printf(seq, "%2d %04X:%04X:%02X %02X %08X:%08X %5d %llu "
- "%d %pK %u",
+ "%d %p %u",
sk->sk_protocol, pn->sobject, pn->dobject,
pn->resource, sk->sk_state,
sk_wmem_alloc_get(sk), sk_rmem_alloc_get(sk),
diff --git a/net/sctp/proc.c b/net/sctp/proc.c
index 43433d7e2acd7..cd99d634fa6d6 100644
--- a/net/sctp/proc.c
+++ b/net/sctp/proc.c
@@ -174,7 +174,7 @@ static int sctp_eps_seq_show(struct seq_file *seq, void *v)
sk = ep->base.sk;
if (!net_eq(sock_net(sk), seq_file_net(seq)))
continue;
- seq_printf(seq, "%8pK %8pK %-3d %-3d %-4d %-5d %5u %5llu ", ep, sk,
+ seq_printf(seq, "%8p %8p %-3d %-3d %-4d %-5d %5u %5llu ", ep, sk,
sctp_sk(sk)->type, sk->sk_state, hash,
ep->base.bind_addr.port,
from_kuid_munged(seq_user_ns(seq), sk_uid(sk)),
@@ -260,7 +260,7 @@ static int sctp_assocs_seq_show(struct seq_file *seq, void *v)
sk = epb->sk;
seq_printf(seq,
- "%8pK %8pK %-3d %-3d %-2d %-4d "
+ "%8p %8p %-3d %-3d %-2d %-4d "
"%4d %8d %8d %7u %5llu %-5d %5d ",
assoc, sk, sctp_sk(sk)->type, sk->sk_state,
assoc->state, 0,
diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
index f7a9d55eee8a1..6a8174977c87a 100644
--- a/net/unix/af_unix.c
+++ b/net/unix/af_unix.c
@@ -3554,7 +3554,7 @@ static int unix_seq_show(struct seq_file *seq, void *v)
struct unix_sock *u = unix_sk(s);
unix_state_lock(s);
- seq_printf(seq, "%pK: %08X %08X %08X %04X %02X %5llu",
+ seq_printf(seq, "%p: %08X %08X %08X %04X %02X %5llu",
s,
refcount_read(&s->sk_refcnt),
0,
--
2.53.0
^ permalink raw reply related
* Re: [PATCH net] net: airoha: fix HTB class modification offload
From: Lorenzo Bianconi @ 2026-07-06 8:02 UTC (permalink / raw)
To: Wayen Yan
Cc: netdev, horms, pabeni, kuba, edumazet, andrew+netdev,
angelogioacchino.delregno, matthias.bgg, linux-arm-kernel,
linux-mediatek
In-Reply-To: <178332096675.2250671.599544331813347302@gmail.com>
[-- Attachment #1: Type: text/plain, Size: 3418 bytes --]
> HTB core does not populate parent_classid for TC_HTB_NODE_MODIFY.
> Airoha currently checks parent_classid against TC_HTB_CLASSID_ROOT
> in a helper shared by both TC_HTB_LEAF_ALLOC_QUEUE and
> TC_HTB_NODE_MODIFY. Since the modify path leaves parent_classid as
> zero, the check always fails and changing parameters of an already
> offloaded HTB class is rejected with -EINVAL.
>
> Move the root-parent check into the allocation path and validate
> modify requests using the per-netdev QoS channel bitmap, consistent
> with the delete and query paths.
>
> Fixes: ef1ca9271313 ("net: airoha: Add sched HTB offload support")
> Signed-off-by: Wayen Yan <win847@gmail.com>
Acked-by: Lorenzo Bianconi <lorenzo@kernel.org>
> ---
> drivers/net/ethernet/airoha/airoha_eth.c | 32 +++++++++++++++++-------
> 1 file changed, 23 insertions(+), 9 deletions(-)
>
> diff --git a/drivers/net/ethernet/airoha/airoha_eth.c b/drivers/net/ethernet/airoha/airoha_eth.c
> index 59001fd4b6f7..8e4e79c1e4c2 100644
> --- a/drivers/net/ethernet/airoha/airoha_eth.c
> +++ b/drivers/net/ethernet/airoha/airoha_eth.c
> @@ -2766,18 +2766,13 @@ static int airoha_qdma_set_tx_rate_limit(struct net_device *netdev,
> return 0;
> }
>
> -static int airoha_tc_htb_modify_queue(struct net_device *dev,
> - struct tc_htb_qopt_offload *opt)
> +static int airoha_tc_htb_set_rate(struct net_device *dev,
> + struct tc_htb_qopt_offload *opt,
> + u32 channel)
> {
> - u32 channel = TC_H_MIN(opt->classid) % AIROHA_NUM_QOS_CHANNELS;
> u32 rate = div_u64(opt->rate, 1000) << 3; /* kbps */
> int err;
>
> - if (opt->parent_classid != TC_HTB_CLASSID_ROOT) {
> - NL_SET_ERR_MSG_MOD(opt->extack, "invalid parent classid");
> - return -EINVAL;
> - }
> -
> err = airoha_qdma_set_tx_rate_limit(dev, channel, rate, opt->quantum);
> if (err)
> NL_SET_ERR_MSG_MOD(opt->extack,
> @@ -2786,6 +2781,20 @@ static int airoha_tc_htb_modify_queue(struct net_device *dev,
> return err;
> }
>
> +static int airoha_tc_htb_modify_queue(struct net_device *netdev,
> + struct tc_htb_qopt_offload *opt)
> +{
> + u32 channel = TC_H_MIN(opt->classid) % AIROHA_NUM_QOS_CHANNELS;
> + struct airoha_gdm_dev *dev = netdev_priv(netdev);
> +
> + if (!test_bit(channel, dev->qos_sq_bmap)) {
> + NL_SET_ERR_MSG_MOD(opt->extack, "invalid queue id");
> + return -EINVAL;
> + }
> +
> + return airoha_tc_htb_set_rate(netdev, opt, channel);
> +}
> +
> static int airoha_tc_htb_alloc_leaf_queue(struct net_device *netdev,
> struct tc_htb_qopt_offload *opt)
> {
> @@ -2794,6 +2803,11 @@ static int airoha_tc_htb_alloc_leaf_queue(struct net_device *netdev,
> struct airoha_gdm_dev *dev = netdev_priv(netdev);
> struct airoha_qdma *qdma = dev->qdma;
>
> + if (opt->parent_classid != TC_HTB_CLASSID_ROOT) {
> + NL_SET_ERR_MSG_MOD(opt->extack, "invalid parent classid");
> + return -EINVAL;
> + }
> +
> /* Here we need to check the requested QDMA channel is not already
> * in use by another net_device running on the same QDMA block.
> */
> @@ -2803,7 +2817,7 @@ static int airoha_tc_htb_alloc_leaf_queue(struct net_device *netdev,
> return -EBUSY;
> }
>
> - err = airoha_tc_htb_modify_queue(netdev, opt);
> + err = airoha_tc_htb_set_rate(netdev, opt, channel);
> if (err)
> goto error;
>
> --
> 2.51.0
>
>
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]
^ permalink raw reply
* Re: [PATCH v4 2/5] drm/ras: Introduce error threshold
From: Raag Jadav @ 2026-07-06 8:03 UTC (permalink / raw)
To: intel-xe, dri-devel, netdev
Cc: simona.vetter, airlied, kuba, lijo.lazar, Hawking.Zhang, davem,
pabeni, edumazet, dev, zachary.mckevitt, rodrigo.vivi,
riana.tauro, michal.wajdeczko, matthew.d.roper, mallesh.koujalagi
In-Reply-To: <20260623101043.255897-3-raag.jadav@intel.com>
Hi Jakub,
On Tue, Jun 23, 2026 at 03:39:56PM +0530, Raag Jadav wrote:
> Add get-error-threshold and set-error-threshold command support which
> allows querying/setting error threshold of the counter. Threshold in RAS
> context means the number of errors the hardware is expected to accumulate
> before it raises them to software. This is to have a fine grained control
> over error notifications that are raised by the hardware.
Anything I can do to move this forward?
> Signed-off-by: Raag Jadav <raag.jadav@intel.com>
> ---
> v2: Document threshold definition (Riana)
> Return -EOPNOTSUPP on threshold callbacks absence (Riana)
> Cancel and free genlmsg on failure (Riana)
> Document threshold bounds checking responsibility (Riana)
> v3: Move documentation from yaml to rst file (Riana)
> s/value/threshold (Riana)
> Use goto for error handling (Riana)
> v4: Clarify 0 threshold expectations (Riana)
> Drop redundant wrapping (Riana)
> ---
> Documentation/gpu/drm-ras.rst | 18 +++
> Documentation/netlink/specs/drm_ras.yaml | 32 +++++
> drivers/gpu/drm/drm_ras.c | 161 +++++++++++++++++++++++
> drivers/gpu/drm/drm_ras_nl.c | 27 ++++
> drivers/gpu/drm/drm_ras_nl.h | 4 +
> include/drm/drm_ras.h | 28 ++++
> include/uapi/drm/drm_ras.h | 3 +
> 7 files changed, 273 insertions(+)
>
> diff --git a/Documentation/gpu/drm-ras.rst b/Documentation/gpu/drm-ras.rst
> index 83c21853b74b..2718f8aee09d 100644
> --- a/Documentation/gpu/drm-ras.rst
> +++ b/Documentation/gpu/drm-ras.rst
> @@ -56,6 +56,10 @@ User space tools can:
> ``node-id`` and ``error-id`` as parameters.
> * Clear specific error counters with the ``clear-error-counter`` command, using both
> ``node-id`` and ``error-id`` as parameters.
> +* Query specific error counter threshold with the ``get-error-threshold`` command, using both
> + ``node-id`` and ``error-id`` as parameters.
> +* Set specific error counter threshold with the ``set-error-threshold`` command, using
> + ``node-id``, ``error-id`` and ``error-threshold`` as parameters.
>
> YAML-based Interface
> --------------------
> @@ -111,3 +115,17 @@ Example: Clear an error counter for a given node
>
> sudo ynl --family drm_ras --do clear-error-counter --json '{"node-id":0, "error-id":1}'
> None
> +
> +Example: Query error threshold of a given counter
> +
> +.. code-block:: bash
> +
> + sudo ynl --family drm_ras --do get-error-threshold --json '{"node-id":0, "error-id":1}'
> + {'error-id': 1, 'error-name': 'error_name1', 'error-threshold': 16}
> +
> +Example: Set error threshold of a given counter
> +
> +.. code-block:: bash
> +
> + sudo ynl --family drm_ras --do set-error-threshold --json '{"node-id":0, "error-id":1, "error-threshold":8}'
> + None
> diff --git a/Documentation/netlink/specs/drm_ras.yaml b/Documentation/netlink/specs/drm_ras.yaml
> index e113056f8c01..9cf7f9cde242 100644
> --- a/Documentation/netlink/specs/drm_ras.yaml
> +++ b/Documentation/netlink/specs/drm_ras.yaml
> @@ -69,6 +69,10 @@ attribute-sets:
> name: error-value
> type: u32
> doc: Current value of the requested error counter.
> + -
> + name: error-threshold
> + type: u32
> + doc: Error threshold of the counter.
>
> operations:
> list:
> @@ -124,3 +128,31 @@ operations:
> do:
> request:
> attributes: *id-attrs
> + -
> + name: get-error-threshold
> + doc: >-
> + Retrieve error threshold of a given counter.
> + The response includes the id, the name, and current threshold
> + of the counter.
> + attribute-set: error-counter-attrs
> + flags: [admin-perm]
> + do:
> + request:
> + attributes: *id-attrs
> + reply:
> + attributes:
> + - error-id
> + - error-name
> + - error-threshold
> + -
> + name: set-error-threshold
> + doc: >-
> + Set error threshold of a given counter.
> + attribute-set: error-counter-attrs
> + flags: [admin-perm]
> + do:
> + request:
> + attributes:
> + - node-id
> + - error-id
> + - error-threshold
> diff --git a/drivers/gpu/drm/drm_ras.c b/drivers/gpu/drm/drm_ras.c
> index 467a169026fc..d60c40ac5427 100644
> --- a/drivers/gpu/drm/drm_ras.c
> +++ b/drivers/gpu/drm/drm_ras.c
> @@ -41,6 +41,13 @@
> * Userspace must provide Node ID, Error ID.
> * Clears specific error counter of a node if supported.
> *
> + * 4. GET_ERROR_THRESHOLD: Query error threshold of a given counter.
> + * Userspace must provide Node ID and Error ID.
> + * Returns the error threshold of a specific counter.
> + *
> + * 5. SET_ERROR_THRESHOLD: Set error threshold of a given counter.
> + * Userspace must provide Node ID, Error ID and threshold to be set.
> + *
> * Node registration:
> *
> * - drm_ras_node_register(): Registers a new node and assigns
> @@ -61,6 +68,16 @@
> * + The error counters in the driver doesn't need to be contiguous, but the
> * driver must return -ENOENT to the query_error_counter as an indication
> * that the ID should be skipped and not listed in the netlink API.
> + * + The driver can optionally implement query_error_threshold() and
> + * set_error_threshold() callbacks to facilitate getting/setting error
> + * threshold of the counter. Threshold in RAS context means the number of
> + * errors the hardware is expected to accumulate before it raises them to
> + * software. This is to have a fine grained control over error notifications
> + * that are raised by the hardware.
> + * + The driver is responsible for error threshold bounds checking.
> + * + Threshold of 0 can mean invalid threshold or act as a disable notifications
> + * toggle for that counter depending on usecase and the driver is responsible
> + * for handling it as needed.
> *
> * Netlink handlers:
> *
> @@ -72,6 +89,10 @@
> * operation, fetching a counter value from a specific node.
> * - drm_ras_nl_clear_error_counter_doit(): Implements the CLEAR_ERROR_COUNTER doit
> * operation, clearing a counter value from a specific node.
> + * - drm_ras_nl_get_error_threshold_doit(): Implements the GET_ERROR_THRESHOLD doit
> + * operation, fetching the error threshold of a specific counter.
> + * - drm_ras_nl_set_error_threshold_doit(): Implements the SET_ERROR_THRESHOLD doit
> + * operation, setting the error threshold of a specific counter.
> */
>
> static DEFINE_XARRAY_ALLOC(drm_ras_xa);
> @@ -168,6 +189,40 @@ static int get_node_error_counter(u32 node_id, u32 error_id,
> return node->query_error_counter(node, error_id, name, value);
> }
>
> +static int get_node_error_threshold(u32 node_id, u32 error_id, const char **name, u32 *threshold)
> +{
> + struct drm_ras_node *node;
> +
> + node = xa_load(&drm_ras_xa, node_id);
> + if (!node)
> + return -ENOENT;
> +
> + if (!node->query_error_threshold)
> + return -EOPNOTSUPP;
> +
> + if (error_id < node->error_counter_range.first || error_id > node->error_counter_range.last)
> + return -EINVAL;
> +
> + return node->query_error_threshold(node, error_id, name, threshold);
> +}
> +
> +static int set_node_error_threshold(u32 node_id, u32 error_id, u32 threshold)
> +{
> + struct drm_ras_node *node;
> +
> + node = xa_load(&drm_ras_xa, node_id);
> + if (!node)
> + return -ENOENT;
> +
> + if (!node->set_error_threshold)
> + return -EOPNOTSUPP;
> +
> + if (error_id < node->error_counter_range.first || error_id > node->error_counter_range.last)
> + return -EINVAL;
> +
> + return node->set_error_threshold(node, error_id, threshold);
> +}
> +
> static int msg_reply_value(struct sk_buff *msg, u32 error_id,
> const char *error_name, u32 value)
> {
> @@ -186,6 +241,22 @@ static int msg_reply_value(struct sk_buff *msg, u32 error_id,
> value);
> }
>
> +static int msg_reply_threshold(struct sk_buff *msg, u32 error_id, const char *error_name,
> + u32 threshold)
> +{
> + int ret;
> +
> + ret = nla_put_u32(msg, DRM_RAS_A_ERROR_COUNTER_ATTRS_ERROR_ID, error_id);
> + if (ret)
> + return ret;
> +
> + ret = nla_put_string(msg, DRM_RAS_A_ERROR_COUNTER_ATTRS_ERROR_NAME, error_name);
> + if (ret)
> + return ret;
> +
> + return nla_put_u32(msg, DRM_RAS_A_ERROR_COUNTER_ATTRS_ERROR_THRESHOLD, threshold);
> +}
> +
> static int doit_reply_value(struct genl_info *info, u32 node_id,
> u32 error_id)
> {
> @@ -225,6 +296,43 @@ static int doit_reply_value(struct genl_info *info, u32 node_id,
> return ret;
> }
>
> +static int doit_reply_threshold(struct genl_info *info, u32 node_id, u32 error_id)
> +{
> + const char *error_name;
> + struct sk_buff *msg;
> + struct nlattr *hdr;
> + u32 threshold;
> + int ret;
> +
> + msg = genlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
> + if (!msg)
> + return -ENOMEM;
> +
> + hdr = genlmsg_iput(msg, info);
> + if (!hdr) {
> + ret = -EMSGSIZE;
> + goto free_msg;
> + }
> +
> + ret = get_node_error_threshold(node_id, error_id, &error_name, &threshold);
> + if (ret)
> + goto cancel_msg;
> +
> + ret = msg_reply_threshold(msg, error_id, error_name, threshold);
> + if (ret)
> + goto cancel_msg;
> +
> + genlmsg_end(msg, hdr);
> +
> + return genlmsg_reply(msg, info);
> +
> +cancel_msg:
> + genlmsg_cancel(msg, hdr);
> +free_msg:
> + nlmsg_free(msg);
> + return ret;
> +}
> +
> /**
> * drm_ras_nl_get_error_counter_dumpit() - Dump all Error Counters
> * @skb: Netlink message buffer
> @@ -358,6 +466,59 @@ int drm_ras_nl_clear_error_counter_doit(struct sk_buff *skb,
> return node->clear_error_counter(node, error_id);
> }
>
> +/**
> + * drm_ras_nl_get_error_threshold_doit() - Query error threshold of a counter
> + * @skb: Netlink message buffer
> + * @info: Generic Netlink info containing attributes of the request
> + *
> + * Extracts the Node ID and Error ID from the netlink attributes and retrieves
> + * the error threshold of the corresponding counter. Sends the result back to
> + * the requesting user via the standard Genl reply.
> + *
> + * Return: 0 on success, or negative errno on failure.
> + */
> +int drm_ras_nl_get_error_threshold_doit(struct sk_buff *skb, struct genl_info *info)
> +{
> + u32 node_id, error_id;
> +
> + if (!info->attrs ||
> + GENL_REQ_ATTR_CHECK(info, DRM_RAS_A_ERROR_COUNTER_ATTRS_NODE_ID) ||
> + GENL_REQ_ATTR_CHECK(info, DRM_RAS_A_ERROR_COUNTER_ATTRS_ERROR_ID))
> + return -EINVAL;
> +
> + node_id = nla_get_u32(info->attrs[DRM_RAS_A_ERROR_COUNTER_ATTRS_NODE_ID]);
> + error_id = nla_get_u32(info->attrs[DRM_RAS_A_ERROR_COUNTER_ATTRS_ERROR_ID]);
> +
> + return doit_reply_threshold(info, node_id, error_id);
> +}
> +
> +/**
> + * drm_ras_nl_set_error_threshold_doit() - Set error threshold of a counter
> + * @skb: Netlink message buffer
> + * @info: Generic Netlink info containing attributes of the request
> + *
> + * Extracts the Node ID, Error ID and threshold from the netlink attributes and
> + * sets the error threshold of the corresponding counter.
> + *
> + * Return: 0 on success, or negative errno on failure.
> + */
> +int drm_ras_nl_set_error_threshold_doit(struct sk_buff *skb, struct genl_info *info)
> +{
> + u32 node_id, error_id, threshold;
> +
> + if (!info->attrs ||
> + GENL_REQ_ATTR_CHECK(info, DRM_RAS_A_ERROR_COUNTER_ATTRS_NODE_ID) ||
> + GENL_REQ_ATTR_CHECK(info, DRM_RAS_A_ERROR_COUNTER_ATTRS_ERROR_ID) ||
> + GENL_REQ_ATTR_CHECK(info, DRM_RAS_A_ERROR_COUNTER_ATTRS_ERROR_THRESHOLD))
> + return -EINVAL;
> +
> + node_id = nla_get_u32(info->attrs[DRM_RAS_A_ERROR_COUNTER_ATTRS_NODE_ID]);
> + error_id = nla_get_u32(info->attrs[DRM_RAS_A_ERROR_COUNTER_ATTRS_ERROR_ID]);
> + threshold = nla_get_u32(info->attrs[DRM_RAS_A_ERROR_COUNTER_ATTRS_ERROR_THRESHOLD]);
> +
> + return set_node_error_threshold(node_id, error_id, threshold);
> +}
> +
> /**
> * drm_ras_node_register() - Register a new RAS node
> * @node: Node structure to register
> diff --git a/drivers/gpu/drm/drm_ras_nl.c b/drivers/gpu/drm/drm_ras_nl.c
> index dea1c1b2494e..02e8e5054d05 100644
> --- a/drivers/gpu/drm/drm_ras_nl.c
> +++ b/drivers/gpu/drm/drm_ras_nl.c
> @@ -28,6 +28,19 @@ static const struct nla_policy drm_ras_clear_error_counter_nl_policy[DRM_RAS_A_E
> [DRM_RAS_A_ERROR_COUNTER_ATTRS_ERROR_ID] = { .type = NLA_U32, },
> };
>
> +/* DRM_RAS_CMD_GET_ERROR_THRESHOLD - do */
> +static const struct nla_policy drm_ras_get_error_threshold_nl_policy[DRM_RAS_A_ERROR_COUNTER_ATTRS_ERROR_ID + 1] = {
> + [DRM_RAS_A_ERROR_COUNTER_ATTRS_NODE_ID] = { .type = NLA_U32, },
> + [DRM_RAS_A_ERROR_COUNTER_ATTRS_ERROR_ID] = { .type = NLA_U32, },
> +};
> +
> +/* DRM_RAS_CMD_SET_ERROR_THRESHOLD - do */
> +static const struct nla_policy drm_ras_set_error_threshold_nl_policy[DRM_RAS_A_ERROR_COUNTER_ATTRS_ERROR_THRESHOLD + 1] = {
> + [DRM_RAS_A_ERROR_COUNTER_ATTRS_NODE_ID] = { .type = NLA_U32, },
> + [DRM_RAS_A_ERROR_COUNTER_ATTRS_ERROR_ID] = { .type = NLA_U32, },
> + [DRM_RAS_A_ERROR_COUNTER_ATTRS_ERROR_THRESHOLD] = { .type = NLA_U32, },
> +};
> +
> /* Ops table for drm_ras */
> static const struct genl_split_ops drm_ras_nl_ops[] = {
> {
> @@ -56,6 +69,20 @@ static const struct genl_split_ops drm_ras_nl_ops[] = {
> .maxattr = DRM_RAS_A_ERROR_COUNTER_ATTRS_ERROR_ID,
> .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO,
> },
> + {
> + .cmd = DRM_RAS_CMD_GET_ERROR_THRESHOLD,
> + .doit = drm_ras_nl_get_error_threshold_doit,
> + .policy = drm_ras_get_error_threshold_nl_policy,
> + .maxattr = DRM_RAS_A_ERROR_COUNTER_ATTRS_ERROR_ID,
> + .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO,
> + },
> + {
> + .cmd = DRM_RAS_CMD_SET_ERROR_THRESHOLD,
> + .doit = drm_ras_nl_set_error_threshold_doit,
> + .policy = drm_ras_set_error_threshold_nl_policy,
> + .maxattr = DRM_RAS_A_ERROR_COUNTER_ATTRS_ERROR_THRESHOLD,
> + .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO,
> + },
> };
>
> struct genl_family drm_ras_nl_family __ro_after_init = {
> diff --git a/drivers/gpu/drm/drm_ras_nl.h b/drivers/gpu/drm/drm_ras_nl.h
> index a398643572a5..57b1e647d833 100644
> --- a/drivers/gpu/drm/drm_ras_nl.h
> +++ b/drivers/gpu/drm/drm_ras_nl.h
> @@ -20,6 +20,10 @@ int drm_ras_nl_get_error_counter_dumpit(struct sk_buff *skb,
> struct netlink_callback *cb);
> int drm_ras_nl_clear_error_counter_doit(struct sk_buff *skb,
> struct genl_info *info);
> +int drm_ras_nl_get_error_threshold_doit(struct sk_buff *skb,
> + struct genl_info *info);
> +int drm_ras_nl_set_error_threshold_doit(struct sk_buff *skb,
> + struct genl_info *info);
>
> extern struct genl_family drm_ras_nl_family;
>
> diff --git a/include/drm/drm_ras.h b/include/drm/drm_ras.h
> index f2a787bc4f64..683a3844f84f 100644
> --- a/include/drm/drm_ras.h
> +++ b/include/drm/drm_ras.h
> @@ -69,6 +69,34 @@ struct drm_ras_node {
> */
> int (*clear_error_counter)(struct drm_ras_node *node, u32 error_id);
>
> + /**
> + * @query_error_threshold:
> + *
> + * This callback is used by drm-ras to query error threshold of a
> + * specific counter.
> + *
> + * Driver should expect query_error_threshold() to be called with
> + * error_id from `error_counter_range.first` to
> + * `error_counter_range.last`.
> + *
> + * Returns: 0 on success, negative error code on failure.
> + */
> + int (*query_error_threshold)(struct drm_ras_node *node, u32 error_id, const char **name,
> + u32 *threshold);
> + /**
> + * @set_error_threshold:
> + *
> + * This callback is used by drm-ras to set error threshold of a specific
> + * counter.
> + *
> + * Driver should expect set_error_threshold() to be called with error_id
> + * from `error_counter_range.first` to `error_counter_range.last`.
> + * Driver is responsible for error threshold bounds checking.
> + *
> + * Returns: 0 on success, negative error code on failure.
> + */
> + int (*set_error_threshold)(struct drm_ras_node *node, u32 error_id, u32 threshold);
> +
> /** @priv: Driver private data */
> void *priv;
> };
> diff --git a/include/uapi/drm/drm_ras.h b/include/uapi/drm/drm_ras.h
> index 218a3ee86805..27c68956495f 100644
> --- a/include/uapi/drm/drm_ras.h
> +++ b/include/uapi/drm/drm_ras.h
> @@ -33,6 +33,7 @@ enum {
> DRM_RAS_A_ERROR_COUNTER_ATTRS_ERROR_ID,
> DRM_RAS_A_ERROR_COUNTER_ATTRS_ERROR_NAME,
> DRM_RAS_A_ERROR_COUNTER_ATTRS_ERROR_VALUE,
> + DRM_RAS_A_ERROR_COUNTER_ATTRS_ERROR_THRESHOLD,
>
> __DRM_RAS_A_ERROR_COUNTER_ATTRS_MAX,
> DRM_RAS_A_ERROR_COUNTER_ATTRS_MAX = (__DRM_RAS_A_ERROR_COUNTER_ATTRS_MAX - 1)
> @@ -42,6 +43,8 @@ enum {
> DRM_RAS_CMD_LIST_NODES = 1,
> DRM_RAS_CMD_GET_ERROR_COUNTER,
> DRM_RAS_CMD_CLEAR_ERROR_COUNTER,
> + DRM_RAS_CMD_GET_ERROR_THRESHOLD,
> + DRM_RAS_CMD_SET_ERROR_THRESHOLD,
>
> __DRM_RAS_CMD_MAX,
> DRM_RAS_CMD_MAX = (__DRM_RAS_CMD_MAX - 1)
> --
> 2.43.0
>
^ permalink raw reply
* [PATCH net] ptp: netc: explicitly clear TMR_OFF during initialization
From: wei.fang @ 2026-07-06 8:12 UTC (permalink / raw)
To: richardcochran, xiaoning.wang, andrew+netdev, davem, edumazet,
kuba, pabeni, Frank.Li
Cc: netdev, imx, wei.fang
From: Clark Wang <xiaoning.wang@nxp.com>
The NETC timer does not support function level reset, so TMR_OFF_L/H
registers are not cleared by pcie_flr(). If TMR_OFF was set to a
non-zero value in a previous binding, it will persist across driver
rebind and cause inaccurate PTP time.
There is also a hardware issue: after a warm reset or soft reset,
TMR_OFF_L/H registers appear to be cleared to zero, but the timer clock
domain internally retains the stale value. When the timer is re-enabled,
TMR_CUR_TIME continues to track the old offset until TMR_OFF is written
explicitly. This can cause incorrect PTP timestamps and even PTP clock
synchronization failures.
Per the recommendation from the IP team, explicitly write 0 to TMR_OFF
in netc_timer_init() to flush the internally cached value and ensure
TMR_CUR_TIME follows the freshly initialized counter.
Fixes: 87a201d59963 ("ptp: netc: add NETC V4 Timer PTP driver support")
Signed-off-by: Clark Wang <xiaoning.wang@nxp.com>
Signed-off-by: Wei Fang <wei.fang@nxp.com>
---
drivers/ptp/ptp_netc.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/drivers/ptp/ptp_netc.c b/drivers/ptp/ptp_netc.c
index 94e952ee6990..5e381c354d74 100644
--- a/drivers/ptp/ptp_netc.c
+++ b/drivers/ptp/ptp_netc.c
@@ -779,6 +779,7 @@ static void netc_timer_init(struct netc_timer *priv)
netc_timer_wr(priv, NETC_TMR_FIPER_CTRL, fiper_ctrl);
netc_timer_wr(priv, NETC_TMR_ECTRL, NETC_TMR_DEFAULT_ETTF_THR);
+ netc_timer_offset_write(priv, 0);
ktime_get_real_ts64(&now);
ns = timespec64_to_ns(&now);
netc_timer_cnt_write(priv, ns);
--
2.34.1
^ permalink raw reply related
* Re: [PATCH nf] ipvs: skip IPv6 extension headers in SCTP state lookup
From: Yizhou Zhao @ 2026-07-06 8:22 UTC (permalink / raw)
To: Julian Anastasov
Cc: netdev, Simon Horman, Pablo Neira Ayuso, Florian Westphal,
Phil Sutter, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, lvs-devel, netfilter-devel, coreteam, linux-kernel,
Yuxiang Yang, Ao Wang, Xuewei Feng, Qi Li, Ke Xu, stable
In-Reply-To: <92783c87-7e6a-e90a-b2fc-e5d1332139e0@ssi.bg>
Hi Julian,
Thanks for your review.
> On Jul 6, 2026, at 01:35, Julian Anastasov <ja@ssi.bg> wrote:
>
> May be it is better starting from ip_vs_set_state()
> to provide new arg 'int iph_len/offset' (set to iph.len), down to
> state_transition(), sctp_state_transition() and set_sctp_state().
> Same for all protos. It should cost less stack and ipv6_find_hdr()
> calls and what matters most, correct iph context in case we
> have IP+ICMP+TCP (with just two ports or even with TCP flags)
> and are scheduling ICMP, i.e. not IP+TCP as usually.
I agree that the already parsed transport-header offset should be
passed from ip_vs_set_state() down to the protocol state_transition()
callbacks, instead of reparsing the skb in set_sctp_state(). We will
send a v2 that does this for SCTP, TCP and the other IPVS protocols
in one combined fix.
> But what I see is that ip_vs_in_icmp*() are missing
> the ip_vs_set_state(cp, IP_VS_DIR_INPUT, skb, pd) call just
> after ip_vs_in_stats() and before ip_vs_icmp_xmit() where
> we should provide ciph.len. That is why we don't reach the
> set_tcp_state() calls to set correct cp->state and timeout
> when scheduling related ICMP. So, this should be fixed too.
For the ICMP path, I agree that the missing ip_vs_set_state() call is
worth looking at, but using ICMP errors to drive the upper L4 state
needs some care, because spoofed ICMP packets can match an
existing embedded tuple before the endpoint TCP/SCTP stack
performs its own validation. Maybe this change needs further
discussion?
Thanks,
Yizhou
^ permalink raw reply
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