Skip to content

Commit

Permalink
net_sched: fix THROTTLED/RUNNING race
Browse files Browse the repository at this point in the history
commit fd245a4 (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 fd245a4, 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 3711210 (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>
  • Loading branch information
Eric Dumazet authored and David S. Miller committed Mar 24, 2011
1 parent 8c64b4c commit ef352e7
Showing 1 changed file with 4 additions and 4 deletions.
8 changes: 4 additions & 4 deletions include/net/sch_generic.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,14 +25,14 @@ struct qdisc_rate_table {
enum qdisc_state_t {
__QDISC_STATE_SCHED,
__QDISC_STATE_DEACTIVATED,
__QDISC_STATE_THROTTLED,
};

/*
* following bits are only changed while qdisc lock is held
*/
enum qdisc___state_t {
__QDISC___STATE_RUNNING = 1,
__QDISC___STATE_THROTTLED = 2,
};

struct qdisc_size_table {
Expand Down Expand Up @@ -106,17 +106,17 @@ static inline void qdisc_run_end(struct Qdisc *qdisc)

static inline bool qdisc_is_throttled(const struct Qdisc *qdisc)
{
return (qdisc->__state & __QDISC___STATE_THROTTLED) ? true : false;
return test_bit(__QDISC_STATE_THROTTLED, &qdisc->state) ? true : false;
}

static inline void qdisc_throttled(struct Qdisc *qdisc)
{
qdisc->__state |= __QDISC___STATE_THROTTLED;
set_bit(__QDISC_STATE_THROTTLED, &qdisc->state);
}

static inline void qdisc_unthrottled(struct Qdisc *qdisc)
{
qdisc->__state &= ~__QDISC___STATE_THROTTLED;
clear_bit(__QDISC_STATE_THROTTLED, &qdisc->state);
}

struct Qdisc_class_ops {
Expand Down

0 comments on commit ef352e7

Please sign in to comment.