Commit 7253c1d1 authored by Eric Dumazet's avatar Eric Dumazet Committed by David S. Miller
Browse files

net_sched: sch_choke: implement lockless choke_dump()



Instead of relying on RTNL, choke_dump() can use READ_ONCE()
annotations, paired with WRITE_ONCE() ones in choke_change().

v2: added a WRITE_ONCE(p->Scell_log, Scell_log)
    per Simon feedback in V1
    Removed the READ_ONCE(q->limit) in choke_enqueue()

Signed-off-by: default avatarEric Dumazet <edumazet@google.com>
Reviewed-by: default avatarSimon Horman <horms@kernel.org>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 8eb54a42
Loading
Loading
Loading
Loading
+6 −6
Original line number Diff line number Diff line
@@ -233,10 +233,10 @@ static inline void red_set_parms(struct red_parms *p,
	int delta = qth_max - qth_min;
	u32 max_p_delta;

	p->qth_min	= qth_min << Wlog;
	p->qth_max	= qth_max << Wlog;
	p->Wlog		= Wlog;
	p->Plog		= Plog;
	WRITE_ONCE(p->qth_min, qth_min << Wlog);
	WRITE_ONCE(p->qth_max, qth_max << Wlog);
	WRITE_ONCE(p->Wlog, Wlog);
	WRITE_ONCE(p->Plog, Plog);
	if (delta <= 0)
		delta = 1;
	p->qth_delta	= delta;
@@ -244,7 +244,7 @@ static inline void red_set_parms(struct red_parms *p,
		max_P = red_maxp(Plog);
		max_P *= delta; /* max_P = (qth_max - qth_min)/2^Plog */
	}
	p->max_P = max_P;
	WRITE_ONCE(p->max_P, max_P);
	max_p_delta = max_P / delta;
	max_p_delta = max(max_p_delta, 1U);
	p->max_P_reciprocal  = reciprocal_value(max_p_delta);
@@ -257,7 +257,7 @@ static inline void red_set_parms(struct red_parms *p,
	p->target_min = qth_min + 2*delta;
	p->target_max = qth_min + 3*delta;

	p->Scell_log	= Scell_log;
	WRITE_ONCE(p->Scell_log, Scell_log);
	p->Scell_max	= (255 << Scell_log);

	if (stab)
+11 −10
Original line number Diff line number Diff line
@@ -405,8 +405,8 @@ static int choke_change(struct Qdisc *sch, struct nlattr *opt,
	} else
		sch_tree_lock(sch);

	q->flags = ctl->flags;
	q->limit = ctl->limit;
	WRITE_ONCE(q->flags, ctl->flags);
	WRITE_ONCE(q->limit, ctl->limit);

	red_set_parms(&q->parms, ctl->qth_min, ctl->qth_max, ctl->Wlog,
		      ctl->Plog, ctl->Scell_log,
@@ -431,15 +431,16 @@ static int choke_init(struct Qdisc *sch, struct nlattr *opt,
static int choke_dump(struct Qdisc *sch, struct sk_buff *skb)
{
	struct choke_sched_data *q = qdisc_priv(sch);
	u8 Wlog = READ_ONCE(q->parms.Wlog);
	struct nlattr *opts = NULL;
	struct tc_red_qopt opt = {
		.limit		= q->limit,
		.flags		= q->flags,
		.qth_min	= q->parms.qth_min >> q->parms.Wlog,
		.qth_max	= q->parms.qth_max >> q->parms.Wlog,
		.Wlog		= q->parms.Wlog,
		.Plog		= q->parms.Plog,
		.Scell_log	= q->parms.Scell_log,
		.limit		= READ_ONCE(q->limit),
		.flags		= READ_ONCE(q->flags),
		.qth_min	= READ_ONCE(q->parms.qth_min) >> Wlog,
		.qth_max	= READ_ONCE(q->parms.qth_max) >> Wlog,
		.Wlog		= Wlog,
		.Plog		= READ_ONCE(q->parms.Plog),
		.Scell_log	= READ_ONCE(q->parms.Scell_log),
	};

	opts = nla_nest_start_noflag(skb, TCA_OPTIONS);
@@ -447,7 +448,7 @@ static int choke_dump(struct Qdisc *sch, struct sk_buff *skb)
		goto nla_put_failure;

	if (nla_put(skb, TCA_CHOKE_PARMS, sizeof(opt), &opt) ||
	    nla_put_u32(skb, TCA_CHOKE_MAX_P, q->parms.max_P))
	    nla_put_u32(skb, TCA_CHOKE_MAX_P, READ_ONCE(q->parms.max_P)))
		goto nla_put_failure;
	return nla_nest_end(skb, opts);