aboutsummaryrefslogtreecommitdiffstats
path: root/net/openvswitch/flow_table.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/openvswitch/flow_table.c')
-rw-r--r--net/openvswitch/flow_table.c88
1 files changed, 43 insertions, 45 deletions
diff --git a/net/openvswitch/flow_table.c b/net/openvswitch/flow_table.c
index c58a0fe3c889..3c268b3d71c3 100644
--- a/net/openvswitch/flow_table.c
+++ b/net/openvswitch/flow_table.c
@@ -153,29 +153,29 @@ static void rcu_free_flow_callback(struct rcu_head *rcu)
153 flow_free(flow); 153 flow_free(flow);
154} 154}
155 155
156static void flow_mask_del_ref(struct sw_flow_mask *mask, bool deferred)
157{
158 if (!mask)
159 return;
160
161 BUG_ON(!mask->ref_count);
162 mask->ref_count--;
163
164 if (!mask->ref_count) {
165 list_del_rcu(&mask->list);
166 if (deferred)
167 kfree_rcu(mask, rcu);
168 else
169 kfree(mask);
170 }
171}
172
173void ovs_flow_free(struct sw_flow *flow, bool deferred) 156void ovs_flow_free(struct sw_flow *flow, bool deferred)
174{ 157{
175 if (!flow) 158 if (!flow)
176 return; 159 return;
177 160
178 flow_mask_del_ref(flow->mask, deferred); 161 if (flow->mask) {
162 struct sw_flow_mask *mask = flow->mask;
163
164 /* ovs-lock is required to protect mask-refcount and
165 * mask list.
166 */
167 ASSERT_OVSL();
168 BUG_ON(!mask->ref_count);
169 mask->ref_count--;
170
171 if (!mask->ref_count) {
172 list_del_rcu(&mask->list);
173 if (deferred)
174 kfree_rcu(mask, rcu);
175 else
176 kfree(mask);
177 }
178 }
179 179
180 if (deferred) 180 if (deferred)
181 call_rcu(&flow->rcu, rcu_free_flow_callback); 181 call_rcu(&flow->rcu, rcu_free_flow_callback);
@@ -188,26 +188,9 @@ static void free_buckets(struct flex_array *buckets)
188 flex_array_free(buckets); 188 flex_array_free(buckets);
189} 189}
190 190
191
191static void __table_instance_destroy(struct table_instance *ti) 192static void __table_instance_destroy(struct table_instance *ti)
192{ 193{
193 int i;
194
195 if (ti->keep_flows)
196 goto skip_flows;
197
198 for (i = 0; i < ti->n_buckets; i++) {
199 struct sw_flow *flow;
200 struct hlist_head *head = flex_array_get(ti->buckets, i);
201 struct hlist_node *n;
202 int ver = ti->node_ver;
203
204 hlist_for_each_entry_safe(flow, n, head, hash_node[ver]) {
205 hlist_del(&flow->hash_node[ver]);
206 ovs_flow_free(flow, false);
207 }
208 }
209
210skip_flows:
211 free_buckets(ti->buckets); 194 free_buckets(ti->buckets);
212 kfree(ti); 195 kfree(ti);
213} 196}
@@ -258,20 +241,38 @@ static void flow_tbl_destroy_rcu_cb(struct rcu_head *rcu)
258 241
259static void table_instance_destroy(struct table_instance *ti, bool deferred) 242static void table_instance_destroy(struct table_instance *ti, bool deferred)
260{ 243{
244 int i;
245
261 if (!ti) 246 if (!ti)
262 return; 247 return;
263 248
249 if (ti->keep_flows)
250 goto skip_flows;
251
252 for (i = 0; i < ti->n_buckets; i++) {
253 struct sw_flow *flow;
254 struct hlist_head *head = flex_array_get(ti->buckets, i);
255 struct hlist_node *n;
256 int ver = ti->node_ver;
257
258 hlist_for_each_entry_safe(flow, n, head, hash_node[ver]) {
259 hlist_del_rcu(&flow->hash_node[ver]);
260 ovs_flow_free(flow, deferred);
261 }
262 }
263
264skip_flows:
264 if (deferred) 265 if (deferred)
265 call_rcu(&ti->rcu, flow_tbl_destroy_rcu_cb); 266 call_rcu(&ti->rcu, flow_tbl_destroy_rcu_cb);
266 else 267 else
267 __table_instance_destroy(ti); 268 __table_instance_destroy(ti);
268} 269}
269 270
270void ovs_flow_tbl_destroy(struct flow_table *table) 271void ovs_flow_tbl_destroy(struct flow_table *table, bool deferred)
271{ 272{
272 struct table_instance *ti = ovsl_dereference(table->ti); 273 struct table_instance *ti = ovsl_dereference(table->ti);
273 274
274 table_instance_destroy(ti, false); 275 table_instance_destroy(ti, deferred);
275} 276}
276 277
277struct sw_flow *ovs_flow_tbl_dump_next(struct table_instance *ti, 278struct sw_flow *ovs_flow_tbl_dump_next(struct table_instance *ti,
@@ -504,16 +505,11 @@ static struct sw_flow_mask *mask_alloc(void)
504 505
505 mask = kmalloc(sizeof(*mask), GFP_KERNEL); 506 mask = kmalloc(sizeof(*mask), GFP_KERNEL);
506 if (mask) 507 if (mask)
507 mask->ref_count = 0; 508 mask->ref_count = 1;
508 509
509 return mask; 510 return mask;
510} 511}
511 512
512static void mask_add_ref(struct sw_flow_mask *mask)
513{
514 mask->ref_count++;
515}
516
517static bool mask_equal(const struct sw_flow_mask *a, 513static bool mask_equal(const struct sw_flow_mask *a,
518 const struct sw_flow_mask *b) 514 const struct sw_flow_mask *b)
519{ 515{
@@ -554,9 +550,11 @@ static int flow_mask_insert(struct flow_table *tbl, struct sw_flow *flow,
554 mask->key = new->key; 550 mask->key = new->key;
555 mask->range = new->range; 551 mask->range = new->range;
556 list_add_rcu(&mask->list, &tbl->mask_list); 552 list_add_rcu(&mask->list, &tbl->mask_list);
553 } else {
554 BUG_ON(!mask->ref_count);
555 mask->ref_count++;
557 } 556 }
558 557
559 mask_add_ref(mask);
560 flow->mask = mask; 558 flow->mask = mask;
561 return 0; 559 return 0;
562} 560}