Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f6f9b93f authored by Jarek Poplawski's avatar Jarek Poplawski Committed by David S. Miller
Browse files

pkt_sched: Fix gen_estimator locks



While passing a qdisc root lock to gen_new_estimator() and
gen_replace_estimator() dev could be deactivated or even before
grafting proper root qdisc as qdisc_sleeping (e.g. qdisc_create), so
using qdisc_root_lock() is not enough. This patch adds
qdisc_root_sleeping_lock() for this, plus additional checks, where
necessary.

Signed-off-by: default avatarJarek Poplawski <jarkao2@gmail.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent f7a54c13
Loading
Loading
Loading
Loading
+8 −0
Original line number Diff line number Diff line
@@ -217,6 +217,14 @@ static inline spinlock_t *qdisc_root_lock(struct Qdisc *qdisc)
	return qdisc_lock(root);
}

static inline spinlock_t *qdisc_root_sleeping_lock(struct Qdisc *qdisc)
{
	struct Qdisc *root = qdisc_root_sleeping(qdisc);

	ASSERT_RTNL();
	return qdisc_lock(root);
}

static inline struct net_device *qdisc_dev(struct Qdisc *qdisc)
{
	return qdisc->dev_queue->dev;
+11 −3
Original line number Diff line number Diff line
@@ -830,9 +830,16 @@ qdisc_create(struct net_device *dev, struct netdev_queue *dev_queue,
			sch->stab = stab;
		}
		if (tca[TCA_RATE]) {
			spinlock_t *root_lock;

			if ((sch->parent != TC_H_ROOT) &&
			    !(sch->flags & TCQ_F_INGRESS))
				root_lock = qdisc_root_sleeping_lock(sch);
			else
				root_lock = qdisc_lock(sch);

			err = gen_new_estimator(&sch->bstats, &sch->rate_est,
						qdisc_root_lock(sch),
						tca[TCA_RATE]);
						root_lock, tca[TCA_RATE]);
			if (err) {
				/*
				 * Any broken qdiscs that would require
@@ -884,7 +891,8 @@ static int qdisc_change(struct Qdisc *sch, struct nlattr **tca)

	if (tca[TCA_RATE])
		gen_replace_estimator(&sch->bstats, &sch->rate_est,
				      qdisc_root_lock(sch), tca[TCA_RATE]);
				      qdisc_root_sleeping_lock(sch),
				      tca[TCA_RATE]);
	return 0;
}

+2 −2
Original line number Diff line number Diff line
@@ -1839,7 +1839,7 @@ cbq_change_class(struct Qdisc *sch, u32 classid, u32 parentid, struct nlattr **t

		if (tca[TCA_RATE])
			gen_replace_estimator(&cl->bstats, &cl->rate_est,
					      qdisc_root_lock(sch),
					      qdisc_root_sleeping_lock(sch),
					      tca[TCA_RATE]);
		return 0;
	}
@@ -1930,7 +1930,7 @@ cbq_change_class(struct Qdisc *sch, u32 classid, u32 parentid, struct nlattr **t

	if (tca[TCA_RATE])
		gen_new_estimator(&cl->bstats, &cl->rate_est,
				  qdisc_root_lock(sch), tca[TCA_RATE]);
				  qdisc_root_sleeping_lock(sch), tca[TCA_RATE]);

	*arg = (unsigned long)cl;
	return 0;
+2 −2
Original line number Diff line number Diff line
@@ -1045,7 +1045,7 @@ hfsc_change_class(struct Qdisc *sch, u32 classid, u32 parentid,

		if (tca[TCA_RATE])
			gen_replace_estimator(&cl->bstats, &cl->rate_est,
					      qdisc_root_lock(sch),
					      qdisc_root_sleeping_lock(sch),
					      tca[TCA_RATE]);
		return 0;
	}
@@ -1104,7 +1104,7 @@ hfsc_change_class(struct Qdisc *sch, u32 classid, u32 parentid,

	if (tca[TCA_RATE])
		gen_new_estimator(&cl->bstats, &cl->rate_est,
				  qdisc_root_lock(sch), tca[TCA_RATE]);
				  qdisc_root_sleeping_lock(sch), tca[TCA_RATE]);
	*arg = (unsigned long)cl;
	return 0;
}
+2 −2
Original line number Diff line number Diff line
@@ -1372,7 +1372,7 @@ static int htb_change_class(struct Qdisc *sch, u32 classid,
			goto failure;

		gen_new_estimator(&cl->bstats, &cl->rate_est,
				  qdisc_root_lock(sch),
				  qdisc_root_sleeping_lock(sch),
				  tca[TCA_RATE] ? : &est.nla);
		cl->refcnt = 1;
		cl->children = 0;
@@ -1427,7 +1427,7 @@ static int htb_change_class(struct Qdisc *sch, u32 classid,
	} else {
		if (tca[TCA_RATE])
			gen_replace_estimator(&cl->bstats, &cl->rate_est,
					      qdisc_root_lock(sch),
					      qdisc_root_sleeping_lock(sch),
					      tca[TCA_RATE]);
		sch_tree_lock(sch);
	}