Subject: [PATCH 4/9] netem: add locking around changes

From: Stephen Hemminger <[email-masked]>
Date: Fri, 06 Aug 2010 12:35:52 -0700

Some safety improvements to netem to make it safer to change paramters
while queue is running.

Use sch_tree_lock() to block all packets during change.

Signed-off-by: Stephen Hemminger <[email-masked]>

--- a/net/sched/sch_netem.c	2010-08-02 16:22:42.389335747 -0700
+++ b/net/sched/sch_netem.c	2010-08-03 08:25:15.611820853 -0700
@@ -318,7 +318,6 @@ static int get_dist_table(struct Qdisc *
 	struct netem_sched_data *q = qdisc_priv(sch);
 	unsigned long n = nla_len(attr)/sizeof(__s16);
 	const __s16 *data = nla_data(attr);
-	spinlock_t *root_lock;
 	struct disttable *d;
 	int i;
 
@@ -333,12 +332,9 @@ static int get_dist_table(struct Qdisc *
 	for (i = 0; i < n; i++)
 		d->table[i] = data[i];
 
-	root_lock = qdisc_root_sleeping_lock(sch);
-
-	spin_lock_bh(root_lock);
 	kfree(q->delay_dist);
 	q->delay_dist = d;
-	spin_unlock_bh(root_lock);
+
 	return 0;
 }
 
@@ -412,6 +408,7 @@ static int netem_change(struct Qdisc *sc
 		return ret;
 	}
 
+	sch_tree_lock(sch);
 	q->latency = qopt->latency;
 	q->jitter = qopt->jitter;
 	q->limit = qopt->limit;
@@ -432,7 +429,7 @@ static int netem_change(struct Qdisc *sc
 	if (tb[TCA_NETEM_DELAY_DIST]) {
 		ret = get_dist_table(sch, tb[TCA_NETEM_DELAY_DIST]);
 		if (ret)
-			return ret;
+			goto out;
 	}
 
 	if (tb[TCA_NETEM_REORDER])
@@ -440,6 +437,8 @@ static int netem_change(struct Qdisc *sc
 
 	if (tb[TCA_NETEM_CORRUPT])
 		get_corrupt(sch, tb[TCA_NETEM_CORRUPT]);
+ out:
+	sch_tree_unlock(sch);
 
 	return 0;
 }