Skip to content

Commit

Permalink
sched: replace __QDISC_STATE_RUNNING bit with a spin lock
Browse files Browse the repository at this point in the history
So that we can use lockdep on it.
The newly introduced sequence lock has the same scope of busylock,
so it shares the same lockdep annotation, but it's only used for
NOLOCK qdiscs.

With this changeset we acquire such lock in the control path around
flushing operation (qdisc reset), to allow more NOLOCK qdisc perf
improvement in the next patch.

Signed-off-by: Paolo Abeni <pabeni@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Paolo Abeni authored and David S. Miller committed May 17, 2018
1 parent b9f672a commit 96009c7
Show file tree
Hide file tree
Showing 2 changed files with 16 additions and 5 deletions.
10 changes: 5 additions & 5 deletions include/net/sch_generic.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ struct qdisc_rate_table {
enum qdisc_state_t {
__QDISC_STATE_SCHED,
__QDISC_STATE_DEACTIVATED,
__QDISC_STATE_RUNNING,
};

struct qdisc_size_table {
Expand Down Expand Up @@ -102,6 +101,7 @@ struct Qdisc {
refcount_t refcnt;

spinlock_t busylock ____cacheline_aligned_in_smp;
spinlock_t seqlock;
};

static inline void qdisc_refcount_inc(struct Qdisc *qdisc)
Expand All @@ -111,17 +111,17 @@ static inline void qdisc_refcount_inc(struct Qdisc *qdisc)
refcount_inc(&qdisc->refcnt);
}

static inline bool qdisc_is_running(const struct Qdisc *qdisc)
static inline bool qdisc_is_running(struct Qdisc *qdisc)
{
if (qdisc->flags & TCQ_F_NOLOCK)
return test_bit(__QDISC_STATE_RUNNING, &qdisc->state);
return spin_is_locked(&qdisc->seqlock);
return (raw_read_seqcount(&qdisc->running) & 1) ? true : false;
}

static inline bool qdisc_run_begin(struct Qdisc *qdisc)
{
if (qdisc->flags & TCQ_F_NOLOCK) {
if (test_and_set_bit(__QDISC_STATE_RUNNING, &qdisc->state))
if (!spin_trylock(&qdisc->seqlock))
return false;
} else if (qdisc_is_running(qdisc)) {
return false;
Expand All @@ -138,7 +138,7 @@ static inline void qdisc_run_end(struct Qdisc *qdisc)
{
write_seqcount_end(&qdisc->running);
if (qdisc->flags & TCQ_F_NOLOCK)
clear_bit(__QDISC_STATE_RUNNING, &qdisc->state);
spin_unlock(&qdisc->seqlock);
}

static inline bool qdisc_may_bulk(const struct Qdisc *qdisc)
Expand Down
11 changes: 11 additions & 0 deletions net/sched/sch_generic.c
Original file line number Diff line number Diff line change
Expand Up @@ -858,6 +858,11 @@ struct Qdisc *qdisc_alloc(struct netdev_queue *dev_queue,
lockdep_set_class(&sch->busylock,
dev->qdisc_tx_busylock ?: &qdisc_tx_busylock);

/* seqlock has the same scope of busylock, for NOLOCK qdisc */
spin_lock_init(&sch->seqlock);
lockdep_set_class(&sch->busylock,
dev->qdisc_tx_busylock ?: &qdisc_tx_busylock);

seqcount_init(&sch->running);
lockdep_set_class(&sch->running,
dev->qdisc_running_key ?: &qdisc_running_key);
Expand Down Expand Up @@ -1097,6 +1102,10 @@ static void dev_deactivate_queue(struct net_device *dev,

qdisc = rtnl_dereference(dev_queue->qdisc);
if (qdisc) {
bool nolock = qdisc->flags & TCQ_F_NOLOCK;

if (nolock)
spin_lock_bh(&qdisc->seqlock);
spin_lock_bh(qdisc_lock(qdisc));

if (!(qdisc->flags & TCQ_F_BUILTIN))
Expand All @@ -1106,6 +1115,8 @@ static void dev_deactivate_queue(struct net_device *dev,
qdisc_reset(qdisc);

spin_unlock_bh(qdisc_lock(qdisc));
if (nolock)
spin_unlock_bh(&qdisc->seqlock);
}
}

Expand Down

0 comments on commit 96009c7

Please sign in to comment.