Skip to content

Commit 2eb6c6a

Browse files
Stanislav Fomichevkuba-moo
authored andcommitted
net: move replay logic to tc_modify_qdisc
Eric reports that by the time we call netdev_lock_ops after rtnl_unlock/rtnl_lock, the dev might point to an invalid device. As suggested by Jakub in [0], move rtnl lock/unlock and request_module outside of qdisc_create. This removes extra complexity with relocking the netdev. 0: https://lore.kernel.org/netdev/[email protected]/ Fixes: a0527ee ("net: hold netdev instance lock during qdisc ndo_setup_tc") Reported-by: Eric Dumazet <[email protected]> Link: https://lore.kernel.org/netdev/[email protected]/T/#me8dfd778ea4c4463acab55644e3f9836bc608771 Signed-off-by: Stanislav Fomichev <[email protected]> Reviewed-by: Eric Dumazet <[email protected]> Link: https://patch.msgid.link/[email protected] Signed-off-by: Jakub Kicinski <[email protected]>
1 parent 67d1a89 commit 2eb6c6a

File tree

1 file changed

+27
-46
lines changed

1 file changed

+27
-46
lines changed

net/sched/sch_api.c

Lines changed: 27 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1267,38 +1267,8 @@ static struct Qdisc *qdisc_create(struct net_device *dev,
12671267
struct qdisc_size_table *stab;
12681268

12691269
ops = qdisc_lookup_ops(kind);
1270-
#ifdef CONFIG_MODULES
1271-
if (ops == NULL && kind != NULL) {
1272-
char name[IFNAMSIZ];
1273-
if (nla_strscpy(name, kind, IFNAMSIZ) >= 0) {
1274-
/* We dropped the RTNL semaphore in order to
1275-
* perform the module load. So, even if we
1276-
* succeeded in loading the module we have to
1277-
* tell the caller to replay the request. We
1278-
* indicate this using -EAGAIN.
1279-
* We replay the request because the device may
1280-
* go away in the mean time.
1281-
*/
1282-
netdev_unlock_ops(dev);
1283-
rtnl_unlock();
1284-
request_module(NET_SCH_ALIAS_PREFIX "%s", name);
1285-
rtnl_lock();
1286-
netdev_lock_ops(dev);
1287-
ops = qdisc_lookup_ops(kind);
1288-
if (ops != NULL) {
1289-
/* We will try again qdisc_lookup_ops,
1290-
* so don't keep a reference.
1291-
*/
1292-
module_put(ops->owner);
1293-
err = -EAGAIN;
1294-
goto err_out;
1295-
}
1296-
}
1297-
}
1298-
#endif
1299-
1300-
err = -ENOENT;
13011270
if (!ops) {
1271+
err = -ENOENT;
13021272
NL_SET_ERR_MSG(extack, "Specified qdisc kind is unknown");
13031273
goto err_out;
13041274
}
@@ -1623,8 +1593,7 @@ static int __tc_modify_qdisc(struct sk_buff *skb, struct nlmsghdr *n,
16231593
struct netlink_ext_ack *extack,
16241594
struct net_device *dev,
16251595
struct nlattr *tca[TCA_MAX + 1],
1626-
struct tcmsg *tcm,
1627-
bool *replay)
1596+
struct tcmsg *tcm)
16281597
{
16291598
struct Qdisc *q = NULL;
16301599
struct Qdisc *p = NULL;
@@ -1789,13 +1758,8 @@ static int __tc_modify_qdisc(struct sk_buff *skb, struct nlmsghdr *n,
17891758
tcm->tcm_parent, tcm->tcm_handle,
17901759
tca, &err, extack);
17911760
}
1792-
if (q == NULL) {
1793-
if (err == -EAGAIN) {
1794-
*replay = true;
1795-
return 0;
1796-
}
1761+
if (!q)
17971762
return err;
1798-
}
17991763

18001764
graft:
18011765
err = qdisc_graft(dev, p, skb, n, clid, q, NULL, extack);
@@ -1808,6 +1772,27 @@ static int __tc_modify_qdisc(struct sk_buff *skb, struct nlmsghdr *n,
18081772
return 0;
18091773
}
18101774

1775+
static void request_qdisc_module(struct nlattr *kind)
1776+
{
1777+
struct Qdisc_ops *ops;
1778+
char name[IFNAMSIZ];
1779+
1780+
if (!kind)
1781+
return;
1782+
1783+
ops = qdisc_lookup_ops(kind);
1784+
if (ops) {
1785+
module_put(ops->owner);
1786+
return;
1787+
}
1788+
1789+
if (nla_strscpy(name, kind, IFNAMSIZ) >= 0) {
1790+
rtnl_unlock();
1791+
request_module(NET_SCH_ALIAS_PREFIX "%s", name);
1792+
rtnl_lock();
1793+
}
1794+
}
1795+
18111796
/*
18121797
* Create/change qdisc.
18131798
*/
@@ -1818,27 +1803,23 @@ static int tc_modify_qdisc(struct sk_buff *skb, struct nlmsghdr *n,
18181803
struct nlattr *tca[TCA_MAX + 1];
18191804
struct net_device *dev;
18201805
struct tcmsg *tcm;
1821-
bool replay;
18221806
int err;
18231807

1824-
replay:
1825-
/* Reinit, just in case something touches this. */
18261808
err = nlmsg_parse_deprecated(n, sizeof(*tcm), tca, TCA_MAX,
18271809
rtm_tca_policy, extack);
18281810
if (err < 0)
18291811
return err;
18301812

1813+
request_qdisc_module(tca[TCA_KIND]);
1814+
18311815
tcm = nlmsg_data(n);
18321816
dev = __dev_get_by_index(net, tcm->tcm_ifindex);
18331817
if (!dev)
18341818
return -ENODEV;
18351819

1836-
replay = false;
18371820
netdev_lock_ops(dev);
1838-
err = __tc_modify_qdisc(skb, n, extack, dev, tca, tcm, &replay);
1821+
err = __tc_modify_qdisc(skb, n, extack, dev, tca, tcm);
18391822
netdev_unlock_ops(dev);
1840-
if (replay)
1841-
goto replay;
18421823

18431824
return err;
18441825
}

0 commit comments

Comments
 (0)