aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHannes Frederic Sowa <hannes@stressinduktion.org>2014-05-11 16:59:30 -0400
committerDavid S. Miller <davem@davemloft.net>2014-05-14 00:37:34 -0400
commit3d4405226d27b3a215e4d03cfa51f536244e5de7 (patch)
treec7b5f491bf08622f82d7abb0591a8ac4c038d4b4
parent773cd38f40b8834be991dbfed36683acc1dd41ee (diff)
net: avoid dependency of net_get_random_once on nop patching
net_get_random_once depends on the static keys infrastructure to patch up the branch to the slow path during boot. This was realized by abusing the static keys api and defining a new initializer to not enable the call site while still indicating that the branch point should get patched up. This was needed to have the fast path considered likely by gcc. The static key initialization during boot up normally walks through all the registered keys and either patches in ideal nops or enables the jump site but omitted that step on x86 if ideal nops where already placed at static_key branch points. Thus net_get_random_once branches not always became active. This patch switches net_get_random_once to the ordinary static_key api and thus places the kernel fast path in the - by gcc considered - unlikely path. Microbenchmarks on Intel and AMD x86-64 showed that the unlikely path actually beats the likely path in terms of cycle cost and that different nop patterns did not make much difference, thus this switch should not be noticeable. Fixes: a48e42920ff38b ("net: introduce new macro net_get_random_once") Reported-by: Tuomas Räsänen <tuomasjjrasanen@tjjr.fi> Cc: Linus Torvalds <torvalds@linux-foundation.org> Signed-off-by: Hannes Frederic Sowa <hannes@stressinduktion.org> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--include/linux/net.h15
-rw-r--r--net/core/utils.c8
2 files changed, 8 insertions, 15 deletions
diff --git a/include/linux/net.h b/include/linux/net.h
index 94734a6259a4..17d83393afcc 100644
--- a/include/linux/net.h
+++ b/include/linux/net.h
@@ -248,24 +248,17 @@ do { \
248bool __net_get_random_once(void *buf, int nbytes, bool *done, 248bool __net_get_random_once(void *buf, int nbytes, bool *done,
249 struct static_key *done_key); 249 struct static_key *done_key);
250 250
251#ifdef HAVE_JUMP_LABEL
252#define ___NET_RANDOM_STATIC_KEY_INIT ((struct static_key) \
253 { .enabled = ATOMIC_INIT(0), .entries = (void *)1 })
254#else /* !HAVE_JUMP_LABEL */
255#define ___NET_RANDOM_STATIC_KEY_INIT STATIC_KEY_INIT_FALSE
256#endif /* HAVE_JUMP_LABEL */
257
258#define net_get_random_once(buf, nbytes) \ 251#define net_get_random_once(buf, nbytes) \
259 ({ \ 252 ({ \
260 bool ___ret = false; \ 253 bool ___ret = false; \
261 static bool ___done = false; \ 254 static bool ___done = false; \
262 static struct static_key ___done_key = \ 255 static struct static_key ___once_key = \
263 ___NET_RANDOM_STATIC_KEY_INIT; \ 256 STATIC_KEY_INIT_TRUE; \
264 if (!static_key_true(&___done_key)) \ 257 if (static_key_true(&___once_key)) \
265 ___ret = __net_get_random_once(buf, \ 258 ___ret = __net_get_random_once(buf, \
266 nbytes, \ 259 nbytes, \
267 &___done, \ 260 &___done, \
268 &___done_key); \ 261 &___once_key); \
269 ___ret; \ 262 ___ret; \
270 }) 263 })
271 264
diff --git a/net/core/utils.c b/net/core/utils.c
index 2f737bf90b3f..eed34338736c 100644
--- a/net/core/utils.c
+++ b/net/core/utils.c
@@ -348,8 +348,8 @@ static void __net_random_once_deferred(struct work_struct *w)
348{ 348{
349 struct __net_random_once_work *work = 349 struct __net_random_once_work *work =
350 container_of(w, struct __net_random_once_work, work); 350 container_of(w, struct __net_random_once_work, work);
351 if (!static_key_enabled(work->key)) 351 BUG_ON(!static_key_enabled(work->key));
352 static_key_slow_inc(work->key); 352 static_key_slow_dec(work->key);
353 kfree(work); 353 kfree(work);
354} 354}
355 355
@@ -367,7 +367,7 @@ static void __net_random_once_disable_jump(struct static_key *key)
367} 367}
368 368
369bool __net_get_random_once(void *buf, int nbytes, bool *done, 369bool __net_get_random_once(void *buf, int nbytes, bool *done,
370 struct static_key *done_key) 370 struct static_key *once_key)
371{ 371{
372 static DEFINE_SPINLOCK(lock); 372 static DEFINE_SPINLOCK(lock);
373 unsigned long flags; 373 unsigned long flags;
@@ -382,7 +382,7 @@ bool __net_get_random_once(void *buf, int nbytes, bool *done,
382 *done = true; 382 *done = true;
383 spin_unlock_irqrestore(&lock, flags); 383 spin_unlock_irqrestore(&lock, flags);
384 384
385 __net_random_once_disable_jump(done_key); 385 __net_random_once_disable_jump(once_key);
386 386
387 return true; 387 return true;
388} 388}