From 6c6eeae0095a8ba9a3c811a32975f45df8b2d35d Mon Sep 17 00:00:00 2001
From: Jesse Gross <jesse@nicira.com>
Date: Wed, 19 Jun 2013 16:10:55 -0700
Subject: [PATCH] Mask deletion

---
 datapath/datapath.c |  8 ++++----
 datapath/flow.c     | 44 +++++++++++++++++---------------------------
 datapath/flow.h     |  8 +++-----
 3 files changed, 24 insertions(+), 36 deletions(-)

diff --git a/datapath/datapath.c b/datapath/datapath.c
index 4849074..039430d 100644
--- a/datapath/datapath.c
+++ b/datapath/datapath.c
@@ -937,13 +937,13 @@ static int ovs_packet_cmd_execute(struct sk_buff *skb, struct genl_info *info)
 	local_bh_enable();
 	rcu_read_unlock();
 
-	ovs_flow_free(flow);
+	ovs_flow_free(flow, false);
 	return err;
 
 err_unlock:
 	rcu_read_unlock();
 err_flow_free:
-	ovs_flow_free(flow);
+	ovs_flow_free(flow, false);
 err_kfree_skb:
 	kfree_skb(packet);
 err:
@@ -1385,7 +1385,7 @@ static int ovs_flow_cmd_new_or_set(struct sk_buff *skb, struct genl_info *info)
 	return 0;
 
 err_flow_free:
-	ovs_flow_free(flow);
+	ovs_flow_free(flow, false);
 err_unlock_ovs:
 	ovs_unlock();
 err_kfree:
@@ -1490,7 +1490,7 @@ static int ovs_flow_cmd_del(struct sk_buff *skb, struct genl_info *info)
 				     info->snd_seq, 0, OVS_FLOW_CMD_DEL);
 	BUG_ON(err < 0);
 
-	ovs_flow_deferred_free(flow);
+	ovs_flow_free(flow, true);
 	ovs_unlock();
 
 	ovs_notify(reply, info, &ovs_dp_flow_multicast_group);
diff --git a/datapath/flow.c b/datapath/flow.c
index 86f3896..a0658fa 100644
--- a/datapath/flow.c
+++ b/datapath/flow.c
@@ -480,21 +480,11 @@ void ovs_flow_tbl_destroy(struct flow_table *table)
 		struct sw_flow *flow;
 		struct hlist_head *head = flex_array_get(table->buckets, i);
 		struct hlist_node *n;
-		struct list_head *ml, *tmp;
 		int ver = table->node_ver;
 
 		hlist_for_each_entry_safe(flow, n, head, hash_node[ver]) {
 			hlist_del_rcu(&flow->hash_node[ver]);
-			flow->mask = NULL;
-			ovs_flow_free(flow);
-		}
-
-		/* Delete the entire mask list, free all masks on the list. */
-		list_for_each_safe(ml, tmp, &table->mask_list) {
-			struct sw_flow_mask *mask;
-			mask = container_of(ml, struct sw_flow_mask, list);
-			list_del_rcu(&mask->list);
-			kfree(mask);
+			ovs_flow_free(flow, false);
 		}
 	}
 
@@ -600,34 +590,31 @@ struct flow_table *ovs_flow_tbl_expand(struct flow_table *table)
 	return __flow_tbl_rehash(table, table->n_buckets * 2);
 }
 
-void ovs_flow_free(struct sw_flow *flow)
+static void __flow_free(struct sw_flow *flow)
 {
-	if (unlikely(!flow))
-		return;
-
-	BUG_ON(flow->mask);
 	kfree((struct sf_flow_acts __force *)flow->sf_acts);
 	kmem_cache_free(flow_cache, flow);
 }
 
-/* RCU callback used by ovs_flow_deferred_free. */
 static void rcu_free_flow_callback(struct rcu_head *rcu)
 {
 	struct sw_flow *flow = container_of(rcu, struct sw_flow, rcu);
 
-	flow->mask = NULL;
-	ovs_flow_free(flow);
+	__flow_free(flow);
 }
 
-/* Schedules 'flow' to be freed after the next RCU grace period.
- * The caller must hold rcu_read_lock for this to be sensible. */
-void ovs_flow_deferred_free(struct sw_flow *flow)
+void ovs_flow_free(struct sw_flow *flow, bool deferred)
 {
-	if (unlikely(!flow))
+	if (!flow)
 		return;
 
-	ovs_sw_flow_mask_del_ref(ovsl_dereference(flow->mask));
-	call_rcu(&flow->rcu, rcu_free_flow_callback);
+	ovs_sw_flow_mask_del_ref((struct sw_flow_mask __force *)flow->mask,
+				 deferred);
+
+	if (deferred)
+		call_rcu(&flow->rcu, rcu_free_flow_callback);
+	else
+		__flow_free(flow);
 }
 
 /* RCU callback used by ovs_flow_deferred_free_acts. */
@@ -1824,7 +1811,7 @@ static void rcu_free_sw_flow_mask_cb(struct rcu_head *rcu)
 	kfree(mask);
 }
 
-void ovs_sw_flow_mask_del_ref(struct sw_flow_mask *mask)
+void ovs_sw_flow_mask_del_ref(struct sw_flow_mask *mask, bool deferred)
 {
 	if (!mask)
 		return;
@@ -1834,7 +1821,10 @@ void ovs_sw_flow_mask_del_ref(struct sw_flow_mask *mask)
 
 	if (!mask->ref_count) {
 		list_del_rcu(&mask->list);
-		call_rcu(&mask->rcu, rcu_free_sw_flow_mask_cb);
+		if (deferred)
+			call_rcu(&mask->rcu, rcu_free_sw_flow_mask_cb);
+		else
+			kfree(mask);
 	}
 }
 
diff --git a/datapath/flow.h b/datapath/flow.h
index d29b621..da97074 100644
--- a/datapath/flow.h
+++ b/datapath/flow.h
@@ -171,7 +171,7 @@ void ovs_flow_exit(void);
 
 struct sw_flow *ovs_flow_alloc(void);
 void ovs_flow_deferred_free(struct sw_flow *);
-void ovs_flow_free(struct sw_flow *);
+void ovs_flow_free(struct sw_flow *, bool deferred);
 
 struct sw_flow_actions *ovs_flow_actions_alloc(int actions_len);
 void ovs_flow_deferred_free_acts(struct sw_flow_actions *);
@@ -194,9 +194,7 @@ struct flow_table {
 	struct flex_array *buckets;
 	unsigned int count, n_buckets;
 	struct rcu_head rcu;
-	struct list_head mask_list;  /* Mask list. Changes to the list
-					are protected ovs_mutex when flow
-					table is in use. */
+	struct list_head mask_list;
 	int node_ver;
 	u32 hash_seed;
 	bool keep_flows;
@@ -260,7 +258,7 @@ ovs_sw_flow_mask_size_roundup(const struct sw_flow_mask *mask)
 
 struct sw_flow_mask *ovs_sw_flow_mask_alloc(void);
 void ovs_sw_flow_mask_add_ref(struct sw_flow_mask *);
-void ovs_sw_flow_mask_del_ref(struct sw_flow_mask *);
+void ovs_sw_flow_mask_del_ref(struct sw_flow_mask *, bool deferred);
 void ovs_sw_flow_mask_insert(struct flow_table *, struct sw_flow_mask *);
 struct sw_flow_mask *ovs_sw_flow_mask_find(const struct flow_table *,
 		const struct sw_flow_mask *);
-- 
1.8.1.2

