[Devel] [kpatch-build VZ7] kmod/patch: Allow the patch to get settings from sysfs and to show data there

Evgenii Shatokhin evgenii.shatokhin at openvz.org
Mon Apr 18 00:37:41 MSK 2022


If a binary patch is used for debugging purposes, it might be needed to
adjust some of its settings in runtime: switch debugging modes, enable or
disable certain features, etc.

The patch might also need a way to report some stats or results of the
debugging to userspace, on demand.

kpatch.ko-based binary patch modules already maintain sysfs directory
/sys/kernel/kpatch/{patch_module_name}/ with useful info. This enhancement
adds two more files in that sysfs directory: 'data_in' and 'data_out'
(naming can be discussed).

The patch can now define functions to be called from show() and store()
operations for these two files, respectively. This way, the user can pass
some data to the patch module by writing them to 'data_in' and can see the
info provided by the patch module via 'data_out'.

See the description of KPATCH_DATA_SHOW_CALLBACK and KPATCH_DATA_STORE_CALLBACK
macros in kmod/patch/kpatch-macros.h for details.

For now, this enhancement is for the kpatch.ko-based patches only. Support
for livepatch/klp-based patches should be implemented later.

Signed-off-by: Evgenii Shatokhin <evgenii.shatokhin at openvz.org>
---
 kmod/patch/kpatch-macros.h     | 56 ++++++++++++++++++++++++++++++++++
 kmod/patch/kpatch-patch-hook.c | 56 ++++++++++++++++++++++++++++++++++
 2 files changed, 112 insertions(+)

diff --git a/kmod/patch/kpatch-macros.h b/kmod/patch/kpatch-macros.h
index 01a8e14..03efb56 100644
--- a/kmod/patch/kpatch-macros.h
+++ b/kmod/patch/kpatch-macros.h
@@ -177,4 +177,60 @@ struct kpatch_unload {
 		printk(_fmt, ## __VA_ARGS__); \
 })
 
+/*
+ * KPATCH_DATA_SHOW_CALLBACK and KPATCH_DATA_STORE_CALLBACK
+ *
+ * The patch can define functions to be called from show() and store()
+ * operations for the files "data_out" and "data_in" in the sysfs directory
+ * of the patch module.
+ *
+ * This can be used to control behaviour of the patch module in runtime and
+ * to report data (e.g. collected statistics or debug data) back to userspace.
+ *
+ * The patch module may define at most one callback of each kind.
+ *
+ * Usage:
+ *
+ * static ssize_t my_show_something(char *buf)
+ * {
+ * 	{write data to 'buf', return the number of bytes written;
+ * 	 'buf' is PAGE_SIZE bytes in size.}
+ * }
+ * KPATCH_DATA_SHOW_CALLBACK(my_show_something);
+ *
+ * static ssize_t my_store_something(const char *buf, size_t count)
+ * {
+ * 	{read the data from 'buf' and adjust the operation of the patch
+ * 	 accordingly:
+ * 	 - enable/disable certain debugging modes
+ * 	 - start or stop collection of certain stats
+ * 	 - etc.}
+ *
+ * 	return count;
+ * }
+ * KPATCH_DATA_STORE_CALLBACK(my_store_something);
+ *
+ * 'buf', 'count' and the return values of the callbacks have the same
+ * meaning as in show() and store() callbacks of sysfs attributes.
+ *
+ * __data_showtest and __data_storetest are used to check the types of the
+ * callbacks at compile time.
+ *
+ * Synchronization:
+ * - The callbacks are executed under the same mutex.
+ * - Synchronization of data accesses from the callbacks and from the rest
+ *   of the patch is up to the patch author.
+ */
+
+typedef ssize_t (*kpatch_data_show_call_t)(char *buf);
+typedef ssize_t (*kpatch_data_store_call_t)(const char *buf, size_t count);
+
+#define KPATCH_DATA_SHOW_CALLBACK(_fn) \
+	static inline kpatch_data_show_call_t __data_showtest(void) { return _fn; } \
+	ssize_t __kpatch_data_show(char *buf) { return _fn(buf); }
+
+#define KPATCH_DATA_STORE_CALLBACK(_fn) \
+	static inline kpatch_data_store_call_t __data_storetest(void) { return _fn; } \
+	ssize_t __kpatch_data_store(const char *buf, size_t count) { return _fn(buf, count); }
+
 #endif /* __KPATCH_MACROS_H_ */
