lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <CANn89iL44SvNKgK-fbm2+bWUpCk+cT0LFVaMGj7HdVOkRiW9Vg@mail.gmail.com>
Date: Tue, 25 Mar 2025 06:21:44 +0100
From: Eric Dumazet <edumazet@...gle.com>
To: Jeff Layton <jlayton@...nel.org>
Cc: "David S. Miller" <davem@...emloft.net>, Jakub Kicinski <kuba@...nel.org>, 
	Paolo Abeni <pabeni@...hat.com>, Simon Horman <horms@...nel.org>, netdev@...r.kernel.org, 
	linux-kernel@...r.kernel.org
Subject: Re: [PATCH] net: add a debugfs files for showing netns refcount
 tracking info

On Mon, Mar 24, 2025 at 9:24 PM Jeff Layton <jlayton@...nel.org> wrote:
>
> CONFIG_NET_NS_REFCNT_TRACKER currently has no convenient way to display
> its tracking info. Add a new net_ns directory in debugfs. Have a
> directory in there for every net, with refcnt and notrefcnt files that
> show the currently tracked active and passive references.
>
> Signed-off-by: Jeff Layton <jlayton@...nel.org>
> ---
> Recently, I had a need to track down some long-held netns references,
> and discovered CONFIG_NET_NS_REFCNT_TRACKER. The main thing that seemed
> to be missing from it though is a simple way to view the currently held
> references on the netns. This adds files in debugfs for this.

Thanks for working on this, this is a very good idea.


> +#define MAX_NS_DEBUG_BUFSIZE   (32 * PAGE_SIZE)
> +
> +static int
> +ns_debug_tracker_show(struct seq_file *f, void *v)
> +{
> +       struct ref_tracker_dir *tracker = f->private;
> +       int len, bufsize = PAGE_SIZE;
> +       char *buf;
> +
> +       for (;;) {
> +               buf = kvmalloc(bufsize, GFP_KERNEL);
> +               if (!buf)
> +                       return -ENOMEM;
> +
> +               len = ref_tracker_dir_snprint(tracker, buf, bufsize);
> +               if (len < bufsize)
> +                       break;
> +
> +               kvfree(buf);
> +               bufsize *= 2;
> +               if (bufsize > MAX_NS_DEBUG_BUFSIZE)
> +                       return -ENOBUFS;
> +       }
> +       seq_write(f, buf, len);
> +       kvfree(buf);
> +       return 0;
> +}

I guess we could first change ref_tracker_dir_snprint(tracker, buf, bufsize)
to ref_tracker_dir_snprint(tracker, buf, bufsize, &needed) to avoid
too many tries in this loop.

Most of ref_tracker_dir_snprint() runs with hard irq being disabled...


