Merge tag 'powerpc-4.8-2' of git://git.kernel.org/pub/scm/linux/kernel/git/powerpc...
[cascardo/linux.git] / kernel / jump_label.c
index 2d693be..93ad6c1 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/err.h>
 #include <linux/static_key.h>
 #include <linux/jump_label_ratelimit.h>
+#include <linux/bug.h>
 
 #ifdef HAVE_JUMP_LABEL
 
@@ -56,6 +57,49 @@ jump_label_sort_entries(struct jump_entry *start, struct jump_entry *stop)
 
 static void jump_label_update(struct static_key *key);
 
+/*
+ * There are similar definitions for the !HAVE_JUMP_LABEL case in jump_label.h.
+ * The use of 'atomic_read()' requires atomic.h and its problematic for some
+ * kernel headers such as kernel.h and others. Since static_key_count() is not
+ * used in the branch statements as it is for the !HAVE_JUMP_LABEL case its ok
+ * to have it be a function here. Similarly, for 'static_key_enable()' and
+ * 'static_key_disable()', which require bug.h. This should allow jump_label.h
+ * to be included from most/all places for HAVE_JUMP_LABEL.
+ */
+int static_key_count(struct static_key *key)
+{
+       /*
+        * -1 means the first static_key_slow_inc() is in progress.
+        *  static_key_enabled() must return true, so return 1 here.
+        */
+       int n = atomic_read(&key->enabled);
+
+       return n >= 0 ? n : 1;
+}
+EXPORT_SYMBOL_GPL(static_key_count);
+
+void static_key_enable(struct static_key *key)
+{
+       int count = static_key_count(key);
+
+       WARN_ON_ONCE(count < 0 || count > 1);
+
+       if (!count)
+               static_key_slow_inc(key);
+}
+EXPORT_SYMBOL_GPL(static_key_enable);
+
+void static_key_disable(struct static_key *key)
+{
+       int count = static_key_count(key);
+
+       WARN_ON_ONCE(count < 0 || count > 1);
+
+       if (count)
+               static_key_slow_dec(key);
+}
+EXPORT_SYMBOL_GPL(static_key_disable);
+
 void static_key_slow_inc(struct static_key *key)
 {
        int v, v1;
@@ -235,6 +279,15 @@ void __init jump_label_init(void)
        struct static_key *key = NULL;
        struct jump_entry *iter;
 
+       /*
+        * Since we are initializing the static_key.enabled field with
+        * with the 'raw' int values (to avoid pulling in atomic.h) in
+        * jump_label.h, let's make sure that is safe. There are only two
+        * cases to check since we initialize to 0 or 1.
+        */
+       BUILD_BUG_ON((int)ATOMIC_INIT(0) != 0);
+       BUILD_BUG_ON((int)ATOMIC_INIT(1) != 1);
+
        if (static_key_initialized)
                return;
 
@@ -287,11 +340,14 @@ static int __jump_label_mod_text_reserved(void *start, void *end)
 {
        struct module *mod;
 
+       preempt_disable();
        mod = __module_text_address((unsigned long)start);
+       WARN_ON_ONCE(__module_text_address((unsigned long)end) != mod);
+       preempt_enable();
+
        if (!mod)
                return 0;
 
-       WARN_ON_ONCE(__module_text_address((unsigned long)end) != mod);
 
        return __jump_label_text_reserved(mod->jump_entries,
                                mod->jump_entries + mod->num_jump_entries,