| From 5b54fdcf5bad195039530d0f1c50b4b24a5027ca Mon Sep 17 00:00:00 2001 |
| From: Sasha Levin <sashal@kernel.org> |
| Date: Mon, 8 Mar 2021 09:38:12 +0100 |
| Subject: u64_stats,lockdep: Fix u64_stats_init() vs lockdep |
| |
| From: Peter Zijlstra <peterz@infradead.org> |
| |
| [ Upstream commit d5b0e0677bfd5efd17c5bbb00156931f0d41cb85 ] |
| |
| Jakub reported that: |
| |
| static struct net_device *rtl8139_init_board(struct pci_dev *pdev) |
| { |
| ... |
| u64_stats_init(&tp->rx_stats.syncp); |
| u64_stats_init(&tp->tx_stats.syncp); |
| ... |
| } |
| |
| results in lockdep getting confused between the RX and TX stats lock. |
| This is because u64_stats_init() is an inline calling seqcount_init(), |
| which is a macro using a static variable to generate a lockdep class. |
| |
| By wrapping that in an inline, we negate the effect of the macro and |
| fold the static key variable, hence the confusion. |
| |
| Fix by also making u64_stats_init() a macro for the case where it |
| matters, leaving the other case an inline for argument validation |
| etc. |
| |
| Reported-by: Jakub Kicinski <kuba@kernel.org> |
| Debugged-by: "Ahmed S. Darwish" <a.darwish@linutronix.de> |
| Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> |
| Tested-by: "Erhard F." <erhard_f@mailbox.org> |
| Link: https://lkml.kernel.org/r/YEXicy6+9MksdLZh@hirez.programming.kicks-ass.net |
| Signed-off-by: Sasha Levin <sashal@kernel.org> |
| --- |
| include/linux/u64_stats_sync.h | 7 ++++--- |
| 1 file changed, 4 insertions(+), 3 deletions(-) |
| |
| diff --git a/include/linux/u64_stats_sync.h b/include/linux/u64_stats_sync.h |
| index a27604f99ed0..11096b561dab 100644 |
| --- a/include/linux/u64_stats_sync.h |
| +++ b/include/linux/u64_stats_sync.h |
| @@ -69,12 +69,13 @@ struct u64_stats_sync { |
| }; |
| |
| |
| +#if BITS_PER_LONG == 32 && defined(CONFIG_SMP) |
| +#define u64_stats_init(syncp) seqcount_init(&(syncp)->seq) |
| +#else |
| static inline void u64_stats_init(struct u64_stats_sync *syncp) |
| { |
| -#if BITS_PER_LONG == 32 && defined(CONFIG_SMP) |
| - seqcount_init(&syncp->seq); |
| -#endif |
| } |
| +#endif |
| |
| static inline void u64_stats_update_begin(struct u64_stats_sync *syncp) |
| { |
| -- |
| 2.30.1 |
| |