* [PATCH v14 0/9] ref_tracker: add ability to register a debugfs file for a ref_tracker_dir
@ 2025-06-10 14:59 Jeff Layton
2025-06-10 14:59 ` [PATCH v14 1/9] ref_tracker: don't use %pK in pr_ostream() output Jeff Layton
` (9 more replies)
0 siblings, 10 replies; 15+ messages in thread
From: Jeff Layton @ 2025-06-10 14:59 UTC (permalink / raw)
To: Andrew Morton, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Simon Horman, Maarten Lankhorst, Maxime Ripard,
Thomas Zimmermann, David Airlie, Simona Vetter, Jani Nikula,
Joonas Lahtinen, Rodrigo Vivi, Tvrtko Ursulin
Cc: Krzysztof Karas, Kuniyuki Iwashima, Qasim Ijaz, Nathan Chancellor,
Andrew Lunn, linux-kernel, netdev, dri-devel, intel-gfx,
Jeff Layton, Thomas Weißschuh
For those just joining in, this series adds a new top-level
"ref_tracker" debugfs directory, and has each ref_tracker_dir register a
file in there as part of its initialization. It also adds the ability to
register a symlink with a more human-usable name that points to the
file, and does some general cleanup of how the ref_tracker object names
are handled.
The big change in this set is in how debugfs entries get removed:
With the last set, Jakub pointed out a warning that showed it calling
debugfs_remove() from RCU callback [1].
While ref_tracker_dir_init is generally safe for sleeping operations,
the same can't be said for ref_tracker_dir_exit(). It can be called from
any context, so it's not safe to sleep in that function. The removal of
debugfs dentries has to be deferred.
This set revamps how the dentries are tracked. Instead of pointers in
the ref_tracker_dir, they are tracked in xarrays from the time they are
instantiated. ref_tracker_dir_exit() will mark the appropriate xarray
entries for deletion and kick off a workqueue job to clean them up
asynchronously.
This unfortunately necessitates some complex locking for
ref_tracker_debugfs_show(), since the debugfs dentries can now outlive
their corresponding ref_tracker_dir. It's not pretty, but it should
work.
[1]: https://netdev-3.bots.linux.dev/vmksft-packetdrill-dbg/results/149560/2-tcp-slow-start-slow-start-app-limited-pkt/stderr
Signed-off-by: Jeff Layton <jlayton@kernel.org>
---
Changes in v14:
- Clean up dentries asynchronously after ref_tracker_dir_exit()
- Link to v13: https://lore.kernel.org/r/20250603-reftrack-dbgfs-v13-0-7b2a425019d8@kernel.org
Changes in v13:
- drop i915 patch
- Link to v12: https://lore.kernel.org/r/20250529-reftrack-dbgfs-v12-0-11b93c0c0b6e@kernel.org
Changes in v12:
- drop redundant pr_warn() calls. Debugfs already warns when these ops fail
- Link to v11: https://lore.kernel.org/r/20250528-reftrack-dbgfs-v11-0-94ae0b165841@kernel.org
Changes in v11:
- don't call ref_tracker_dir_init() more than once for same i915 objects
- use %llx in format for net_cookie in symlink name
- Link to v10: https://lore.kernel.org/r/20250527-reftrack-dbgfs-v10-0-dc55f7705691@kernel.org
Changes in v10:
- drop the i915 symlink patch
- Link to v9: https://lore.kernel.org/r/20250509-reftrack-dbgfs-v9-0-8ab888a4524d@kernel.org
Changes in v9:
- fix typo in ref_tracker_dir_init() kerneldoc header
- Link to v8: https://lore.kernel.org/r/20250507-reftrack-dbgfs-v8-0-607717d3bb98@kernel.org
Changes in v8:
- fix up compiler warnings that the KTR warned about
- ensure builds with CONFIG_DEBUG_FS=n and CONFIG_REF_TRACKER=y work
- Link to v7: https://lore.kernel.org/r/20250505-reftrack-dbgfs-v7-0-f78c5d97bcca@kernel.org
Changes in v7:
- include net->net_cookie in netns symlink name
- add __ostream_printf to ref_tracker_dir_symlink() stub function
- remove unneeded #include of seq_file.h
- Link to v6: https://lore.kernel.org/r/20250430-reftrack-dbgfs-v6-0-867c29aff03a@kernel.org
Changes in v6:
- clean up kerneldoc comment for ref_tracker_dir_debugfs()
- add missing stub function for ref_tracker_dir_symlink()
- temporary __maybe_unused on ref_tracker_dir_seq_print() to silence compiler warning
- Link to v5: https://lore.kernel.org/r/20250428-reftrack-dbgfs-v5-0-1cbbdf2038bd@kernel.org
Changes in v5:
- add class string to each ref_tracker_dir
- auto-register debugfs file for every tracker in ref_tracker_dir_init
- add function to allow adding a symlink for each tracker
- add patches to create symlinks for netns's and i915 entries
- change output format to print class@%p instead of name@%p
- eliminate the name field in ref_tracker_dir
- fix off-by-one bug when NULL terminating name string
- Link to v4: https://lore.kernel.org/r/20250418-reftrack-dbgfs-v4-0-5ca5c7899544@kernel.org
Changes in v4:
- Drop patch to widen ref_tracker_dir_.name, use NAME_MAX+1 (256) instead since this only affects dentry name
- Link to v3: https://lore.kernel.org/r/20250417-reftrack-dbgfs-v3-0-c3159428c8fb@kernel.org
Changes in v3:
- don't overwrite dir->name in ref_tracker_dir_debugfs
- define REF_TRACKER_NAMESZ and use it when setting name
- Link to v2: https://lore.kernel.org/r/20250415-reftrack-dbgfs-v2-0-b18c4abd122f@kernel.org
Changes in v2:
- Add patch to do %pK -> %p conversion in ref_tracker.c
- Pass in output function to pr_ostream() instead of if statement
- Widen ref_tracker_dir.name to 64 bytes to accomodate unique names
- Eliminate error handling with debugfs manipulation
- Incorporate pointer value into netdev name
- Link to v1: https://lore.kernel.org/r/20250414-reftrack-dbgfs-v1-0-f03585832203@kernel.org
---
Jeff Layton (9):
ref_tracker: don't use %pK in pr_ostream() output
ref_tracker: add a top level debugfs directory for ref_tracker
ref_tracker: have callers pass output function to pr_ostream()
ref_tracker: add a static classname string to each ref_tracker_dir
ref_tracker: allow pr_ostream() to print directly to a seq_file
ref_tracker: automatically register a file in debugfs for a ref_tracker_dir
ref_tracker: add a way to create a symlink to the ref_tracker_dir debugfs file
net: add symlinks to ref_tracker_dir for netns
ref_tracker: eliminate the ref_tracker_dir name field
drivers/gpu/drm/display/drm_dp_tunnel.c | 2 +-
drivers/gpu/drm/i915/intel_runtime_pm.c | 4 +-
drivers/gpu/drm/i915/intel_wakeref.c | 3 +-
include/linux/ref_tracker.h | 50 +++++-
lib/ref_tracker.c | 275 ++++++++++++++++++++++++++++++--
net/core/dev.c | 2 +-
net/core/net_namespace.c | 34 +++-
7 files changed, 344 insertions(+), 26 deletions(-)
---
base-commit: 8630c59e99363c4b655788fd01134aef9bcd9264
change-id: 20250413-reftrack-dbgfs-3767b303e2fa
Best regards,
--
Jeff Layton <jlayton@kernel.org>
^ permalink raw reply [flat|nested] 15+ messages in thread
* [PATCH v14 1/9] ref_tracker: don't use %pK in pr_ostream() output
2025-06-10 14:59 [PATCH v14 0/9] ref_tracker: add ability to register a debugfs file for a ref_tracker_dir Jeff Layton
@ 2025-06-10 14:59 ` Jeff Layton
2025-06-10 14:59 ` [PATCH v14 2/9] ref_tracker: add a top level debugfs directory for ref_tracker Jeff Layton
` (8 subsequent siblings)
9 siblings, 0 replies; 15+ messages in thread
From: Jeff Layton @ 2025-06-10 14:59 UTC (permalink / raw)
To: Andrew Morton, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Simon Horman, Maarten Lankhorst, Maxime Ripard,
Thomas Zimmermann, David Airlie, Simona Vetter, Jani Nikula,
Joonas Lahtinen, Rodrigo Vivi, Tvrtko Ursulin
Cc: Krzysztof Karas, Kuniyuki Iwashima, Qasim Ijaz, Nathan Chancellor,
Andrew Lunn, linux-kernel, netdev, dri-devel, intel-gfx,
Jeff Layton, Thomas Weißschuh
As Thomas Weißschuh points out [1], it is now preferable to use %p
instead of hashed pointers with printk(), since raw pointers should no
longer be leaked into the kernel log. Change the ref_tracker
infrastructure to use %p instead of %pK in its formats.
[1]: https://lore.kernel.org/netdev/20250414-restricted-pointers-net-v1-0-12af0ce46cdd@linutronix.de/
Cc: Thomas Weißschuh <thomas.weissschuh@linutronix.de>
Reviewed-by: Thomas Weißschuh <thomas.weissschuh@linutronix.de>
Reviewed-by: Krzysztof Karas <krzysztof.karas@intel.com>
Signed-off-by: Jeff Layton <jlayton@kernel.org>
---
lib/ref_tracker.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/lib/ref_tracker.c b/lib/ref_tracker.c
index cf5609b1ca79361763abe5a3a98484a3ee591ff2..de71439e12a3bab6456910986fa611dfbdd97980 100644
--- a/lib/ref_tracker.c
+++ b/lib/ref_tracker.c
@@ -96,7 +96,7 @@ __ref_tracker_dir_pr_ostream(struct ref_tracker_dir *dir,
stats = ref_tracker_get_stats(dir, display_limit);
if (IS_ERR(stats)) {
- pr_ostream(s, "%s@%pK: couldn't get stats, error %pe\n",
+ pr_ostream(s, "%s@%p: couldn't get stats, error %pe\n",
dir->name, dir, stats);
return;
}
@@ -107,13 +107,13 @@ __ref_tracker_dir_pr_ostream(struct ref_tracker_dir *dir,
stack = stats->stacks[i].stack_handle;
if (sbuf && !stack_depot_snprint(stack, sbuf, STACK_BUF_SIZE, 4))
sbuf[0] = 0;
- pr_ostream(s, "%s@%pK has %d/%d users at\n%s\n", dir->name, dir,
+ pr_ostream(s, "%s@%p has %d/%d users at\n%s\n", dir->name, dir,
stats->stacks[i].count, stats->total, sbuf);
skipped -= stats->stacks[i].count;
}
if (skipped)
- pr_ostream(s, "%s@%pK skipped reports about %d/%d users.\n",
+ pr_ostream(s, "%s@%p skipped reports about %d/%d users.\n",
dir->name, dir, skipped, stats->total);
kfree(sbuf);
--
2.49.0
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH v14 2/9] ref_tracker: add a top level debugfs directory for ref_tracker
2025-06-10 14:59 [PATCH v14 0/9] ref_tracker: add ability to register a debugfs file for a ref_tracker_dir Jeff Layton
2025-06-10 14:59 ` [PATCH v14 1/9] ref_tracker: don't use %pK in pr_ostream() output Jeff Layton
@ 2025-06-10 14:59 ` Jeff Layton
2025-06-10 14:59 ` [PATCH v14 3/9] ref_tracker: have callers pass output function to pr_ostream() Jeff Layton
` (7 subsequent siblings)
9 siblings, 0 replies; 15+ messages in thread
From: Jeff Layton @ 2025-06-10 14:59 UTC (permalink / raw)
To: Andrew Morton, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Simon Horman, Maarten Lankhorst, Maxime Ripard,
Thomas Zimmermann, David Airlie, Simona Vetter, Jani Nikula,
Joonas Lahtinen, Rodrigo Vivi, Tvrtko Ursulin
Cc: Krzysztof Karas, Kuniyuki Iwashima, Qasim Ijaz, Nathan Chancellor,
Andrew Lunn, linux-kernel, netdev, dri-devel, intel-gfx,
Jeff Layton
Add a new "ref_tracker" directory in debugfs. Each individual refcount
tracker can register files under there to display info about
currently-held references.
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
Reviewed-by: Krzysztof Karas <krzysztof.karas@intel.com>
Signed-off-by: Jeff Layton <jlayton@kernel.org>
---
lib/ref_tracker.c | 13 +++++++++++++
1 file changed, 13 insertions(+)
diff --git a/lib/ref_tracker.c b/lib/ref_tracker.c
index de71439e12a3bab6456910986fa611dfbdd97980..d374e5273e1497cac0d70c02c282baa2c3ab63fe 100644
--- a/lib/ref_tracker.c
+++ b/lib/ref_tracker.c
@@ -273,3 +273,16 @@ int ref_tracker_free(struct ref_tracker_dir *dir,
return 0;
}
EXPORT_SYMBOL_GPL(ref_tracker_free);
+
+#ifdef CONFIG_DEBUG_FS
+#include <linux/debugfs.h>
+
+static struct dentry *ref_tracker_debug_dir = (struct dentry *)-ENOENT;
+
+static int __init ref_tracker_debugfs_init(void)
+{
+ ref_tracker_debug_dir = debugfs_create_dir("ref_tracker", NULL);
+ return 0;
+}
+late_initcall(ref_tracker_debugfs_init);
+#endif /* CONFIG_DEBUG_FS */
--
2.49.0
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH v14 3/9] ref_tracker: have callers pass output function to pr_ostream()
2025-06-10 14:59 [PATCH v14 0/9] ref_tracker: add ability to register a debugfs file for a ref_tracker_dir Jeff Layton
2025-06-10 14:59 ` [PATCH v14 1/9] ref_tracker: don't use %pK in pr_ostream() output Jeff Layton
2025-06-10 14:59 ` [PATCH v14 2/9] ref_tracker: add a top level debugfs directory for ref_tracker Jeff Layton
@ 2025-06-10 14:59 ` Jeff Layton
2025-06-11 9:42 ` Krzysztof Karas
2025-06-10 14:59 ` [PATCH v14 4/9] ref_tracker: add a static classname string to each ref_tracker_dir Jeff Layton
` (6 subsequent siblings)
9 siblings, 1 reply; 15+ messages in thread
From: Jeff Layton @ 2025-06-10 14:59 UTC (permalink / raw)
To: Andrew Morton, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Simon Horman, Maarten Lankhorst, Maxime Ripard,
Thomas Zimmermann, David Airlie, Simona Vetter, Jani Nikula,
Joonas Lahtinen, Rodrigo Vivi, Tvrtko Ursulin
Cc: Krzysztof Karas, Kuniyuki Iwashima, Qasim Ijaz, Nathan Chancellor,
Andrew Lunn, linux-kernel, netdev, dri-devel, intel-gfx,
Jeff Layton
In a later patch, we'll be adding a 3rd mechanism for outputting
ref_tracker info via seq_file. Instead of a conditional, have the caller
set a pointer to an output function in struct ostream. As part of this,
the log prefix must be explicitly passed in, as it's too late for the
pr_fmt macro.
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
Signed-off-by: Jeff Layton <jlayton@kernel.org>
---
include/linux/ref_tracker.h | 2 ++
lib/ref_tracker.c | 52 ++++++++++++++++++++++++++++++++-------------
2 files changed, 39 insertions(+), 15 deletions(-)
diff --git a/include/linux/ref_tracker.h b/include/linux/ref_tracker.h
index 8eac4f3d52547ccbaf9dcd09962ce80d26fbdff8..a0a1ee43724ffa00e60c116be18e481bfe1d1455 100644
--- a/include/linux/ref_tracker.h
+++ b/include/linux/ref_tracker.h
@@ -6,6 +6,8 @@
#include <linux/spinlock.h>
#include <linux/stackdepot.h>
+#define __ostream_printf __printf(2, 3)
+
struct ref_tracker;
struct ref_tracker_dir {
diff --git a/lib/ref_tracker.c b/lib/ref_tracker.c
index d374e5273e1497cac0d70c02c282baa2c3ab63fe..42872f406b2a91b5bc611405cae7ce883fd8ed22 100644
--- a/lib/ref_tracker.c
+++ b/lib/ref_tracker.c
@@ -63,21 +63,38 @@ ref_tracker_get_stats(struct ref_tracker_dir *dir, unsigned int limit)
}
struct ostream {
+ void __ostream_printf (*func)(struct ostream *stream, char *fmt, ...);
+ char *prefix;
char *buf;
int size, used;
};
+static void __ostream_printf pr_ostream_log(struct ostream *stream, char *fmt, ...)
+{
+ va_list args;
+
+ va_start(args, fmt);
+ vprintk(fmt, args);
+ va_end(args);
+}
+
+static void __ostream_printf pr_ostream_buf(struct ostream *stream, char *fmt, ...)
+{
+ int ret, len = stream->size - stream->used;
+ va_list args;
+
+ va_start(args, fmt);
+ ret = vsnprintf(stream->buf + stream->used, len, fmt, args);
+ va_end(args);
+ if (ret > 0)
+ stream->used += min(ret, len);
+}
+
#define pr_ostream(stream, fmt, args...) \
({ \
struct ostream *_s = (stream); \
\
- if (!_s->buf) { \
- pr_err(fmt, ##args); \
- } else { \
- int ret, len = _s->size - _s->used; \
- ret = snprintf(_s->buf + _s->used, len, pr_fmt(fmt), ##args); \
- _s->used += min(ret, len); \
- } \
+ _s->func(_s, fmt, ##args); \
})
static void
@@ -96,8 +113,8 @@ __ref_tracker_dir_pr_ostream(struct ref_tracker_dir *dir,
stats = ref_tracker_get_stats(dir, display_limit);
if (IS_ERR(stats)) {
- pr_ostream(s, "%s@%p: couldn't get stats, error %pe\n",
- dir->name, dir, stats);
+ pr_ostream(s, "%s%s@%p: couldn't get stats, error %pe\n",
+ s->prefix, dir->name, dir, stats);
return;
}
@@ -107,14 +124,15 @@ __ref_tracker_dir_pr_ostream(struct ref_tracker_dir *dir,
stack = stats->stacks[i].stack_handle;
if (sbuf && !stack_depot_snprint(stack, sbuf, STACK_BUF_SIZE, 4))
sbuf[0] = 0;
- pr_ostream(s, "%s@%p has %d/%d users at\n%s\n", dir->name, dir,
- stats->stacks[i].count, stats->total, sbuf);
+ pr_ostream(s, "%s%s@%p has %d/%d users at\n%s\n", s->prefix,
+ dir->name, dir, stats->stacks[i].count,
+ stats->total, sbuf);
skipped -= stats->stacks[i].count;
}
if (skipped)
- pr_ostream(s, "%s@%p skipped reports about %d/%d users.\n",
- dir->name, dir, skipped, stats->total);
+ pr_ostream(s, "%s%s@%p skipped reports about %d/%d users.\n",
+ s->prefix, dir->name, dir, skipped, stats->total);
kfree(sbuf);
@@ -124,7 +142,8 @@ __ref_tracker_dir_pr_ostream(struct ref_tracker_dir *dir,
void ref_tracker_dir_print_locked(struct ref_tracker_dir *dir,
unsigned int display_limit)
{
- struct ostream os = {};
+ struct ostream os = { .func = pr_ostream_log,
+ .prefix = "ref_tracker: " };
__ref_tracker_dir_pr_ostream(dir, display_limit, &os);
}
@@ -143,7 +162,10 @@ EXPORT_SYMBOL(ref_tracker_dir_print);
int ref_tracker_dir_snprint(struct ref_tracker_dir *dir, char *buf, size_t size)
{
- struct ostream os = { .buf = buf, .size = size };
+ struct ostream os = { .func = pr_ostream_buf,
+ .prefix = "ref_tracker: ",
+ .buf = buf,
+ .size = size };
unsigned long flags;
spin_lock_irqsave(&dir->lock, flags);
--
2.49.0
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH v14 4/9] ref_tracker: add a static classname string to each ref_tracker_dir
2025-06-10 14:59 [PATCH v14 0/9] ref_tracker: add ability to register a debugfs file for a ref_tracker_dir Jeff Layton
` (2 preceding siblings ...)
2025-06-10 14:59 ` [PATCH v14 3/9] ref_tracker: have callers pass output function to pr_ostream() Jeff Layton
@ 2025-06-10 14:59 ` Jeff Layton
2025-06-11 10:32 ` Krzysztof Karas
2025-06-10 14:59 ` [PATCH v14 5/9] ref_tracker: allow pr_ostream() to print directly to a seq_file Jeff Layton
` (5 subsequent siblings)
9 siblings, 1 reply; 15+ messages in thread
From: Jeff Layton @ 2025-06-10 14:59 UTC (permalink / raw)
To: Andrew Morton, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Simon Horman, Maarten Lankhorst, Maxime Ripard,
Thomas Zimmermann, David Airlie, Simona Vetter, Jani Nikula,
Joonas Lahtinen, Rodrigo Vivi, Tvrtko Ursulin
Cc: Krzysztof Karas, Kuniyuki Iwashima, Qasim Ijaz, Nathan Chancellor,
Andrew Lunn, linux-kernel, netdev, dri-devel, intel-gfx,
Jeff Layton
A later patch in the series will be adding debugfs files for each
ref_tracker that get created in ref_tracker_dir_init(). The format will
be "class@%px". The current "name" string can vary between
ref_tracker_dir objects of the same type, so it's not suitable for this
purpose.
Add a new "class" string to the ref_tracker dir that describes the
the type of object (sans any individual info for that object).
Also, in the i915 driver, gate the creation of debugfs files on whether
the dentry pointer is still set to NULL. CI has shown that the
ref_tracker_dir can be initialized more than once.
Signed-off-by: Jeff Layton <jlayton@kernel.org>
---
drivers/gpu/drm/display/drm_dp_tunnel.c | 2 +-
drivers/gpu/drm/i915/intel_runtime_pm.c | 4 +++-
drivers/gpu/drm/i915/intel_wakeref.c | 3 ++-
include/linux/ref_tracker.h | 4 ++++
lib/test_ref_tracker.c | 2 +-
net/core/dev.c | 2 +-
net/core/net_namespace.c | 4 ++--
7 files changed, 14 insertions(+), 7 deletions(-)
diff --git a/drivers/gpu/drm/display/drm_dp_tunnel.c b/drivers/gpu/drm/display/drm_dp_tunnel.c
index 076edf1610480275c62395334ab0536befa42f15..b9c12b8bf2a3e400b6d8e9d184145834c603b9e1 100644
--- a/drivers/gpu/drm/display/drm_dp_tunnel.c
+++ b/drivers/gpu/drm/display/drm_dp_tunnel.c
@@ -1920,7 +1920,7 @@ drm_dp_tunnel_mgr_create(struct drm_device *dev, int max_group_count)
}
#ifdef CONFIG_DRM_DISPLAY_DP_TUNNEL_STATE_DEBUG
- ref_tracker_dir_init(&mgr->ref_tracker, 16, "dptun");
+ ref_tracker_dir_init(&mgr->ref_tracker, 16, "drm_dptun", "dptun");
#endif
for (i = 0; i < max_group_count; i++) {
diff --git a/drivers/gpu/drm/i915/intel_runtime_pm.c b/drivers/gpu/drm/i915/intel_runtime_pm.c
index 8d9f4c410546e4144d4bc8bbc6696f3bd9498848..90d90145a1890bf788e789858ddad3b3d8e3b978 100644
--- a/drivers/gpu/drm/i915/intel_runtime_pm.c
+++ b/drivers/gpu/drm/i915/intel_runtime_pm.c
@@ -59,7 +59,9 @@ static struct drm_i915_private *rpm_to_i915(struct intel_runtime_pm *rpm)
static void init_intel_runtime_pm_wakeref(struct intel_runtime_pm *rpm)
{
- ref_tracker_dir_init(&rpm->debug, INTEL_REFTRACK_DEAD_COUNT, dev_name(rpm->kdev));
+ if (!rpm->debug.class)
+ ref_tracker_dir_init(&rpm->debug, INTEL_REFTRACK_DEAD_COUNT,
+ "intel_runtime_pm", dev_name(rpm->kdev));
}
static intel_wakeref_t
diff --git a/drivers/gpu/drm/i915/intel_wakeref.c b/drivers/gpu/drm/i915/intel_wakeref.c
index 07e81be4d3920febece34709c63a63204a41583c..21dcee7c9a659ac1fb0aa19f3018647be3bda754 100644
--- a/drivers/gpu/drm/i915/intel_wakeref.c
+++ b/drivers/gpu/drm/i915/intel_wakeref.c
@@ -114,7 +114,8 @@ void __intel_wakeref_init(struct intel_wakeref *wf,
"wakeref.work", &key->work, 0);
#if IS_ENABLED(CONFIG_DRM_I915_DEBUG_WAKEREF)
- ref_tracker_dir_init(&wf->debug, INTEL_REFTRACK_DEAD_COUNT, name);
+ if (!wf->debug.class)
+ ref_tracker_dir_init(&wf->debug, INTEL_REFTRACK_DEAD_COUNT, "intel_wakeref", name);
#endif
}
diff --git a/include/linux/ref_tracker.h b/include/linux/ref_tracker.h
index a0a1ee43724ffa00e60c116be18e481bfe1d1455..3968f993db81e95c0d58c81454311841c1b9cd35 100644
--- a/include/linux/ref_tracker.h
+++ b/include/linux/ref_tracker.h
@@ -19,6 +19,7 @@ struct ref_tracker_dir {
bool dead;
struct list_head list; /* List of active trackers */
struct list_head quarantine; /* List of dead trackers */
+ const char *class; /* object classname */
char name[32];
#endif
};
@@ -27,6 +28,7 @@ struct ref_tracker_dir {
static inline void ref_tracker_dir_init(struct ref_tracker_dir *dir,
unsigned int quarantine_count,
+ const char *class,
const char *name)
{
INIT_LIST_HEAD(&dir->list);
@@ -36,6 +38,7 @@ static inline void ref_tracker_dir_init(struct ref_tracker_dir *dir,
dir->dead = false;
refcount_set(&dir->untracked, 1);
refcount_set(&dir->no_tracker, 1);
+ dir->class = class;
strscpy(dir->name, name, sizeof(dir->name));
stack_depot_init();
}
@@ -60,6 +63,7 @@ int ref_tracker_free(struct ref_tracker_dir *dir,
static inline void ref_tracker_dir_init(struct ref_tracker_dir *dir,
unsigned int quarantine_count,
+ const char *class,
const char *name)
{
}
diff --git a/lib/test_ref_tracker.c b/lib/test_ref_tracker.c
index b983ceb12afcb84ad60360a1e6fec0072e78ef79..d263502a4c1db248f64a66a468e96c8e4cffab25 100644
--- a/lib/test_ref_tracker.c
+++ b/lib/test_ref_tracker.c
@@ -64,7 +64,7 @@ static int __init test_ref_tracker_init(void)
{
int i;
- ref_tracker_dir_init(&ref_dir, 100, "selftest");
+ ref_tracker_dir_init(&ref_dir, 100, "selftest", "selftest");
timer_setup(&test_ref_tracker_timer, test_ref_tracker_timer_func, 0);
mod_timer(&test_ref_tracker_timer, jiffies + 1);
diff --git a/net/core/dev.c b/net/core/dev.c
index be97c440ecd5f993344ae08d76c0b5216c4d296a..12cf4e5ae9c5437bcfec657e37b7e08792bc14bf 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -11715,7 +11715,7 @@ struct net_device *alloc_netdev_mqs(int sizeof_priv, const char *name,
dev->priv_len = sizeof_priv;
- ref_tracker_dir_init(&dev->refcnt_tracker, 128, name);
+ ref_tracker_dir_init(&dev->refcnt_tracker, 128, "netdev", name);
#ifdef CONFIG_PCPU_DEV_REFCNT
dev->pcpu_refcnt = alloc_percpu(int);
if (!dev->pcpu_refcnt)
diff --git a/net/core/net_namespace.c b/net/core/net_namespace.c
index ae54f26709ca242567e5d62d7b5dcc7f6303da57..aa1e34181ed6f353921a23411fa227b612db661a 100644
--- a/net/core/net_namespace.c
+++ b/net/core/net_namespace.c
@@ -403,8 +403,8 @@ static __net_init void preinit_net(struct net *net, struct user_namespace *user_
{
refcount_set(&net->passive, 1);
refcount_set(&net->ns.count, 1);
- ref_tracker_dir_init(&net->refcnt_tracker, 128, "net refcnt");
- ref_tracker_dir_init(&net->notrefcnt_tracker, 128, "net notrefcnt");
+ ref_tracker_dir_init(&net->refcnt_tracker, 128, "net_refcnt", "net_refcnt");
+ ref_tracker_dir_init(&net->notrefcnt_tracker, 128, "net_notrefcnt", "net_notrefcnt");
get_random_bytes(&net->hash_mix, sizeof(u32));
net->dev_base_seq = 1;
--
2.49.0
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH v14 5/9] ref_tracker: allow pr_ostream() to print directly to a seq_file
2025-06-10 14:59 [PATCH v14 0/9] ref_tracker: add ability to register a debugfs file for a ref_tracker_dir Jeff Layton
` (3 preceding siblings ...)
2025-06-10 14:59 ` [PATCH v14 4/9] ref_tracker: add a static classname string to each ref_tracker_dir Jeff Layton
@ 2025-06-10 14:59 ` Jeff Layton
2025-06-11 10:52 ` Krzysztof Karas
2025-06-10 14:59 ` [PATCH v14 6/9] ref_tracker: automatically register a file in debugfs for a ref_tracker_dir Jeff Layton
` (4 subsequent siblings)
9 siblings, 1 reply; 15+ messages in thread
From: Jeff Layton @ 2025-06-10 14:59 UTC (permalink / raw)
To: Andrew Morton, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Simon Horman, Maarten Lankhorst, Maxime Ripard,
Thomas Zimmermann, David Airlie, Simona Vetter, Jani Nikula,
Joonas Lahtinen, Rodrigo Vivi, Tvrtko Ursulin
Cc: Krzysztof Karas, Kuniyuki Iwashima, Qasim Ijaz, Nathan Chancellor,
Andrew Lunn, linux-kernel, netdev, dri-devel, intel-gfx,
Jeff Layton
Allow pr_ostream to also output directly to a seq_file without an
intermediate buffer. The first caller of +ref_tracker_dir_seq_print()
will come in a later patch, so mark that __maybe_unused for now. That
designation will be removed once it is used.
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
Signed-off-by: Jeff Layton <jlayton@kernel.org>
---
lib/ref_tracker.c | 26 ++++++++++++++++++++++++++
1 file changed, 26 insertions(+)
diff --git a/lib/ref_tracker.c b/lib/ref_tracker.c
index 42872f406b2a91b5bc611405cae7ce883fd8ed22..73b606570cce9e551d13e65365a87dc4ce748b13 100644
--- a/lib/ref_tracker.c
+++ b/lib/ref_tracker.c
@@ -8,6 +8,7 @@
#include <linux/slab.h>
#include <linux/stacktrace.h>
#include <linux/stackdepot.h>
+#include <linux/seq_file.h>
#define REF_TRACKER_STACK_ENTRIES 16
#define STACK_BUF_SIZE 1024
@@ -66,6 +67,7 @@ struct ostream {
void __ostream_printf (*func)(struct ostream *stream, char *fmt, ...);
char *prefix;
char *buf;
+ struct seq_file *seq;
int size, used;
};
@@ -301,6 +303,30 @@ EXPORT_SYMBOL_GPL(ref_tracker_free);
static struct dentry *ref_tracker_debug_dir = (struct dentry *)-ENOENT;
+static void __ostream_printf pr_ostream_seq(struct ostream *stream, char *fmt, ...)
+{
+ va_list args;
+
+ va_start(args, fmt);
+ seq_vprintf(stream->seq, fmt, args);
+ va_end(args);
+}
+
+static __maybe_unused int
+ref_tracker_dir_seq_print(struct ref_tracker_dir *dir, struct seq_file *seq)
+{
+ struct ostream os = { .func = pr_ostream_seq,
+ .prefix = "",
+ .seq = seq };
+ unsigned long flags;
+
+ spin_lock_irqsave(&dir->lock, flags);
+ __ref_tracker_dir_pr_ostream(dir, 16, &os);
+ spin_unlock_irqrestore(&dir->lock, flags);
+
+ return os.used;
+}
+
static int __init ref_tracker_debugfs_init(void)
{
ref_tracker_debug_dir = debugfs_create_dir("ref_tracker", NULL);
--
2.49.0
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH v14 6/9] ref_tracker: automatically register a file in debugfs for a ref_tracker_dir
2025-06-10 14:59 [PATCH v14 0/9] ref_tracker: add ability to register a debugfs file for a ref_tracker_dir Jeff Layton
` (4 preceding siblings ...)
2025-06-10 14:59 ` [PATCH v14 5/9] ref_tracker: allow pr_ostream() to print directly to a seq_file Jeff Layton
@ 2025-06-10 14:59 ` Jeff Layton
2025-06-17 8:24 ` kernel test robot
2025-06-10 14:59 ` [PATCH v14 7/9] ref_tracker: add a way to create a symlink to the ref_tracker_dir debugfs file Jeff Layton
` (3 subsequent siblings)
9 siblings, 1 reply; 15+ messages in thread
From: Jeff Layton @ 2025-06-10 14:59 UTC (permalink / raw)
To: Andrew Morton, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Simon Horman, Maarten Lankhorst, Maxime Ripard,
Thomas Zimmermann, David Airlie, Simona Vetter, Jani Nikula,
Joonas Lahtinen, Rodrigo Vivi, Tvrtko Ursulin
Cc: Krzysztof Karas, Kuniyuki Iwashima, Qasim Ijaz, Nathan Chancellor,
Andrew Lunn, linux-kernel, netdev, dri-devel, intel-gfx,
Jeff Layton
Currently, there is no convenient way to see the info that the
ref_tracking infrastructure collects. Attempt to create a file in
debugfs when called from ref_tracker_dir_init().
The file is given the name "class@%px", as having the unmodified address
is helpful for debugging. This should be safe since this directory is only
accessible by root
While ref_tracker_dir_init() is generally called from a context where
sleeping is OK, ref_tracker_dir_exit() can be called from anywhere.
Thus, dentry cleanup must be handled asynchronously.
Add a new global xarray that has entries with the ref_tracker_dir
pointer as the index and the corresponding debugfs dentry pointer as the
value. Instead of removing the debugfs dentry, have
ref_tracker_dir_exit() set a mark on the xarray entry and schedule a
workqueue job. The workqueue job then walks the xarray looking for
marked entries, and removes their xarray entries and the debugfs
dentries.
Because of this, the debugfs dentry can outlive the corresponding
ref_tracker_dir. Have ref_tracker_debugfs_show() take extra care to
ensure that it's safe to dereference the dir pointer before using it.
Signed-off-by: Jeff Layton <jlayton@kernel.org>
---
include/linux/ref_tracker.h | 17 +++++
lib/ref_tracker.c | 147 ++++++++++++++++++++++++++++++++++++++++++--
2 files changed, 159 insertions(+), 5 deletions(-)
diff --git a/include/linux/ref_tracker.h b/include/linux/ref_tracker.h
index 3968f993db81e95c0d58c81454311841c1b9cd35..28bbf436a8f4646cfac181d618195a9460bda196 100644
--- a/include/linux/ref_tracker.h
+++ b/include/linux/ref_tracker.h
@@ -26,6 +26,18 @@ struct ref_tracker_dir {
#ifdef CONFIG_REF_TRACKER
+#ifdef CONFIG_DEBUG_FS
+
+void ref_tracker_dir_debugfs(struct ref_tracker_dir *dir);
+
+#else /* CONFIG_DEBUG_FS */
+
+static inline void ref_tracker_dir_debugfs(struct ref_tracker_dir *dir)
+{
+}
+
+#endif /* CONFIG_DEBUG_FS */
+
static inline void ref_tracker_dir_init(struct ref_tracker_dir *dir,
unsigned int quarantine_count,
const char *class,
@@ -40,6 +52,7 @@ static inline void ref_tracker_dir_init(struct ref_tracker_dir *dir,
refcount_set(&dir->no_tracker, 1);
dir->class = class;
strscpy(dir->name, name, sizeof(dir->name));
+ ref_tracker_dir_debugfs(dir);
stack_depot_init();
}
@@ -68,6 +81,10 @@ static inline void ref_tracker_dir_init(struct ref_tracker_dir *dir,
{
}
+static inline void ref_tracker_dir_debugfs(struct ref_tracker_dir *dir)
+{
+}
+
static inline void ref_tracker_dir_exit(struct ref_tracker_dir *dir)
{
}
diff --git a/lib/ref_tracker.c b/lib/ref_tracker.c
index 73b606570cce9e551d13e65365a87dc4ce748b13..4f1c4fe5e6b1274b6aeb733a3f8c06d1dff003f5 100644
--- a/lib/ref_tracker.c
+++ b/lib/ref_tracker.c
@@ -29,6 +29,35 @@ struct ref_tracker_dir_stats {
} stacks[];
};
+#ifdef CONFIG_DEBUG_FS
+#include <linux/xarray.h>
+
+/*
+ * ref_tracker_dir_init() is usually called in allocation-safe contexts, but
+ * the same is not true of ref_tracker_dir_exit() which can be called from
+ * anywhere an object is freed. Removing debugfs dentries is a blocking
+ * operation, so we defer that work to the debugfs_reap_worker.
+ *
+ * Each dentry is tracked in the appropriate xarray. When
+ * ref_tracker_dir_exit() is called, its entries in the xarrays are marked and
+ * the workqueue job is scheduled. The worker then runs and deletes any marked
+ * dentries asynchronously.
+ */
+static struct xarray debugfs_dentries;
+static struct work_struct debugfs_reap_worker;
+
+#define REF_TRACKER_DIR_DEAD XA_MARK_0
+static inline void ref_tracker_debugfs_mark(struct ref_tracker_dir *dir)
+{
+ xa_set_mark(&debugfs_dentries, (unsigned long)dir, REF_TRACKER_DIR_DEAD);
+ schedule_work(&debugfs_reap_worker);
+}
+#else
+static inline void ref_tracker_debugfs_mark(struct ref_tracker_dir *dir)
+{
+}
+#endif
+
static struct ref_tracker_dir_stats *
ref_tracker_get_stats(struct ref_tracker_dir *dir, unsigned int limit)
{
@@ -185,6 +214,11 @@ void ref_tracker_dir_exit(struct ref_tracker_dir *dir)
bool leak = false;
dir->dead = true;
+ /*
+ * The xarray entries must be marked before the dir->lock is taken to
+ * protect simultaneous debugfs readers.
+ */
+ ref_tracker_debugfs_mark(dir);
spin_lock_irqsave(&dir->lock, flags);
list_for_each_entry_safe(tracker, n, &dir->quarantine, head) {
list_del(&tracker->head);
@@ -312,23 +346,126 @@ static void __ostream_printf pr_ostream_seq(struct ostream *stream, char *fmt, .
va_end(args);
}
-static __maybe_unused int
-ref_tracker_dir_seq_print(struct ref_tracker_dir *dir, struct seq_file *seq)
+static int ref_tracker_dir_seq_print(struct ref_tracker_dir *dir, struct seq_file *seq)
{
struct ostream os = { .func = pr_ostream_seq,
.prefix = "",
.seq = seq };
- unsigned long flags;
- spin_lock_irqsave(&dir->lock, flags);
__ref_tracker_dir_pr_ostream(dir, 16, &os);
- spin_unlock_irqrestore(&dir->lock, flags);
return os.used;
}
+static int ref_tracker_debugfs_show(struct seq_file *f, void *v)
+{
+ struct ref_tracker_dir *dir = f->private;
+ unsigned long index = (unsigned long)dir;
+ unsigned long flags;
+ int ret;
+
+ /*
+ * "dir" may not exist at this point if ref_tracker_dir_exit() has
+ * already been called. Take care not to dereference it until its
+ * legitimacy is established.
+ *
+ * The xa_lock is necessary to ensure that "dir" doesn't disappear
+ * before its lock can be taken. If it's in the hash and not marked
+ * dead, then it's safe to take dir->lock which prevents
+ * ref_tracker_dir_exit() from completing. Once the dir->lock is
+ * acquired, the xa_lock can be released. All of this must be IRQ-safe.
+ */
+ xa_lock_irqsave(&debugfs_dentries, flags);
+ if (!xa_load(&debugfs_dentries, index) ||
+ xa_get_mark(&debugfs_dentries, index, REF_TRACKER_DIR_DEAD)) {
+ xa_unlock_irqrestore(&debugfs_dentries, flags);
+ return -ENODATA;
+ }
+
+ spin_lock(&dir->lock);
+ xa_unlock(&debugfs_dentries);
+ ret = ref_tracker_dir_seq_print(dir, f);
+ spin_unlock_irqrestore(&dir->lock, flags);
+ return ret;
+}
+
+static int ref_tracker_debugfs_open(struct inode *inode, struct file *filp)
+{
+ struct ref_tracker_dir *dir = inode->i_private;
+
+ return single_open(filp, ref_tracker_debugfs_show, dir);
+}
+
+static const struct file_operations ref_tracker_debugfs_fops = {
+ .owner = THIS_MODULE,
+ .open = ref_tracker_debugfs_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+/**
+ * ref_tracker_dir_debugfs - create debugfs file for ref_tracker_dir
+ * @dir: ref_tracker_dir to be associated with debugfs file
+ *
+ * In most cases, a debugfs file will be created automatically for every
+ * ref_tracker_dir. If the object was created before debugfs is brought up
+ * then that may fail. In those cases, it is safe to call this at a later
+ * time to create the file.
+ */
+void ref_tracker_dir_debugfs(struct ref_tracker_dir *dir)
+{
+ char name[NAME_MAX + 1];
+ struct dentry *dentry;
+ int ret;
+
+ /* No-op if already created */
+ dentry = xa_load(&debugfs_dentries, (unsigned long)dir);
+ if (dentry && !xa_is_err(dentry))
+ return;
+
+ ret = snprintf(name, sizeof(name), "%s@%px", dir->class, dir);
+ name[sizeof(name) - 1] = '\0';
+
+ if (ret < sizeof(name)) {
+ dentry = debugfs_create_file(name, S_IFREG | 0400,
+ ref_tracker_debug_dir, dir,
+ &ref_tracker_debugfs_fops);
+ if (!IS_ERR(dentry)) {
+ void *old;
+
+ old = xa_store(&debugfs_dentries, (unsigned long)dir,
+ dentry, GFP_KERNEL);
+
+ if (xa_is_err(old))
+ debugfs_remove(dentry);
+ else
+ WARN_ON_ONCE(old);
+ }
+ }
+}
+EXPORT_SYMBOL(ref_tracker_dir_debugfs);
+
+static void debugfs_reap_work(struct work_struct *work)
+{
+ struct dentry *dentry;
+ unsigned long index;
+ bool reaped;
+
+ do {
+ reaped = false;
+ xa_for_each_marked(&debugfs_dentries, index, dentry, REF_TRACKER_DIR_DEAD) {
+ xa_erase(&debugfs_dentries, index);
+ debugfs_remove(dentry);
+ reaped = true;
+ }
+ } while (reaped);
+}
+
static int __init ref_tracker_debugfs_init(void)
{
+ INIT_WORK(&debugfs_reap_worker, debugfs_reap_work);
+ xa_init_flags(&debugfs_dentries, XA_FLAGS_LOCK_IRQ);
ref_tracker_debug_dir = debugfs_create_dir("ref_tracker", NULL);
return 0;
}
--
2.49.0
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH v14 7/9] ref_tracker: add a way to create a symlink to the ref_tracker_dir debugfs file
2025-06-10 14:59 [PATCH v14 0/9] ref_tracker: add ability to register a debugfs file for a ref_tracker_dir Jeff Layton
` (5 preceding siblings ...)
2025-06-10 14:59 ` [PATCH v14 6/9] ref_tracker: automatically register a file in debugfs for a ref_tracker_dir Jeff Layton
@ 2025-06-10 14:59 ` Jeff Layton
2025-06-10 14:59 ` [PATCH v14 8/9] net: add symlinks to ref_tracker_dir for netns Jeff Layton
` (2 subsequent siblings)
9 siblings, 0 replies; 15+ messages in thread
From: Jeff Layton @ 2025-06-10 14:59 UTC (permalink / raw)
To: Andrew Morton, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Simon Horman, Maarten Lankhorst, Maxime Ripard,
Thomas Zimmermann, David Airlie, Simona Vetter, Jani Nikula,
Joonas Lahtinen, Rodrigo Vivi, Tvrtko Ursulin
Cc: Krzysztof Karas, Kuniyuki Iwashima, Qasim Ijaz, Nathan Chancellor,
Andrew Lunn, linux-kernel, netdev, dri-devel, intel-gfx,
Jeff Layton
Add the ability for a subsystem to add a user-friendly symlink that
points to a ref_tracker_dir's debugfs file. Add a separate
debugfs_symlinks xarray and use that to track symlinks. The reaper
workqueue job will remove symlinks before their corresponding dentries.
Signed-off-by: Jeff Layton <jlayton@kernel.org>
---
include/linux/ref_tracker.h | 11 +++++++++++
lib/ref_tracker.c | 47 +++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 58 insertions(+)
diff --git a/include/linux/ref_tracker.h b/include/linux/ref_tracker.h
index 28bbf436a8f4646cfac181d618195a9460bda196..e1323de93bf6b891aa14ad8d9b4b28d02e10f9f7 100644
--- a/include/linux/ref_tracker.h
+++ b/include/linux/ref_tracker.h
@@ -29,6 +29,7 @@ struct ref_tracker_dir {
#ifdef CONFIG_DEBUG_FS
void ref_tracker_dir_debugfs(struct ref_tracker_dir *dir);
+void ref_tracker_dir_symlink(struct ref_tracker_dir *dir, const char *fmt, ...);
#else /* CONFIG_DEBUG_FS */
@@ -36,6 +37,11 @@ static inline void ref_tracker_dir_debugfs(struct ref_tracker_dir *dir)
{
}
+static inline __ostream_printf
+void ref_tracker_dir_symlink(struct ref_tracker_dir *dir, const char *fmt, ...)
+{
+}
+
#endif /* CONFIG_DEBUG_FS */
static inline void ref_tracker_dir_init(struct ref_tracker_dir *dir,
@@ -85,6 +91,11 @@ static inline void ref_tracker_dir_debugfs(struct ref_tracker_dir *dir)
{
}
+static inline __ostream_printf
+void ref_tracker_dir_symlink(struct ref_tracker_dir *dir, const char *fmt, ...)
+{
+}
+
static inline void ref_tracker_dir_exit(struct ref_tracker_dir *dir)
{
}
diff --git a/lib/ref_tracker.c b/lib/ref_tracker.c
index 4f1c4fe5e6b1274b6aeb733a3f8c06d1dff003f5..a78741308a2c2dc7aff65519970ad081b59e0de5 100644
--- a/lib/ref_tracker.c
+++ b/lib/ref_tracker.c
@@ -44,11 +44,13 @@ struct ref_tracker_dir_stats {
* dentries asynchronously.
*/
static struct xarray debugfs_dentries;
+static struct xarray debugfs_symlinks;
static struct work_struct debugfs_reap_worker;
#define REF_TRACKER_DIR_DEAD XA_MARK_0
static inline void ref_tracker_debugfs_mark(struct ref_tracker_dir *dir)
{
+ xa_set_mark(&debugfs_symlinks, (unsigned long)dir, REF_TRACKER_DIR_DEAD);
xa_set_mark(&debugfs_dentries, (unsigned long)dir, REF_TRACKER_DIR_DEAD);
schedule_work(&debugfs_reap_worker);
}
@@ -446,6 +448,45 @@ void ref_tracker_dir_debugfs(struct ref_tracker_dir *dir)
}
EXPORT_SYMBOL(ref_tracker_dir_debugfs);
+void __ostream_printf ref_tracker_dir_symlink(struct ref_tracker_dir *dir, const char *fmt, ...)
+{
+ char name[NAME_MAX + 1];
+ struct dentry *symlink, *dentry;
+ va_list args;
+ int ret;
+
+ symlink = xa_load(&debugfs_symlinks, (unsigned long)dir);
+ dentry = xa_load(&debugfs_dentries, (unsigned long)dir);
+
+ /* Already created?*/
+ if (symlink && !xa_is_err(symlink))
+ return;
+
+ if (!dentry || xa_is_err(dentry))
+ return;
+
+ va_start(args, fmt);
+ ret = vsnprintf(name, sizeof(name), fmt, args);
+ va_end(args);
+ name[sizeof(name) - 1] = '\0';
+
+ if (ret < sizeof(name)) {
+ symlink = debugfs_create_symlink(name, ref_tracker_debug_dir,
+ dentry->d_name.name);
+ if (!IS_ERR(symlink)) {
+ void *old;
+
+ old = xa_store(&debugfs_symlinks, (unsigned long)dir,
+ symlink, GFP_KERNEL);
+ if (xa_is_err(old))
+ debugfs_remove(symlink);
+ else
+ WARN_ON_ONCE(old);
+ }
+ }
+}
+EXPORT_SYMBOL(ref_tracker_dir_symlink);
+
static void debugfs_reap_work(struct work_struct *work)
{
struct dentry *dentry;
@@ -454,6 +495,11 @@ static void debugfs_reap_work(struct work_struct *work)
do {
reaped = false;
+ xa_for_each_marked(&debugfs_symlinks, index, dentry, REF_TRACKER_DIR_DEAD) {
+ xa_erase(&debugfs_symlinks, index);
+ debugfs_remove(dentry);
+ reaped = true;
+ }
xa_for_each_marked(&debugfs_dentries, index, dentry, REF_TRACKER_DIR_DEAD) {
xa_erase(&debugfs_dentries, index);
debugfs_remove(dentry);
@@ -466,6 +512,7 @@ static int __init ref_tracker_debugfs_init(void)
{
INIT_WORK(&debugfs_reap_worker, debugfs_reap_work);
xa_init_flags(&debugfs_dentries, XA_FLAGS_LOCK_IRQ);
+ xa_init_flags(&debugfs_symlinks, XA_FLAGS_LOCK_IRQ);
ref_tracker_debug_dir = debugfs_create_dir("ref_tracker", NULL);
return 0;
}
--
2.49.0
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH v14 8/9] net: add symlinks to ref_tracker_dir for netns
2025-06-10 14:59 [PATCH v14 0/9] ref_tracker: add ability to register a debugfs file for a ref_tracker_dir Jeff Layton
` (6 preceding siblings ...)
2025-06-10 14:59 ` [PATCH v14 7/9] ref_tracker: add a way to create a symlink to the ref_tracker_dir debugfs file Jeff Layton
@ 2025-06-10 14:59 ` Jeff Layton
2025-06-10 14:59 ` [PATCH v14 9/9] ref_tracker: eliminate the ref_tracker_dir name field Jeff Layton
2025-06-11 14:15 ` [PATCH v14 0/9] ref_tracker: add ability to register a debugfs file for a ref_tracker_dir Jakub Kicinski
9 siblings, 0 replies; 15+ messages in thread
From: Jeff Layton @ 2025-06-10 14:59 UTC (permalink / raw)
To: Andrew Morton, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Simon Horman, Maarten Lankhorst, Maxime Ripard,
Thomas Zimmermann, David Airlie, Simona Vetter, Jani Nikula,
Joonas Lahtinen, Rodrigo Vivi, Tvrtko Ursulin
Cc: Krzysztof Karas, Kuniyuki Iwashima, Qasim Ijaz, Nathan Chancellor,
Andrew Lunn, linux-kernel, netdev, dri-devel, intel-gfx,
Jeff Layton
After assigning the inode number to the namespace, use it to create a
unique name for each netns refcount tracker with the ns.inum and
net_cookie values in it, and register a symlink to the debugfs file for
it.
init_net is registered before the ref_tracker dir is created, so add a
late_initcall() to register its files and symlinks.
Signed-off-by: Jeff Layton <jlayton@kernel.org>
---
net/core/net_namespace.c | 30 +++++++++++++++++++++++++++++-
1 file changed, 29 insertions(+), 1 deletion(-)
diff --git a/net/core/net_namespace.c b/net/core/net_namespace.c
index aa1e34181ed6f353921a23411fa227b612db661a..45de05d8f0877a4e717bdad4ed776ae27f98944a 100644
--- a/net/core/net_namespace.c
+++ b/net/core/net_namespace.c
@@ -791,12 +791,40 @@ struct net *get_net_ns_by_pid(pid_t pid)
}
EXPORT_SYMBOL_GPL(get_net_ns_by_pid);
+#ifdef CONFIG_NET_NS_REFCNT_TRACKER
+static void net_ns_net_debugfs(struct net *net)
+{
+ ref_tracker_dir_symlink(&net->refcnt_tracker, "netns-%llx-%u-refcnt",
+ net->net_cookie, net->ns.inum);
+ ref_tracker_dir_symlink(&net->notrefcnt_tracker, "netns-%llx-%u-notrefcnt",
+ net->net_cookie, net->ns.inum);
+}
+
+static int __init init_net_debugfs(void)
+{
+ ref_tracker_dir_debugfs(&init_net.refcnt_tracker);
+ ref_tracker_dir_debugfs(&init_net.notrefcnt_tracker);
+ net_ns_net_debugfs(&init_net);
+ return 0;
+}
+late_initcall(init_net_debugfs);
+#else
+static void net_ns_net_debugfs(struct net *net)
+{
+}
+#endif
+
static __net_init int net_ns_net_init(struct net *net)
{
+ int ret;
+
#ifdef CONFIG_NET_NS
net->ns.ops = &netns_operations;
#endif
- return ns_alloc_inum(&net->ns);
+ ret = ns_alloc_inum(&net->ns);
+ if (!ret)
+ net_ns_net_debugfs(net);
+ return ret;
}
static __net_exit void net_ns_net_exit(struct net *net)
--
2.49.0
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH v14 9/9] ref_tracker: eliminate the ref_tracker_dir name field
2025-06-10 14:59 [PATCH v14 0/9] ref_tracker: add ability to register a debugfs file for a ref_tracker_dir Jeff Layton
` (7 preceding siblings ...)
2025-06-10 14:59 ` [PATCH v14 8/9] net: add symlinks to ref_tracker_dir for netns Jeff Layton
@ 2025-06-10 14:59 ` Jeff Layton
2025-06-11 14:15 ` [PATCH v14 0/9] ref_tracker: add ability to register a debugfs file for a ref_tracker_dir Jakub Kicinski
9 siblings, 0 replies; 15+ messages in thread
From: Jeff Layton @ 2025-06-10 14:59 UTC (permalink / raw)
To: Andrew Morton, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Simon Horman, Maarten Lankhorst, Maxime Ripard,
Thomas Zimmermann, David Airlie, Simona Vetter, Jani Nikula,
Joonas Lahtinen, Rodrigo Vivi, Tvrtko Ursulin
Cc: Krzysztof Karas, Kuniyuki Iwashima, Qasim Ijaz, Nathan Chancellor,
Andrew Lunn, linux-kernel, netdev, dri-devel, intel-gfx,
Jeff Layton
Now that we have dentries and the ability to create meaningful symlinks
to them, don't keep a name string in each tracker. Switch the output
format to print "class@address", and drop the name field.
Also, add a kerneldoc header for ref_tracker_dir_init().
Signed-off-by: Jeff Layton <jlayton@kernel.org>
---
drivers/gpu/drm/display/drm_dp_tunnel.c | 2 +-
drivers/gpu/drm/i915/intel_runtime_pm.c | 2 +-
drivers/gpu/drm/i915/intel_wakeref.c | 2 +-
include/linux/ref_tracker.h | 20 ++++++++++++++------
lib/ref_tracker.c | 6 +++---
lib/test_ref_tracker.c | 2 +-
net/core/dev.c | 2 +-
net/core/net_namespace.c | 4 ++--
8 files changed, 24 insertions(+), 16 deletions(-)
diff --git a/drivers/gpu/drm/display/drm_dp_tunnel.c b/drivers/gpu/drm/display/drm_dp_tunnel.c
index b9c12b8bf2a3e400b6d8e9d184145834c603b9e1..1205a4432eb4142344fb6eed1cb5ba5b21ec6953 100644
--- a/drivers/gpu/drm/display/drm_dp_tunnel.c
+++ b/drivers/gpu/drm/display/drm_dp_tunnel.c
@@ -1920,7 +1920,7 @@ drm_dp_tunnel_mgr_create(struct drm_device *dev, int max_group_count)
}
#ifdef CONFIG_DRM_DISPLAY_DP_TUNNEL_STATE_DEBUG
- ref_tracker_dir_init(&mgr->ref_tracker, 16, "drm_dptun", "dptun");
+ ref_tracker_dir_init(&mgr->ref_tracker, 16, "drm_dptun");
#endif
for (i = 0; i < max_group_count; i++) {
diff --git a/drivers/gpu/drm/i915/intel_runtime_pm.c b/drivers/gpu/drm/i915/intel_runtime_pm.c
index 90d90145a1890bf788e789858ddad3b3d8e3b978..7ce3e6de0c1970697e0e58198e1e3852975ee7bc 100644
--- a/drivers/gpu/drm/i915/intel_runtime_pm.c
+++ b/drivers/gpu/drm/i915/intel_runtime_pm.c
@@ -61,7 +61,7 @@ static void init_intel_runtime_pm_wakeref(struct intel_runtime_pm *rpm)
{
if (!rpm->debug.class)
ref_tracker_dir_init(&rpm->debug, INTEL_REFTRACK_DEAD_COUNT,
- "intel_runtime_pm", dev_name(rpm->kdev));
+ "intel_runtime_pm");
}
static intel_wakeref_t
diff --git a/drivers/gpu/drm/i915/intel_wakeref.c b/drivers/gpu/drm/i915/intel_wakeref.c
index 21dcee7c9a659ac1fb0aa19f3018647be3bda754..080535fc71d8c25dcc848eefd063361bbe21b305 100644
--- a/drivers/gpu/drm/i915/intel_wakeref.c
+++ b/drivers/gpu/drm/i915/intel_wakeref.c
@@ -115,7 +115,7 @@ void __intel_wakeref_init(struct intel_wakeref *wf,
#if IS_ENABLED(CONFIG_DRM_I915_DEBUG_WAKEREF)
if (!wf->debug.class)
- ref_tracker_dir_init(&wf->debug, INTEL_REFTRACK_DEAD_COUNT, "intel_wakeref", name);
+ ref_tracker_dir_init(&wf->debug, INTEL_REFTRACK_DEAD_COUNT, "intel_wakeref");
#endif
}
diff --git a/include/linux/ref_tracker.h b/include/linux/ref_tracker.h
index e1323de93bf6b891aa14ad8d9b4b28d02e10f9f7..d10563afd91c0c551e08896fa5354e0a5894ba7c 100644
--- a/include/linux/ref_tracker.h
+++ b/include/linux/ref_tracker.h
@@ -20,7 +20,6 @@ struct ref_tracker_dir {
struct list_head list; /* List of active trackers */
struct list_head quarantine; /* List of dead trackers */
const char *class; /* object classname */
- char name[32];
#endif
};
@@ -44,10 +43,21 @@ void ref_tracker_dir_symlink(struct ref_tracker_dir *dir, const char *fmt, ...)
#endif /* CONFIG_DEBUG_FS */
+/**
+ * ref_tracker_dir_init - initialize a ref_tracker dir
+ * @dir: ref_tracker_dir to be initialized
+ * @quarantine_count: max number of entries to be tracked
+ * @class: pointer to static string that describes object type
+ *
+ * Initialize a ref_tracker_dir. If debugfs is configured, then a file
+ * will also be created for it under the top-level ref_tracker debugfs
+ * directory.
+ *
+ * Note that @class must point to a static string.
+ */
static inline void ref_tracker_dir_init(struct ref_tracker_dir *dir,
unsigned int quarantine_count,
- const char *class,
- const char *name)
+ const char *class)
{
INIT_LIST_HEAD(&dir->list);
INIT_LIST_HEAD(&dir->quarantine);
@@ -57,7 +67,6 @@ static inline void ref_tracker_dir_init(struct ref_tracker_dir *dir,
refcount_set(&dir->untracked, 1);
refcount_set(&dir->no_tracker, 1);
dir->class = class;
- strscpy(dir->name, name, sizeof(dir->name));
ref_tracker_dir_debugfs(dir);
stack_depot_init();
}
@@ -82,8 +91,7 @@ int ref_tracker_free(struct ref_tracker_dir *dir,
static inline void ref_tracker_dir_init(struct ref_tracker_dir *dir,
unsigned int quarantine_count,
- const char *class,
- const char *name)
+ const char *class)
{
}
diff --git a/lib/ref_tracker.c b/lib/ref_tracker.c
index a78741308a2c2dc7aff65519970ad081b59e0de5..39f8e931680a0b84cd7a8588db659bfe2b348821 100644
--- a/lib/ref_tracker.c
+++ b/lib/ref_tracker.c
@@ -147,7 +147,7 @@ __ref_tracker_dir_pr_ostream(struct ref_tracker_dir *dir,
stats = ref_tracker_get_stats(dir, display_limit);
if (IS_ERR(stats)) {
pr_ostream(s, "%s%s@%p: couldn't get stats, error %pe\n",
- s->prefix, dir->name, dir, stats);
+ s->prefix, dir->class, dir, stats);
return;
}
@@ -158,14 +158,14 @@ __ref_tracker_dir_pr_ostream(struct ref_tracker_dir *dir,
if (sbuf && !stack_depot_snprint(stack, sbuf, STACK_BUF_SIZE, 4))
sbuf[0] = 0;
pr_ostream(s, "%s%s@%p has %d/%d users at\n%s\n", s->prefix,
- dir->name, dir, stats->stacks[i].count,
+ dir->class, dir, stats->stacks[i].count,
stats->total, sbuf);
skipped -= stats->stacks[i].count;
}
if (skipped)
pr_ostream(s, "%s%s@%p skipped reports about %d/%d users.\n",
- s->prefix, dir->name, dir, skipped, stats->total);
+ s->prefix, dir->class, dir, skipped, stats->total);
kfree(sbuf);
diff --git a/lib/test_ref_tracker.c b/lib/test_ref_tracker.c
index d263502a4c1db248f64a66a468e96c8e4cffab25..b983ceb12afcb84ad60360a1e6fec0072e78ef79 100644
--- a/lib/test_ref_tracker.c
+++ b/lib/test_ref_tracker.c
@@ -64,7 +64,7 @@ static int __init test_ref_tracker_init(void)
{
int i;
- ref_tracker_dir_init(&ref_dir, 100, "selftest", "selftest");
+ ref_tracker_dir_init(&ref_dir, 100, "selftest");
timer_setup(&test_ref_tracker_timer, test_ref_tracker_timer_func, 0);
mod_timer(&test_ref_tracker_timer, jiffies + 1);
diff --git a/net/core/dev.c b/net/core/dev.c
index 12cf4e5ae9c5437bcfec657e37b7e08792bc14bf..92a830162dd8f9e311d31e5285e394b0e9f20d42 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -11715,7 +11715,7 @@ struct net_device *alloc_netdev_mqs(int sizeof_priv, const char *name,
dev->priv_len = sizeof_priv;
- ref_tracker_dir_init(&dev->refcnt_tracker, 128, "netdev", name);
+ ref_tracker_dir_init(&dev->refcnt_tracker, 128, "netdev");
#ifdef CONFIG_PCPU_DEV_REFCNT
dev->pcpu_refcnt = alloc_percpu(int);
if (!dev->pcpu_refcnt)
diff --git a/net/core/net_namespace.c b/net/core/net_namespace.c
index 45de05d8f0877a4e717bdad4ed776ae27f98944a..d0f607507ee8d0b6d31f11a49421b5f0a985bd3b 100644
--- a/net/core/net_namespace.c
+++ b/net/core/net_namespace.c
@@ -403,8 +403,8 @@ static __net_init void preinit_net(struct net *net, struct user_namespace *user_
{
refcount_set(&net->passive, 1);
refcount_set(&net->ns.count, 1);
- ref_tracker_dir_init(&net->refcnt_tracker, 128, "net_refcnt", "net_refcnt");
- ref_tracker_dir_init(&net->notrefcnt_tracker, 128, "net_notrefcnt", "net_notrefcnt");
+ ref_tracker_dir_init(&net->refcnt_tracker, 128, "net_refcnt");
+ ref_tracker_dir_init(&net->notrefcnt_tracker, 128, "net_notrefcnt");
get_random_bytes(&net->hash_mix, sizeof(u32));
net->dev_base_seq = 1;
--
2.49.0
^ permalink raw reply related [flat|nested] 15+ messages in thread
* Re: [PATCH v14 3/9] ref_tracker: have callers pass output function to pr_ostream()
2025-06-10 14:59 ` [PATCH v14 3/9] ref_tracker: have callers pass output function to pr_ostream() Jeff Layton
@ 2025-06-11 9:42 ` Krzysztof Karas
0 siblings, 0 replies; 15+ messages in thread
From: Krzysztof Karas @ 2025-06-11 9:42 UTC (permalink / raw)
To: Jeff Layton
Cc: Andrew Morton, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Simon Horman, Maarten Lankhorst, Maxime Ripard,
Thomas Zimmermann, David Airlie, Simona Vetter, Jani Nikula,
Joonas Lahtinen, Rodrigo Vivi, Tvrtko Ursulin, Kuniyuki Iwashima,
Qasim Ijaz, Nathan Chancellor, Andrew Lunn, linux-kernel, netdev,
dri-devel, intel-gfx
Hi Jeff,
> In a later patch, we'll be adding a 3rd mechanism for outputting
> ref_tracker info via seq_file. Instead of a conditional, have the caller
> set a pointer to an output function in struct ostream. As part of this,
> the log prefix must be explicitly passed in, as it's too late for the
> pr_fmt macro.
>
> Reviewed-by: Andrew Lunn <andrew@lunn.ch>
> Signed-off-by: Jeff Layton <jlayton@kernel.org>
> ---
Looks good:
Reviewed-by: Krzysztof Karas <krzysztof.karas@intel.com>
Best Regards,
Krzysztof
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH v14 4/9] ref_tracker: add a static classname string to each ref_tracker_dir
2025-06-10 14:59 ` [PATCH v14 4/9] ref_tracker: add a static classname string to each ref_tracker_dir Jeff Layton
@ 2025-06-11 10:32 ` Krzysztof Karas
0 siblings, 0 replies; 15+ messages in thread
From: Krzysztof Karas @ 2025-06-11 10:32 UTC (permalink / raw)
To: Jeff Layton
Cc: Andrew Morton, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Simon Horman, Maarten Lankhorst, Maxime Ripard,
Thomas Zimmermann, David Airlie, Simona Vetter, Jani Nikula,
Joonas Lahtinen, Rodrigo Vivi, Tvrtko Ursulin, Kuniyuki Iwashima,
Qasim Ijaz, Nathan Chancellor, Andrew Lunn, linux-kernel, netdev,
dri-devel, intel-gfx
Hi Jeff,
> A later patch in the series will be adding debugfs files for each
> ref_tracker that get created in ref_tracker_dir_init(). The format will
> be "class@%px". The current "name" string can vary between
> ref_tracker_dir objects of the same type, so it's not suitable for this
> purpose.
>
> Add a new "class" string to the ref_tracker dir that describes the
> the type of object (sans any individual info for that object).
>
> Also, in the i915 driver, gate the creation of debugfs files on whether
> the dentry pointer is still set to NULL. CI has shown that the
> ref_tracker_dir can be initialized more than once.
>
> Signed-off-by: Jeff Layton <jlayton@kernel.org>
> ---
Looks good:
Reviewed-by: Krzysztof Karas <krzysztof.karas@intel.com>
A side note:
I was wondering if we could improve naming a bit, but I think it
is not worth the effort. Names like "dptun" instead of
"dp_tunnel" and including "wakeref" only in
__intel_wakeref_init() but not in init_intel_runtime_pm_wakeref()
in "intel_runtime_pm" string stand out, but it is quite clear
what these names mean, so I added my r-b.
Best Regards,
Krzysztof
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH v14 5/9] ref_tracker: allow pr_ostream() to print directly to a seq_file
2025-06-10 14:59 ` [PATCH v14 5/9] ref_tracker: allow pr_ostream() to print directly to a seq_file Jeff Layton
@ 2025-06-11 10:52 ` Krzysztof Karas
0 siblings, 0 replies; 15+ messages in thread
From: Krzysztof Karas @ 2025-06-11 10:52 UTC (permalink / raw)
To: Jeff Layton
Cc: Andrew Morton, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Simon Horman, Maarten Lankhorst, Maxime Ripard,
Thomas Zimmermann, David Airlie, Simona Vetter, Jani Nikula,
Joonas Lahtinen, Rodrigo Vivi, Tvrtko Ursulin, Kuniyuki Iwashima,
Qasim Ijaz, Nathan Chancellor, Andrew Lunn, linux-kernel, netdev,
dri-devel, intel-gfx
Hi Jeff,
> Allow pr_ostream to also output directly to a seq_file without an
> intermediate buffer. The first caller of +ref_tracker_dir_seq_print()
> will come in a later patch, so mark that __maybe_unused for now. That
> designation will be removed once it is used.
>
> Reviewed-by: Andrew Lunn <andrew@lunn.ch>
> Signed-off-by: Jeff Layton <jlayton@kernel.org>
> ---
Reviewed-by: Krzysztof Karas <krzysztof.karas@intel.com>
Best Regards,
Krzysztof
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH v14 0/9] ref_tracker: add ability to register a debugfs file for a ref_tracker_dir
2025-06-10 14:59 [PATCH v14 0/9] ref_tracker: add ability to register a debugfs file for a ref_tracker_dir Jeff Layton
` (8 preceding siblings ...)
2025-06-10 14:59 ` [PATCH v14 9/9] ref_tracker: eliminate the ref_tracker_dir name field Jeff Layton
@ 2025-06-11 14:15 ` Jakub Kicinski
9 siblings, 0 replies; 15+ messages in thread
From: Jakub Kicinski @ 2025-06-11 14:15 UTC (permalink / raw)
To: Jeff Layton
Cc: Andrew Morton, David S. Miller, Eric Dumazet, Paolo Abeni,
Simon Horman, Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
David Airlie, Simona Vetter, Jani Nikula, Joonas Lahtinen,
Rodrigo Vivi, Tvrtko Ursulin, Krzysztof Karas, Kuniyuki Iwashima,
Qasim Ijaz, Nathan Chancellor, Andrew Lunn, linux-kernel, netdev,
dri-devel, intel-gfx, Thomas Weißschuh
On Tue, 10 Jun 2025 10:59:20 -0400 Jeff Layton wrote:
> For those just joining in, this series adds a new top-level
> "ref_tracker" debugfs directory, and has each ref_tracker_dir register a
> file in there as part of its initialization. It also adds the ability to
> register a symlink with a more human-usable name that points to the
> file, and does some general cleanup of how the ref_tracker object names
> are handled.
Still has the lockdep problem. Please triple check that it's fixed
before you post next version, the number of warnings this series
generates is quite burdensome for our CI.
[ 440.139336][ C1] ================================
[ 440.139684][ C1] WARNING: inconsistent lock state
[ 440.140019][ C1] 6.15.0-virtme #1 Not tainted
[ 440.140360][ C1] --------------------------------
[ 440.140705][ C1] inconsistent {SOFTIRQ-ON-W} -> {IN-SOFTIRQ-W} usage.
[ 440.141124][ C1] ksoftirqd/1/22 [HC0[0]:SC1[1]:HE1:SE0] takes:
[ 440.141541][ C1] ffffffffad243218 (&xa->xa_lock#8){+.?.}-{3:3}, at: xa_set_mark+0x73/0x120
[ 440.142146][ C1] {SOFTIRQ-ON-W} state was registered at:
[ 440.142485][ C1] __lock_acquire+0x20b/0x7e0
[ 440.142832][ C1] lock_acquire.part.0+0xb6/0x240
[ 440.143181][ C1] _raw_spin_lock+0x33/0x40
[ 440.143521][ C1] xa_store+0x1c/0x50
[ 440.143784][ C1] ref_tracker_dir_debugfs+0x168/0x1b0
[ 440.144137][ C1] init_net_debugfs+0x15/0x70
[ 440.144480][ C1] do_one_initcall+0x8c/0x1e0
[ 440.144845][ C1] do_initcalls+0x176/0x280
[ 440.145184][ C1] kernel_init_freeable+0x22d/0x300
[ 440.145530][ C1] kernel_init+0x20/0x200
[ 440.145871][ C1] ret_from_fork+0x240/0x320
[ 440.146205][ C1] ret_from_fork_asm+0x1a/0x30
[ 440.146545][ C1] irq event stamp: 5141102
[ 440.146886][ C1] hardirqs last enabled at (5141102): [<ffffffffa96fa4ed>] _raw_spin_unlock_irqrestore+0x5d/0x80
[ 440.147613][ C1] hardirqs last disabled at (5141101): [<ffffffffa96fa1cb>] _raw_spin_lock_irqsave+0x5b/0x60
[ 440.148283][ C1] softirqs last enabled at (5139838): [<ffffffffa6c8ef18>] handle_softirqs+0x358/0x620
[ 440.148883][ C1] softirqs last disabled at (5139843): [<ffffffffa6c8f41f>] run_ksoftirqd+0x3f/0x70
https://netdev-3.bots.linux.dev/vmksft-mptcp-dbg/results/160722/1-mptcp-join-sh/stderr
https://netdev-3.bots.linux.dev/vmksft-mptcp-dbg/results/160722/vm-crash-thr0-0
--
pw-bot: cr
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH v14 6/9] ref_tracker: automatically register a file in debugfs for a ref_tracker_dir
2025-06-10 14:59 ` [PATCH v14 6/9] ref_tracker: automatically register a file in debugfs for a ref_tracker_dir Jeff Layton
@ 2025-06-17 8:24 ` kernel test robot
0 siblings, 0 replies; 15+ messages in thread
From: kernel test robot @ 2025-06-17 8:24 UTC (permalink / raw)
To: Jeff Layton
Cc: oe-lkp, lkp, linux-kernel, Andrew Morton, David S. Miller,
Eric Dumazet, Jakub Kicinski, Paolo Abeni, Simon Horman,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
Simona Vetter, Jani Nikula, Joonas Lahtinen, Rodrigo Vivi,
Tvrtko Ursulin, Krzysztof Karas, Kuniyuki Iwashima, Qasim Ijaz,
Nathan Chancellor, Andrew Lunn, netdev, dri-devel, intel-gfx,
Jeff Layton, oliver.sang
Hello,
kernel test robot noticed "BUG:spinlock_trylock_failure_on_UP_on_CPU" on:
commit: 1d67742f4a90af28c0f655a9ed8d730459b1f220 ("[PATCH v14 6/9] ref_tracker: automatically register a file in debugfs for a ref_tracker_dir")
url: https://github.com/intel-lab-lkp/linux/commits/Jeff-Layton/ref_tracker-don-t-use-pK-in-pr_ostream-output/20250610-230236
patch link: https://lore.kernel.org/all/20250610-reftrack-dbgfs-v14-6-efb532861428@kernel.org/
patch subject: [PATCH v14 6/9] ref_tracker: automatically register a file in debugfs for a ref_tracker_dir
in testcase: boot
config: i386-randconfig-051-20250611
compiler: clang-20
test machine: qemu-system-i386 -enable-kvm -cpu SandyBridge -smp 2 -m 4G
(please refer to attached dmesg/kmsg for entire log/backtrace)
+---------------------------------------------+------------+------------+
| | ac254e0747 | 1d67742f4a |
+---------------------------------------------+------------+------------+
| BUG:spinlock_trylock_failure_on_UP_on_CPU | 0 | 12 |
| WARNING:at_kernel/workqueue.c:#__queue_work | 0 | 12 |
| EIP:__queue_work | 0 | 12 |
+---------------------------------------------+------------+------------+
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <oliver.sang@intel.com>
| Closes: https://lore.kernel.org/oe-lkp/202506171517.a1e85b6f-lkp@intel.com
[ 13.649422][ T1] BUG: spinlock trylock failure on UP on CPU#0, swapper/1
[ 13.650195][ T1] lock: debugfs_dentries+0x0/0x34, .magic: 00000000, .owner: <none>/-1, .owner_cpu: 0
[ 13.651211][ T1] CPU: 0 UID: 0 PID: 1 Comm: swapper Not tainted 6.15.0-13749-g1d67742f4a90 #1 PREEMPT(undef)
[ 13.652340][ T1] Call Trace:
[ 13.652705][ T1] __dump_stack (lib/dump_stack.c:95)
[ 13.653206][ T1] dump_stack_lvl (lib/dump_stack.c:123)
[ 13.653363][ T1] dump_stack (lib/dump_stack.c:129)
[ 13.653363][ T1] spin_dump (kernel/locking/spinlock_debug.c:71)
[ 13.653363][ T1] do_raw_spin_trylock (kernel/locking/spinlock_debug.c:?)
[ 13.653363][ T1] ? xa_set_mark (lib/xarray.c:2075 lib/xarray.c:2146)
[ 13.653363][ T1] _raw_spin_lock (include/linux/spinlock_api_smp.h:134 kernel/locking/spinlock.c:154)
[ 13.653363][ T1] xa_set_mark (lib/xarray.c:2075 lib/xarray.c:2146)
[ 13.653363][ T1] ref_tracker_dir_exit (include/linux/workqueue.h:723 lib/ref_tracker.c:53 lib/ref_tracker.c:221)
[ 13.653363][ T1] ? kvfree (mm/slub.c:5059)
[ 13.653363][ T1] free_netdev (net/core/dev.c:11880)
[ 13.653363][ T1] free_arcdev (drivers/net/arcnet/arcnet.c:503)
[ 13.653363][ T1] com90io_init (drivers/net/arcnet/com90io.c:401)
[ 13.653363][ T1] do_one_initcall (init/main.c:1273)
[ 13.653363][ T1] ? com90io_setup (drivers/net/arcnet/com90io.c:384)
[ 13.653363][ T1] ? __lock_acquire (kernel/locking/lockdep.c:4677)
[ 13.653363][ T1] ? kvm_sched_clock_read (arch/x86/kernel/kvmclock.c:91)
[ 13.653363][ T1] ? sched_clock_noinstr (arch/x86/kernel/tsc.c:271)
[ 13.653363][ T1] ? local_clock_noinstr (kernel/sched/clock.c:269 kernel/sched/clock.c:306)
[ 13.653363][ T1] ? __lock_acquire (kernel/locking/lockdep.c:4677)
[ 13.653363][ T1] ? local_clock_noinstr (kernel/sched/clock.c:269 kernel/sched/clock.c:306)
[ 13.653363][ T1] ? __this_cpu_preempt_check (lib/smp_processor_id.c:67)
[ 13.653363][ T1] ? kvm_sched_clock_read (arch/x86/kernel/kvmclock.c:91)
[ 13.653363][ T1] ? sched_clock_noinstr (arch/x86/kernel/tsc.c:271)
[ 13.653363][ T1] ? local_clock_noinstr (kernel/sched/clock.c:269 kernel/sched/clock.c:306)
[ 13.653363][ T1] ? __this_cpu_preempt_check (lib/smp_processor_id.c:67)
[ 13.653363][ T1] ? irqtime_account_irq (kernel/sched/cputime.c:?)
[ 13.653363][ T1] ? __this_cpu_preempt_check (lib/smp_processor_id.c:67)
[ 13.653363][ T1] ? lockdep_hardirqs_on (kernel/locking/lockdep.c:4475)
[ 13.653363][ T1] ? trace_hardirqs_on (kernel/trace/trace_preemptirq.c:80)
[ 13.653363][ T1] ? irqentry_exit (kernel/entry/common.c:?)
[ 13.653363][ T1] ? vmware_sched_clock (arch/x86/kernel/apic/apic.c:1050)
[ 13.653363][ T1] ? sysvec_apic_timer_interrupt (arch/x86/kernel/apic/apic.c:1050)
[ 13.653363][ T1] ? handle_exception (arch/x86/entry/entry_32.S:1048)
[ 13.653363][ T1] ? strlen (arch/x86/lib/string_32.c:?)
[ 13.653363][ T1] ? next_arg (lib/cmdline.c:273)
[ 13.653363][ T1] ? parameq (kernel/params.c:90 kernel/params.c:99)
[ 13.653363][ T1] ? parse_args (kernel/params.c:153)
[ 13.653363][ T1] do_initcall_level (init/main.c:1334)
[ 13.653363][ T1] do_initcalls (init/main.c:1348)
[ 13.653363][ T1] do_basic_setup (init/main.c:1371)
[ 13.653363][ T1] kernel_init_freeable (init/main.c:1585)
[ 13.653363][ T1] ? rest_init (init/main.c:1465)
[ 13.653363][ T1] kernel_init (init/main.c:1475)
[ 13.653363][ T1] ret_from_fork (arch/x86/kernel/process.c:154)
[ 13.653363][ T1] ? debug_smp_processor_id (lib/smp_processor_id.c:60)
[ 13.653363][ T1] ? rest_init (init/main.c:1465)
[ 13.653363][ T1] ret_from_fork_asm (arch/x86/entry/entry_32.S:737)
[ 13.653363][ T1] entry_INT80_32 (arch/x86/entry/entry_32.S:945)
[ 13.679093][ T1] ------------[ cut here ]------------
[ 13.679700][ T1] WARNING: CPU: 0 PID: 1 at kernel/workqueue.c:2325 __queue_work (kernel/workqueue.c:2325)
[ 13.680616][ T1] Modules linked in:
[ 13.681057][ T1] CPU: 0 UID: 0 PID: 1 Comm: swapper Not tainted 6.15.0-13749-g1d67742f4a90 #1 PREEMPT(undef)
[ 13.682176][ T1] EIP: __queue_work (kernel/workqueue.c:2325)
[ 13.682700][ T1] Code: 4d ec 8b 40 04 89 45 f0 31 db 39 c8 0f 95 c3 b8 98 9f dd d5 89 da 31 c9 6a 00 e8 d4 de 11 00 83 c4 04 8b 45 ec 39 45 f0 74 1a <0f> 0b b8 b0 9f dd d5 89 da 31 c9 6a 00 e8 b7 de 11 00 83 c4 04 e9
All code
========
0: 4d ec rex.WRB in (%dx),%al
2: 8b 40 04 mov 0x4(%rax),%eax
5: 89 45 f0 mov %eax,-0x10(%rbp)
8: 31 db xor %ebx,%ebx
a: 39 c8 cmp %ecx,%eax
c: 0f 95 c3 setne %bl
f: b8 98 9f dd d5 mov $0xd5dd9f98,%eax
14: 89 da mov %ebx,%edx
16: 31 c9 xor %ecx,%ecx
18: 6a 00 push $0x0
1a: e8 d4 de 11 00 call 0x11def3
1f: 83 c4 04 add $0x4,%esp
22: 8b 45 ec mov -0x14(%rbp),%eax
25: 39 45 f0 cmp %eax,-0x10(%rbp)
28: 74 1a je 0x44
2a:* 0f 0b ud2 <-- trapping instruction
2c: b8 b0 9f dd d5 mov $0xd5dd9fb0,%eax
31: 89 da mov %ebx,%edx
33: 31 c9 xor %ecx,%ecx
35: 6a 00 push $0x0
37: e8 b7 de 11 00 call 0x11def3
3c: 83 c4 04 add $0x4,%esp
3f: e9 .byte 0xe9
Code starting with the faulting instruction
===========================================
0: 0f 0b ud2
2: b8 b0 9f dd d5 mov $0xd5dd9fb0,%eax
7: 89 da mov %ebx,%edx
9: 31 c9 xor %ecx,%ecx
b: 6a 00 push $0x0
d: e8 b7 de 11 00 call 0x11dec9
12: 83 c4 04 add $0x4,%esp
15: e9 .byte 0xe9
[ 13.683052][ T1] EAX: d67dc32c EBX: 00000001 ECX: 00000000 EDX: 00000000
[ 13.683052][ T1] ESI: c0321000 EDI: d576af44 EBP: c03a7b9c ESP: c03a7b7c
[ 13.683052][ T1] DS: 007b ES: 007b FS: 0000 GS: 0000 SS: 0068 EFLAGS: 00010017
[ 13.683052][ T1] CR0: 80050033 CR2: b7ded3d5 CR3: 16086000 CR4: 000406d0
[ 13.683052][ T1] DR0: 00000000 DR1: 00000000 DR2: 00000000 DR3: 00000000
[ 13.683052][ T1] DR6: fffe0ff0 DR7: 00000400
[ 13.683052][ T1] Call Trace:
[ 13.683052][ T1] queue_work_on (kernel/workqueue.c:2392)
[ 13.683052][ T1] ref_tracker_dir_exit (lib/ref_tracker.c:222)
[ 13.683052][ T1] ? kvfree (mm/slub.c:5059)
[ 13.683052][ T1] free_netdev (net/core/dev.c:11880)
[ 13.683052][ T1] free_arcdev (drivers/net/arcnet/arcnet.c:503)
[ 13.683052][ T1] com90io_init (drivers/net/arcnet/com90io.c:401)
[ 13.683052][ T1] do_one_initcall (init/main.c:1273)
[ 13.683052][ T1] ? com90io_setup (drivers/net/arcnet/com90io.c:384)
[ 13.683052][ T1] ? __lock_acquire (kernel/locking/lockdep.c:4677)
[ 13.683052][ T1] ? kvm_sched_clock_read (arch/x86/kernel/kvmclock.c:91)
[ 13.683052][ T1] ? sched_clock_noinstr (arch/x86/kernel/tsc.c:271)
[ 13.683052][ T1] ? local_clock_noinstr (kernel/sched/clock.c:269 kernel/sched/clock.c:306)
[ 13.683052][ T1] ? __lock_acquire (kernel/locking/lockdep.c:4677)
[ 13.683052][ T1] ? local_clock_noinstr (kernel/sched/clock.c:269 kernel/sched/clock.c:306)
[ 13.683052][ T1] ? __this_cpu_preempt_check (lib/smp_processor_id.c:67)
[ 13.683052][ T1] ? kvm_sched_clock_read (arch/x86/kernel/kvmclock.c:91)
[ 13.683052][ T1] ? sched_clock_noinstr (arch/x86/kernel/tsc.c:271)
[ 13.683052][ T1] ? local_clock_noinstr (kernel/sched/clock.c:269 kernel/sched/clock.c:306)
[ 13.683052][ T1] ? __this_cpu_preempt_check (lib/smp_processor_id.c:67)
[ 13.683052][ T1] ? irqtime_account_irq (kernel/sched/cputime.c:?)
[ 13.683052][ T1] ? __this_cpu_preempt_check (lib/smp_processor_id.c:67)
[ 13.683052][ T1] ? lockdep_hardirqs_on (kernel/locking/lockdep.c:4475)
[ 13.683052][ T1] ? trace_hardirqs_on (kernel/trace/trace_preemptirq.c:80)
[ 13.683052][ T1] ? irqentry_exit (kernel/entry/common.c:?)
[ 13.683052][ T1] ? vmware_sched_clock (arch/x86/kernel/apic/apic.c:1050)
[ 13.683052][ T1] ? sysvec_apic_timer_interrupt (arch/x86/kernel/apic/apic.c:1050)
[ 13.683052][ T1] ? handle_exception (arch/x86/entry/entry_32.S:1048)
[ 13.683052][ T1] ? strlen (arch/x86/lib/string_32.c:?)
[ 13.683052][ T1] ? next_arg (lib/cmdline.c:273)
[ 13.683052][ T1] ? parameq (kernel/params.c:90 kernel/params.c:99)
[ 13.683052][ T1] ? parse_args (kernel/params.c:153)
[ 13.683052][ T1] do_initcall_level (init/main.c:1334)
[ 13.683052][ T1] do_initcalls (init/main.c:1348)
[ 13.683052][ T1] do_basic_setup (init/main.c:1371)
[ 13.683052][ T1] kernel_init_freeable (init/main.c:1585)
[ 13.683052][ T1] ? rest_init (init/main.c:1465)
[ 13.683052][ T1] kernel_init (init/main.c:1475)
[ 13.683052][ T1] ret_from_fork (arch/x86/kernel/process.c:154)
[ 13.683052][ T1] ? debug_smp_processor_id (lib/smp_processor_id.c:60)
[ 13.683052][ T1] ? rest_init (init/main.c:1465)
[ 13.683052][ T1] ret_from_fork_asm (arch/x86/entry/entry_32.S:737)
[ 13.683052][ T1] entry_INT80_32 (arch/x86/entry/entry_32.S:945)
[ 13.683052][ T1] irq event stamp: 81333
[ 13.683052][ T1] hardirqs last enabled at (81333): _raw_spin_unlock_irqrestore (arch/x86/include/asm/irqflags.h:19 arch/x86/include/asm/irqflags.h:109 arch/x86/include/asm/irqflags.h:151 include/linux/spinlock_api_smp.h:151 kernel/locking/spinlock.c:194)
[ 13.683052][ T1] hardirqs last disabled at (81332): kvfree_call_rcu (mm/slab_common.c:1443 mm/slab_common.c:1834 mm/slab_common.c:1963)
[ 13.683052][ T1] softirqs last enabled at (80274): handle_softirqs (arch/x86/include/asm/preempt.h:27 kernel/softirq.c:426 kernel/softirq.c:607)
[ 13.683052][ T1] softirqs last disabled at (80265): __do_softirq (kernel/softirq.c:614)
[ 13.683052][ T1] ---[ end trace 0000000000000000 ]---
The kernel config and materials to reproduce are available at:
https://download.01.org/0day-ci/archive/20250617/202506171517.a1e85b6f-lkp@intel.com
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply [flat|nested] 15+ messages in thread
end of thread, other threads:[~2025-06-17 8:25 UTC | newest]
Thread overview: 15+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-06-10 14:59 [PATCH v14 0/9] ref_tracker: add ability to register a debugfs file for a ref_tracker_dir Jeff Layton
2025-06-10 14:59 ` [PATCH v14 1/9] ref_tracker: don't use %pK in pr_ostream() output Jeff Layton
2025-06-10 14:59 ` [PATCH v14 2/9] ref_tracker: add a top level debugfs directory for ref_tracker Jeff Layton
2025-06-10 14:59 ` [PATCH v14 3/9] ref_tracker: have callers pass output function to pr_ostream() Jeff Layton
2025-06-11 9:42 ` Krzysztof Karas
2025-06-10 14:59 ` [PATCH v14 4/9] ref_tracker: add a static classname string to each ref_tracker_dir Jeff Layton
2025-06-11 10:32 ` Krzysztof Karas
2025-06-10 14:59 ` [PATCH v14 5/9] ref_tracker: allow pr_ostream() to print directly to a seq_file Jeff Layton
2025-06-11 10:52 ` Krzysztof Karas
2025-06-10 14:59 ` [PATCH v14 6/9] ref_tracker: automatically register a file in debugfs for a ref_tracker_dir Jeff Layton
2025-06-17 8:24 ` kernel test robot
2025-06-10 14:59 ` [PATCH v14 7/9] ref_tracker: add a way to create a symlink to the ref_tracker_dir debugfs file Jeff Layton
2025-06-10 14:59 ` [PATCH v14 8/9] net: add symlinks to ref_tracker_dir for netns Jeff Layton
2025-06-10 14:59 ` [PATCH v14 9/9] ref_tracker: eliminate the ref_tracker_dir name field Jeff Layton
2025-06-11 14:15 ` [PATCH v14 0/9] ref_tracker: add ability to register a debugfs file for a ref_tracker_dir Jakub Kicinski
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).