<html><head><meta name="color-scheme" content="light dark"></head><body><pre style="word-wrap: break-word; white-space: pre-wrap;">From 1ffba0c4d1122688268e59832a5e2bbc0917cac7 Mon Sep 17 00:00:00 2001
From: Camelia Groza &lt;camelia.groza@nxp.com&gt;
Date: Wed, 3 Oct 2018 16:37:06 +0300
Subject: [PATCH] sdk_dpaa: ceetm: avoid double frees on error paths

The stack calls the destroy() callback when a qdisc init() fails.
We stop calling it ourselves and trust the stack do the cleanup.

Signed-off-by: Camelia Groza &lt;camelia.groza@nxp.com&gt;
---
 .../ethernet/freescale/sdk_dpaa/dpaa_eth_ceetm.c   | 94 ++++++++--------------
 1 file changed, 34 insertions(+), 60 deletions(-)

--- a/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_ceetm.c
+++ b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_ceetm.c
@@ -687,16 +687,13 @@ static int ceetm_init_root(struct Qdisc
 
 	/* Validate inputs */
 	if (sch-&gt;parent != TC_H_ROOT) {
-		pr_err("CEETM: a root ceetm qdisc can not be attached to a class\n");
-		tcf_block_put(priv-&gt;block);
-		qdisc_class_hash_destroy(&amp;priv-&gt;clhash);
+		pr_err("CEETM: a root ceetm qdisc must be root\n");
 		return -EINVAL;
 	}
 
 	if (!mac_dev) {
 		pr_err("CEETM: the interface is lacking a mac\n");
-		err = -EINVAL;
-		goto err_init_root;
+		return -EINVAL;
 	}
 
 	/* Pre-allocate underlying pfifo qdiscs.
@@ -713,8 +710,7 @@ static int ceetm_init_root(struct Qdisc
 				    sizeof(priv-&gt;root.qdiscs[0]),
 				    GFP_KERNEL);
 	if (!priv-&gt;root.qdiscs) {
-		err = -ENOMEM;
-		goto err_init_root;
+		return -ENOMEM;
 	}
 
 	for (i = 0; i &lt; dev-&gt;num_tx_queues; i++) {
@@ -724,10 +720,8 @@ static int ceetm_init_root(struct Qdisc
 
 		qdisc = qdisc_create_dflt(dev_queue, &amp;pfifo_qdisc_ops,
 					  parent_id, extack);
-		if (!qdisc) {
-			err = -ENOMEM;
-			goto err_init_root;
-		}
+		if (!qdisc)
+			return -ENOMEM;
 
 		priv-&gt;root.qdiscs[i] = qdisc;
 		qdisc-&gt;flags |= TCQ_F_ONETXQUEUE;
@@ -739,8 +733,7 @@ static int ceetm_init_root(struct Qdisc
 	if (!priv-&gt;root.qstats) {
 		pr_err(KBUILD_BASENAME " : %s : alloc_percpu() failed\n",
 		       __func__);
-		err = -ENOMEM;
-		goto err_init_root;
+		return -ENOMEM;
 	}
 
 	priv-&gt;shaped = qopt-&gt;shaped;
@@ -754,7 +747,7 @@ static int ceetm_init_root(struct Qdisc
 	if (err) {
 		pr_err(KBUILD_BASENAME " : %s : failed to claim the SP\n",
 		       __func__);
-		goto err_init_root;
+		return err;
 	}
 
 	priv-&gt;root.sp = sp;
@@ -766,7 +759,7 @@ static int ceetm_init_root(struct Qdisc
 	if (err) {
 		pr_err(KBUILD_BASENAME " : %s : failed to claim the LNI\n",
 		       __func__);
-		goto err_init_root;
+		return err;
 	}
 
 	priv-&gt;root.lni = lni;
@@ -775,7 +768,7 @@ static int ceetm_init_root(struct Qdisc
 	if (err) {
 		pr_err(KBUILD_BASENAME " : %s : failed to link the SP and LNI\n",
 		       __func__);
-		goto err_init_root;
+		return err;
 	}
 
 	lni-&gt;sp = sp;
@@ -786,7 +779,7 @@ static int ceetm_init_root(struct Qdisc
 		if (err) {
 			pr_err(KBUILD_BASENAME " : %s : failed to configure the LNI shaper\n",
 			       __func__);
-			goto err_init_root;
+			return err;
 		}
 
 		bps = priv-&gt;root.rate &lt;&lt; 3; /* Bps -&gt; bps */
@@ -794,7 +787,7 @@ static int ceetm_init_root(struct Qdisc
 		if (err) {
 			pr_err(KBUILD_BASENAME " : %s : failed to configure the LNI shaper\n",
 			       __func__);
-			goto err_init_root;
+			return err;
 		}
 
 		bps = priv-&gt;root.ceil &lt;&lt; 3; /* Bps -&gt; bps */
@@ -802,7 +795,7 @@ static int ceetm_init_root(struct Qdisc
 		if (err) {
 			pr_err(KBUILD_BASENAME " : %s : failed to configure the LNI shaper\n",
 			       __func__);
-			goto err_init_root;
+			return err;
 		}
 	}
 
@@ -810,10 +803,6 @@ static int ceetm_init_root(struct Qdisc
 
 	dpa_enable_ceetm(dev);
 	return 0;
-
-err_init_root:
-	ceetm_destroy(sch);
-	return err;
 }
 
 /* Configure a prio ceetm qdisc */
@@ -830,15 +819,13 @@ static int ceetm_init_prio(struct Qdisc
 
 	if (sch-&gt;parent == TC_H_ROOT) {
 		pr_err("CEETM: a prio ceetm qdisc can not be root\n");
-		err = -EINVAL;
-		goto err_init_prio;
+		return -EINVAL;
 	}
 
 	parent_qdisc = qdisc_lookup(dev, TC_H_MAJ(sch-&gt;parent));
 	if (strcmp(parent_qdisc-&gt;ops-&gt;id, ceetm_qdisc_ops.id)) {
 		pr_err("CEETM: a ceetm qdisc can not be attached to other qdisc/class types\n");
-		err = -EINVAL;
-		goto err_init_prio;
+		return -EINVAL;
 	}
 
 	/* Obtain the parent root ceetm_class */
@@ -846,8 +833,7 @@ static int ceetm_init_prio(struct Qdisc
 
 	if (!parent_cl || parent_cl-&gt;type != CEETM_ROOT) {
 		pr_err("CEETM: a prio ceetm qdiscs can be added only under a root ceetm class\n");
-		err = -EINVAL;
-		goto err_init_prio;
+		return -EINVAL;
 	}
 
 	priv-&gt;prio.parent = parent_cl;
@@ -863,8 +849,7 @@ static int ceetm_init_prio(struct Qdisc
 		if (!child_cl) {
 			pr_err(KBUILD_BASENAME " : %s : kzalloc() failed\n",
 			       __func__);
-			err = -ENOMEM;
-			goto err_init_prio;
+			return -ENOMEM;
 		}
 
 		child_cl-&gt;prio.cstats = alloc_percpu(struct ceetm_class_stats);
@@ -907,8 +892,7 @@ static int ceetm_init_prio(struct Qdisc
 
 err_init_prio_cls:
 	ceetm_cls_destroy(sch, child_cl);
-err_init_prio:
-	ceetm_destroy(sch);
+	/* Note: ceetm_destroy() will be called by our caller */
 	return err;
 }
 
@@ -928,16 +912,14 @@ static int ceetm_init_wbfs(struct Qdisc
 	/* Validate inputs */
 	if (sch-&gt;parent == TC_H_ROOT) {
 		pr_err("CEETM: a wbfs ceetm qdiscs can not be root\n");
-		err = -EINVAL;
-		goto err_init_wbfs;
+		return -EINVAL;
 	}
 
 	/* Obtain the parent prio ceetm qdisc */
 	parent_qdisc = qdisc_lookup(dev, TC_H_MAJ(sch-&gt;parent));
 	if (strcmp(parent_qdisc-&gt;ops-&gt;id, ceetm_qdisc_ops.id)) {
 		pr_err("CEETM: a ceetm qdisc can not be attached to other qdisc/class types\n");
-		err = -EINVAL;
-		goto err_init_wbfs;
+		return -EINVAL;
 	}
 
 	/* Obtain the parent prio ceetm class */
@@ -946,28 +928,24 @@ static int ceetm_init_wbfs(struct Qdisc
 
 	if (!parent_cl || parent_cl-&gt;type != CEETM_PRIO) {
 		pr_err("CEETM: a wbfs ceetm qdiscs can be added only under a prio ceetm class\n");
-		err = -EINVAL;
-		goto err_init_wbfs;
+		return -EINVAL;
 	}
 
 	if (!qopt-&gt;qcount || !qopt-&gt;qweight[0]) {
 		pr_err("CEETM: qcount and qweight are mandatory for a wbfs ceetm qdisc\n");
-		err = -EINVAL;
-		goto err_init_wbfs;
+		return -EINVAL;
 	}
 
 	priv-&gt;shaped = parent_cl-&gt;shaped;
 
 	if (!priv-&gt;shaped &amp;&amp; (qopt-&gt;cr || qopt-&gt;er)) {
 		pr_err("CEETM: CR/ER can be enabled only for shaped wbfs ceetm qdiscs\n");
-		err = -EINVAL;
-		goto err_init_wbfs;
+		return -EINVAL;
 	}
 
 	if (priv-&gt;shaped &amp;&amp; !(qopt-&gt;cr || qopt-&gt;er)) {
 		pr_err("CEETM: either CR or ER must be enabled for shaped wbfs ceetm qdiscs\n");
-		err = -EINVAL;
-		goto err_init_wbfs;
+		return -EINVAL;
 	}
 
 	/* Obtain the parent root ceetm class */
@@ -975,16 +953,14 @@ static int ceetm_init_wbfs(struct Qdisc
 	if ((root_cl-&gt;root.wbfs_grp_a &amp;&amp; root_cl-&gt;root.wbfs_grp_b) ||
 	    root_cl-&gt;root.wbfs_grp_large) {
 		pr_err("CEETM: no more wbfs classes are available\n");
-		err = -EINVAL;
-		goto err_init_wbfs;
+		return -EINVAL;
 	}
 
 	if ((root_cl-&gt;root.wbfs_grp_a || root_cl-&gt;root.wbfs_grp_b) &amp;&amp;
 	    qopt-&gt;qcount == CEETM_MAX_WBFS_QCOUNT) {
 		pr_err("CEETM: only %d wbfs classes are available\n",
 		       CEETM_MIN_WBFS_QCOUNT);
-		err = -EINVAL;
-		goto err_init_wbfs;
+		return -EINVAL;
 	}
 
 	priv-&gt;wbfs.parent = parent_cl;
@@ -1013,7 +989,7 @@ static int ceetm_init_wbfs(struct Qdisc
 		if (err) {
 			pr_err(KBUILD_BASENAME " : %s : failed to get group details\n",
 			       __func__);
-			goto err_init_wbfs;
+			return err;
 		}
 
 		small_group = true;
@@ -1031,7 +1007,7 @@ static int ceetm_init_wbfs(struct Qdisc
 		if (err) {
 			pr_err(KBUILD_BASENAME " : %s : failed to get group details\n",
 			       __func__);
-			goto err_init_wbfs;
+			return err;
 		}
 
 		small_group = true;
@@ -1044,7 +1020,7 @@ static int ceetm_init_wbfs(struct Qdisc
 	err = qman_ceetm_channel_set_group(priv-&gt;wbfs.ch, small_group, prio_a,
 					   prio_b);
 	if (err)
-		goto err_init_wbfs;
+		return err;
 
 	if (priv-&gt;shaped) {
 		err = qman_ceetm_channel_set_group_cr_eligibility(priv-&gt;wbfs.ch,
@@ -1053,7 +1029,7 @@ static int ceetm_init_wbfs(struct Qdisc
 		if (err) {
 			pr_err(KBUILD_BASENAME " : %s : failed to set group CR eligibility\n",
 			       __func__);
-			goto err_init_wbfs;
+			return err;
 		}
 
 		err = qman_ceetm_channel_set_group_er_eligibility(priv-&gt;wbfs.ch,
@@ -1062,7 +1038,7 @@ static int ceetm_init_wbfs(struct Qdisc
 		if (err) {
 			pr_err(KBUILD_BASENAME " : %s : failed to set group ER eligibility\n",
 			       __func__);
-			goto err_init_wbfs;
+			return err;
 		}
 	}
 
@@ -1072,8 +1048,7 @@ static int ceetm_init_wbfs(struct Qdisc
 		if (!child_cl) {
 			pr_err(KBUILD_BASENAME " : %s : kzalloc() failed\n",
 			       __func__);
-			err = -ENOMEM;
-			goto err_init_wbfs;
+			return -ENOMEM;
 		}
 
 		child_cl-&gt;wbfs.cstats = alloc_percpu(struct ceetm_class_stats);
@@ -1130,8 +1105,7 @@ static int ceetm_init_wbfs(struct Qdisc
 
 err_init_wbfs_cls:
 	ceetm_cls_destroy(sch, child_cl);
-err_init_wbfs:
-	ceetm_destroy(sch);
+	/* Note: ceetm_destroy() will be called by our caller */
 	return err;
 }
 
@@ -1202,7 +1176,7 @@ static int ceetm_init(struct Qdisc *sch,
 		break;
 	default:
 		pr_err(KBUILD_BASENAME " : %s : invalid qdisc\n", __func__);
-		ceetm_destroy(sch);
+		/* Note: ceetm_destroy() will be called by our caller */
 		ret = -EINVAL;
 	}
 
@@ -1549,7 +1523,7 @@ static int ceetm_cls_change(struct Qdisc
 	}
 
 	if (!cl &amp;&amp; priv-&gt;type != CEETM_ROOT) {
-		pr_err("CEETM: only root ceetm classes can be attached to the root ceetm qdisc\n");
+		pr_err("CEETM: root ceetm classes can be attached to the root ceetm qdisc only\n");
 		return -EINVAL;
 	}
 
</pre></body></html>