error = PTR_ERR(new_acts);
if (IS_ERR(new_acts))
goto error;
- old_acts = rcu_dereference(flow->sf_acts);
+
+ old_acts = rcu_dereference_protected(flow->sf_acts,
+ lockdep_is_held(&dp->mutex));
if (old_acts->actions_len != new_acts->actions_len ||
memcmp(old_acts->actions, new_acts->actions,
old_acts->actions_len)) {
return 0;
}
-static int do_answer_query(struct sw_flow *flow, u32 query_flags,
+static int do_answer_query(struct datapath *dp, struct sw_flow *flow,
+ u32 query_flags,
struct odp_flow_stats __user *ustats,
struct nlattr __user *actions,
u32 __user *actions_lenp)
if (!actions_len)
return 0;
- sf_acts = rcu_dereference(flow->sf_acts);
+ sf_acts = rcu_dereference_protected(flow->sf_acts,
+ lockdep_is_held(&dp->mutex));
if (put_user(sf_acts->actions_len, actions_lenp) ||
(actions && copy_to_user(actions, sf_acts->actions,
min(sf_acts->actions_len, actions_len))))
return 0;
}
-static int answer_query(struct sw_flow *flow, u32 query_flags,
- struct odp_flow __user *ufp)
+static int answer_query(struct datapath *dp, struct sw_flow *flow,
+ u32 query_flags, struct odp_flow __user *ufp)
{
struct nlattr __user *actions;
if (get_user(actions, (struct nlattr __user * __user *)&ufp->actions))
return -EFAULT;
- return do_answer_query(flow, query_flags,
+ return do_answer_query(dp, flow, query_flags,
&ufp->stats, actions, &ufp->actions_len);
}
if (IS_ERR(flow))
return PTR_ERR(flow);
- error = answer_query(flow, 0, ufp);
+ error = answer_query(dp, flow, 0, ufp);
flow_deferred_free(flow);
return error;
}
if (!flow_node)
error = put_user(ENOENT, &ufp->stats.error);
else
- error = answer_query(flow_cast(flow_node), uf.flags, ufp);
+ error = answer_query(dp, flow_cast(flow_node), uf.flags, ufp);
if (error)
return -EFAULT;
}
}
struct list_flows_cbdata {
+ struct datapath *dp;
struct odp_flow __user *uflows;
u32 n_flows;
u32 listed_flows;
if (copy_to_user(&ufp->key, &flow->key, sizeof flow->key))
return -EFAULT;
- error = answer_query(flow, 0, ufp);
+ error = answer_query(cbdata->dp, flow, 0, ufp);
if (error)
return error;
if (!flowvec->n_flows)
return 0;
+ cbdata.dp = dp;
cbdata.uflows = (struct odp_flow __user *)flowvec->flows;
cbdata.n_flows = flowvec->n_flows;
cbdata.listed_flows = 0;
return 0;
}
-static int compat_answer_query(struct sw_flow *flow, u32 query_flags,
+static int compat_answer_query(struct datapath *dp, struct sw_flow *flow,
+ u32 query_flags,
struct compat_odp_flow __user *ufp)
{
compat_uptr_t actions;
if (get_user(actions, &ufp->actions))
return -EFAULT;
- return do_answer_query(flow, query_flags, &ufp->stats,
+ return do_answer_query(dp, flow, query_flags, &ufp->stats,
compat_ptr(actions), &ufp->actions_len);
}
if (IS_ERR(flow))
return PTR_ERR(flow);
- error = compat_answer_query(flow, 0, ufp);
+ error = compat_answer_query(dp, flow, 0, ufp);
flow_deferred_free(flow);
return error;
}
if (!flow_node)
error = put_user(ENOENT, &ufp->stats.error);
else
- error = compat_answer_query(flow_cast(flow_node), uf.flags, ufp);
+ error = compat_answer_query(dp, flow_cast(flow_node),
+ uf.flags, ufp);
if (error)
return -EFAULT;
}
}
struct compat_list_flows_cbdata {
+ struct datapath *dp;
struct compat_odp_flow __user *uflows;
u32 n_flows;
u32 listed_flows;
if (copy_to_user(&ufp->key, &flow->key, sizeof flow->key))
return -EFAULT;
- error = compat_answer_query(flow, 0, ufp);
+ error = compat_answer_query(cbdata->dp, flow, 0, ufp);
if (error)
return error;
if (!n_flows)
return 0;
+ cbdata.dp = dp;
cbdata.uflows = flows;
cbdata.n_flows = n_flows;
cbdata.listed_flows = 0;