]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - lib/vsprintf.c
ARM: dts: imx6ul: add support for Ka-Ro electronics TXUL mainboard
[karo-tx-linux.git] / lib / vsprintf.c
index 48ff9c36644d64c324c5c243212f282e406dce2f..525c8e19bda2b8a4e7398d7fc19064b2abc84b45 100644 (file)
@@ -35,6 +35,8 @@
 #include <linux/blkdev.h>
 #endif
 
+#include "../mm/internal.h"    /* For the trace_print_flags arrays */
+
 #include <asm/page.h>          /* for PAGE_SIZE */
 #include <asm/sections.h>      /* for dereference_function_descriptor() */
 #include <asm/byteorder.h>     /* cpu_to_le16 */
@@ -1407,6 +1409,72 @@ char *clock(char *buf, char *end, struct clk *clk, struct printf_spec spec,
        }
 }
 
+static
+char *format_flags(char *buf, char *end, unsigned long flags,
+                                       const struct trace_print_flags *names)
+{
+       unsigned long mask;
+       const struct printf_spec strspec = {
+               .field_width = -1,
+               .precision = -1,
+       };
+       const struct printf_spec numspec = {
+               .flags = SPECIAL|SMALL,
+               .field_width = -1,
+               .precision = -1,
+               .base = 16,
+       };
+
+       for ( ; flags && names->name; names++) {
+               mask = names->mask;
+               if ((flags & mask) != mask)
+                       continue;
+
+               buf = string(buf, end, names->name, strspec);
+
+               flags &= ~mask;
+               if (flags) {
+                       if (buf < end)
+                               *buf = '|';
+                       buf++;
+               }
+       }
+
+       if (flags)
+               buf = number(buf, end, flags, numspec);
+
+       return buf;
+}
+
+static noinline_for_stack
+char *flags_string(char *buf, char *end, void *flags_ptr, const char *fmt)
+{
+       unsigned long flags;
+       const struct trace_print_flags *names;
+
+       switch (fmt[1]) {
+       case 'p':
+               flags = *(unsigned long *)flags_ptr;
+               /* Remove zone id */
+               flags &= (1UL << NR_PAGEFLAGS) - 1;
+               names = pageflag_names;
+               break;
+       case 'v':
+               flags = *(unsigned long *)flags_ptr;
+               names = vmaflag_names;
+               break;
+       case 'g':
+               flags = *(gfp_t *)flags_ptr;
+               names = gfpflag_names;
+               break;
+       default:
+               WARN_ONCE(1, "Unsupported flags modifier: %c\n", fmt[1]);
+               return buf;
+       }
+
+       return format_flags(buf, end, flags, names);
+}
+
 int kptr_restrict __read_mostly;
 
 /*
@@ -1495,6 +1563,11 @@ int kptr_restrict __read_mostly;
  * - 'Cn' For a clock, it prints the name (Common Clock Framework) or address
  *        (legacy clock framework) of the clock
  * - 'Cr' For a clock, it prints the current rate of the clock
+ * - 'G' For flags to be printed as a collection of symbolic strings that would
+ *       construct the specific value. Supported flags given by option:
+ *       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
  *
  * ** Please update also Documentation/printk-formats.txt when making changes **
  *
@@ -1590,22 +1663,23 @@ char *pointer(const char *fmt, char *buf, char *end, void *ptr,
                        return buf;
                }
        case 'K':
-               /*
-                * %pK cannot be used in IRQ context because its test
-                * for CAP_SYSLOG would be meaningless.
-                */
-               if (kptr_restrict && (in_irq() || in_serving_softirq() ||
-                                     in_nmi())) {
-                       if (spec.field_width == -1)
-                               spec.field_width = default_width;
-                       return string(buf, end, "pK-error", spec);
-               }
-
                switch (kptr_restrict) {
                case 0:
                        /* Always print %pK values */
                        break;
                case 1: {
+                       const struct cred *cred;
+
+                       /*
+                        * kptr_restrict==1 cannot be used in IRQ context
+                        * because its test for CAP_SYSLOG would be meaningless.
+                        */
+                       if (in_irq() || in_serving_softirq() || in_nmi()) {
+                               if (spec.field_width == -1)
+                                       spec.field_width = default_width;
+                               return string(buf, end, "pK-error", spec);
+                       }
+
                        /*
                         * Only print the real pointer value if the current
                         * process has CAP_SYSLOG and is running with the
@@ -1615,8 +1689,7 @@ char *pointer(const char *fmt, char *buf, char *end, void *ptr,
                         * leak pointer values if a binary opens a file using
                         * %pK and then elevates privileges before reading it.
                         */
-                       const struct cred *cred = current_cred();
-
+                       cred = current_cred();
                        if (!has_capability_noaudit(current, CAP_SYSLOG) ||
                            !uid_eq(cred->euid, cred->uid) ||
                            !gid_eq(cred->egid, cred->gid))
@@ -1648,6 +1721,8 @@ char *pointer(const char *fmt, char *buf, char *end, void *ptr,
                return bdev_name(buf, end, ptr, spec, fmt);
 #endif
 
+       case 'G':
+               return flags_string(buf, end, ptr, fmt);
        }
        spec.flags |= SMALL;
        if (spec.field_width == -1) {