diff options
Diffstat (limited to 'net/openvswitch/flow_table.c')
-rw-r--r-- | net/openvswitch/flow_table.c | 88 |
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 | ||
156 | static 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 | |||
173 | void ovs_flow_free(struct sw_flow *flow, bool deferred) | 156 | void 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 | |||
191 | static void __table_instance_destroy(struct table_instance *ti) | 192 | static 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 | |||
210 | skip_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 | ||
259 | static void table_instance_destroy(struct table_instance *ti, bool deferred) | 242 | static 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 | |||
264 | skip_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 | ||
270 | void ovs_flow_tbl_destroy(struct flow_table *table) | 271 | void 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 | ||
277 | struct sw_flow *ovs_flow_tbl_dump_next(struct table_instance *ti, | 278 | struct 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 | ||
512 | static void mask_add_ref(struct sw_flow_mask *mask) | ||
513 | { | ||
514 | mask->ref_count++; | ||
515 | } | ||
516 | |||
517 | static bool mask_equal(const struct sw_flow_mask *a, | 513 | static 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 | } |