|
@@ -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 **
|
|
|
*
|
|
@@ -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) {
|