* Ingo Molnar <mi...@kernel.org> wrote: > > * Greg KH <gre...@linuxfoundation.org> wrote: > > > On Mon, Nov 14, 2016 at 10:16:55AM -0800, Christoph Hellwig wrote: > > > On Mon, Nov 14, 2016 at 06:39:48PM +0100, Peter Zijlstra wrote: > > > > Since we need to change the implementation, stop exposing internals. > > > > > > > > Provide kref_read() to read the current reference count; typically > > > > used for debug messages. > > > > > > Can we just provide a printk specifier for a kref value instead as > > > that is the only valid use case for reading the value? > > > > Yeah, that would be great as no one should be doing anything > > logic-related based on the kref value. > > Find below a patch that implements %pAk for 'struct kref' count printing and > %pAr for atomic_t counter printing. > > This is against vanilla upstream.
The patch below is against Peter's refcount series. Note that this patch depends on this patch in Peter's series: kref: Implement using refcount_t Thanks, Ingo ==================================> Subject: printk, locking/atomics, kref: Introduce new %pAr and %pAk format string options for atomic_t and 'struct kref' From: Ingo Molnar <mi...@kernel.org> Date: Tue Nov 15 08:53:14 CET 2016 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: %pAr - print the atomic_t count in decimal %pAk - print the struct kref count in decimal Also add printf testcases: [ 0.328495] test_printf: all 268 tests passed Cc: Arnaldo Carvalho de Melo <a...@kernel.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> 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: + + %pAr 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 %pAr (atomic_t) and %pAk (struct kref) count printing: + */ +static void __init test_atomics__atomic_t(void) +{ + atomic_t count = ATOMIC_INIT(1); + + test("1", "%pAr", &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 'r': + { + 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: + * r atomic_t ('r'aw 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) {