[PATCH 2/4] ref_tracker: add ability to register a file in debugfs for a ref_tracker_dir

Jeff Layton posted 4 patches 8 months, 1 week ago
[PATCH 2/4] ref_tracker: add ability to register a file in debugfs for a ref_tracker_dir
Posted by Jeff Layton 8 months, 1 week ago
Currently, there is no convenient way to see the info that the
ref_tracking infrastructure collects. Add a new function that other
subsystems can optionally call to update the name field in the
ref_tracker_dir and register a corresponding seq_file for it in the
top-level ref_tracker directory.

Also, alter the pr_ostream infrastructure to allow the caller to specify
a seq_file to which the output should go instead of printing to an
arbitrary buffer or the kernel's ring buffer.

Signed-off-by: Jeff Layton <jlayton@kernel.org>
---
 include/linux/ref_tracker.h | 13 +++++++
 lib/ref_tracker.c           | 84 +++++++++++++++++++++++++++++++++++++++++++--
 2 files changed, 94 insertions(+), 3 deletions(-)

diff --git a/include/linux/ref_tracker.h b/include/linux/ref_tracker.h
index 8eac4f3d52547ccbaf9dcd09962ce80d26fbdff8..77a55a32c067216fa02ba349498f53bd289aee0c 100644
--- a/include/linux/ref_tracker.h
+++ b/include/linux/ref_tracker.h
@@ -5,6 +5,7 @@
 #include <linux/types.h>
 #include <linux/spinlock.h>
 #include <linux/stackdepot.h>
+#include <linux/seq_file.h>
 
 struct ref_tracker;
 
@@ -17,6 +18,9 @@ struct ref_tracker_dir {
 	bool			dead;
 	struct list_head	list; /* List of active trackers */
 	struct list_head	quarantine; /* List of dead trackers */
+#ifdef CONFIG_DEBUG_FS
+	struct dentry		*dentry;
+#endif
 	char			name[32];
 #endif
 };
@@ -34,10 +38,15 @@ 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);
+#ifdef CONFIG_DEBUG_FS
+	dir->dentry = NULL;
+#endif
 	strscpy(dir->name, name, sizeof(dir->name));
 	stack_depot_init();
 }
 
+void ref_tracker_dir_debugfs(struct ref_tracker_dir *dir, const char *name);
+
 void ref_tracker_dir_exit(struct ref_tracker_dir *dir);
 
 void ref_tracker_dir_print_locked(struct ref_tracker_dir *dir,
@@ -62,6 +71,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, const char *name)
+{
+}
+
 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 c96994134fe1ddfcbf644cc75b36b7e94461ec48..10452f66283b081460ef7f4f5640e30487bb1595 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
@@ -30,6 +31,14 @@ struct ref_tracker_dir_stats {
 	} stacks[];
 };
 
