mlxsw: spectrum: qdiscs: prio: Delete child qdiscs when removing bands
authorNogah Frankel <nogahf@mellanox.com>
Wed, 28 Feb 2018 09:45:05 +0000 (10:45 +0100)
committerDavid S. Miller <davem@davemloft.net>
Wed, 28 Feb 2018 17:06:01 +0000 (12:06 -0500)
When the number the bands of sch_prio is decreased, child qdiscs on the
deleted bands would get deleted as well.
This change and deletions are being done under sch_tree_lock of the
sch_prio qdisc. Part of the destruction of qdisc is unoffloading it, if
it is offloaded. Un-offloading can't be done inside this lock.
Move the offload command to be done before reducing the number of bands,
so unoffloading of the qdiscs that are about to be deleted could be done
outside of the lock.

Signed-off-by: Nogah Frankel <nogahf@mellanox.com>
Reviewed-by: Yuval Mintz <yuvalm@mellanox.com>
Signed-off-by: Jiri Pirko <jiri@mellanox.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/mellanox/mlxsw/spectrum_qdisc.c
net/sched/sch_prio.c

index bed7495d35d630c1789adcfb72ff928a249a1db9..a2a3ac09c3bc5beb5964783f0f763cd7b63f4440 100644 (file)
@@ -547,7 +547,12 @@ mlxsw_sp_qdisc_prio_replace(struct mlxsw_sp_port *mlxsw_sp_port,
                        child_qdisc->stats_base.backlog = backlog;
                }
        }
-
+       for (; band < IEEE_8021QAZ_MAX_TCS; band++) {
+               tclass = MLXSW_SP_PRIO_BAND_TO_TCLASS(band);
+               child_qdisc = &mlxsw_sp_port->tclass_qdiscs[tclass];
+               child_qdisc->prio_bitmap = 0;
+               mlxsw_sp_qdisc_destroy(mlxsw_sp_port, child_qdisc);
+       }
        return 0;
 }
 
index efbf51f3577893d90cb0dd01e261b1c6f7cf622c..ba2d6d17d95abfc41598bf0010920d8c025e62c7 100644 (file)
@@ -142,9 +142,8 @@ prio_reset(struct Qdisc *sch)
        sch->q.qlen = 0;
 }
 
-static int prio_offload(struct Qdisc *sch, bool enable)
+static int prio_offload(struct Qdisc *sch, struct tc_prio_qopt *qopt)
 {
-       struct prio_sched_data *q = qdisc_priv(sch);
        struct net_device *dev = qdisc_dev(sch);
        struct tc_prio_qopt_offload opt = {
                .handle = sch->handle,
@@ -154,10 +153,10 @@ static int prio_offload(struct Qdisc *sch, bool enable)
        if (!tc_can_offload(dev) || !dev->netdev_ops->ndo_setup_tc)
                return -EOPNOTSUPP;
 
-       if (enable) {
+       if (qopt) {
                opt.command = TC_PRIO_REPLACE;
-               opt.replace_params.bands = q->bands;
-               memcpy(&opt.replace_params.priomap, q->prio2band,
+               opt.replace_params.bands = qopt->bands;
+               memcpy(&opt.replace_params.priomap, qopt->priomap,
                       TC_PRIO_MAX + 1);
                opt.replace_params.qstats = &sch->qstats;
        } else {
@@ -174,7 +173,7 @@ prio_destroy(struct Qdisc *sch)
        struct prio_sched_data *q = qdisc_priv(sch);
 
        tcf_block_put(q->block);
-       prio_offload(sch, false);
+       prio_offload(sch, NULL);
        for (prio = 0; prio < q->bands; prio++)
                qdisc_destroy(q->queues[prio]);
 }
@@ -211,6 +210,7 @@ static int prio_tune(struct Qdisc *sch, struct nlattr *opt,
                }
        }
 
+       prio_offload(sch, qopt);
        sch_tree_lock(sch);
        q->bands = qopt->bands;
        memcpy(q->prio2band, qopt->priomap, TC_PRIO_MAX+1);
@@ -230,7 +230,6 @@ static int prio_tune(struct Qdisc *sch, struct nlattr *opt,
        }
 
        sch_tree_unlock(sch);
-       prio_offload(sch, true);
        return 0;
 }