diff --git a/kmod/patch/kpatch-patch-hook.c b/kmod/patch/kpatch-patch-hook.c
index 3d2b923..87ad484 100644
--- a/kmod/patch/kpatch-patch-hook.c
+++ b/kmod/patch/kpatch-patch-hook.c
@@ -25,6 +25,7 @@
 #include <linux/kallsyms.h>
 #include <linux/rcupdate.h>
 #include <linux/version.h>
+#include <linux/mutex.h>
 #include "kpatch.h"
 #include "kpatch-patch.h"
 
@@ -41,6 +42,12 @@ extern char __kpatch_checksum[];
 
 static struct kpatch_module kpmod;
 
+/*
+ * The mutex serializes show() and store() operations for the data files
+ * in sysfs.
+ */
+static DEFINE_MUTEX(kpatch_data_mutex);
+
 static ssize_t patch_enabled_show(struct kobject *kobj,
 				  struct kobj_attribute *attr, char *buf)
 {
@@ -89,14 +96,63 @@ static ssize_t patch_checksum_show(struct kobject *kobj,
 	return snprintf(buf, PAGE_SIZE, "%s\n", __kpatch_checksum);
 }
 
+/*
+ * Default callbacks for show() and store() operations for the data_* files
+ * in the sysfs directory of the patch module.
+ * Can be overridden by the patch.
+ */
+ssize_t __weak __kpatch_data_show(char *buf) { return 0; }
+ssize_t __weak __kpatch_data_store(const char *buf, size_t count) { return count; }
+
+static ssize_t kpatch_data_out_show(struct kobject *kobj,
+				    struct kobj_attribute *attr,
+				    char *buf)
+{
+	ssize_t ret;
+
+	ret = mutex_lock_killable(&kpatch_data_mutex);
+	if (ret)
+		return ret;
+
+	ret = __kpatch_data_show(buf);
+	if (!ret) {
+		strcpy(buf, "\n");
+		ret = 2;
+	}
+	mutex_unlock(&kpatch_data_mutex);
+	return ret;
+}
+
+static ssize_t kpatch_data_in_store(struct kobject *kobj,
+				    struct kobj_attribute *attr,
+				    const char *buf,
+				    size_t count)
+{
+	ssize_t ret;
+
+	ret = mutex_lock_killable(&kpatch_data_mutex);
+	if (ret)
+		return ret;
+
+	ret = __kpatch_data_store(buf, count);
+	mutex_unlock(&kpatch_data_mutex);
+	return ret;
+}
+
 static struct kobj_attribute patch_enabled_attr =
 	__ATTR(enabled, 0644, patch_enabled_show, patch_enabled_store);
 static struct kobj_attribute patch_checksum_attr =
 	__ATTR(checksum, 0444, patch_checksum_show, NULL);
+static struct kobj_attribute kpatch_data_out_attr =
+	__ATTR(data_out, 0400, kpatch_data_out_show, NULL);
+static struct kobj_attribute kpatch_data_in_attr =
+	__ATTR(data_in, 0200, NULL, kpatch_data_in_store);
 
 static struct attribute *patch_attrs[] = {
 	&patch_enabled_attr.attr,
 	&patch_checksum_attr.attr,
+	&kpatch_data_out_attr.attr,
+	&kpatch_data_in_attr.attr,
 	NULL,
 };
 
-- 
2.32.0



More information about the Devel mailing list