From 8cb8816d32b4c358192fa109c3e0e71564f70483 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Sun, 30 Mar 2014 00:26:26 +0000 Subject: [PATCH] backports: backport net_get_random_once() Commit a48e4292 introduced as of v3.13 is used by 6lowpan which we backport. We carry this over for older kernels that don't define it -- but we remain sane by requiring at least 3.5 which is where tons of the jump label / static key stuff seems to have last settled. Backporting this to any older kernel than 3.5 has a huge string of dependencies which although I was able to resovle the other depdendencies on 6lowpan on new net core re-architecture on skb fragment reassembly makes it pointless to carry. Mark my words: !! do not try to backport this to kernels older than 3.5 !! mcgrof@ergon ~/linux (git::master)$ git describe --contains a48e4292 v3.13-rc1~105^2~157^2~4 commit a48e42920ff38bc90bbf75143fff4555723d4540 Author: Hannes Frederic Sowa Date: Sat Oct 19 21:48:55 2013 +0200 net: introduce new macro net_get_random_once Cc: Hannes Frederic Sowa Cc: Alexander Smirnov Cc: Dmitry Eremin-Solenikov Cc: linux-zigbee-devel@lists.sourceforge.net Signed-off-by: Luis R. Rodriguez --- backport/backport-include/linux/net.h | 51 +++++++++++++++++++++++++ backport/compat/backport-3.13.c | 54 +++++++++++++++++++++++++++ 2 files changed, 105 insertions(+) diff --git a/backport/backport-include/linux/net.h b/backport/backport-include/linux/net.h index 07981dae7ae3..687ad0bc4cf9 100644 --- a/backport/backport-include/linux/net.h +++ b/backport/backport-include/linux/net.h @@ -1,6 +1,7 @@ #ifndef __BACKPORT_LINUX_NET_H #define __BACKPORT_LINUX_NET_H #include_next +#include /* This backports: * @@ -46,4 +47,54 @@ do { \ type dst = ({ __sockaddr_check_size(sizeof(*dst)); (type) src; }) #endif +/* + * Avoid backporting this if a distro did the work already, this + * takes the check a bit further than just using LINUX_BACKPORT() + * namespace, curious if any distro will hit a wall with this. + * Also curious if any distro will be daring enough to even try + * to backport this to a release older than 3.5. + */ +#ifndef ___NET_RANDOM_STATIC_KEY_INIT +/* + * Backporting this before 3.5 is extremely tricky -- I tried, due + * to the fact that it relies on static keys, which were refactored + * and optimized through a series of generation of patches from jump + * labels. These in turn have also been optimized through kernel revisions + * and have architecture specific code, which if you commit to backporting + * may affect tracing. My recommendation is that if you have a need for + * static keys you just require at least 3.5 to remain sane. + */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,5,0) +#define __BACKPORT_NET_GET_RANDOM_ONCE 1 +#endif +#endif /* ___NET_RANDOM_STATIC_KEY_INIT */ + +#ifdef __BACKPORT_NET_GET_RANDOM_ONCE +#define __net_get_random_once LINUX_BACKPORT(__net_get_random_once) +bool __net_get_random_once(void *buf, int nbytes, bool *done, + struct static_key *done_key); + +#ifdef HAVE_JUMP_LABEL +#define ___NET_RANDOM_STATIC_KEY_INIT ((struct static_key) \ + { .enabled = ATOMIC_INIT(0), .entries = (void *)1 }) +#else /* !HAVE_JUMP_LABEL */ +#define ___NET_RANDOM_STATIC_KEY_INIT STATIC_KEY_INIT_FALSE +#endif /* HAVE_JUMP_LABEL */ + +#define net_get_random_once(buf, nbytes) \ + ({ \ + bool ___ret = false; \ + static bool ___done = false; \ + static struct static_key ___done_key = \ + ___NET_RANDOM_STATIC_KEY_INIT; \ + if (!static_key_true(&___done_key)) \ + ___ret = __net_get_random_once(buf, \ + nbytes, \ + &___done, \ + &___done_key); \ + ___ret; \ + }) + +#endif /* __BACKPORT_NET_GET_RANDOM_ONCE */ + #endif /* __BACKPORT_LINUX_NET_H */ diff --git a/backport/compat/backport-3.13.c b/backport/compat/backport-3.13.c index d5b702937090..a76108818cbf 100644 --- a/backport/compat/backport-3.13.c +++ b/backport/compat/backport-3.13.c @@ -1,5 +1,7 @@ /* * Copyright (c) 2013 Hauke Mehrtens + * Copyright (c) 2013 Hannes Frederic Sowa + * Copyright (c) 2014 Luis R. Rodriguez * * Backport functionality introduced in Linux 3.13. * @@ -16,6 +18,7 @@ #include #include #include +#include static void devm_rdev_release(struct device *dev, void *res) { @@ -225,3 +228,54 @@ int backport_genl_unregister_family(struct genl_family *family) return err; } EXPORT_SYMBOL_GPL(backport_genl_unregister_family); + +#ifdef __BACKPORT_NET_GET_RANDOM_ONCE +struct __net_random_once_work { + struct work_struct work; + struct static_key *key; +}; + +static void __net_random_once_deferred(struct work_struct *w) +{ + struct __net_random_once_work *work = + container_of(w, struct __net_random_once_work, work); + if (!static_key_enabled(work->key)) + static_key_slow_inc(work->key); + kfree(work); +} + +static void __net_random_once_disable_jump(struct static_key *key) +{ + struct __net_random_once_work *w; + + w = kmalloc(sizeof(*w), GFP_ATOMIC); + if (!w) + return; + + INIT_WORK(&w->work, __net_random_once_deferred); + w->key = key; + schedule_work(&w->work); +} + +bool __net_get_random_once(void *buf, int nbytes, bool *done, + struct static_key *done_key) +{ + static DEFINE_SPINLOCK(lock); + unsigned long flags; + + spin_lock_irqsave(&lock, flags); + if (*done) { + spin_unlock_irqrestore(&lock, flags); + return false; + } + + get_random_bytes(buf, nbytes); + *done = true; + spin_unlock_irqrestore(&lock, flags); + + __net_random_once_disable_jump(done_key); + + return true; +} +EXPORT_SYMBOL_GPL(__net_get_random_once); +#endif /* __BACKPORT_NET_GET_RANDOM_ONCE */ -- 2.30.2