A datapath pointer is available only when holding a lock.  Change
ovs_flow_cmd_fill_info() and ovs_flow_cmd_build_info() to take a
dp_ifindex directly, rather than a datapath pointer that is then
(only) used to get the dp_ifindex.  This is useful, since the
dp_ifindex is available even when the datapath pointer is not, both
before and after taking a lock, which makes further critical section
reduction possible.

Signed-off-by: Jarno Rajahalme <jrajaha...@nicira.com>
---
v5: Split to a separate patch, relaxed locking requirements.

 datapath/datapath.c |   58 ++++++++++++++++++++++++++++++++-------------------
 datapath/flow.c     |    6 ++++--
 datapath/flow.h     |    2 +-
 3 files changed, 41 insertions(+), 25 deletions(-)

diff --git a/datapath/datapath.c b/datapath/datapath.c
index d1b0155..01913f6 100644
--- a/datapath/datapath.c
+++ b/datapath/datapath.c
@@ -663,8 +663,17 @@ static size_t ovs_flow_cmd_msg_size(const struct 
sw_flow_actions *acts)
                + nla_total_size(acts->actions_len); /* OVS_FLOW_ATTR_ACTIONS */
 }
 
-/* Called with ovs_mutex or RCU read lock. */
-static int ovs_flow_cmd_fill_info(struct sw_flow *flow, struct datapath *dp,
+/* Allow a flow to be accessed if:
+ * - RCU read lock is held, or
+ * - OVS mutex is held, or
+ * - the flow has already been removed from the flow table. */
+#define ovsl_dereference_flow_acts(flow)                               \
+       rcu_dereference_check(flow->sf_acts, (lockdep_ovsl_is_held()    \
+                                             || ovs_flow_removed(flow)))
+
+/* Must be called with rcu_read_lock or ovs_mutex if 'flow' is in the flow
+ * table. */
+static int ovs_flow_cmd_fill_info(const struct sw_flow *flow, int dp_ifindex,
                                  struct sk_buff *skb, u32 portid,
                                  u32 seq, u32 flags, u8 cmd)
 {
@@ -681,7 +690,7 @@ static int ovs_flow_cmd_fill_info(struct sw_flow *flow, 
struct datapath *dp,
        if (!ovs_header)
                return -EMSGSIZE;
 
-       ovs_header->dp_ifindex = get_dpifindex(dp);
+       ovs_header->dp_ifindex = dp_ifindex;
 
        /* Fill flow key. */
        nla = nla_nest_start(skb, OVS_FLOW_ATTR_KEY);
@@ -730,8 +739,7 @@ static int ovs_flow_cmd_fill_info(struct sw_flow *flow, 
struct datapath *dp,
        if (start) {
                const struct sw_flow_actions *sf_acts;
 
-               sf_acts = rcu_dereference_ovsl(flow->sf_acts);
-
+               sf_acts = ovsl_dereference_flow_acts(flow);
                err = ovs_nla_put_actions(sf_acts->actions,
                                          sf_acts->actions_len, skb);
                if (!err)
@@ -754,8 +762,9 @@ error:
        return err;
 }
 
-/* Must be called with ovs_mutex. */
-static struct sk_buff *ovs_flow_cmd_alloc_info(struct sw_flow *flow,
+/* Must be called with rcu_read_lock or ovs_mutex if 'flow' is in the flow
+ * table. */
+static struct sk_buff *ovs_flow_cmd_alloc_info(const struct sw_flow *flow,
                                               struct genl_info *info,
                                               bool always)
 {
@@ -765,7 +774,7 @@ static struct sk_buff *ovs_flow_cmd_alloc_info(struct 
sw_flow *flow,
        if (!always && !ovs_must_notify(info, &ovs_dp_flow_multicast_group))
                return NULL;
 
-       len = ovs_flow_cmd_msg_size(ovsl_dereference(flow->sf_acts));
+       len = ovs_flow_cmd_msg_size(ovsl_dereference_flow_acts(flow));
 
        skb = genlmsg_new_unicast(len, info, GFP_KERNEL);
 
@@ -775,11 +784,12 @@ static struct sk_buff *ovs_flow_cmd_alloc_info(struct 
sw_flow *flow,
        return skb;
 }
 
-/* Must be called with ovs_mutex. */
-static struct sk_buff *ovs_flow_cmd_build_info(struct sw_flow *flow,
-                                              struct datapath *dp,
-                                              struct genl_info *info,
-                                              u8 cmd, bool always)
+/* Must be called with rcu_read_lock or ovs_mutex if 'flow' is in the flow
+ * table. */
+static struct sk_buff *ovs_flow_cmd_build_info(const struct sw_flow *flow,
+                                              int dp_ifindex,
+                                              struct genl_info *info, u8 cmd,
+                                              bool always)
 {
        struct sk_buff *skb;
        int retval;
@@ -788,8 +798,9 @@ static struct sk_buff *ovs_flow_cmd_build_info(struct 
sw_flow *flow,
        if (!skb || IS_ERR(skb))
                return skb;
 
-       retval = ovs_flow_cmd_fill_info(flow, dp, skb, info->snd_portid,
-                                       info->snd_seq, 0, cmd);
+       retval = ovs_flow_cmd_fill_info(flow, dp_ifindex, skb,
+                                       info->snd_portid, info->snd_seq, 0,
+                                       cmd);
        BUG_ON(retval < 0);
        return skb;
 }
@@ -870,8 +881,8 @@ static int ovs_flow_cmd_new_or_set(struct sk_buff *skb, 
struct genl_info *info)
                        goto err_flow_free;
                }
 
-               reply = ovs_flow_cmd_build_info(flow, dp, info,
-                                               OVS_FLOW_CMD_NEW, false);
+               reply = ovs_flow_cmd_build_info(flow, ovs_header->dp_ifindex,
+                                               info, OVS_FLOW_CMD_NEW, false);
        } else {
                /* We found a matching flow. */
                /* Bail out if we're not allowed to modify an existing flow.
@@ -897,8 +908,9 @@ static int ovs_flow_cmd_new_or_set(struct sk_buff *skb, 
struct genl_info *info)
                        rcu_assign_pointer(flow->sf_acts, acts);
                        ovs_nla_free_flow_actions(old_acts);
                }
-               reply = ovs_flow_cmd_build_info(flow, dp, info,
-                                               OVS_FLOW_CMD_NEW, false);
+
+               reply = ovs_flow_cmd_build_info(flow, ovs_header->dp_ifindex,
+                                               info, OVS_FLOW_CMD_NEW, false);
 
                /* Clear stats. */
                if (a[OVS_FLOW_ATTR_CLEAR])
@@ -960,7 +972,8 @@ static int ovs_flow_cmd_get(struct sk_buff *skb, struct 
genl_info *info)
                goto unlock;
        }
 
-       reply = ovs_flow_cmd_build_info(flow, dp, info, OVS_FLOW_CMD_NEW, true);
+       reply = ovs_flow_cmd_build_info(flow, ovs_header->dp_ifindex, info,
+                                       OVS_FLOW_CMD_NEW, true);
        if (IS_ERR(reply)) {
                err = PTR_ERR(reply);
                goto unlock;
@@ -1016,7 +1029,8 @@ static int ovs_flow_cmd_del(struct sk_buff *skb, struct 
genl_info *info)
        ovs_flow_tbl_remove(&dp->table, flow);
 
        if (reply) {
-               err = ovs_flow_cmd_fill_info(flow, dp, reply, info->snd_portid,
+               err = ovs_flow_cmd_fill_info(flow, ovs_header->dp_ifindex,
+                                            reply, info->snd_portid,
                                             info->snd_seq, 0,
                                             OVS_FLOW_CMD_DEL);
                BUG_ON(err < 0);
@@ -1057,7 +1071,7 @@ static int ovs_flow_cmd_dump(struct sk_buff *skb, struct 
netlink_callback *cb)
                if (!flow)
                        break;
 
-               if (ovs_flow_cmd_fill_info(flow, dp, skb,
+               if (ovs_flow_cmd_fill_info(flow, ovs_header->dp_ifindex, skb,
                                           NETLINK_CB(cb->skb).portid,
                                           cb->nlh->nlmsg_seq, NLM_F_MULTI,
                                           OVS_FLOW_CMD_NEW) < 0)
diff --git a/datapath/flow.c b/datapath/flow.c
index 5d1d2f2..6d7c3b5 100644
--- a/datapath/flow.c
+++ b/datapath/flow.c
@@ -123,8 +123,10 @@ unlock:
        spin_unlock(&stats->lock);
 }
 
-/* Called with ovs_mutex. */
-void ovs_flow_stats_get(struct sw_flow *flow, struct ovs_flow_stats *ovs_stats,
+/* Must be called with rcu_read_lock or ovs_mutex if 'flow' is in the flow
+ * table. */
+void ovs_flow_stats_get(const struct sw_flow *flow,
+                       struct ovs_flow_stats *ovs_stats,
                        unsigned long *used, __be16 *tcp_flags)
 {
        int node;
diff --git a/datapath/flow.h b/datapath/flow.h
index 5587577..25eba04 100644
--- a/datapath/flow.h
+++ b/datapath/flow.h
@@ -183,7 +183,7 @@ struct arp_eth_header {
 } __packed;
 
 void ovs_flow_stats_update(struct sw_flow *flow, struct sk_buff *skb);
-void ovs_flow_stats_get(struct sw_flow *flow, struct ovs_flow_stats *stats,
+void ovs_flow_stats_get(const struct sw_flow *, struct ovs_flow_stats *,
                        unsigned long *used, __be16 *tcp_flags);
 void ovs_flow_stats_clear(struct sw_flow *flow);
 u64 ovs_flow_used_time(unsigned long flow_jiffies);
-- 
1.7.10.4

_______________________________________________
dev mailing list
dev@openvswitch.org
http://openvswitch.org/mailman/listinfo/dev

Reply via email to