Skip to content

Commit

Permalink
pkt_sched: Fix qdisc_watchdog() vs. dev_deactivate() race
Browse files Browse the repository at this point in the history
dev_deactivate() can skip rescheduling of a qdisc by qdisc_watchdog()
or other timer calling netif_schedule() after dev_queue_deactivate().
We prevent this checking aliveness before scheduling the timer. Since
during deactivation the root qdisc is available only as qdisc_sleeping
additional accessor qdisc_root_sleeping() is created.

With feedback from Herbert Xu <herbert@gondor.apana.org.au>

Signed-off-by: Jarek Poplawski <jarkao2@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Jarek Poplawski authored and David S. Miller committed Aug 21, 2008
1 parent 5e739d1 commit 2540e05
Show file tree
Hide file tree
Showing 3 changed files with 13 additions and 0 deletions.
5 changes: 5 additions & 0 deletions include/net/sch_generic.h
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,11 @@ static inline struct Qdisc *qdisc_root(struct Qdisc *qdisc)
return qdisc->dev_queue->qdisc;
}

static inline struct Qdisc *qdisc_root_sleeping(struct Qdisc *qdisc)
{
return qdisc->dev_queue->qdisc_sleeping;
}

/* The qdisc root lock is a mechanism by which to top level
* of a qdisc tree can be locked from any qdisc node in the
* forest. This allows changing the configuration of some
Expand Down
4 changes: 4 additions & 0 deletions net/sched/sch_api.c
Original file line number Diff line number Diff line change
Expand Up @@ -444,6 +444,10 @@ void qdisc_watchdog_schedule(struct qdisc_watchdog *wd, psched_time_t expires)
{
ktime_t time;

if (test_bit(__QDISC_STATE_DEACTIVATED,
&qdisc_root_sleeping(wd->qdisc)->state))
return;

wd->qdisc->flags |= TCQ_F_THROTTLED;
time = ktime_set(0, 0);
time = ktime_add_ns(time, PSCHED_US2NS(expires));
Expand Down
4 changes: 4 additions & 0 deletions net/sched/sch_cbq.c
Original file line number Diff line number Diff line change
Expand Up @@ -521,6 +521,10 @@ static void cbq_ovl_delay(struct cbq_class *cl)
struct cbq_sched_data *q = qdisc_priv(cl->qdisc);
psched_tdiff_t delay = cl->undertime - q->now;

if (test_bit(__QDISC_STATE_DEACTIVATED,
&qdisc_root_sleeping(cl->qdisc)->state))
return;

if (!cl->delayed) {
psched_time_t sched = q->now;
ktime_t expires;
Expand Down

0 comments on commit 2540e05

Please sign in to comment.