diff --git a/net/openvswitch/flow_table.c b/net/openvswitch/flow_table.c index 8c12675cbb67..cc7859db445a 100644 --- a/net/openvswitch/flow_table.c +++ b/net/openvswitch/flow_table.c @@ -294,7 +294,7 @@ static int tbl_mask_array_add_mask(struct flow_table *tbl, } static void tbl_mask_array_del_mask(struct flow_table *tbl, - struct sw_flow_mask *mask) + struct sw_flow_mask *mask, bool destroy) { struct mask_array *ma = ovsl_dereference(tbl->mask_array); int i, ma_count = READ_ONCE(ma->count); @@ -314,6 +314,11 @@ static void tbl_mask_array_del_mask(struct flow_table *tbl, rcu_assign_pointer(ma->masks[i], ma->masks[ma_count -1]); RCU_INIT_POINTER(ma->masks[ma_count -1], NULL); + if (destroy) { + kfree(mask); + return; + } + kfree_rcu(mask, rcu); /* Shrink the mask array if necessary. */ @@ -326,7 +331,8 @@ static void tbl_mask_array_del_mask(struct flow_table *tbl, } /* Remove 'mask' from the mask list, if it is not needed any more. */ -static void flow_mask_remove(struct flow_table *tbl, struct sw_flow_mask *mask) +static void flow_mask_remove(struct flow_table *tbl, struct sw_flow_mask *mask, + bool destroy) { if (mask) { /* ovs-lock is required to protect mask-refcount and @@ -337,7 +343,7 @@ static void flow_mask_remove(struct flow_table *tbl, struct sw_flow_mask *mask) mask->ref_count--; if (!mask->ref_count) - tbl_mask_array_del_mask(tbl, mask); + tbl_mask_array_del_mask(tbl, mask, destroy); } } @@ -470,7 +476,7 @@ static void table_instance_flow_free(struct flow_table *table, table->ufid_count--; } - flow_mask_remove(table, flow->mask); + flow_mask_remove(table, flow->mask, !count); } static void table_instance_destroy(struct flow_table *table, @@ -521,9 +527,9 @@ void ovs_flow_tbl_destroy(struct flow_table *table) struct mask_cache *mc = rcu_dereference_raw(table->mask_cache); struct mask_array *ma = rcu_dereference_raw(table->mask_array); + table_instance_destroy(table, ti, ufid_ti, false); call_rcu(&mc->rcu, mask_cache_rcu_cb); call_rcu(&ma->rcu, mask_array_rcu_cb); - table_instance_destroy(table, ti, ufid_ti, false); } struct sw_flow *ovs_flow_tbl_dump_next(struct table_instance *ti,