From: Hannes Frederic Sowa <han...@stressinduktion.org>

Make the get_random_once() helper generic enough, so that functions
in general would only be called once, where one user of this is then
net_get_random_once().

The only implementation specific call is to get_random_bytes(), all
the rest of this *_once() facility would be duplicated among different
subsystems otherwise. The new do_once() helper will be used by prandom()
later on, but might also be useful for other scenarios as well where a
one-time initialization in often-called, possibly fast-path code could
occur.

Signed-off-by: Hannes Frederic Sowa <han...@stressinduktion.org>
Signed-off-by: Daniel Borkmann <dan...@iogearbox.net>
---
 include/linux/once.h | 25 ++++++++++++++++++-------
 lib/once.c           | 34 +++++++++++++++++++++-------------
 2 files changed, 39 insertions(+), 20 deletions(-)

diff --git a/include/linux/once.h b/include/linux/once.h
index 2a83b53..f7a51d5 100644
--- a/include/linux/once.h
+++ b/include/linux/once.h
@@ -3,22 +3,33 @@
 
 #include <linux/types.h>
 #include <linux/jump_label.h>
+#include <linux/uio.h>
 
-bool __get_random_once(void *buf, int nbytes, bool *done,
-                      struct static_key *once_key);
+bool __do_once(void (*func)(void *arg), void *arg, bool *done,
+              struct static_key *once_key);
 
-#define get_random_once(buf, nbytes)                                   \
+#define do_once(func, arg)                                             \
        ({                                                              \
                bool ___ret = false;                                    \
                static bool ___done = false;                            \
                static struct static_key ___once_key =                  \
                        STATIC_KEY_INIT_TRUE;                           \
                if (static_key_true(&___once_key))                      \
-                       ___ret = __get_random_once((buf),               \
-                                                  (nbytes),            \
-                                                  &___done,            \
-                                                  &___once_key);       \
+                       ___ret = __do_once((func), (arg),               \
+                                          &___done,                    \
+                                          &___once_key);               \
                ___ret;                                                 \
        })
 
+void get_random_once_kvec(void *arg);
+
+#define get_random_once(buf, nbytes)                                   \
+       ({                                                              \
+               struct kvec __v = {                                     \
+                       .iov_base = (buf),                              \
+                       .iov_len = (nbytes),                            \
+               };                                                      \
+               do_once(get_random_once_kvec, &__v);                    \
+       })
+
 #endif /* _LINUX_ONCE_H */
diff --git a/lib/once.c b/lib/once.c
index 2d5a7de..1e62944 100644
--- a/lib/once.c
+++ b/lib/once.c
@@ -3,36 +3,36 @@
 #include <linux/once.h>
 #include <linux/random.h>
 
-struct __random_once_work {
+struct __once_work {
        struct work_struct work;
        struct static_key *key;
 };
 
-static void __random_once_deferred(struct work_struct *w)
+static void __once_deferred(struct work_struct *w)
 {
-       struct __random_once_work *work;
+       struct __once_work *work;
 
-       work = container_of(w, struct __random_once_work, work);
+       work = container_of(w, struct __once_work, work);
        BUG_ON(!static_key_enabled(work->key));
        static_key_slow_dec(work->key);
        kfree(work);
 }
 
-static void __random_once_disable_jump(struct static_key *key)
+static void __once_disable_jump(struct static_key *key)
 {
-       struct __random_once_work *w;
+       struct __once_work *w;
 
        w = kmalloc(sizeof(*w), GFP_ATOMIC);
        if (!w)
                return;
 
-       INIT_WORK(&w->work, __random_once_deferred);
+       INIT_WORK(&w->work, __once_deferred);
        w->key = key;
        schedule_work(&w->work);
 }
 
-bool __get_random_once(void *buf, int nbytes, bool *done,
-                      struct static_key *once_key)
+bool __do_once(void (*func)(void *arg), void *arg, bool *done,
+              struct static_key *once_key)
 {
        static DEFINE_SPINLOCK(lock);
        unsigned long flags;
@@ -43,12 +43,20 @@ bool __get_random_once(void *buf, int nbytes, bool *done,
                return false;
        }
 
-       get_random_bytes(buf, nbytes);
+       func(arg);
        *done = true;
        spin_unlock_irqrestore(&lock, flags);
 
-       __random_once_disable_jump(once_key);
-
+       __once_disable_jump(once_key);
        return true;
 }
-EXPORT_SYMBOL(__get_random_once);
+EXPORT_SYMBOL(__do_once);
+
+/* Helper function for once users. */
+void get_random_once_kvec(void *arg)
+{
+       struct kvec *v = arg;
+
+       get_random_bytes(v->iov_base, v->iov_len);
+}
+EXPORT_SYMBOL(get_random_once_kvec);
-- 
1.9.3

--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to