* Peter Zijlstra <pet...@infradead.org> wrote:

> On Tue, Nov 15, 2016 at 09:43:55AM +0100, Ingo Molnar wrote:
> > +atomic variables such atomic_t or struct kref:
> > +
> > +   %pAr    atomic_t count
> 
> Why 'r' for atomic_t ? I was expecting 'a' for atomic_t or something.
> That then also leaves 'r' available for refcount_t.

'r' was for 'raw atomic count', but you are right - new patch attached below.

Thanks,

        Ingo

==========
Subject: printk, locking/atomics, kref: Introduce new %pAa and %pAk format 
string options for atomic_t and 'struct kref'
From: Ingo Molnar <mi...@kernel.org>
Date: Tue, 15 Nov 2016 09:43:55 +0100

A decade of kref internals exposed to driver writers has proven that
exposing internals to them is a bad idea.

Make the bad patterns a bit easier to detect and allow cleaner
printouts by offering two new printk format string extensions:

        %pAa - print the atomic_t count in decimal
        %pAk - print the struct kref count in decimal

Also add printf testcases:

  [    0.334919] test_printf: all 268 tests passed

Cc: Arnaldo Carvalho de Melo <a...@kernel.org>
Cc: Christoph Hellwig <h...@infradead.org>
Cc: Greg Kroah-Hartman <gre...@linuxfoundation.org>
Cc: Linus Torvalds <torva...@linux-foundation.org>
Cc: Peter Zijlstra <pet...@infradead.org>
Cc: Thomas Gleixner <t...@linutronix.de>
Cc: a...@arndb.de
Cc: d...@progbits.org
Cc: elena.reshet...@intel.com
Cc: keesc...@chromium.org
Cc: will.dea...@arm.com
Link: http://lkml.kernel.org/r/20161115084355.ga24...@gmail.com
Signed-off-by: Ingo Molnar <mi...@kernel.org>
---
 Documentation/printk-formats.txt |   10 +++++++++
 lib/test_printf.c                |   28 ++++++++++++++++++++++++++
 lib/vsprintf.c                   |   42 +++++++++++++++++++++++++++++++++++++++
 3 files changed, 80 insertions(+)

Index: tip/Documentation/printk-formats.txt
===================================================================
--- tip.orig/Documentation/printk-formats.txt
+++ tip/Documentation/printk-formats.txt
@@ -316,6 +316,16 @@ Flags bitfields such as page flags, gfp_
 
        Passed by reference.
 
+atomic variables such atomic_t or struct kref:
+
+       %pAa    atomic_t count
+       %pAk    struct kref count
+
+       For printing the current count value of atomic variables. This is
+       preferred to accessing the counts directly.
+
+       Passed by reference.
+
 Network device features:
 
        %pNF    0x000000000000c000
Index: tip/lib/test_printf.c
===================================================================
--- tip.orig/lib/test_printf.c
+++ tip/lib/test_printf.c
@@ -20,6 +20,8 @@
 #include <linux/gfp.h>
 #include <linux/mm.h>
 
+#include <linux/kref.h>
+
 #define BUF_SIZE 256
 #define PAD_SIZE 16
 #define FILL_CHAR '$'
@@ -462,6 +464,31 @@ flags(void)
        kfree(cmp_buffer);
 }
 
+/*
+ * Testcases for %pAa (atomic_t) and %pAk (struct kref) count printing:
+ */
+static void __init test_atomics__atomic_t(void)
+{
+       atomic_t count = ATOMIC_INIT(1);
+
+       test("1", "%pAa", &count);
+}
+
+static void __init test_atomics__kref(void)
+{
+       struct kref kref;
+
+       kref_init(&kref);
+
+       test("1", "%pAk", &kref);
+}
+
+static void __init test_atomics(void)
+{
+       test_atomics__atomic_t();
+       test_atomics__kref();
+}
+
 static void __init
 test_pointer(void)
 {
@@ -481,6 +508,7 @@ test_pointer(void)
        bitmap();
        netdev_features();
        flags();
+       test_atomics();
 }
 
 static int __init
Index: tip/lib/vsprintf.c
===================================================================
--- tip.orig/lib/vsprintf.c
+++ tip/lib/vsprintf.c
@@ -38,6 +38,8 @@
 
 #include "../mm/internal.h"    /* For the trace_print_flags arrays */
 
+#include <linux/kref.h>
+
 #include <asm/page.h>          /* for PAGE_SIZE */
 #include <asm/sections.h>      /* for dereference_function_descriptor() */
 #include <asm/byteorder.h>     /* cpu_to_le16 */
@@ -1470,6 +1472,40 @@ char *flags_string(char *buf, char *end,
        return format_flags(buf, end, flags, names);
 }
 
+static noinline_for_stack
+char *atomic_var(char *buf, char *end, void *atomic_ptr, const char *fmt)
+{
+       unsigned long num;
+       const struct printf_spec numspec = {
+               .flags          = SPECIAL|SMALL,
+               .field_width    = -1,
+               .precision      = -1,
+               .base           = 10,
+       };
+
+       switch (fmt[1]) {
+               case 'a':
+               {
+                       atomic_t *count_p = (void *)atomic_ptr;
+
+                       num = atomic_read(count_p);
+                       break;
+               }
+               case 'k':
+               {
+                       struct kref *kref_p = (void *)atomic_ptr;
+
+                       num = refcount_read(&kref_p->refcount);
+                       break;
+               }
+               default:
+                       WARN_ONCE(1, "Unsupported atomics modifier: %c\n", 
fmt[1]);
+                       return buf;
+       }
+
+       return number(buf, end, num, numspec);
+}
+
 int kptr_restrict __read_mostly;
 
 /*
@@ -1563,6 +1599,10 @@ int kptr_restrict __read_mostly;
  *       p page flags (see struct page) given as pointer to unsigned long
  *       g gfp flags (GFP_* and __GFP_*) given as pointer to gfp_t
  *       v vma flags (VM_*) given as pointer to unsigned long
+ * - 'A' For the count of atomic variables to be printed.
+ *       Supported flags given by option:
+ *        a atomic_t    ('a'tomic count)
+ *        k struct kref ('k'ref count)
  *
  * ** Please update also Documentation/printk-formats.txt when making changes 
**
  *
@@ -1718,6 +1758,8 @@ char *pointer(const char *fmt, char *buf
 
        case 'G':
                return flags_string(buf, end, ptr, fmt);
+       case 'A':
+               return atomic_var(buf, end, ptr, fmt);
        }
        spec.flags |= SMALL;
        if (spec.field_width == -1) {

Reply via email to