[PATCH 2/2] selftests/livepatch: Add tests for kprefcount_t support

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



From: Roman Rashchupkin <raschupkin.ri@xxxxxxxxx>

Signed-off-by: Roman Rashchupkin <raschupkin.ri@xxxxxxxxx>
---
 tools/testing/selftests/livepatch/Makefile    |   3 +-
 .../selftests/livepatch/test-kprefcount.sh    |  16 +++
 .../selftests/livepatch/test_modules/Makefile |   4 +-
 .../test_modules/test_klp_kprefcount.c        | 120 ++++++++++++++++++
 .../test_modules/test_klp_refcount.c          |  65 ++++++++++
 5 files changed, 206 insertions(+), 2 deletions(-)
 create mode 100755 tools/testing/selftests/livepatch/test-kprefcount.sh
 create mode 100644 tools/testing/selftests/livepatch/test_modules/test_klp_kprefcount.c
 create mode 100644 tools/testing/selftests/livepatch/test_modules/test_klp_refcount.c

diff --git a/tools/testing/selftests/livepatch/Makefile b/tools/testing/selftests/livepatch/Makefile
index 35418a4790be..48926ebc77f2 100644
--- a/tools/testing/selftests/livepatch/Makefile
+++ b/tools/testing/selftests/livepatch/Makefile
@@ -10,7 +10,8 @@ TEST_PROGS := \
 	test-state.sh \
 	test-ftrace.sh \
 	test-sysfs.sh \
-	test-syscall.sh
+	test-syscall.sh \
+	test-kprefcount.sh
 
 TEST_FILES := settings
 
diff --git a/tools/testing/selftests/livepatch/test-kprefcount.sh b/tools/testing/selftests/livepatch/test-kprefcount.sh
new file mode 100755
index 000000000000..8ea6c18f59dd
--- /dev/null
+++ b/tools/testing/selftests/livepatch/test-kprefcount.sh
@@ -0,0 +1,16 @@
+#!/bin/sh
+insmod test_modules/test_klp_refcount.ko
+insmod test_modules/test_klp_kprefcount.ko
+livepatch_enabled=/sys/kernel/livepatch/test_klp_kprefcount/enabled
+while [ ! -e $livepatch_enabled -o $(cat $livepatch_enabled) -eq 0 ]; do
+	sleep 0.01;
+done
+echo 0 > $livepatch_enabled
+while [ $(cat $livepatch_enabled) -eq 1 ]; do
+	sleep 0.01;
+done
+while [ -e $livepatch_enabled ]; do
+	sleep 0.01;
+done
+rmmod test_klp_kprefcount
+rmmod test_klp_refcount
diff --git a/tools/testing/selftests/livepatch/test_modules/Makefile b/tools/testing/selftests/livepatch/test_modules/Makefile
index e6e638c4bcba..c26797372e0d 100644
--- a/tools/testing/selftests/livepatch/test_modules/Makefile
+++ b/tools/testing/selftests/livepatch/test_modules/Makefile
@@ -11,7 +11,9 @@ obj-m += test_klp_atomic_replace.o \
 	test_klp_state2.o \
 	test_klp_state3.o \
 	test_klp_shadow_vars.o \
-	test_klp_syscall.o
+	test_klp_syscall.o \
+	test_klp_refcount.o \
+	test_klp_kprefcount.o
 
 # Ensure that KDIR exists, otherwise skip the compilation
 modules:
