[ovs-dev] [PATCH 1/2] datapath: Always execute actions in BH context.
Pravin B Shelar
pshelar at nicira.com
Wed Oct 5 19:39:02 UTC 2011
Following patch make sure that BH is disabled while running
execute_actions() on packets from userspace. RCU annotation for BH is
used to fix false positive warning message.
Signed-off-by: Pravin B Shelar <pshelar at nicira.com>
Bug #7621
---
datapath/actions.c | 5 +++--
datapath/datapath.c | 6 ++++--
datapath/linux/compat/include/linux/rcupdate.h | 4 +++-
datapath/tunnel.c | 8 ++++----
datapath/vport-patch.c | 2 +-
5 files changed, 15 insertions(+), 10 deletions(-)
diff --git a/datapath/actions.c b/datapath/actions.c
index 36437a4..76d378f 100644
--- a/datapath/actions.c
+++ b/datapath/actions.c
@@ -234,7 +234,7 @@ static int do_output(struct datapath *dp, struct sk_buff *skb, int out_port)
if (unlikely(!skb))
return -ENOMEM;
- vport = rcu_dereference(dp->ports[out_port]);
+ vport = rcu_dereference_bh(dp->ports[out_port]);
if (unlikely(!vport)) {
kfree_skb(skb);
return -ENODEV;
@@ -383,10 +383,11 @@ static int do_execute_actions(struct datapath *dp, struct sk_buff *skb,
/* Execute a list of actions against 'skb'. */
int execute_actions(struct datapath *dp, struct sk_buff *skb)
{
- struct sw_flow_actions *acts = rcu_dereference(OVS_CB(skb)->flow->sf_acts);
+ struct sw_flow_actions *acts;
struct loop_counter *loop;
int error;
+ acts = rcu_dereference_bh(OVS_CB(skb)->flow->sf_acts);
/* Check whether we've looped too much. */
loop = loop_get_counter();
if (unlikely(++loop->count > MAX_LOOPS))
diff --git a/datapath/datapath.c b/datapath/datapath.c
index 15c1e33..b912ee3 100644
--- a/datapath/datapath.c
+++ b/datapath/datapath.c
@@ -304,7 +304,8 @@ void dp_process_received_packet(struct vport *p, struct sk_buff *skb)
}
/* Look up flow. */
- flow = flow_tbl_lookup(rcu_dereference(dp->table), &key, key_len);
+ flow = flow_tbl_lookup(rcu_dereference_bh(dp->table),
+ &key, key_len);
if (unlikely(!flow)) {
struct dp_upcall_info upcall;
@@ -705,8 +706,9 @@ static int ovs_packet_cmd_execute(struct sk_buff *skb, struct genl_info *info)
if (flow->key.eth.in_port < DP_MAX_PORTS)
OVS_CB(packet)->vport = get_vport_protected(dp,
flow->key.eth.in_port);
-
+ local_bh_disable();
err = execute_actions(dp, packet);
+ local_bh_enable();
rcu_read_unlock();
flow_put(flow);
diff --git a/datapath/linux/compat/include/linux/rcupdate.h b/datapath/linux/compat/include/linux/rcupdate.h
index 99459ea..6c9a0a6 100644
--- a/datapath/linux/compat/include/linux/rcupdate.h
+++ b/datapath/linux/compat/include/linux/rcupdate.h
@@ -17,5 +17,7 @@ static inline int rcu_read_lock_held(void)
return 1;
}
#endif
-
+#ifndef rcu_dereference_bh
+#define rcu_dereference_bh(p) rcu_dereference(p)
+#endif
#endif /* linux/rcupdate.h wrapper */
diff --git a/datapath/tunnel.c b/datapath/tunnel.c
index 3576df8..176c5c6 100644
--- a/datapath/tunnel.c
+++ b/datapath/tunnel.c
@@ -898,7 +898,7 @@ static struct tnl_cache *build_cache(struct vport *vport,
if (err || is_frag)
goto done;
- flow = flow_tbl_lookup(rcu_dereference(dst_vport->dp->table),
+ flow = flow_tbl_lookup(rcu_dereference_bh(dst_vport->dp->table),
&flow_key, flow_key_len);
if (flow) {
cache->flow = flow;
@@ -920,7 +920,7 @@ static struct rtable *find_route(struct vport *vport,
u8 tos, struct tnl_cache **cache)
{
struct tnl_vport *tnl_vport = tnl_vport_priv(vport);
- struct tnl_cache *cur_cache = rcu_dereference(tnl_vport->cache);
+ struct tnl_cache *cur_cache = rcu_dereference_bh(tnl_vport->cache);
*cache = NULL;
tos = RT_TOS(tos);
@@ -1074,8 +1074,7 @@ free_frags:
int tnl_send(struct vport *vport, struct sk_buff *skb)
{
struct tnl_vport *tnl_vport = tnl_vport_priv(vport);
- const struct tnl_mutable_config *mutable = rcu_dereference(tnl_vport->mutable);
-
+ const struct tnl_mutable_config *mutable;
enum vport_err_type err = VPORT_E_TX_ERROR;
struct rtable *rt;
struct dst_entry *unattached_dst = NULL;
@@ -1119,6 +1118,7 @@ int tnl_send(struct vport *vport, struct sk_buff *skb)
else
inner_tos = 0;
+ mutable = rcu_dereference_bh(tnl_vport->mutable);
if (mutable->flags & TNL_F_TOS_INHERIT)
tos = inner_tos;
else
diff --git a/datapath/vport-patch.c b/datapath/vport-patch.c
index 9554f12..c18b59d 100644
--- a/datapath/vport-patch.c
+++ b/datapath/vport-patch.c
@@ -271,7 +271,7 @@ static int patch_get_options(const struct vport *vport, struct sk_buff *skb)
static int patch_send(struct vport *vport, struct sk_buff *skb)
{
struct patch_vport *patch_vport = patch_vport_priv(vport);
- struct vport *peer = rcu_dereference(patch_vport->peer);
+ struct vport *peer = rcu_dereference_bh(patch_vport->peer);
int skb_len = skb->len;
if (!peer) {
--
1.7.1
More information about the dev
mailing list