Skip to content

Commit 46e5da4

Browse files
jrfastabdavem330
authored andcommitted
net: qdisc: use rcu prefix and silence sparse warnings
Add __rcu notation to qdisc handling by doing this we can make smatch output more legible. And anyways some of the cases should be using rcu_dereference() see qdisc_all_tx_empty(), qdisc_tx_chainging(), and so on. Also *wake_queue() API is commonly called from driver timer routines without rcu lock or rtnl lock. So I added rcu_read_lock() blocks around netif_wake_subqueue and netif_tx_wake_queue. Signed-off-by: John Fastabend <john.r.fastabend@intel.com> Acked-by: Eric Dumazet <edumazet@google.com> Signed-off-by: David S. Miller <davem@davemloft.net>
1 parent d101564 commit 46e5da4

File tree

6 files changed

+82
-42
lines changed

6 files changed

+82
-42
lines changed

include/linux/netdevice.h

Lines changed: 4 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -543,7 +543,7 @@ struct netdev_queue {
543543
* read mostly part
544544
*/
545545
struct net_device *dev;
546-
struct Qdisc *qdisc;
546+
struct Qdisc __rcu *qdisc;
547547
struct Qdisc *qdisc_sleeping;
548548
#ifdef CONFIG_SYSFS
549549
struct kobject kobj;
@@ -2356,12 +2356,7 @@ static inline void input_queue_tail_incr_save(struct softnet_data *sd,
23562356
DECLARE_PER_CPU_ALIGNED(struct softnet_data, softnet_data);
23572357

23582358
void __netif_schedule(struct Qdisc *q);
2359-
2360-
static inline void netif_schedule_queue(struct netdev_queue *txq)
2361-
{
2362-
if (!(txq->state & QUEUE_STATE_ANY_XOFF))
2363-
__netif_schedule(txq->qdisc);
2364-
}
2359+
void netif_schedule_queue(struct netdev_queue *txq);
23652360

23662361
static inline void netif_tx_schedule_all(struct net_device *dev)
23672362
{
@@ -2397,11 +2392,7 @@ static inline void netif_tx_start_all_queues(struct net_device *dev)
23972392
}
23982393
}
23992394

2400-
static inline void netif_tx_wake_queue(struct netdev_queue *dev_queue)
2401-
{
2402-
if (test_and_clear_bit(__QUEUE_STATE_DRV_XOFF, &dev_queue->state))
2403-
__netif_schedule(dev_queue->qdisc);
2404-
}
2395+
void netif_tx_wake_queue(struct netdev_queue *dev_queue);
24052396

24062397
/**
24072398
* netif_wake_queue - restart transmit
@@ -2673,19 +2664,7 @@ static inline bool netif_subqueue_stopped(const struct net_device *dev,
26732664
return __netif_subqueue_stopped(dev, skb_get_queue_mapping(skb));
26742665
}
26752666

2676-
/**
2677-
* netif_wake_subqueue - allow sending packets on subqueue
2678-
* @dev: network device
2679-
* @queue_index: sub queue index
2680-
*
2681-
* Resume individual transmit queue of a device with multiple transmit queues.
2682-
*/
2683-
static inline void netif_wake_subqueue(struct net_device *dev, u16 queue_index)
2684-
{
2685-
struct netdev_queue *txq = netdev_get_tx_queue(dev, queue_index);
2686-
if (test_and_clear_bit(__QUEUE_STATE_DRV_XOFF, &txq->state))
2687-
__netif_schedule(txq->qdisc);
2688-
}
2667+
void netif_wake_subqueue(struct net_device *dev, u16 queue_index);
26892668

26902669
#ifdef CONFIG_XPS
26912670
int netif_set_xps_queue(struct net_device *dev, const struct cpumask *mask,

include/net/sch_generic.h

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -259,7 +259,9 @@ static inline spinlock_t *qdisc_lock(struct Qdisc *qdisc)
259259

260260
static inline struct Qdisc *qdisc_root(const struct Qdisc *qdisc)
261261
{
262-
return qdisc->dev_queue->qdisc;
262+
struct Qdisc *q = rcu_dereference_rtnl(qdisc->dev_queue->qdisc);
263+
264+
return q;
263265
}
264266

265267
static inline struct Qdisc *qdisc_root_sleeping(const struct Qdisc *qdisc)
@@ -384,7 +386,7 @@ static inline void qdisc_reset_all_tx_gt(struct net_device *dev, unsigned int i)
384386
struct Qdisc *qdisc;
385387

386388
for (; i < dev->num_tx_queues; i++) {
387-
qdisc = netdev_get_tx_queue(dev, i)->qdisc;
389+
qdisc = rtnl_dereference(netdev_get_tx_queue(dev, i)->qdisc);
388390
if (qdisc) {
389391
spin_lock_bh(qdisc_lock(qdisc));
390392
qdisc_reset(qdisc);
@@ -402,23 +404,29 @@ static inline void qdisc_reset_all_tx(struct net_device *dev)
402404
static inline bool qdisc_all_tx_empty(const struct net_device *dev)
403405
{
404406
unsigned int i;
407+
408+
rcu_read_lock();
405409
for (i = 0; i < dev->num_tx_queues; i++) {
406410
struct netdev_queue *txq = netdev_get_tx_queue(dev, i);
407-
const struct Qdisc *q = txq->qdisc;
411+
const struct Qdisc *q = rcu_dereference(txq->qdisc);
408412

409-
if (q->q.qlen)
413+
if (q->q.qlen) {
414+
rcu_read_unlock();
410415
return false;
416+
}
411417
}
418+
rcu_read_unlock();
412419
return true;
413420
}
414421

415422
/* Are any of the TX qdiscs changing? */
416423
static inline bool qdisc_tx_changing(const struct net_device *dev)
417424
{
418425
unsigned int i;
426+
419427
for (i = 0; i < dev->num_tx_queues; i++) {
420428
struct netdev_queue *txq = netdev_get_tx_queue(dev, i);
421-
if (txq->qdisc != txq->qdisc_sleeping)
429+
if (rcu_access_pointer(txq->qdisc) != txq->qdisc_sleeping)
422430
return true;
423431
}
424432
return false;
@@ -428,9 +436,10 @@ static inline bool qdisc_tx_changing(const struct net_device *dev)
428436
static inline bool qdisc_tx_is_noop(const struct net_device *dev)
429437
{
430438
unsigned int i;
439+
431440
for (i = 0; i < dev->num_tx_queues; i++) {
432441
struct netdev_queue *txq = netdev_get_tx_queue(dev, i);
433-
if (txq->qdisc != &noop_qdisc)
442+
if (rcu_access_pointer(txq->qdisc) != &noop_qdisc)
434443
return false;
435444
}
436445
return true;

net/core/dev.c

Lines changed: 49 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2177,6 +2177,53 @@ static struct dev_kfree_skb_cb *get_kfree_skb_cb(const struct sk_buff *skb)
21772177
return (struct dev_kfree_skb_cb *)skb->cb;
21782178
}
21792179

2180+
void netif_schedule_queue(struct netdev_queue *txq)
2181+
{
2182+
rcu_read_lock();
2183+
if (!(txq->state & QUEUE_STATE_ANY_XOFF)) {
2184+
struct Qdisc *q = rcu_dereference(txq->qdisc);
2185+
2186+
__netif_schedule(q);
2187+
}
2188+
rcu_read_unlock();
2189+
}
2190+
EXPORT_SYMBOL(netif_schedule_queue);
2191+
2192+
/**
2193+
* netif_wake_subqueue - allow sending packets on subqueue
2194+
* @dev: network device
2195+
* @queue_index: sub queue index
2196+
*
2197+
* Resume individual transmit queue of a device with multiple transmit queues.
2198+
*/
2199+
void netif_wake_subqueue(struct net_device *dev, u16 queue_index)
2200+
{
2201+
struct netdev_queue *txq = netdev_get_tx_queue(dev, queue_index);
2202+
2203+
if (test_and_clear_bit(__QUEUE_STATE_DRV_XOFF, &txq->state)) {
2204+
struct Qdisc *q;
2205+
2206+
rcu_read_lock();
2207+
q = rcu_dereference(txq->qdisc);
2208+
__netif_schedule(q);
2209+
rcu_read_unlock();
2210+
}
2211+
}
2212+
EXPORT_SYMBOL(netif_wake_subqueue);
2213+
2214+
void netif_tx_wake_queue(struct netdev_queue *dev_queue)
2215+
{
2216+
if (test_and_clear_bit(__QUEUE_STATE_DRV_XOFF, &dev_queue->state)) {
2217+
struct Qdisc *q;
2218+
2219+
rcu_read_lock();
2220+
q = rcu_dereference(dev_queue->qdisc);
2221+
__netif_schedule(q);
2222+
rcu_read_unlock();
2223+
}
2224+
}
2225+
EXPORT_SYMBOL(netif_tx_wake_queue);
2226+
21802227
void __dev_kfree_skb_irq(struct sk_buff *skb, enum skb_free_reason reason)
21812228
{
21822229
unsigned long flags;
@@ -3432,7 +3479,7 @@ static int ing_filter(struct sk_buff *skb, struct netdev_queue *rxq)
34323479
skb->tc_verd = SET_TC_RTTL(skb->tc_verd, ttl);
34333480
skb->tc_verd = SET_TC_AT(skb->tc_verd, AT_INGRESS);
34343481

3435-
q = rxq->qdisc;
3482+
q = rcu_dereference(rxq->qdisc);
34363483
if (q != &noop_qdisc) {
34373484
spin_lock(qdisc_lock(q));
34383485
if (likely(!test_bit(__QDISC_STATE_DEACTIVATED, &q->state)))
@@ -3449,7 +3496,7 @@ static inline struct sk_buff *handle_ing(struct sk_buff *skb,
34493496
{
34503497
struct netdev_queue *rxq = rcu_dereference(skb->dev->ingress_queue);
34513498

3452-
if (!rxq || rxq->qdisc == &noop_qdisc)
3499+
if (!rxq || rcu_access_pointer(rxq->qdisc) == &noop_qdisc)
34533500
goto out;
34543501

34553502
if (*pt_prev) {

net/sched/sch_generic.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -783,7 +783,7 @@ static void dev_deactivate_queue(struct net_device *dev,
783783
struct Qdisc *qdisc_default = _qdisc_default;
784784
struct Qdisc *qdisc;
785785

786-
qdisc = dev_queue->qdisc;
786+
qdisc = rtnl_dereference(dev_queue->qdisc);
787787
if (qdisc) {
788788
spin_lock_bh(qdisc_lock(qdisc));
789789

@@ -876,7 +876,7 @@ static void dev_init_scheduler_queue(struct net_device *dev,
876876
{
877877
struct Qdisc *qdisc = _qdisc;
878878

879-
dev_queue->qdisc = qdisc;
879+
rcu_assign_pointer(dev_queue->qdisc, qdisc);
880880
dev_queue->qdisc_sleeping = qdisc;
881881
}
882882

net/sched/sch_mqprio.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -231,7 +231,7 @@ static int mqprio_dump(struct Qdisc *sch, struct sk_buff *skb)
231231
memset(&sch->qstats, 0, sizeof(sch->qstats));
232232

233233
for (i = 0; i < dev->num_tx_queues; i++) {
234-
qdisc = netdev_get_tx_queue(dev, i)->qdisc;
234+
qdisc = rtnl_dereference(netdev_get_tx_queue(dev, i)->qdisc);
235235
spin_lock_bh(qdisc_lock(qdisc));
236236
sch->q.qlen += qdisc->q.qlen;
237237
sch->bstats.bytes += qdisc->bstats.bytes;
@@ -340,7 +340,9 @@ static int mqprio_dump_class_stats(struct Qdisc *sch, unsigned long cl,
340340
spin_unlock_bh(d->lock);
341341

342342
for (i = tc.offset; i < tc.offset + tc.count; i++) {
343-
qdisc = netdev_get_tx_queue(dev, i)->qdisc;
343+
struct netdev_queue *q = netdev_get_tx_queue(dev, i);
344+
345+
qdisc = rtnl_dereference(q->qdisc);
344346
spin_lock_bh(qdisc_lock(qdisc));
345347
bstats.bytes += qdisc->bstats.bytes;
346348
bstats.packets += qdisc->bstats.packets;

net/sched/sch_teql.c

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -96,19 +96,22 @@ teql_dequeue(struct Qdisc *sch)
9696
struct teql_sched_data *dat = qdisc_priv(sch);
9797
struct netdev_queue *dat_queue;
9898
struct sk_buff *skb;
99+
struct Qdisc *q;
99100

100101
skb = __skb_dequeue(&dat->q);
101102
dat_queue = netdev_get_tx_queue(dat->m->dev, 0);
103+
q = rcu_dereference_bh(dat_queue->qdisc);
104+
102105
if (skb == NULL) {
103-
struct net_device *m = qdisc_dev(dat_queue->qdisc);
106+
struct net_device *m = qdisc_dev(q);
104107
if (m) {
105108
dat->m->slaves = sch;
106109
netif_wake_queue(m);
107110
}
108111
} else {
109112
qdisc_bstats_update(sch, skb);
110113
}
111-
sch->q.qlen = dat->q.qlen + dat_queue->qdisc->q.qlen;
114+
sch->q.qlen = dat->q.qlen + q->q.qlen;
112115
return skb;
113116
}
114117

@@ -157,9 +160,9 @@ teql_destroy(struct Qdisc *sch)
157160
txq = netdev_get_tx_queue(master->dev, 0);
158161
master->slaves = NULL;
159162

160-
root_lock = qdisc_root_sleeping_lock(txq->qdisc);
163+
root_lock = qdisc_root_sleeping_lock(rtnl_dereference(txq->qdisc));
161164
spin_lock_bh(root_lock);
162-
qdisc_reset(txq->qdisc);
165+
qdisc_reset(rtnl_dereference(txq->qdisc));
163166
spin_unlock_bh(root_lock);
164167
}
165168
}
@@ -266,7 +269,7 @@ static inline int teql_resolve(struct sk_buff *skb,
266269
struct dst_entry *dst = skb_dst(skb);
267270
int res;
268271

269-
if (txq->qdisc == &noop_qdisc)
272+
if (rcu_access_pointer(txq->qdisc) == &noop_qdisc)
270273
return -ENODEV;
271274

272275
if (!dev->header_ops || !dst)

0 commit comments

Comments
 (0)