Skip to content

Commit 13baa00

Browse files
edumazetdavem330
authored andcommitted
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 5fa8bbd ("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 <[email protected]> Reported-by: Dmitry Vyukov <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 540e289 commit 13baa00

File tree

1 file changed

+31
-4
lines changed

1 file changed

+31
-4
lines changed

net/core/dev.c

Lines changed: 31 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1698,27 +1698,54 @@ EXPORT_SYMBOL_GPL(net_dec_egress_queue);
16981698
static struct static_key netstamp_needed __read_mostly;
16991699
#ifdef HAVE_JUMP_LABEL
17001700
static atomic_t netstamp_needed_deferred;
1701+
static atomic_t netstamp_wanted;
17011702
static void netstamp_clear(struct work_struct *work)
17021703
{
17031704
int deferred = atomic_xchg(&netstamp_needed_deferred, 0);
1705+
int wanted;
17041706

1705-
while (deferred--)
1706-
static_key_slow_dec(&netstamp_needed);
1707+
wanted = atomic_add_return(deferred, &netstamp_wanted);
1708+
if (wanted > 0)
1709+
static_key_enable(&netstamp_needed);
1710+
else
1711+
static_key_disable(&netstamp_needed);
17071712
}
17081713
static DECLARE_WORK(netstamp_work, netstamp_clear);
17091714
#endif
17101715

17111716
void net_enable_timestamp(void)
17121717
{
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
17131731
static_key_slow_inc(&netstamp_needed);
1732+
#endif
17141733
}
17151734
EXPORT_SYMBOL(net_enable_timestamp);
17161735

17171736
void net_disable_timestamp(void)
17181737
{
17191738
#ifdef HAVE_JUMP_LABEL
1720-
/* net_disable_timestamp() can be called from non process context */
1721-
atomic_inc(&netstamp_needed_deferred);
1739+
int wanted;
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);
17221749
schedule_work(&netstamp_work);
17231750
#else
17241751
static_key_slow_dec(&netstamp_needed);

0 commit comments

Comments
 (0)