diff options
author | John Fastabend <john.fastabend@gmail.com> | 2014-09-12 23:04:52 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2014-09-13 12:30:25 -0400 |
commit | 46e5da40aec256155cfedee96dd21a75da941f2c (patch) | |
tree | cc3986c52025d252c2a063053692595e60c80e13 /include/net/sch_generic.h | |
parent | d1015645dd535bbf10e52a3ef6d02ee0c3e0b267 (diff) |
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>
Diffstat (limited to 'include/net/sch_generic.h')
-rw-r--r-- | include/net/sch_generic.h | 21 |
1 files changed, 15 insertions, 6 deletions
diff --git a/include/net/sch_generic.h b/include/net/sch_generic.h index a3cfb8ebeb53..56838ab29b42 100644 --- a/include/net/sch_generic.h +++ b/include/net/sch_generic.h | |||
@@ -259,7 +259,9 @@ static inline spinlock_t *qdisc_lock(struct Qdisc *qdisc) | |||
259 | 259 | ||
260 | static inline struct Qdisc *qdisc_root(const struct Qdisc *qdisc) | 260 | static inline struct Qdisc *qdisc_root(const struct Qdisc *qdisc) |
261 | { | 261 | { |
262 | return qdisc->dev_queue->qdisc; | 262 | struct Qdisc *q = rcu_dereference_rtnl(qdisc->dev_queue->qdisc); |
263 | |||
264 | return q; | ||
263 | } | 265 | } |
264 | 266 | ||
265 | static inline struct Qdisc *qdisc_root_sleeping(const struct Qdisc *qdisc) | 267 | 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) | |||
384 | struct Qdisc *qdisc; | 386 | struct Qdisc *qdisc; |
385 | 387 | ||
386 | for (; i < dev->num_tx_queues; i++) { | 388 | 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); |
388 | if (qdisc) { | 390 | if (qdisc) { |
389 | spin_lock_bh(qdisc_lock(qdisc)); | 391 | spin_lock_bh(qdisc_lock(qdisc)); |
390 | qdisc_reset(qdisc); | 392 | qdisc_reset(qdisc); |
@@ -402,13 +404,18 @@ static inline void qdisc_reset_all_tx(struct net_device *dev) | |||
402 | static inline bool qdisc_all_tx_empty(const struct net_device *dev) | 404 | static inline bool qdisc_all_tx_empty(const struct net_device *dev) |
403 | { | 405 | { |
404 | unsigned int i; | 406 | unsigned int i; |
407 | |||
408 | rcu_read_lock(); | ||
405 | for (i = 0; i < dev->num_tx_queues; i++) { | 409 | for (i = 0; i < dev->num_tx_queues; i++) { |
406 | struct netdev_queue *txq = netdev_get_tx_queue(dev, i); | 410 | 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); |
408 | 412 | ||
409 | if (q->q.qlen) | 413 | if (q->q.qlen) { |
414 | rcu_read_unlock(); | ||
410 | return false; | 415 | return false; |
416 | } | ||
411 | } | 417 | } |
418 | rcu_read_unlock(); | ||
412 | return true; | 419 | return true; |
413 | } | 420 | } |
414 | 421 | ||
@@ -416,9 +423,10 @@ static inline bool qdisc_all_tx_empty(const struct net_device *dev) | |||
416 | static inline bool qdisc_tx_changing(const struct net_device *dev) | 423 | static inline bool qdisc_tx_changing(const struct net_device *dev) |
417 | { | 424 | { |
418 | unsigned int i; | 425 | unsigned int i; |
426 | |||
419 | for (i = 0; i < dev->num_tx_queues; i++) { | 427 | for (i = 0; i < dev->num_tx_queues; i++) { |
420 | struct netdev_queue *txq = netdev_get_tx_queue(dev, i); | 428 | 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) |
422 | return true; | 430 | return true; |
423 | } | 431 | } |
424 | return false; | 432 | return false; |
@@ -428,9 +436,10 @@ static inline bool qdisc_tx_changing(const struct net_device *dev) | |||
428 | static inline bool qdisc_tx_is_noop(const struct net_device *dev) | 436 | static inline bool qdisc_tx_is_noop(const struct net_device *dev) |
429 | { | 437 | { |
430 | unsigned int i; | 438 | unsigned int i; |
439 | |||
431 | for (i = 0; i < dev->num_tx_queues; i++) { | 440 | for (i = 0; i < dev->num_tx_queues; i++) { |
432 | struct netdev_queue *txq = netdev_get_tx_queue(dev, i); | 441 | 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) |
434 | return false; | 443 | return false; |
435 | } | 444 | } |
436 | return true; | 445 | return true; |