net/sched: make stab available before ops->init() call
authorVladimir Oltean <vladimir.oltean@nxp.com>
Tue, 7 Feb 2023 13:54:35 +0000 (15:54 +0200)
committerDavid S. Miller <davem@davemloft.net>
Wed, 8 Feb 2023 09:48:53 +0000 (09:48 +0000)
Some qdiscs like taprio turn out to be actually pretty reliant on a well
configured stab, to not underestimate the skb transmission time (by
properly accounting for L1 overhead).

In a future change, taprio will need the stab, if configured by the
user, to be available at ops->init() time. It will become even more
important in upcoming work, when the overhead will be used for the
queueMaxSDU calculation that is passed to an offloading driver.

However, rcu_assign_pointer(sch->stab, stab) is called right after
ops->init(), making it unavailable, and I don't really see a good reason
for that.

Move it earlier, which nicely seems to simplify the error handling path
as well.

Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
Reviewed-by: Kurt Kanzenbach <kurt@linutronix.de>
Signed-off-by: David S. Miller <davem@davemloft.net>
net/sched/sch_api.c

index c14018a..e978063 100644 (file)
@@ -1282,12 +1282,6 @@ static struct Qdisc *qdisc_create(struct net_device *dev,
        if (err)
                goto err_out3;
 
-       if (ops->init) {
-               err = ops->init(sch, tca[TCA_OPTIONS], extack);
-               if (err != 0)
-                       goto err_out5;
-       }
-
        if (tca[TCA_STAB]) {
                stab = qdisc_get_stab(tca[TCA_STAB], extack);
                if (IS_ERR(stab)) {
@@ -1296,11 +1290,18 @@ static struct Qdisc *qdisc_create(struct net_device *dev,
                }
                rcu_assign_pointer(sch->stab, stab);
        }
+
+       if (ops->init) {
+               err = ops->init(sch, tca[TCA_OPTIONS], extack);
+               if (err != 0)
+                       goto err_out5;
+       }
+
        if (tca[TCA_RATE]) {
                err = -EOPNOTSUPP;
                if (sch->flags & TCQ_F_MQROOT) {
                        NL_SET_ERR_MSG(extack, "Cannot attach rate estimator to a multi-queue root qdisc");
-                       goto err_out4;
+                       goto err_out5;
                }
 
                err = gen_new_estimator(&sch->bstats,
@@ -1311,7 +1312,7 @@ static struct Qdisc *qdisc_create(struct net_device *dev,
                                        tca[TCA_RATE]);
                if (err) {
                        NL_SET_ERR_MSG(extack, "Failed to generate new estimator");
-                       goto err_out4;
+                       goto err_out5;
                }
        }
 
@@ -1321,6 +1322,8 @@ static struct Qdisc *qdisc_create(struct net_device *dev,
        return sch;
 
 err_out5:
+       qdisc_put_stab(rtnl_dereference(sch->stab));
+err_out4:
        /* ops->init() failed, we call ->destroy() like qdisc_create_dflt() */
        if (ops->destroy)
                ops->destroy(sch);
@@ -1332,16 +1335,6 @@ err_out2:
 err_out:
        *errp = err;
        return NULL;
-
-err_out4:
-       /*
-        * Any broken qdiscs that would require a ops->reset() here?
-        * The qdisc was never in action so it shouldn't be necessary.
-        */
-       qdisc_put_stab(rtnl_dereference(sch->stab));
-       if (ops->destroy)
-               ops->destroy(sch);
-       goto err_out3;
 }
 
 static int qdisc_change(struct Qdisc *sch, struct nlattr **tca,