Skip to content

Commit a70c328

Browse files
edumazetgregkh
authored andcommitted
net: net_enable_timestamp() can be called from irq contexts
[ Upstream commit 13baa00ad01bb3a9f893e3a08cbc2d072fc0c15d ] 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: b90e579 ("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> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent f331d64 commit a70c328

1 file changed

Lines changed: 31 additions & 4 deletions

File tree

net/core/dev.c

Lines changed: 31 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1677,27 +1677,54 @@ EXPORT_SYMBOL_GPL(net_dec_ingress_queue);
16771677
static struct static_key netstamp_needed __read_mostly;
16781678
#ifdef HAVE_JUMP_LABEL
16791679
static atomic_t netstamp_needed_deferred;
1680+
static atomic_t netstamp_wanted;
16801681
static void netstamp_clear(struct work_struct *work)
16811682
{
16821683
int deferred = atomic_xchg(&netstamp_needed_deferred, 0);
1684+
int wanted;
16831685

1684-
while (deferred--)
1685-
static_key_slow_dec(&netstamp_needed);
1686+
wanted = atomic_add_return(deferred, &netstamp_wanted);
1687+
if (wanted > 0)
1688+
static_key_enable(&netstamp_needed);
1689+
else
1690+
static_key_disable(&netstamp_needed);
16861691
}
16871692
static DECLARE_WORK(netstamp_work, netstamp_clear);
16881693
#endif
16891694

16901695
void net_enable_timestamp(void)
16911696
{
1697+
#ifdef HAVE_JUMP_LABEL
1698+
int wanted;
1699+
1700+
while (1) {
1701+
wanted = atomic_read(&netstamp_wanted);
1702+
if (wanted <= 0)
1703+
break;
1704+
if (atomic_cmpxchg(&netstamp_wanted, wanted, wanted + 1) == wanted)
1705+
return;
1706+
}
1707+
atomic_inc(&netstamp_needed_deferred);
1708+
schedule_work(&netstamp_work);
1709+
#else
16921710
static_key_slow_inc(&netstamp_needed);
1711+
#endif
16931712
}
16941713
EXPORT_SYMBOL(net_enable_timestamp);
16951714

16961715
void net_disable_timestamp(void)
16971716
{
16981717
#ifdef HAVE_JUMP_LABEL
1699-
/* net_disable_timestamp() can be called from non process context */
1700-
atomic_inc(&netstamp_needed_deferred);
1718+
int wanted;
1719+
1720+
while (1) {
1721+
wanted = atomic_read(&netstamp_wanted);
1722+
if (wanted <= 1)
1723+
break;
1724+
if (atomic_cmpxchg(&netstamp_wanted, wanted, wanted - 1) == wanted)
1725+
return;
1726+
}
1727+
atomic_dec(&netstamp_needed_deferred);
17011728
schedule_work(&netstamp_work);
17021729
#else
17031730
static_key_slow_dec(&netstamp_needed);

0 commit comments

Comments
 (0)