diff --git a/drivers/gpu/drm/i915/intel_wakeref.c
b/drivers/gpu/drm/i915/intel_wakeref.c
index 87f2460473127af65a9a793c7f1934fafe41e79e..6650421b4f00c318adec72cd7c17a76832f14cce
100644
--- a/drivers/gpu/drm/i915/intel_wakeref.c
+++ b/drivers/gpu/drm/i915/intel_wakeref.c
@@ -208,7 +208,7 @@ void intel_ref_tracker_show(struct ref_tracker_dir *dir,
        if (!buf)
                return;

-       count = ref_tracker_dir_snprint(dir, buf, buf_size);
+       count = ref_tracker_dir_snprint(dir, buf, buf_size, NULL);
        if (!count)
                goto free;
        /* printk does not like big buffers, so we split it */
diff --git a/include/linux/ref_tracker.h b/include/linux/ref_tracker.h
index 8eac4f3d52547ccbaf9dcd09962ce80d26fbdff8..19bd42088434b661810082350a9d5afcbff6a88a
100644
--- a/include/linux/ref_tracker.h
+++ b/include/linux/ref_tracker.h
@@ -46,7 +46,7 @@ void ref_tracker_dir_print_locked(struct ref_tracker_dir *dir,
 void ref_tracker_dir_print(struct ref_tracker_dir *dir,
                           unsigned int display_limit);

-int ref_tracker_dir_snprint(struct ref_tracker_dir *dir, char *buf,
size_t size);
+int ref_tracker_dir_snprint(struct ref_tracker_dir *dir, char *buf,
size_t size, size_t *needed);

 int ref_tracker_alloc(struct ref_tracker_dir *dir,
                      struct ref_tracker **trackerp, gfp_t gfp);
@@ -77,7 +77,7 @@ static inline void ref_tracker_dir_print(struct
ref_tracker_dir *dir,
 }

 static inline int ref_tracker_dir_snprint(struct ref_tracker_dir *dir,
-                                         char *buf, size_t size)
+                                         char *buf, size_t size,
size_t *needed)
 {
        return 0;
 }
diff --git a/lib/ref_tracker.c b/lib/ref_tracker.c
index cf5609b1ca79361763abe5a3a98484a3ee591ff2..d8d02dab7ce67caf91ae22f9391abe2c92481c7f
100644
--- a/lib/ref_tracker.c
+++ b/lib/ref_tracker.c
@@ -65,6 +65,7 @@ ref_tracker_get_stats(struct ref_tracker_dir *dir,
unsigned int limit)
 struct ostream {
        char *buf;
        int size, used;
+       size_t needed;
 };

 #define pr_ostream(stream, fmt, args...) \
@@ -76,6 +77,7 @@ struct ostream {
        } else { \
                int ret, len = _s->size - _s->used; \
                ret = snprintf(_s->buf + _s->used, len, pr_fmt(fmt), ##args); \
+               _s->needed += ret; \
                _s->used += min(ret, len); \
        } \
 })
@@ -141,7 +143,7 @@ void ref_tracker_dir_print(struct ref_tracker_dir *dir,
 }
 EXPORT_SYMBOL(ref_tracker_dir_print);

-int ref_tracker_dir_snprint(struct ref_tracker_dir *dir, char *buf,
size_t size)
+int ref_tracker_dir_snprint(struct ref_tracker_dir *dir, char *buf,
size_t size, size_t *needed)
 {
        struct ostream os = { .buf = buf, .size = size };
        unsigned long flags;
@@ -150,6 +152,8 @@ int ref_tracker_dir_snprint(struct ref_tracker_dir
*dir, char *buf, size_t size)
        __ref_tracker_dir_pr_ostream(dir, 16, &os);
        spin_unlock_irqrestore(&dir->lock, flags);

+       if (needed)
+               *needed = os.needed;
        return os.used;
 }
 EXPORT_SYMBOL(ref_tracker_dir_snprint);
diff --git a/net/core/net_namespace.c b/net/core/net_namespace.c
index ce4b01cc7aca15ddf74f4160580871868e693fb8..61ce889ab29c2b726eab064b0ecb39838db30229
100644
--- a/net/core/net_namespace.c
+++ b/net/core/net_namespace.c
@@ -1529,13 +1529,14 @@ struct ns_debug_net {
        struct dentry *notrefcnt;
 };

-#define MAX_NS_DEBUG_BUFSIZE   (32 * PAGE_SIZE)
+#define MAX_NS_DEBUG_BUFSIZE   (1 << 20)

 static int
 ns_debug_tracker_show(struct seq_file *f, void *v)
 {
        struct ref_tracker_dir *tracker = f->private;
        int len, bufsize = PAGE_SIZE;
+       size_t needed;
        char *buf;

        for (;;) {
@@ -1543,12 +1544,12 @@ ns_debug_tracker_show(struct seq_file *f, void *v)
                if (!buf)
                        return -ENOMEM;

-               len = ref_tracker_dir_snprint(tracker, buf, bufsize);
+               len = ref_tracker_dir_snprint(tracker, buf, bufsize, &needed);
                if (len < bufsize)
                        break;

                kvfree(buf);
-               bufsize *= 2;
+               bufsize = round_up(needed, PAGE_SIZE);
                if (bufsize > MAX_NS_DEBUG_BUFSIZE)
                        return -ENOBUFS;
        }

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