aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEric Dumazet <edumazet@google.com>2017-03-01 17:28:39 -0500
committerDavid S. Miller <davem@davemloft.net>2017-03-01 23:55:57 -0500
commit13baa00ad01bb3a9f893e3a08cbc2d072fc0c15d (patch)
treeebcc0624dcccf6c25949f3e52c26a75f542bb7b8
parent540e2894f7905538740aaf122bd8e0548e1c34a4 (diff)
net: net_enable_timestamp() can be called from irq contexts
It is now very clear that silly TCP listeners might play with enabling/disabling timestamping while new children are added to their accept queue. Meaning net_enable_timestamp() can be called from BH context while current state of the static key is not enabled. Lets play safe and allow all contexts. The work queue is scheduled only under the problematic cases, which are the static key enable/disable transition, to not slow down critical paths. This extends and improves what we did in commit 5fa8bbda38c6 ("net: use a work queue to defer net_disable_timestamp() work") Fixes: b90e5794c5bd ("net: dont call jump_label_dec from irq context") Signed-off-by: Eric Dumazet <edumazet@google.com> Reported-by: Dmitry Vyukov <dvyukov@google.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--net/core/dev.c35
1 files changed, 31 insertions, 4 deletions
diff --git a/net/core/dev.c b/net/core/dev.c
index e63bf61b19be..8637b2b71f3d 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -1698,27 +1698,54 @@ EXPORT_SYMBOL_GPL(net_dec_egress_queue);
1698static struct static_key netstamp_needed __read_mostly; 1698static struct static_key netstamp_needed __read_mostly;
1699#ifdef HAVE_JUMP_LABEL 1699#ifdef HAVE_JUMP_LABEL
1700static atomic_t netstamp_needed_deferred; 1700static atomic_t netstamp_needed_deferred;
1701static atomic_t netstamp_wanted;
1701static void netstamp_clear(struct work_struct *work) 1702static void netstamp_clear(struct work_struct *work)
1702{ 1703{
1703 int deferred = atomic_xchg(&netstamp_needed_deferred, 0); 1704 int deferred = atomic_xchg(&netstamp_needed_deferred, 0);
1705 int wanted;
1704 1706
1705 while (deferred--) 1707 wanted = atomic_add_return(deferred, &netstamp_wanted);
1706 static_key_slow_dec(&netstamp_needed); 1708 if (wanted > 0)
1709 static_key_enable(&netstamp_needed);
1710 else
1711 static_key_disable(&netstamp_needed);
1707} 1712}
1708static DECLARE_WORK(netstamp_work, netstamp_clear); 1713static DECLARE_WORK(netstamp_work, netstamp_clear);
1709#endif 1714#endif
1710 1715
1711void net_enable_timestamp(void) 1716void net_enable_timestamp(void)
1712{ 1717{
1718#ifdef HAVE_JUMP_LABEL
1719 int wanted;
1720
1721 while (1) {
1722 wanted = atomic_read(&netstamp_wanted);
1723 if (wanted <= 0)
1724 break;
1725 if (atomic_cmpxchg(&netstamp_wanted, wanted, wanted + 1) == wanted)
1726 return;
1727 }
1728 atomic_inc(&netstamp_needed_deferred);
1729 schedule_work(&netstamp_work);
1730#else
1713 static_key_slow_inc(&netstamp_needed); 1731 static_key_slow_inc(&netstamp_needed);
1732#endif
1714} 1733}
1715EXPORT_SYMBOL(net_enable_timestamp); 1734EXPORT_SYMBOL(net_enable_timestamp);
1716 1735
1717void net_disable_timestamp(void) 1736void net_disable_timestamp(void)
1718{ 1737{
1719#ifdef HAVE_JUMP_LABEL 1738#ifdef HAVE_JUMP_LABEL
1720 /* net_disable_timestamp() can be called from non process context */ 1739 int wanted;
1721 atomic_inc(&netstamp_needed_deferred); 1740
1741 while (1) {
1742 wanted = atomic_read(&netstamp_wanted);
1743 if (wanted <= 1)
1744 break;
1745 if (atomic_cmpxchg(&netstamp_wanted, wanted, wanted - 1) == wanted)
1746 return;
1747 }
1748 atomic_dec(&netstamp_needed_deferred);
1722 schedule_work(&netstamp_work); 1749 schedule_work(&netstamp_work);
1723#else 1750#else
1724 static_key_slow_dec(&netstamp_needed); 1751 static_key_slow_dec(&netstamp_needed);