From f416c8d616012b0369cd53d43960fc9da166229b Mon Sep 17 00:00:00 2001 From: Jarno Rajahalme Date: Thu, 24 Apr 2014 08:21:49 -0700 Subject: [PATCH] ofproto: RCU postpone rule destruction. This allows rules to be used without taking references while RCU protected. The last step of destroying an ofproto also needs to be postponed, as the rule destruction requires the class structure to be available at the postponed destruction callback. Signed-off-by: Jarno Rajahalme Acked-by: Ethan Jackson --- ofproto/ofproto.c | 40 ++++++++++++++++++++++++++-------------- 1 file changed, 26 insertions(+), 14 deletions(-) diff --git a/ofproto/ofproto.c b/ofproto/ofproto.c index f16005cec..f10d3ae68 100644 --- a/ofproto/ofproto.c +++ b/ofproto/ofproto.c @@ -259,7 +259,6 @@ struct ofport_usage { }; /* rule. */ -static void ofproto_rule_destroy__(struct rule *); static void ofproto_rule_send_removed(struct rule *, uint8_t reason); static bool rule_is_modifiable(const struct rule *rule, enum ofputil_flow_mod_flags flag); @@ -1372,7 +1371,8 @@ ofproto_destroy(struct ofproto *p) } p->ofproto_class->destruct(p); - ofproto_destroy__(p); + /* Destroying rules is deferred, must have 'ofproto' around for them. */ + ovsrcu_postpone(ofproto_destroy__, p); } /* Destroys the datapath with the respective 'name' and 'type'. With the Linux @@ -2642,6 +2642,23 @@ update_mtu(struct ofproto *p, struct ofport *port) } } +static void +ofproto_rule_destroy__(struct rule *rule) + OVS_NO_THREAD_SAFETY_ANALYSIS +{ + cls_rule_destroy(CONST_CAST(struct cls_rule *, &rule->cr)); + rule_actions_destroy(rule_get_actions(rule)); + ovs_mutex_destroy(&rule->mutex); + rule->ofproto->ofproto_class->rule_dealloc(rule); +} + +static void +rule_destroy_cb(struct rule *rule) +{ + rule->ofproto->ofproto_class->rule_destruct(rule); + ofproto_rule_destroy__(rule); +} + void ofproto_rule_ref(struct rule *rule) { @@ -2650,25 +2667,20 @@ ofproto_rule_ref(struct rule *rule) } } +/* Decrements 'rule''s ref_count and schedules 'rule' to be destroyed if the + * ref_count reaches 0. + * + * Use of RCU allows short term use (between RCU quiescent periods) without + * keeping a reference. A reference must be taken if the rule needs to + * stay around accross the RCU quiescent periods. */ void ofproto_rule_unref(struct rule *rule) { if (rule && ovs_refcount_unref(&rule->ref_count) == 1) { - rule->ofproto->ofproto_class->rule_destruct(rule); - ofproto_rule_destroy__(rule); + ovsrcu_postpone(rule_destroy_cb, rule); } } -static void -ofproto_rule_destroy__(struct rule *rule) - OVS_NO_THREAD_SAFETY_ANALYSIS -{ - cls_rule_destroy(CONST_CAST(struct cls_rule *, &rule->cr)); - rule_actions_destroy(rule_get_actions(rule)); - ovs_mutex_destroy(&rule->mutex); - rule->ofproto->ofproto_class->rule_dealloc(rule); -} - static uint32_t get_provider_meter_id(const struct ofproto *, uint32_t of_meter_id); -- 2.43.0