Skip to content

Commit 9cfe942

Browse files
edumazetwtarreau
authored andcommitted
net: net_enable_timestamp() can be called from irq contexts
commit 13baa00 upstream. 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]> Signed-off-by: Willy Tarreau <[email protected]>
1 parent 12f1a0f commit 9cfe942

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
@@ -1560,27 +1560,54 @@ EXPORT_SYMBOL(call_netdevice_notifiers);
15601560
static struct static_key netstamp_needed __read_mostly;
15611561
#ifdef HAVE_JUMP_LABEL
15621562
static atomic_t netstamp_needed_deferred;
1563+
static atomic_t netstamp_wanted;
15631564
static void netstamp_clear(struct work_struct *work)
15641565
{
15651566
int deferred = atomic_xchg(&netstamp_needed_deferred, 0);
1567+
int wanted;
15661568

1567-
while (deferred--)
1568-
static_key_slow_dec(&netstamp_needed);
1569+
wanted = atomic_add_return(deferred, &netstamp_wanted);
1570+
if (wanted > 0)
1571+
static_key_enable(&netstamp_needed);
1572+
else
1573+
static_key_disable(&netstamp_needed);
15691574
}
15701575
static DECLARE_WORK(netstamp_work, netstamp_clear);
15711576
#endif
15721577

15731578
void net_enable_timestamp(void)
15741579
{
1580+
#ifdef HAVE_JUMP_LABEL
1581+
int wanted;
1582+
1583+
while (1) {
1584+
wanted = atomic_read(&netstamp_wanted);
1585+
if (wanted <= 0)
1586+
break;
1587+
if (atomic_cmpxchg(&netstamp_wanted, wanted, wanted + 1) == wanted)
1588+
return;
1589+
}
1590+
atomic_inc(&netstamp_needed_deferred);
1591+
schedule_work(&netstamp_work);
1592+
#else
15751593
static_key_slow_inc(&netstamp_needed);
1594+
#endif
15761595
}
15771596
EXPORT_SYMBOL(net_enable_timestamp);
15781597

15791598
void net_disable_timestamp(void)
15801599
{
15811600
#ifdef HAVE_JUMP_LABEL
1582-
/* net_disable_timestamp() can be called from non process context */
1583-
atomic_inc(&netstamp_needed_deferred);
1601+
int wanted;
1602+
1603+
while (1) {
1604+
wanted = atomic_read(&netstamp_wanted);
1605+
if (wanted <= 1)
1606+
break;
1607+
if (atomic_cmpxchg(&netstamp_wanted, wanted, wanted - 1) == wanted)
1608+
return;
1609+
}
1610+
atomic_dec(&netstamp_needed_deferred);
15841611
schedule_work(&netstamp_work);
15851612
#else
15861613
static_key_slow_dec(&netstamp_needed);

0 commit comments

Comments
 (0)