[PATCH net-next 3/3] net: add READ_ONCE()/WRITE_ONCE() annotations for dev->prio_tc_map
Eric Dumazet <[email protected]>
| Newsgroups | org.kernel.vger.netdev |
|---|---|
| Message-ID | <[email protected]> |
Concurrent fast-path readers access dev->prio_tc_map (e.g. via skb_tx_hash(), netdev_get_prio_tc_map(), and qdiscs) while writers update entries in dev->prio_tc_map or reset/clear the map via netdev_reset_tc() and netdev_unbind_sb_channel(). Furthermore, memset() in netdev_reset_tc() and netdev_unbind_sb_channel() provides no guarantee of performing atomic word/byte stores. Add READ_ONCE() and WRITE_ONCE() annotations to netdev_get_prio_tc_map() and netdev_set_prio_tc_map(), replace memset() in dev.c with explicit WRITE_ONCE() loops, and update direct array accesses in qdiscs to use netdev_get_prio_tc_map(). Signed-off-by: Eric Dumazet <[email protected]> --- include/linux/netdevice.h | 4 ++-- net/core/dev.c | 6 ++++-- net/sched/sch_mqprio_lib.c | 3 ++- net/sched/sch_taprio.c | 2 +- 4 files changed, 9 insertions(+), 6 deletions(-) diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index db0002bd68f90fa4dd087edabc11549bc8ee0f66..de307c01d33eb8835bdbe32118c2fc086e53a51c 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -2671,7 +2671,7 @@ static inline bool netif_elide_gro(const struct net_device *dev) static inline int netdev_get_prio_tc_map(const struct net_device *dev, u32 prio) { - return dev->prio_tc_map[prio & TC_BITMASK]; + return READ_ONCE(dev->prio_tc_map[prio & TC_BITMASK]); } static inline @@ -2680,7 +2680,7 @@ int netdev_set_prio_tc_map(struct net_device *dev, u8 prio, u8 tc) if (tc >= READ_ONCE(dev->num_tc)) return -EINVAL; - dev->prio_tc_map[prio & TC_BITMASK] = tc & TC_BITMASK; + WRITE_ONCE(dev->prio_tc_map[prio & TC_BITMASK], tc & TC_BITMASK); return 0; } diff --git a/net/core/dev.c b/net/core/dev.c index 8ffae11d272e979bab5b64f4d912d3d97f738d48..d52285ac01a54fdafa63703f1af134e19d028ffd 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -3124,7 +3124,8 @@ void netdev_reset_tc(struct net_device *dev) WRITE_ONCE(dev->num_tc, 0); for (i = 0; i < TC_MAX_QUEUE; i++) WRITE_ONCE(dev->tc_to_txq[i].combined, 0); - memset(dev->prio_tc_map, 0, sizeof(dev->prio_tc_map)); + for (i = 0; i <= TC_BITMASK; i++) + WRITE_ONCE(dev->prio_tc_map[i], 0); } EXPORT_SYMBOL(netdev_reset_tc); @@ -3172,7 +3173,8 @@ void netdev_unbind_sb_channel(struct net_device *dev, #endif for (i = 0; i < TC_MAX_QUEUE; i++) WRITE_ONCE(sb_dev->tc_to_txq[i].combined, 0); - memset(sb_dev->prio_tc_map, 0, sizeof(sb_dev->prio_tc_map)); + for (i = 0; i <= TC_BITMASK; i++) + WRITE_ONCE(sb_dev->prio_tc_map[i], 0); while (txq-- != &dev->_tx[0]) { if (txq->sb_dev == sb_dev) diff --git a/net/sched/sch_mqprio_lib.c b/net/sched/sch_mqprio_lib.c index b60e130c70781479eed0ea5a02d01197f03f4895..888935e34d4381f85aaf4c97cf9c4bacb93e13f1 100644 --- a/net/sched/sch_mqprio_lib.c +++ b/net/sched/sch_mqprio_lib.c @@ -105,7 +105,8 @@ void mqprio_qopt_reconstruct(struct net_device *dev, struct tc_mqprio_qopt *qopt int tc, num_tc = netdev_get_num_tc(dev); qopt->num_tc = num_tc; - memcpy(qopt->prio_tc_map, dev->prio_tc_map, sizeof(qopt->prio_tc_map)); + for (tc = 0; tc <= TC_BITMASK; tc++) + qopt->prio_tc_map[tc] = netdev_get_prio_tc_map(dev, tc); for (tc = 0; tc < num_tc; tc++) { struct netdev_tc_txq res; diff --git a/net/sched/sch_taprio.c b/net/sched/sch_taprio.c index 18fcb4e78456a2f74fa5d3465175d100a39575b4..39ac5b97aa3af83fe63ab5ff9173c39700f6bbb0 100644 --- a/net/sched/sch_taprio.c +++ b/net/sched/sch_taprio.c @@ -1813,7 +1813,7 @@ static int taprio_mqprio_cmp(const struct net_device *dev, } for (i = 0; i <= TC_BITMASK; i++) - if (dev->prio_tc_map[i] != mqprio->prio_tc_map[i]) + if (netdev_get_prio_tc_map(dev, i) != mqprio->prio_tc_map[i]) return -1; return 0; -- 2.55.0.679.g6767b8d81c-goog