diff options
author | Luis R. Rodriguez <mcgrof@do-not-panic.com> | 2014-03-30 00:26:26 +0000 |
---|---|---|
committer | Luis R. Rodriguez <mcgrof@do-not-panic.com> | 2014-04-08 18:16:21 -0700 |
commit | 8cb8816d32b4c358192fa109c3e0e71564f70483 (patch) | |
tree | 3cb226972f89fad6f607f90f15e15e9879847c26 | |
parent | 210120790c3b500b9096df1523d849d993d08521 (diff) |
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 <hannes@stressinduktion.org>
Date: Sat Oct 19 21:48:55 2013 +0200
net: introduce new macro net_get_random_once
Cc: Hannes Frederic Sowa <hannes@stressinduktion.org>
Cc: Alexander Smirnov <alex.bluesman.smirnov@gmail.com>
Cc: Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
Cc: linux-zigbee-devel@lists.sourceforge.net
Signed-off-by: Luis R. Rodriguez <mcgrof@do-not-panic.com>
-rw-r--r-- | backport/backport-include/linux/net.h | 51 | ||||
-rw-r--r-- | backport/compat/backport-3.13.c | 54 |
2 files changed, 105 insertions, 0 deletions
diff --git a/backport/backport-include/linux/net.h b/backport/backport-include/linux/net.h index 07981dae..687ad0bc 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 <linux/net.h> +#include <linux/static_key.h> /* 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 d5b70293..a7610881 100644 --- a/backport/compat/backport-3.13.c +++ b/backport/compat/backport-3.13.c @@ -1,5 +1,7 @@ /* * Copyright (c) 2013 Hauke Mehrtens <hauke@hauke-m.de> + * Copyright (c) 2013 Hannes Frederic Sowa <hannes@stressinduktion.org> + * Copyright (c) 2014 Luis R. Rodriguez <mcgrof@do-not-panic.com> * * Backport functionality introduced in Linux 3.13. * @@ -16,6 +18,7 @@ #include <linux/module.h> #include <linux/regulator/driver.h> #include <linux/device.h> +#include <linux/static_key.h> 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 */ |