diff options
-rw-r--r-- | net/core/dev.c | 35 |
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); | |||
1698 | static struct static_key netstamp_needed __read_mostly; | 1698 | static struct static_key netstamp_needed __read_mostly; |
1699 | #ifdef HAVE_JUMP_LABEL | 1699 | #ifdef HAVE_JUMP_LABEL |
1700 | static atomic_t netstamp_needed_deferred; | 1700 | static atomic_t netstamp_needed_deferred; |
1701 | static atomic_t netstamp_wanted; | ||
1701 | static void netstamp_clear(struct work_struct *work) | 1702 | static 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 | } |
1708 | static DECLARE_WORK(netstamp_work, netstamp_clear); | 1713 | static DECLARE_WORK(netstamp_work, netstamp_clear); |
1709 | #endif | 1714 | #endif |
1710 | 1715 | ||
1711 | void net_enable_timestamp(void) | 1716 | void 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 | } |
1715 | EXPORT_SYMBOL(net_enable_timestamp); | 1734 | EXPORT_SYMBOL(net_enable_timestamp); |
1716 | 1735 | ||
1717 | void net_disable_timestamp(void) | 1736 | void 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); |