Commit a90f6dce authored by Davide Caratti's avatar Davide Caratti Committed by Jakub Kicinski
Browse files

net/sched: don't use dynamic lockdep keys with clsact/ingress/noqueue

Currently we are registering one dynamic lockdep key for each allocated
qdisc, to avoid false deadlock reports when mirred (or TC eBPF) redirects
packets to another device while the root lock is acquired [1].
Since dynamic keys are a limited resource, we can save them at least for
qdiscs that are not meant to acquire the root lock in the traffic path,
or to carry traffic at all, like:

 - clsact
 - ingress
 - noqueue

Don't register dynamic keys for the above schedulers, so that we hit
MAX_LOCKDEP_KEYS later in our tests.

[1] https://github.com/multipath-tcp/mptcp_net-next/issues/451



Changes in v2:
 - change ordering of spin_lock_init() vs. lockdep_register_key()
   (Jakub Kicinski)

Signed-off-by: default avatarDavide Caratti <dcaratti@redhat.com>
Link: https://patch.msgid.link/94448f7fa7c4f52d2ce416a4895ec87d456d7417.1770220576.git.dcaratti@redhat.com


Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parent 7e7fcfb0
Loading
Loading
Loading
Loading
+24 −0
Original line number Diff line number Diff line
@@ -308,4 +308,28 @@ static inline unsigned int qdisc_peek_len(struct Qdisc *sch)
	return len;
}

static inline void qdisc_lock_init(struct Qdisc *sch,
				   const struct Qdisc_ops *ops)
{
	spin_lock_init(&sch->q.lock);

	/* Skip dynamic keys if nesting is not possible */
	if (ops->static_flags & TCQ_F_INGRESS ||
	    ops == &noqueue_qdisc_ops)
		return;

	lockdep_register_key(&sch->root_lock_key);
	lockdep_set_class(&sch->q.lock, &sch->root_lock_key);
}

static inline void qdisc_lock_uninit(struct Qdisc *sch,
				     const struct Qdisc_ops *ops)
{
	if (ops->static_flags & TCQ_F_INGRESS ||
	    ops == &noqueue_qdisc_ops)
		return;

	lockdep_unregister_key(&sch->root_lock_key);
}

#endif
+1 −1
Original line number Diff line number Diff line
@@ -1353,7 +1353,7 @@ static struct Qdisc *qdisc_create(struct net_device *dev,
		ops->destroy(sch);
	qdisc_put_stab(rtnl_dereference(sch->stab));
err_out3:
	lockdep_unregister_key(&sch->root_lock_key);
	qdisc_lock_uninit(sch, ops);
	netdev_put(dev, &sch->dev_tracker);
	qdisc_free(sch);
err_out2:
+3 −5
Original line number Diff line number Diff line
@@ -955,9 +955,7 @@ struct Qdisc *qdisc_alloc(struct netdev_queue *dev_queue,
	__skb_queue_head_init(&sch->gso_skb);
	__skb_queue_head_init(&sch->skb_bad_txq);
	gnet_stats_basic_sync_init(&sch->bstats);
	lockdep_register_key(&sch->root_lock_key);
	spin_lock_init(&sch->q.lock);
	lockdep_set_class(&sch->q.lock, &sch->root_lock_key);
	qdisc_lock_init(sch, ops);

	if (ops->static_flags & TCQ_F_CPUSTATS) {
		sch->cpu_bstats =
@@ -987,7 +985,7 @@ struct Qdisc *qdisc_alloc(struct netdev_queue *dev_queue,

	return sch;
errout1:
	lockdep_unregister_key(&sch->root_lock_key);
	qdisc_lock_uninit(sch, ops);
	kfree(sch);
errout:
	return ERR_PTR(err);
@@ -1076,7 +1074,7 @@ static void __qdisc_destroy(struct Qdisc *qdisc)
	if (ops->destroy)
		ops->destroy(qdisc);

	lockdep_unregister_key(&qdisc->root_lock_key);
	qdisc_lock_uninit(qdisc, ops);
	bpf_module_put(ops, ops->owner);
	netdev_put(dev, &qdisc->dev_tracker);