sch_netem: return errcode before setting params
authorYang Yingliang <yangyingliang@huawei.com>
Fri, 14 Feb 2014 02:30:41 +0000 (10:30 +0800)
committerDavid S. Miller <davem@davemloft.net>
Fri, 14 Feb 2014 05:15:20 +0000 (00:15 -0500)
get_dist_table() and get_loss_clg() may be failed. These
two functions should be called after setting the members
of qdisc_priv(sch), or it will break the old settings while
either of them is failed.

Signed-off-by: Yang Yingliang <yangyingliang@huawei.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
net/sched/sch_netem.c

index de1059af6da14c563115147852c4f52b80a9387d..b341943555a908590c495eb3c8b66e159a54a465 100644 (file)
@@ -821,6 +821,8 @@ static int netem_change(struct Qdisc *sch, struct nlattr *opt)
        struct netem_sched_data *q = qdisc_priv(sch);
        struct nlattr *tb[TCA_NETEM_MAX + 1];
        struct tc_netem_qopt *qopt;
+       struct clgstate old_clg;
+       int old_loss_model = CLG_RANDOM;
        int ret;
 
        if (opt == NULL)
@@ -831,6 +833,33 @@ static int netem_change(struct Qdisc *sch, struct nlattr *opt)
        if (ret < 0)
                return ret;
 
+       /* backup q->clg and q->loss_model */
+       old_clg = q->clg;
+       old_loss_model = q->loss_model;
+
+       if (tb[TCA_NETEM_LOSS]) {
+               ret = get_loss_clg(sch, tb[TCA_NETEM_LOSS]);
+               if (ret) {
+                       q->loss_model = old_loss_model;
+                       return ret;
+               }
+       } else {
+               q->loss_model = CLG_RANDOM;
+       }
+
+       if (tb[TCA_NETEM_DELAY_DIST]) {
+               ret = get_dist_table(sch, tb[TCA_NETEM_DELAY_DIST]);
+               if (ret) {
+                       /* recover clg and loss_model, in case of
+                        * q->clg and q->loss_model were modified
+                        * in get_loss_clg()
+                        */
+                       q->clg = old_clg;
+                       q->loss_model = old_loss_model;
+                       return ret;
+               }
+       }
+
        sch->limit = qopt->limit;
 
        q->latency = qopt->latency;
@@ -850,12 +879,6 @@ static int netem_change(struct Qdisc *sch, struct nlattr *opt)
        if (tb[TCA_NETEM_CORR])
                get_correlation(sch, tb[TCA_NETEM_CORR]);
 
-       if (tb[TCA_NETEM_DELAY_DIST]) {
-               ret = get_dist_table(sch, tb[TCA_NETEM_DELAY_DIST]);
-               if (ret)
-                       return ret;
-       }
-
        if (tb[TCA_NETEM_REORDER])
                get_reorder(sch, tb[TCA_NETEM_REORDER]);
 
@@ -872,10 +895,6 @@ static int netem_change(struct Qdisc *sch, struct nlattr *opt)
        if (tb[TCA_NETEM_ECN])
                q->ecn = nla_get_u32(tb[TCA_NETEM_ECN]);
 
-       q->loss_model = CLG_RANDOM;
-       if (tb[TCA_NETEM_LOSS])
-               ret = get_loss_clg(sch, tb[TCA_NETEM_LOSS]);
-
        return ret;
 }