+#ifdef CONFIG_DEBUG_FS
+static void ref_tracker_debugfs_remove(struct ref_tracker_dir *dir);
+#else
+static inline void ref_tracker_debugfs_remove(struct ref_tracker_dir *dir)
+{
+}
+#endif
+
 static struct ref_tracker_dir_stats *
 ref_tracker_get_stats(struct ref_tracker_dir *dir, unsigned int limit)
 {
@@ -66,6 +75,7 @@ ref_tracker_get_stats(struct ref_tracker_dir *dir, unsigned int limit)
 
 struct ostream {
 	char *buf;
+	struct seq_file *seq;
 	int size, used;
 };
 
@@ -73,7 +83,9 @@ struct ostream {
 ({ \
 	struct ostream *_s = (stream); \
 \
-	if (!_s->buf) { \
+	if (_s->seq) { \
+		seq_printf(_s->seq, fmt, ##args); \
+	} else if (!_s->buf) { \
 		pr_err(fmt, ##args); \
 	} else { \
 		int ret, len = _s->size - _s->used; \
@@ -163,6 +175,7 @@ void ref_tracker_dir_exit(struct ref_tracker_dir *dir)
 	bool leak = false;
 
 	dir->dead = true;
+	ref_tracker_debugfs_remove(dir);
 	spin_lock_irqsave(&dir->lock, flags);
 	list_for_each_entry_safe(tracker, n, &dir->quarantine, head) {
 		list_del(&tracker->head);
@@ -279,7 +292,72 @@ EXPORT_SYMBOL_GPL(ref_tracker_free);
 #ifdef CONFIG_DEBUG_FS
 #include <linux/debugfs.h>
 
-static int __init ref_tracker_debug_init(void)
+static int ref_tracker_dir_seq_print(struct ref_tracker_dir *dir, struct seq_file *seq)
+{
+	struct ostream os = { .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;
+
+	return ref_tracker_dir_seq_print(dir, f);
+}
+
+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 finalize
+ * @name: updated name of the ref_tracker_dir
+ *
+ * In some cases, the name given to a ref_tracker_dir is based on incomplete information,
+ * and may not be unique. Call this to finalize the name of @dir, and create a debugfs
+ * file for it.
+ */
+void ref_tracker_dir_debugfs(struct ref_tracker_dir *dir, const char *name)
+{
+	strscpy(dir->name, name, sizeof(dir->name));
+
+	if (ref_tracker_debug_dir) {
+		dir->dentry = debugfs_create_file(dir->name, S_IFREG | 0400,
+						  ref_tracker_debug_dir, dir,
+						  &ref_tracker_debugfs_fops);
+		if (IS_ERR(dir->dentry)) {
+			pr_warn("ref_tracker: unable to create debugfs file for %s: %pe\n",
+				dir->name, dir->dentry);
+			dir->dentry = NULL;
+		}
+	}
+}
+EXPORT_SYMBOL(ref_tracker_dir_debugfs);
+
+static void ref_tracker_debugfs_remove(struct ref_tracker_dir *dir)
+{
+	debugfs_remove(dir->dentry);
+}
+
+static int __init ref_tracker_debugfs_init(void)
 {
 	ref_tracker_debug_dir = debugfs_create_dir("ref_tracker", NULL);
 	if (IS_ERR(ref_tracker_debug_dir)) {
@@ -289,5 +367,5 @@ static int __init ref_tracker_debug_init(void)
 	}
 	return 0;
 }
-late_initcall(ref_tracker_debug_init);
+late_initcall(ref_tracker_debugfs_init);
 #endif /* CONFIG_DEBUG_FS */

-- 
2.49.0
Re: [PATCH 2/4] ref_tracker: add ability to register a file in debugfs for a ref_tracker_dir
Posted by Andrew Lunn 8 months, 1 week ago
On Mon, Apr 14, 2025 at 10:45:47AM -0400, Jeff Layton wrote:
> Currently, there is no convenient way to see the info that the
> ref_tracking infrastructure collects. Add a new function that other
> subsystems can optionally call to update the name field in the
> ref_tracker_dir and register a corresponding seq_file for it in the
> top-level ref_tracker directory.
> 
> Also, alter the pr_ostream infrastructure to allow the caller to specify
> a seq_file to which the output should go instead of printing to an
> arbitrary buffer or the kernel's ring buffer.

When i see an Also, or And, or a list in a commit message, i always
think, should this be multiple patches?

>  struct ostream {
>  	char *buf;
> +	struct seq_file *seq;
>  	int size, used;
>  };
>  
> @@ -73,7 +83,9 @@ struct ostream {
>  ({ \
>  	struct ostream *_s = (stream); \
>  \
> -	if (!_s->buf) { \
> +	if (_s->seq) { \
> +		seq_printf(_s->seq, fmt, ##args); \
> +	} else if (!_s->buf) { \
>  		pr_err(fmt, ##args); \
>  	} else { \
>  		int ret, len = _s->size - _s->used; \

The pr_ostream() macro is getting pretty convoluted. It currently
supports two user cases:

struct ostream os = {}; which means just use pr_err().

And os.buf points to an allocated buffer and the output should be
dumped there.

You are about to add a third.

Is it about time this got split up into three helper functions, and
you pass one to __ref_tracker_dir_pr_ostream()? Your choice.

> +/**
> + * ref_tracker_dir_debugfs - create debugfs file for ref_tracker_dir
> + * @dir: ref_tracker_dir to finalize
> + * @name: updated name of the ref_tracker_dir
> + *
> + * In some cases, the name given to a ref_tracker_dir is based on incomplete information,
> + * and may not be unique. Call this to finalize the name of @dir, and create a debugfs
> + * file for it.

Maybe extend the documentation with a comment that is name is not
unique within debugfs directory, a warning will be emitted but it is
not fatal to the tracker.

> + */
> +void ref_tracker_dir_debugfs(struct ref_tracker_dir *dir, const char *name)
> +{
> +	strscpy(dir->name, name, sizeof(dir->name));

I don't know about this. Should we really overwrite the name passed
earlier? Would it be better to treat the name here only as the debugfs
filename?

> +	if (ref_tracker_debug_dir) {

Not needed

> +		dir->dentry = debugfs_create_file(dir->name, S_IFREG | 0400,
> +						  ref_tracker_debug_dir, dir,
> +						  &ref_tracker_debugfs_fops);
> +		if (IS_ERR(dir->dentry)) {
> +			pr_warn("ref_tracker: unable to create debugfs file for %s: %pe\n",
> +				dir->name, dir->dentry);
> +			dir->dentry = NULL;

this last statement should also be unneeded.

	Andrew
Re: [PATCH 2/4] ref_tracker: add ability to register a file in debugfs for a ref_tracker_dir
Posted by Jeff Layton 8 months, 1 week ago
On Tue, 2025-04-15 at 01:08 +0200, Andrew Lunn wrote:
> On Mon, Apr 14, 2025 at 10:45:47AM -0400, Jeff Layton wrote:
> > Currently, there is no convenient way to see the info that the
> > ref_tracking infrastructure collects. Add a new function that other
> > subsystems can optionally call to update the name field in the
> > ref_tracker_dir and register a corresponding seq_file for it in the
> > top-level ref_tracker directory.
> > 
> > Also, alter the pr_ostream infrastructure to allow the caller to specify
> > a seq_file to which the output should go instead of printing to an
> > arbitrary buffer or the kernel's ring buffer.
> 
> When i see an Also, or And, or a list in a commit message, i always
> think, should this be multiple patches?
> 

Sure. I actually had this part in a separate patch earlier, but I don't
usually like adding functions with no callers and this patch was pretty
small. I can break it up though.

> >  struct ostream {
> >  	char *buf;
> > +	struct seq_file *seq;
> >  	int size, used;
> >  };
> >  
> > @@ -73,7 +83,9 @@ struct ostream {
> >  ({ \
> >  	struct ostream *_s = (stream); \
> >  \
> > -	if (!_s->buf) { \
> > +	if (_s->seq) { \
> > +		seq_printf(_s->seq, fmt, ##args); \
> > +	} else if (!_s->buf) { \
> >  		pr_err(fmt, ##args); \
> >  	} else { \
> >  		int ret, len = _s->size - _s->used; \
> 
> The pr_ostream() macro is getting pretty convoluted. It currently
> supports two user cases:
> 
> struct ostream os = {}; which means just use pr_err().
> 
> And os.buf points to an allocated buffer and the output should be
> dumped there.
> 
> You are about to add a third.
> 
> Is it about time this got split up into three helper functions, and
> you pass one to __ref_tracker_dir_pr_ostream()? Your choice.
> 

Maybe? It doesn't seem worth it for this, but I'll take a look.

> > +/**
> > + * ref_tracker_dir_debugfs - create debugfs file for ref_tracker_dir
> > + * @dir: ref_tracker_dir to finalize
> > + * @name: updated name of the ref_tracker_dir
> > + *
> > + * In some cases, the name given to a ref_tracker_dir is based on incomplete information,
> > + * and may not be unique. Call this to finalize the name of @dir, and create a debugfs
> > + * file for it.
> 
> Maybe extend the documentation with a comment that is name is not
> unique within debugfs directory, a warning will be emitted but it is
> not fatal to the tracker.
> 

Ok.

> > + */
> > +void ref_tracker_dir_debugfs(struct ref_tracker_dir *dir, const char *name)
> > +{
> > +	strscpy(dir->name, name, sizeof(dir->name));
> 
> I don't know about this. Should we really overwrite the name passed
> earlier? Would it be better to treat the name here only as the debugfs
> filename?
> 

I think it's safe. The only thing that currently uses ->name is
pr_ostream(), AFAICT.

> > +	if (ref_tracker_debug_dir) {
> 
> Not needed
> 

If we call debugfs_create_file() and pass in NULL as the parent, it
will try to create the entry at the root of debugfs. We can get rid of
this though if we initialize ref_tracker_debug_dir to an ERR_PTR value.
I'll see about doing that.

> > +		dir->dentry = debugfs_create_file(dir->name, S_IFREG | 0400,
> > +						  ref_tracker_debug_dir, dir,
> > +						  &ref_tracker_debugfs_fops);
> > +		if (IS_ERR(dir->dentry)) {
> > +			pr_warn("ref_tracker: unable to create debugfs file for %s: %pe\n",
> > +				dir->name, dir->dentry);
> > +			dir->dentry = NULL;
> 
> this last statement should also be unneeded.
> 

Only if ref_tracker_debug_dir is initialized to an ERR_PTR.
-- 
Jeff Layton <jlayton@kernel.org>
Re: [PATCH 2/4] ref_tracker: add ability to register a file in debugfs for a ref_tracker_dir
Posted by Jeff Layton 8 months, 1 week ago
On Tue, 2025-04-15 at 06:23 -0400, Jeff Layton wrote:
> On Tue, 2025-04-15 at 01:08 +0200, Andrew Lunn wrote:
> > On Mon, Apr 14, 2025 at 10:45:47AM -0400, Jeff Layton wrote:
> > > Currently, there is no convenient way to see the info that the
> > > ref_tracking infrastructure collects. Add a new function that other
> > > subsystems can optionally call to update the name field in the
> > > ref_tracker_dir and register a corresponding seq_file for it in the
> > > top-level ref_tracker directory.
> > > 
> > > Also, alter the pr_ostream infrastructure to allow the caller to specify
> > > a seq_file to which the output should go instead of printing to an
> > > arbitrary buffer or the kernel's ring buffer.
> > 
> > When i see an Also, or And, or a list in a commit message, i always
> > think, should this be multiple patches?
> > 
> 
> Sure. I actually had this part in a separate patch earlier, but I don't
> usually like adding functions with no callers and this patch was pretty
> small. I can break it up though.
> 
> > >  struct ostream {
> > >  	char *buf;
> > > +	struct seq_file *seq;
> > >  	int size, used;
> > >  };
> > >  
> > > @@ -73,7 +83,9 @@ struct ostream {
> > >  ({ \
> > >  	struct ostream *_s = (stream); \
> > >  \
> > > -	if (!_s->buf) { \
> > > +	if (_s->seq) { \
> > > +		seq_printf(_s->seq, fmt, ##args); \
> > > +	} else if (!_s->buf) { \
> > >  		pr_err(fmt, ##args); \
> > >  	} else { \
> > >  		int ret, len = _s->size - _s->used; \
> > 
> > The pr_ostream() macro is getting pretty convoluted. It currently
> > supports two user cases:
> > 
> > struct ostream os = {}; which means just use pr_err().
> > 
> > And os.buf points to an allocated buffer and the output should be
> > dumped there.
> > 
> > You are about to add a third.
> > 
> > Is it about time this got split up into three helper functions, and
> > you pass one to __ref_tracker_dir_pr_ostream()? Your choice.
> > 
> 
> Maybe? It doesn't seem worth it for this, but I'll take a look.
> 
> > 

I took a crack at this and it's trickier than it looks. We have to pass
a variadic function pointer (which is fine), but that means that they
can't use handy macros like pr_err. We have to call functions that can
take a va_list (which is also fine).

The part I'm having trouble with is incorporating the pr_fmt(). I've
attached the patch I have on top of the current series. It doesn't
compile for me. If I remove the pr_fmt() calls and just pass in the
format string, it does compile.

What am I doing wrong here?

-------------------------8<---------------------------------

[PATCH] ref_tracker: have callers pass output function to pr_ostream

Signed-off-by: Jeff Layton <jlayton@kernel.org>
---
 lib/ref_tracker.c | 44 ++++++++++++++++++++++++++++++++------------
 1 file changed, 32 insertions(+), 12 deletions(-)

diff --git a/lib/ref_tracker.c b/lib/ref_tracker.c
index 4cc49cc21f5b..e131fdc51838 100644
--- a/lib/ref_tracker.c
+++ b/lib/ref_tracker.c
@@ -77,21 +77,41 @@ struct ostream {
 	char *buf;
 	struct seq_file *seq;
 	int size, used;
+	void (*func)(struct ostream *stream, char *fmt, ...);
 };
 
+#define ref_tracker_log(fmt, args) vprintk_emit(0, LOGLEVEL_ERR, NULL,
pr_fmt(fmt), args)
+
+static void pr_ostream_log(struct ostream *stream, char *fmt, ...)
+{
+	va_list args;
+
+	ref_tracker_log(fmt, args);
+}
+
+#define ref_tracker_vsnprintf(buf, size, fmt, args) vsnprintf(buf,
size, pr_fmt(fmt), args)
+
+static void pr_ostream_buf(struct ostream *stream, char *fmt, ...)
+{
+	int ret, len = stream->size - stream->used;
+	va_list args;
+
+	ret = ref_tracker_vsnprintf(stream->buf + stream->used, len,
fmt, args);
+	stream->used += min(ret, len);
+}
+
+static void pr_ostream_seq(struct ostream *stream, char *fmt, ...)
+{
+	va_list args;
+
+	seq_vprintf(stream->seq, fmt, args);
+}
+
 #define pr_ostream(stream, fmt, args...) \
 ({ \
 	struct ostream *_s = (stream); \
 \
-	if (_s->seq) { \
-		seq_printf(_s->seq, fmt, ##args); \
-	} else 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
@@ -138,7 +158,7 @@ __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 };
 
 	__ref_tracker_dir_pr_ostream(dir, display_limit, &os);
 }
@@ -157,7 +177,7 @@ 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 = { .buf = buf, .size = size, .func =
pr_ostream_buf };
 	unsigned long flags;
 
 	spin_lock_irqsave(&dir->lock, flags);
@@ -294,7 +314,7 @@ EXPORT_SYMBOL_GPL(ref_tracker_free);
 
 static int ref_tracker_dir_seq_print(struct ref_tracker_dir *dir,
struct seq_file *seq)
 {
-	struct ostream os = { .seq = seq };
+	struct ostream os = { .seq = seq, .func = pr_ostream_seq };
 	unsigned long flags;
 
 	spin_lock_irqsave(&dir->lock, flags);
-- 
2.49.0
Re: [PATCH 2/4] ref_tracker: add ability to register a file in debugfs for a ref_tracker_dir
Posted by Jeff Layton 8 months, 1 week ago
On Tue, 2025-04-15 at 08:54 -0400, Jeff Layton wrote:
> On Tue, 2025-04-15 at 06:23 -0400, Jeff Layton wrote:
> > On Tue, 2025-04-15 at 01:08 +0200, Andrew Lunn wrote:
> > > On Mon, Apr 14, 2025 at 10:45:47AM -0400, Jeff Layton wrote:
> > > > Currently, there is no convenient way to see the info that the
> > > > ref_tracking infrastructure collects. Add a new function that other
> > > > subsystems can optionally call to update the name field in the
> > > > ref_tracker_dir and register a corresponding seq_file for it in the
> > > > top-level ref_tracker directory.
> > > > 
> > > > Also, alter the pr_ostream infrastructure to allow the caller to specify
> > > > a seq_file to which the output should go instead of printing to an
> > > > arbitrary buffer or the kernel's ring buffer.
> > > 
> > > When i see an Also, or And, or a list in a commit message, i always
> > > think, should this be multiple patches?
> > > 
> > 
> > Sure. I actually had this part in a separate patch earlier, but I don't
> > usually like adding functions with no callers and this patch was pretty
> > small. I can break it up though.
> > 
> > > >  struct ostream {
> > > >  	char *buf;
> > > > +	struct seq_file *seq;
> > > >  	int size, used;
> > > >  };
> > > >  
> > > > @@ -73,7 +83,9 @@ struct ostream {
> > > >  ({ \
> > > >  	struct ostream *_s = (stream); \
> > > >  \
> > > > -	if (!_s->buf) { \
> > > > +	if (_s->seq) { \
> > > > +		seq_printf(_s->seq, fmt, ##args); \
> > > > +	} else if (!_s->buf) { \
> > > >  		pr_err(fmt, ##args); \
> > > >  	} else { \
> > > >  		int ret, len = _s->size - _s->used; \
> > > 
> > > The pr_ostream() macro is getting pretty convoluted. It currently
> > > supports two user cases:
> > > 
> > > struct ostream os = {}; which means just use pr_err().
> > > 
> > > And os.buf points to an allocated buffer and the output should be
> > > dumped there.
> > > 
> > > You are about to add a third.
> > > 
> > > Is it about time this got split up into three helper functions, and
> > > you pass one to __ref_tracker_dir_pr_ostream()? Your choice.
> > > 
> > 
> > Maybe? It doesn't seem worth it for this, but I'll take a look.
> > 
> > > 
> 
> I took a crack at this and it's trickier than it looks. We have to pass
> a variadic function pointer (which is fine), but that means that they
> can't use handy macros like pr_err. We have to call functions that can
> take a va_list (which is also fine).
> 
> The part I'm having trouble with is incorporating the pr_fmt(). I've
> attached the patch I have on top of the current series. It doesn't
> compile for me. If I remove the pr_fmt() calls and just pass in the
> format string, it does compile.
> 
> What am I doing wrong here?
> 
> -------------------------8<---------------------------------
> 
> [PATCH] ref_tracker: have callers pass output function to pr_ostream
> 
> Signed-off-by: Jeff Layton <jlayton@kernel.org>
> ---
>  lib/ref_tracker.c | 44 ++++++++++++++++++++++++++++++++------------
>  1 file changed, 32 insertions(+), 12 deletions(-)
> 
> diff --git a/lib/ref_tracker.c b/lib/ref_tracker.c
> index 4cc49cc21f5b..e131fdc51838 100644
> --- a/lib/ref_tracker.c
> +++ b/lib/ref_tracker.c
> @@ -77,21 +77,41 @@ struct ostream {
>  	char *buf;
>  	struct seq_file *seq;
>  	int size, used;
> +	void (*func)(struct ostream *stream, char *fmt, ...);
>  };
>  
> +#define ref_tracker_log(fmt, args) vprintk_emit(0, LOGLEVEL_ERR, NULL,
> pr_fmt(fmt), args)
> +
> +static void pr_ostream_log(struct ostream *stream, char *fmt, ...)
> +{
> +	va_list args;
> +
> +	ref_tracker_log(fmt, args);
> +}
> +

Oh, duh, I figured it out -- the problem is that the compiler can't
implicitly concatenate a string literal and a variable (of course).

I think we can just pass a prefix string in struct ostream that we can
add into the pr_ostream calls. I'll plan to send an updated set after a
bit more testing.
-- 
Jeff Layton <jlayton@kernel.org>
Re: [PATCH 2/4] ref_tracker: add ability to register a file in debugfs for a ref_tracker_dir
Posted by Andrew Lunn 8 months, 1 week ago
> -static int __init ref_tracker_debug_init(void)

[snip]

> +static int __init ref_tracker_debugfs_init(void)
>  {
>  	ref_tracker_debug_dir = debugfs_create_dir("ref_tracker", NULL);
>  	if (IS_ERR(ref_tracker_debug_dir)) {
> @@ -289,5 +367,5 @@ static int __init ref_tracker_debug_init(void)
>  	}
>  	return 0;
>  }
> -late_initcall(ref_tracker_debug_init);
> +late_initcall(ref_tracker_debugfs_init);

You just added this in the previous patch. Please give it the correct
name from the start.

	Andrew