summaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/Kconfig.debug13
-rw-r--r--lib/atomic64_test.c2
-rw-r--r--lib/cpumask.c1
-rw-r--r--lib/list_debug.c9
-rw-r--r--lib/test_printf.c53
-rw-r--r--lib/test_static_keys.c62
-rw-r--r--lib/ucs2_string.c62
-rw-r--r--lib/vsprintf.c75
8 files changed, 247 insertions, 30 deletions
diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
index 8bfd1aca7a3d..f28f7fad452f 100644
--- a/lib/Kconfig.debug
+++ b/lib/Kconfig.debug
@@ -1442,6 +1442,19 @@ config DEBUG_BLOCK_EXT_DEVT
Say N if you are unsure.
+config CPU_HOTPLUG_STATE_CONTROL
+ bool "Enable CPU hotplug state control"
+ depends on DEBUG_KERNEL
+ depends on HOTPLUG_CPU
+ default n
+ help
+ Allows to write steps between "offline" and "online" to the CPUs
+ sysfs target file so states can be stepped granular. This is a debug
+ option for now as the hotplug machinery cannot be stopped and
+ restarted at arbitrary points yet.
+
+ Say N if your are unsure.
+
config NOTIFIER_ERROR_INJECTION
tristate "Notifier error injection"
depends on DEBUG_KERNEL
diff --git a/lib/atomic64_test.c b/lib/atomic64_test.c
index d62de8bf022d..123481814320 100644
--- a/lib/atomic64_test.c
+++ b/lib/atomic64_test.c
@@ -17,7 +17,7 @@
#include <linux/atomic.h>
#ifdef CONFIG_X86
-#include <asm/processor.h> /* for boot_cpu_has below */
+#include <asm/cpufeature.h> /* for boot_cpu_has below */
#endif
#define TEST(bit, op, c_op, val) \
diff --git a/lib/cpumask.c b/lib/cpumask.c
index 5a70f6196f57..81dedaab36cc 100644
--- a/lib/cpumask.c
+++ b/lib/cpumask.c
@@ -41,6 +41,7 @@ int cpumask_any_but(const struct cpumask *mask, unsigned int cpu)
break;
return i;
}
+EXPORT_SYMBOL(cpumask_any_but);
/* These are not inline because of header tangles. */
#ifdef CONFIG_CPUMASK_OFFSTACK
diff --git a/lib/list_debug.c b/lib/list_debug.c
index 3345a089ef7b..3859bf63561c 100644
--- a/lib/list_debug.c
+++ b/lib/list_debug.c
@@ -12,13 +12,6 @@
#include <linux/kernel.h>
#include <linux/rculist.h>
-static struct list_head force_poison;
-void list_force_poison(struct list_head *entry)
-{
- entry->next = &force_poison;
- entry->prev = &force_poison;
-}
-
/*
* Insert a new entry between two known consecutive entries.
*
@@ -30,8 +23,6 @@ void __list_add(struct list_head *new,
struct list_head *prev,
struct list_head *next)
{
- WARN(new->next == &force_poison || new->prev == &force_poison,
- "list_add attempted on force-poisoned entry\n");
WARN(next->prev != prev,
"list_add corruption. next->prev should be "
"prev (%p), but was %p. (next=%p).\n",
diff --git a/lib/test_printf.c b/lib/test_printf.c
index 4f6ae60433bc..563f10e6876a 100644
--- a/lib/test_printf.c
+++ b/lib/test_printf.c
@@ -17,6 +17,9 @@
#include <linux/socket.h>
#include <linux/in.h>
+#include <linux/gfp.h>
+#include <linux/mm.h>
+
#define BUF_SIZE 256
#define PAD_SIZE 16
#define FILL_CHAR '$'
@@ -411,6 +414,55 @@ netdev_features(void)
}
static void __init
+flags(void)
+{
+ unsigned long flags;
+ gfp_t gfp;
+ char *cmp_buffer;
+
+ flags = 0;
+ test("", "%pGp", &flags);
+
+ /* Page flags should filter the zone id */
+ flags = 1UL << NR_PAGEFLAGS;
+ test("", "%pGp", &flags);
+
+ flags |= 1UL << PG_uptodate | 1UL << PG_dirty | 1UL << PG_lru
+ | 1UL << PG_active | 1UL << PG_swapbacked;
+ test("uptodate|dirty|lru|active|swapbacked", "%pGp", &flags);
+
+
+ flags = VM_READ | VM_EXEC | VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC
+ | VM_DENYWRITE;
+ test("read|exec|mayread|maywrite|mayexec|denywrite", "%pGv", &flags);
+
+ gfp = GFP_TRANSHUGE;
+ test("GFP_TRANSHUGE", "%pGg", &gfp);
+
+ gfp = GFP_ATOMIC|__GFP_DMA;
+ test("GFP_ATOMIC|GFP_DMA", "%pGg", &gfp);
+
+ gfp = __GFP_ATOMIC;
+ test("__GFP_ATOMIC", "%pGg", &gfp);
+
+ cmp_buffer = kmalloc(BUF_SIZE, GFP_KERNEL);
+ if (!cmp_buffer)
+ return;
+
+ /* Any flags not translated by the table should remain numeric */
+ gfp = ~__GFP_BITS_MASK;
+ snprintf(cmp_buffer, BUF_SIZE, "%#lx", (unsigned long) gfp);
+ test(cmp_buffer, "%pGg", &gfp);
+
+ snprintf(cmp_buffer, BUF_SIZE, "__GFP_ATOMIC|%#lx",
+ (unsigned long) gfp);
+ gfp |= __GFP_ATOMIC;
+ test(cmp_buffer, "%pGg", &gfp);
+
+ kfree(cmp_buffer);
+}
+
+static void __init
test_pointer(void)
{
plain();
@@ -428,6 +480,7 @@ test_pointer(void)
struct_clk();
bitmap();
netdev_features();
+ flags();
}
static int __init
diff --git a/lib/test_static_keys.c b/lib/test_static_keys.c
index c61b299e367f..915d75df2086 100644
--- a/lib/test_static_keys.c
+++ b/lib/test_static_keys.c
@@ -46,8 +46,11 @@ struct test_key {
bool (*test_key)(void);
};
-#define test_key_func(key, branch) \
- ({bool func(void) { return branch(key); } func; })
+#define test_key_func(key, branch) \
+static bool key ## _ ## branch(void) \
+{ \
+ return branch(&key); \
+}
static void invert_key(struct static_key *key)
{
@@ -92,6 +95,25 @@ static int verify_keys(struct test_key *keys, int size, bool invert)
return 0;
}
+test_key_func(old_true_key, static_key_true)
+test_key_func(old_false_key, static_key_false)
+test_key_func(true_key, static_branch_likely)
+test_key_func(true_key, static_branch_unlikely)
+test_key_func(false_key, static_branch_likely)
+test_key_func(false_key, static_branch_unlikely)
+test_key_func(base_old_true_key, static_key_true)
+test_key_func(base_inv_old_true_key, static_key_true)
+test_key_func(base_old_false_key, static_key_false)
+test_key_func(base_inv_old_false_key, static_key_false)
+test_key_func(base_true_key, static_branch_likely)
+test_key_func(base_true_key, static_branch_unlikely)
+test_key_func(base_inv_true_key, static_branch_likely)
+test_key_func(base_inv_true_key, static_branch_unlikely)
+test_key_func(base_false_key, static_branch_likely)
+test_key_func(base_false_key, static_branch_unlikely)
+test_key_func(base_inv_false_key, static_branch_likely)
+test_key_func(base_inv_false_key, static_branch_unlikely)
+
static int __init test_static_key_init(void)
{
int ret;
@@ -102,95 +124,95 @@ static int __init test_static_key_init(void)
{
.init_state = true,
.key = &old_true_key,
- .test_key = test_key_func(&old_true_key, static_key_true),
+ .test_key = &old_true_key_static_key_true,
},
{
.init_state = false,
.key = &old_false_key,
- .test_key = test_key_func(&old_false_key, static_key_false),
+ .test_key = &old_false_key_static_key_false,
},
/* internal keys - new keys */
{
.init_state = true,
.key = &true_key.key,
- .test_key = test_key_func(&true_key, static_branch_likely),
+ .test_key = &true_key_static_branch_likely,
},
{
.init_state = true,
.key = &true_key.key,
- .test_key = test_key_func(&true_key, static_branch_unlikely),
+ .test_key = &true_key_static_branch_unlikely,
},
{
.init_state = false,
.key = &false_key.key,
- .test_key = test_key_func(&false_key, static_branch_likely),
+ .test_key = &false_key_static_branch_likely,
},
{
.init_state = false,
.key = &false_key.key,
- .test_key = test_key_func(&false_key, static_branch_unlikely),
+ .test_key = &false_key_static_branch_unlikely,
},
/* external keys - old keys */
{
.init_state = true,
.key = &base_old_true_key,
- .test_key = test_key_func(&base_old_true_key, static_key_true),
+ .test_key = &base_old_true_key_static_key_true,
},
{
.init_state = false,
.key = &base_inv_old_true_key,
- .test_key = test_key_func(&base_inv_old_true_key, static_key_true),
+ .test_key = &base_inv_old_true_key_static_key_true,
},
{
.init_state = false,
.key = &base_old_false_key,
- .test_key = test_key_func(&base_old_false_key, static_key_false),
+ .test_key = &base_old_false_key_static_key_false,
},
{
.init_state = true,
.key = &base_inv_old_false_key,
- .test_key = test_key_func(&base_inv_old_false_key, static_key_false),
+ .test_key = &base_inv_old_false_key_static_key_false,
},
/* external keys - new keys */
{
.init_state = true,
.key = &base_true_key.key,
- .test_key = test_key_func(&base_true_key, static_branch_likely),
+ .test_key = &base_true_key_static_branch_likely,
},
{
.init_state = true,
.key = &base_true_key.key,
- .test_key = test_key_func(&base_true_key, static_branch_unlikely),
+ .test_key = &base_true_key_static_branch_unlikely,
},
{
.init_state = false,
.key = &base_inv_true_key.key,
- .test_key = test_key_func(&base_inv_true_key, static_branch_likely),
+ .test_key = &base_inv_true_key_static_branch_likely,
},
{
.init_state = false,
.key = &base_inv_true_key.key,
- .test_key = test_key_func(&base_inv_true_key, static_branch_unlikely),
+ .test_key = &base_inv_true_key_static_branch_unlikely,
},
{
.init_state = false,
.key = &base_false_key.key,
- .test_key = test_key_func(&base_false_key, static_branch_likely),
+ .test_key = &base_false_key_static_branch_likely,
},
{
.init_state = false,
.key = &base_false_key.key,
- .test_key = test_key_func(&base_false_key, static_branch_unlikely),
+ .test_key = &base_false_key_static_branch_unlikely,
},
{
.init_state = true,
.key = &base_inv_false_key.key,
- .test_key = test_key_func(&base_inv_false_key, static_branch_likely),
+ .test_key = &base_inv_false_key_static_branch_likely,
},
{
.init_state = true,
.key = &base_inv_false_key.key,
- .test_key = test_key_func(&base_inv_false_key, static_branch_unlikely),
+ .test_key = &base_inv_false_key_static_branch_unlikely,
},
};
diff --git a/lib/ucs2_string.c b/lib/ucs2_string.c
index 6f500ef2301d..f0b323abb4c6 100644
--- a/lib/ucs2_string.c
+++ b/lib/ucs2_string.c
@@ -49,3 +49,65 @@ ucs2_strncmp(const ucs2_char_t *a, const ucs2_char_t *b, size_t len)
}
}
EXPORT_SYMBOL(ucs2_strncmp);
+
+unsigned long
+ucs2_utf8size(const ucs2_char_t *src)
+{
+ unsigned long i;
+ unsigned long j = 0;
+
+ for (i = 0; i < ucs2_strlen(src); i++) {
+ u16 c = src[i];
+
+ if (c >= 0x800)
+ j += 3;
+ else if (c >= 0x80)
+ j += 2;
+ else
+ j += 1;
+ }
+
+ return j;
+}
+EXPORT_SYMBOL(ucs2_utf8size);
+
+/*
+ * copy at most maxlength bytes of whole utf8 characters to dest from the
+ * ucs2 string src.
+ *
+ * The return value is the number of characters copied, not including the
+ * final NUL character.
+ */
+unsigned long
+ucs2_as_utf8(u8 *dest, const ucs2_char_t *src, unsigned long maxlength)
+{
+ unsigned int i;
+ unsigned long j = 0;
+ unsigned long limit = ucs2_strnlen(src, maxlength);
+
+ for (i = 0; maxlength && i < limit; i++) {
+ u16 c = src[i];
+
+ if (c >= 0x800) {
+ if (maxlength < 3)
+ break;
+ maxlength -= 3;
+ dest[j++] = 0xe0 | (c & 0xf000) >> 12;
+ dest[j++] = 0x80 | (c & 0x0fc0) >> 6;
+ dest[j++] = 0x80 | (c & 0x003f);
+ } else if (c >= 0x80) {
+ if (maxlength < 2)
+ break;
+ maxlength -= 2;
+ dest[j++] = 0xc0 | (c & 0x7c0) >> 6;
+ dest[j++] = 0x80 | (c & 0x03f);
+ } else {
+ maxlength -= 1;
+ dest[j++] = c & 0x7f;
+ }
+ }
+ if (maxlength)
+ dest[j] = '\0';
+ return j;
+}
+EXPORT_SYMBOL(ucs2_as_utf8);
diff --git a/lib/vsprintf.c b/lib/vsprintf.c
index f44e178e6ede..525c8e19bda2 100644
--- a/lib/vsprintf.c
+++ b/lib/vsprintf.c
@@ -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) {