net_sched: fix THROTTLED/RUNNING race

commit fd245a4adb52 (net_sched: move TCQ_F_THROTTLED flag)
added a race.

qdisc_watchdog() is run from softirq, so special care should be taken or
we can lose one state transition (THROTTLED/RUNNING)

Prior to fd245a4adb52, we were manipulating q->flags (qdisc->flags &=
~TCQ_F_THROTTLED;) and this manipulation could only race with
qdisc_warn_nonwc().

Since we want to avoid atomic ops in qdisc fast path - it was the
meaning of commit 371121057607e (QDISC_STATE_RUNNING dont need atomic
bit ops) - fix is to move THROTTLE bit into 'state' field, this one
being manipulated with SMP and IRQ safe operations.

Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by Eric Dumazet and committed by David S. Miller ef352e7c 8c64b4cc

+4 -4
+4 -4
include/net/sch_generic.h
··· 25 enum qdisc_state_t { 26 __QDISC_STATE_SCHED, 27 __QDISC_STATE_DEACTIVATED, 28 }; 29 30 /* ··· 33 */ 34 enum qdisc___state_t { 35 __QDISC___STATE_RUNNING = 1, 36 - __QDISC___STATE_THROTTLED = 2, 37 }; 38 39 struct qdisc_size_table { ··· 106 107 static inline bool qdisc_is_throttled(const struct Qdisc *qdisc) 108 { 109 - return (qdisc->__state & __QDISC___STATE_THROTTLED) ? true : false; 110 } 111 112 static inline void qdisc_throttled(struct Qdisc *qdisc) 113 { 114 - qdisc->__state |= __QDISC___STATE_THROTTLED; 115 } 116 117 static inline void qdisc_unthrottled(struct Qdisc *qdisc) 118 { 119 - qdisc->__state &= ~__QDISC___STATE_THROTTLED; 120 } 121 122 struct Qdisc_class_ops {
··· 25 enum qdisc_state_t { 26 __QDISC_STATE_SCHED, 27 __QDISC_STATE_DEACTIVATED, 28 + __QDISC_STATE_THROTTLED, 29 }; 30 31 /* ··· 32 */ 33 enum qdisc___state_t { 34 __QDISC___STATE_RUNNING = 1, 35 }; 36 37 struct qdisc_size_table { ··· 106 107 static inline bool qdisc_is_throttled(const struct Qdisc *qdisc) 108 { 109 + return test_bit(__QDISC_STATE_THROTTLED, &qdisc->state) ? true : false; 110 } 111 112 static inline void qdisc_throttled(struct Qdisc *qdisc) 113 { 114 + set_bit(__QDISC_STATE_THROTTLED, &qdisc->state); 115 } 116 117 static inline void qdisc_unthrottled(struct Qdisc *qdisc) 118 { 119 + clear_bit(__QDISC_STATE_THROTTLED, &qdisc->state); 120 } 121 122 struct Qdisc_class_ops {