diff --git a/tools/testing/selftests/livepatch/test_modules/test_klp_kprefcount.c b/tools/testing/selftests/livepatch/test_modules/test_klp_kprefcount.c
new file mode 100644
index 000000000000..063f286ebcec
--- /dev/null
+++ b/tools/testing/selftests/livepatch/test_modules/test_klp_kprefcount.c
@@ -0,0 +1,120 @@
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/livepatch.h>
+#include <linux/livepatch_refcount.h>
+
+extern refcount_t test_refcount;
+extern int TEST_LIVEPATCH_KPREFCOUNT;
+
+#define ITER 100
+#define NREF 10
+#define KP_NREF 10
+static struct ref_holder {
+	unsigned char v;
+} kp_ref_holders[KP_NREF] = { 0 };
+kprefcount_t *kp_test_ref = 0;
+
+static int livepatch_refcount_test_iter(void)
+{
+	int k, i;
+	for (k=0; k<ITER; k++) {
+		for (i=0; i<KP_NREF; i++)
+			refcount_inc(&test_refcount);
+		for (i=0; i<KP_NREF; i++)
+			if (kprefcount_dec_and_test(kp_test_ref, 0, 1)) {
+				pr_alert("livepatch refcount underflow\n");
+				return -1;
+			}
+	}
+	TEST_LIVEPATCH_KPREFCOUNT = 0;
+	return 0;
+}
+
+struct delayed_work kp_work_refcount;
+static void kp_test_refcount(struct work_struct *work)
+{
+	int i, k;
+	for (k=0; k<ITER; k++) {
+		for (i=0; i<KP_NREF; i++)
+			kprefcount_dec(kp_test_ref, &kp_ref_holders[i].v, 1);
+		// Intentional refcounter underflow for additional testing
+		for (i=0; i<KP_NREF-1; i++)
+			kprefcount_inc(kp_test_ref, &kp_ref_holders[i].v, 1);
+	}
+}
+
+static void kp_post_patch_callback(struct klp_object *klp_obj)
+{
+	schedule_delayed_work(&kp_work_refcount, 0);
+}
+
+static void kp_pre_unpatch_callback(struct klp_object *klp_obj)
+{
+	cancel_delayed_work_sync(&kp_work_refcount);
+}
+
+static struct klp_func funcs[] = {
+	{
+		.old_name = "refcount_test_iter",
+		.new_func = livepatch_refcount_test_iter,
+	}, { }
+};
+
+static struct klp_object objs[] = {
+	{
+		.name = "test_klp_refcount",
+		.funcs = funcs,
+		.callbacks = {
+			.post_patch = kp_post_patch_callback,
+			.pre_unpatch = kp_pre_unpatch_callback,
+		},
+	}, { }
+};
+
+static struct klp_patch patch = {
+	.mod = THIS_MODULE,
+	.objs = objs,
+};
+
+struct delayed_work work_refcount;
+
+static void do_test_refcount(struct work_struct *work)
+{
+	int i;
+	for (i=0; i<NREF; i++) {
+		if (refcount_read(&test_refcount) <= 1)
+			pr_info("LIVEPATCH refcount test done.\n");
+			return;
+		refcount_dec(&test_refcount);
+		if (refcount_read(&test_refcount) < 0)
+			pr_alert("post-livepatch refcount underflow\n");
+	}
+	for (i=0; i<NREF; i++)
+		refcount_inc(&test_refcount);
+}
+
+static int refcount_test_init(void)
+{
+	int ret;
+	kp_test_ref = kprefcount_alloc(&test_refcount, GFP_KERNEL);
+	if (!kp_test_ref) {
+		pr_alert("kprefcount_livepatch: memory allocation_failed");
+		return -1;
+	}
+	ret = klp_enable_patch(&patch);
+	INIT_DELAYED_WORK(&kp_work_refcount, kp_test_refcount);
+	return 0;
+}
+
+static void refcount_test_exit(void)
+{
+}
+
+module_init(refcount_test_init);
+module_exit(refcount_test_exit);
+MODULE_INFO(livepatch, "Y");
+MODULE_AUTHOR("Roman Rashchupkin <raschupkin.ri@xxxxxxxxx>");
+MODULE_DESCRIPTION("Livepatch test: kprefcount");
+MODULE_LICENSE("GPL");
diff --git a/tools/testing/selftests/livepatch/test_modules/test_klp_refcount.c b/tools/testing/selftests/livepatch/test_modules/test_klp_refcount.c
new file mode 100644
index 000000000000..bd9c57e63476
--- /dev/null
+++ b/tools/testing/selftests/livepatch/test_modules/test_klp_refcount.c
@@ -0,0 +1,65 @@
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/livepatch.h>
+#include <linux/livepatch_refcount.h>
+
+#define ITER 100
+#define NREF 10
+int TEST_LIVEPATCH_KPREFCOUNT = 1;
+EXPORT_SYMBOL(TEST_LIVEPATCH_KPREFCOUNT);
+refcount_t test_refcount = REFCOUNT_INIT(1);
+EXPORT_SYMBOL(test_refcount);
+
+int refcount_test_iter(void)
+{
+	int i;
+	for (i=0; i<NREF; i++)
+		refcount_inc(&test_refcount);
+	for (i=0; i<NREF; i++)
+		if (refcount_dec_and_test(&test_refcount))
+			return -1;
+	return 0;
+}
+
+int refcount_test(void)
+{
+	int i;
+	for (i=0; i<ITER; i++) {
+		if (refcount_test_iter())
+			return -1;
+	}
+	return 0;
+}
+EXPORT_SYMBOL(refcount_test);
+
+struct delayed_work kp_test_work;
+void start_refcount_test(struct work_struct *work)
+{
+	if (!TEST_LIVEPATCH_KPREFCOUNT)
+		return;
+	if (refcount_test()) {
+		pr_alert(KERN_ERR "refcount_test: error.\n");
+		return;
+	}
+	schedule_delayed_work(&kp_test_work, msecs_to_jiffies(50));
+}
+
+static int refcount_test_init(void)
+{
+	INIT_DELAYED_WORK(&kp_test_work, start_refcount_test);
+	schedule_delayed_work(&kp_test_work, msecs_to_jiffies(50));
+	return 0;
+}
+
+static void refcount_test_exit(void)
+{
+	cancel_delayed_work_sync(&kp_test_work);
+}
+
+module_init(refcount_test_init);
+module_exit(refcount_test_exit);
+MODULE_AUTHOR("Roman Rashchupkin <raschupkin.ri@xxxxxxxxx>");
+MODULE_DESCRIPTION("Livepatch test: refcount");
+MODULE_LICENSE("GPL");
-- 
2.43.0





[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Index of Archives]     [Linux Kernel]     [Linux NFS]     [Linux NILFS]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux SCSI]

  Powered by Linux