From: Jeff Mahoney <jeffm@suse.com>
Subject: SUSE: factor out unsupported feature handling
Patch-mainline: Never, SUSE-specific
References: FATE#314697, FATE#317919, FATE#315263
With btrfs, ext4, and now XFS having unsupported features, it makes sense
to factor out the handling of them into a common implementation. Later
we might use the same to make the messages more consistent.
Signed-off-by: Jeff Mahoney <jeffm@suse.com>
---
include/linux/unsupported-feature.h | 48 ++++++++++++++++++++++++++
kernel/Makefile | 2 +
kernel/unsupported-feature.c | 65 ++++++++++++++++++++++++++++++++++++
3 files changed, 115 insertions(+)
--- /dev/null
+++ b/include/linux/unsupported-feature.h
@@ -0,0 +1,48 @@
+#ifndef _UNSUPPORTED_FEATURE_H_
+#define _UNSUPPORTED_FEATURE_H_
+
+#ifdef CONFIG_SUSE_KERNEL_SUPPORTED
+struct unsupported_feature {
+ const char *subsys_name;
+ bool allowed;
+};
+
+static inline bool suse_allow_unsupported(struct unsupported_feature *uf)
+{
+ return uf->allowed;
+}
+
+extern struct kernel_param_ops suse_allow_unsupported_param_ops;
+void suse_mark_unsupported(const struct unsupported_feature *uf,
+ struct module *module);
+
+#define DECLARE_SUSE_UNSUPPORTED_FEATURE(name) \
+extern struct unsupported_feature name ##__allow_unsupported; \
+static inline bool name ## _allow_unsupported(void) \
+{ \
+ return suse_allow_unsupported(&name ##__allow_unsupported); \
+} \
+ \
+static inline void name ## _mark_unsupported(void) \
+{ \
+ suse_mark_unsupported(&name ##__allow_unsupported, THIS_MODULE); \
+}
+
+#define DEFINE_SUSE_UNSUPPORTED_FEATURE(name) \
+struct unsupported_feature name ##__allow_unsupported = { \
+ .subsys_name = __stringify(name), \
+ .allowed = false, \
+}; \
+module_param_cb(allow_unsupported, &suse_allow_unsupported_param_ops, \
+ &name ## __allow_unsupported, 0644); \
+MODULE_PARM_DESC(allow_unsupported, \
+ "Allow using feature that are out of supported scope");
+
+#else
+#define DECLARE_SUSE_UNSUPPORTED_FEATURE(name) \
+static inline bool name ## _allow_unsupported(void) { return true; } \
+static inline void name ## _mark_unsupported(void) { }
+#define DEFINE_SUSE_UNSUPPORTED_FEATURE(name)
+#endif
+
+#endif /* _UNSUPPORTED_FEATURE_H_ */
--- a/kernel/Makefile
+++ b/kernel/Makefile
@@ -112,6 +112,8 @@ obj-$(CONFIG_MEMBARRIER) += membarrier.o
obj-$(CONFIG_HAS_IOMEM) += memremap.o
+obj-$(CONFIG_SUSE_KERNEL_SUPPORTED) += unsupported-feature.o
+
$(obj)/configs.o: $(obj)/config_data.h
targets += config_data.gz
--- /dev/null
+++ b/kernel/unsupported-feature.c
@@ -0,0 +1,65 @@
+#include <linux/kernel.h>
+#include <linux/moduleparam.h>
+#include <linux/unsupported-feature.h>
+
+static inline struct unsupported_feature *
+to_unsupported_feature(const struct kernel_param *kp)
+{
+ return kp->arg;
+}
+
+static int suse_set_allow_unsupported(const char *buffer,
+ const struct kernel_param *kp)
+{
+ int ret;
+ struct unsupported_feature *uf = to_unsupported_feature(kp);
+ struct kernel_param dummy_kp = *kp;
+ bool newval;
+
+ dummy_kp.arg = &newval;
+
+ ret = param_set_bool(buffer, &dummy_kp);
+ if (ret)
+ return ret;
+ if (uf->allowed && !newval) {
+ pr_info("%s: disallowing unsupported features, kernel remains tainted.\n",
+ uf->subsys_name);
+ uf->allowed = false;
+ } else if (!uf->allowed && newval) {
+ pr_info("%s: allowing unsupported features, kernel tainted.\n",
+ uf->subsys_name);
+ add_taint(TAINT_NO_SUPPORT, LOCKDEP_STILL_OK);
+ uf->allowed = true;
+ }
+ return 0;
+}
+
+static int suse_get_allow_unsupported(char *buffer,
+ const struct kernel_param *kp)
+{
+ struct unsupported_feature *uf = to_unsupported_feature(kp);
+ struct kernel_param dummy_kp = *kp;
+
+ dummy_kp.arg = &uf->allowed;
+ return param_get_bool(buffer, &dummy_kp);
+}
+
+struct kernel_param_ops suse_allow_unsupported_param_ops = {
+ .set = suse_set_allow_unsupported,
+ .get = suse_get_allow_unsupported,
+};
+EXPORT_SYMBOL_GPL(suse_allow_unsupported_param_ops);
+
+/* including above breaks kABI due to struct module becoming defined */
+#include <linux/module.h>
+
+void suse_mark_unsupported(const struct unsupported_feature *uf,
+ struct module *module)
+{
+ if (module && !test_and_set_bit(TAINT_NO_SUPPORT, &module->taints))
+ pr_warn("%s: marking %s unsupported\n",
+ uf->subsys_name, module_name(module));
+}
+EXPORT_SYMBOL_GPL(suse_mark_unsupported);
+
+