diff options
Diffstat (limited to 'net/openvswitch/flow_table.c')
-rw-r--r-- | net/openvswitch/flow_table.c | 44 |
1 files changed, 25 insertions, 19 deletions
diff --git a/net/openvswitch/flow_table.c b/net/openvswitch/flow_table.c index d8ef37b937bd..c80df6f42fee 100644 --- a/net/openvswitch/flow_table.c +++ b/net/openvswitch/flow_table.c | |||
@@ -159,25 +159,6 @@ void ovs_flow_free(struct sw_flow *flow, bool deferred) | |||
159 | if (!flow) | 159 | if (!flow) |
160 | return; | 160 | return; |
161 | 161 | ||
162 | if (flow->mask) { | ||
163 | struct sw_flow_mask *mask = flow->mask; | ||
164 | |||
165 | /* ovs-lock is required to protect mask-refcount and | ||
166 | * mask list. | ||
167 | */ | ||
168 | ASSERT_OVSL(); | ||
169 | BUG_ON(!mask->ref_count); | ||
170 | mask->ref_count--; | ||
171 | |||
172 | if (!mask->ref_count) { | ||
173 | list_del_rcu(&mask->list); | ||
174 | if (deferred) | ||
175 | kfree_rcu(mask, rcu); | ||
176 | else | ||
177 | kfree(mask); | ||
178 | } | ||
179 | } | ||
180 | |||
181 | if (deferred) | 162 | if (deferred) |
182 | call_rcu(&flow->rcu, rcu_free_flow_callback); | 163 | call_rcu(&flow->rcu, rcu_free_flow_callback); |
183 | else | 164 | else |
@@ -491,6 +472,25 @@ static struct table_instance *table_instance_expand(struct table_instance *ti) | |||
491 | return table_instance_rehash(ti, ti->n_buckets * 2); | 472 | return table_instance_rehash(ti, ti->n_buckets * 2); |
492 | } | 473 | } |
493 | 474 | ||
475 | /* Remove 'mask' from the mask list, if it is not needed any more. */ | ||
476 | static void flow_mask_remove(struct flow_table *tbl, struct sw_flow_mask *mask) | ||
477 | { | ||
478 | if (mask) { | ||
479 | /* ovs-lock is required to protect mask-refcount and | ||
480 | * mask list. | ||
481 | */ | ||
482 | ASSERT_OVSL(); | ||
483 | BUG_ON(!mask->ref_count); | ||
484 | mask->ref_count--; | ||
485 | |||
486 | if (!mask->ref_count) { | ||
487 | list_del_rcu(&mask->list); | ||
488 | kfree_rcu(mask, rcu); | ||
489 | } | ||
490 | } | ||
491 | } | ||
492 | |||
493 | /* Must be called with OVS mutex held. */ | ||
494 | void ovs_flow_tbl_remove(struct flow_table *table, struct sw_flow *flow) | 494 | void ovs_flow_tbl_remove(struct flow_table *table, struct sw_flow *flow) |
495 | { | 495 | { |
496 | struct table_instance *ti = ovsl_dereference(table->ti); | 496 | struct table_instance *ti = ovsl_dereference(table->ti); |
@@ -498,6 +498,11 @@ void ovs_flow_tbl_remove(struct flow_table *table, struct sw_flow *flow) | |||
498 | BUG_ON(table->count == 0); | 498 | BUG_ON(table->count == 0); |
499 | hlist_del_rcu(&flow->hash_node[ti->node_ver]); | 499 | hlist_del_rcu(&flow->hash_node[ti->node_ver]); |
500 | table->count--; | 500 | table->count--; |
501 | |||
502 | /* RCU delete the mask. 'flow->mask' is not NULLed, as it should be | ||
503 | * accessible as long as the RCU read lock is held. | ||
504 | */ | ||
505 | flow_mask_remove(table, flow->mask); | ||
501 | } | 506 | } |
502 | 507 | ||
503 | static struct sw_flow_mask *mask_alloc(void) | 508 | static struct sw_flow_mask *mask_alloc(void) |
@@ -560,6 +565,7 @@ static int flow_mask_insert(struct flow_table *tbl, struct sw_flow *flow, | |||
560 | return 0; | 565 | return 0; |
561 | } | 566 | } |
562 | 567 | ||
568 | /* Must be called with OVS mutex held. */ | ||
563 | int ovs_flow_tbl_insert(struct flow_table *table, struct sw_flow *flow, | 569 | int ovs_flow_tbl_insert(struct flow_table *table, struct sw_flow *flow, |
564 | struct sw_flow_mask *mask) | 570 | struct sw_flow_mask *mask) |
565 | { | 571 | { |