Improve alloc_percpu: Simple testing patch.

Note that we can use the ptr ops on static percpu vars now.  We should
remove the "per_cpu__" token-pasting which was designed to catch raw
usage, and use sparse annotations instead.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Cc: Christoph Lameter <cl@linux-foundation.org>
---
 init/Kconfig        |    6 +++
 lib/Makefile        |    1 
 lib/test-cpualloc.c |   96 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 103 insertions(+)

diff --git a/init/Kconfig b/init/Kconfig
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -934,6 +934,12 @@ config STOP_MACHINE
 	help
 	  Need stop_machine() primitive.
 
+config TEST_CPUALLOC
+	tristate "Test alloc_percpu"
+	depends on DEBUG_KERNEL
+	help
+	  This tests the replacement alloc_percpu() implementation.
+
 source "block/Kconfig"
 
 config PREEMPT_NOTIFIERS
diff --git a/lib/Makefile b/lib/Makefile
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -71,6 +71,7 @@ obj-$(CONFIG_TEXTSEARCH_FSM) += ts_fsm.o
 obj-$(CONFIG_TEXTSEARCH_FSM) += ts_fsm.o
 obj-$(CONFIG_SMP) += percpu_counter.o
 obj-$(CONFIG_AUDIT_GENERIC) += audit.o
+obj-$(CONFIG_TEST_CPUALLOC) += test-cpualloc.o
 
 obj-$(CONFIG_SWIOTLB) += swiotlb.o
 obj-$(CONFIG_IOMMU_HELPER) += iommu-helper.o
diff --git a/lib/test-cpualloc.c b/lib/test-cpualloc.c
new file mode 100644
--- /dev/null
+++ b/lib/test-cpualloc.c
@@ -0,0 +1,96 @@
+/* Not a very informative test: it just crashes if something's wrong. */
+#include <linux/percpu.h>
+#include <linux/module.h>
+
+static DEFINE_PER_CPU(u32, static_pcpu);
+
+static void test_percpu(u32 __percpu *p, u32 expected)
+{
+	BUG_ON(*per_cpu_ptr(p, smp_processor_id()) != expected);
+	BUG_ON(*get_cpu_ptr(p) != expected);
+	BUG_ON(read_percpu_ptr(p) != expected);
+	put_cpu_ptr(p);
+}
+
+static int init(void)
+{
+	void __percpu *p;
+	void *thisp;
+	u32 __percpu *p32;
+	u32 *thisp32;
+	unsigned int i;
+
+	printk(KERN_INFO "Testing cpualloc for %u cpus\n",
+	       cpus_weight(cpu_possible_map));
+
+	p = __alloc_percpu(100, 128);
+	/* Don't expect failure. */
+	BUG_ON(!p);
+
+	thisp = get_cpu_ptr(p);
+	for_each_possible_cpu(i) {
+		unsigned int j;
+		/* Must be aligned. */
+		BUG_ON((unsigned long)per_cpu_ptr(p, i) % 128);
+		/* Must be zeroed. */
+		for (j = 0; j < 100; j++)
+			BUG_ON(((char *)per_cpu_ptr(p, i))[j]);
+		if (i == smp_processor_id())
+			BUG_ON(per_cpu_ptr(p, i) != thisp);
+		/* Check they're different pointers. */
+		memset(per_cpu_ptr(p, i), 0xFF, 100);
+	}
+	free_percpu(p);
+	put_cpu_ptr(p);
+
+	p32 = alloc_percpu(u32);
+	/* Don't expect failure. */
+	BUG_ON(!p32);
+
+	thisp32 = get_cpu_ptr(p32);
+	for_each_possible_cpu(i) {
+		/* Must be aligned. */
+		BUG_ON((unsigned long)per_cpu_ptr(p32, i) % __alignof__(u32));
+		/* Must be zeroed. */
+		BUG_ON(*per_cpu_ptr(p32, i));
+		if (i == smp_processor_id())
+			BUG_ON(per_cpu_ptr(p32, i) != thisp32);
+		/* Check they're different pointers. */
+		*per_cpu_ptr(p32, i) = -1U;
+	}
+	put_cpu_ptr(p32);
+
+	test_percpu(p32, -1U);
+	free_percpu(p32);
+
+	/* It even works on static percpu vars. */
+	p32 = &static_pcpu;
+	thisp32 = get_cpu_ptr(p32);
+	for_each_possible_cpu(i) {
+		/* Must be aligned. */
+		BUG_ON((unsigned long)per_cpu_ptr(p32, i) % __alignof__(u32));
+		/* Must be zeroed. */
+		BUG_ON(*per_cpu_ptr(p32, i));
+		if (i == smp_processor_id())
+			BUG_ON(per_cpu_ptr(p32, i) != thisp32);
+		/* Check they're different pointers. */
+		*per_cpu_ptr(p32, i) = -1U;
+	}
+	put_cpu_ptr(p32);
+	test_percpu(p32, -1U);
+
+	BUG_ON(read_percpu_var(static_pcpu) != 0);
+	get_cpu_var(static_pcpu) = 7712;
+	BUG_ON(read_percpu_var(static_pcpu) != 7712);
+	put_cpu_var(static_pcpu);
+
+	test_percpu(&static_pcpu, -1U);
+
+	return 0;
+}
+
+static void fini(void)
+{
+}
+module_init(init);
+module_exit(fini);
