X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=datapath%2Fdatapath.c;h=b95c8f25539fc5d98f44707804c78f44fc629a3c;hb=4faaba2b90979e1106b8c9b0430481f2cc62364d;hp=5e2821a543496a1ac42195be01f3a1c1452cf01c;hpb=e1040c772fbebc3abe9e7222f9c540112c4dca81;p=openvswitch diff --git a/datapath/datapath.c b/datapath/datapath.c index 5e2821a5..b95c8f25 100644 --- a/datapath/datapath.c +++ b/datapath/datapath.c @@ -77,7 +77,8 @@ struct datapath *get_dp(int dp_idx) { if (dp_idx < 0 || dp_idx >= ODP_MAX) return NULL; - return rcu_dereference(dps[dp_idx]); + return rcu_dereference_check(dps[dp_idx], rcu_read_lock_held() || + lockdep_is_held(&dp_mutex)); } EXPORT_SYMBOL_GPL(get_dp); @@ -93,10 +94,15 @@ static struct datapath *get_dp_locked(int dp_idx) return dp; } +static struct tbl *get_table_protected(struct datapath *dp) +{ + return rcu_dereference_protected(dp->table, lockdep_is_held(&dp->mutex)); +} + /* Must be called with rcu_read_lock or RTNL lock. */ const char *dp_name(const struct datapath *dp) { - return vport_get_name(dp->ports[ODPP_LOCAL]); + return vport_get_name(rcu_dereference_rtnl(dp->ports[ODPP_LOCAL])); } static inline size_t br_nlmsg_size(void) @@ -139,7 +145,8 @@ static int dp_fill_ifinfo(struct sk_buff *skb, hdr->ifi_change = 0; NLA_PUT_STRING(skb, IFLA_IFNAME, vport_get_name(port)); - NLA_PUT_U32(skb, IFLA_MASTER, vport_get_ifindex(dp->ports[ODPP_LOCAL])); + NLA_PUT_U32(skb, IFLA_MASTER, + vport_get_ifindex(rtnl_dereference(dp->ports[ODPP_LOCAL]))); NLA_PUT_U32(skb, IFLA_MTU, vport_get_mtu(port)); #ifdef IFLA_OPERSTATE NLA_PUT_U8(skb, IFLA_OPERSTATE, @@ -263,8 +270,10 @@ static int create_dp(int dp_idx, const char __user *devnamep) dp->drop_frags = 0; dp->stats_percpu = alloc_percpu(struct dp_stats_percpu); - if (!dp->stats_percpu) + if (!dp->stats_percpu) { + err = -ENOMEM; goto err_destroy_local_port; + } rcu_assign_pointer(dps[dp_idx], dp); dp_sysfs_add_dp(dp); @@ -493,7 +502,8 @@ void dp_process_received_packet(struct vport *p, struct sk_buff *skb) flow_node = tbl_lookup(rcu_dereference(dp->table), &key, flow_hash(&key), flow_cmp); if (unlikely(!flow_node)) { - dp_output_control(dp, skb, _ODPL_MISS_NR, OVS_CB(skb)->tun_id); + dp_output_control(dp, skb, _ODPL_MISS_NR, + (__force u64)OVS_CB(skb)->tun_id); stats_counter_off = offsetof(struct dp_stats_percpu, n_missed); goto out; } @@ -640,7 +650,7 @@ err: static int flush_flows(struct datapath *dp) { - struct tbl *old_table = rcu_dereference(dp->table); + struct tbl *old_table = get_table_protected(dp); struct tbl *new_table; new_table = tbl_create(0); @@ -787,7 +797,7 @@ static void clear_stats(struct sw_flow *flow) static int expand_table(struct datapath *dp) { - struct tbl *old_table = rcu_dereference(dp->table); + struct tbl *old_table = get_table_protected(dp); struct tbl *new_table; new_table = tbl_expand(old_table); @@ -807,9 +817,11 @@ static int do_put_flow(struct datapath *dp, struct odp_flow_put *uf, struct sw_flow *flow; struct tbl *table; int error; + u32 hash; - table = rcu_dereference(dp->table); - flow_node = tbl_lookup(table, &uf->flow.key, flow_hash(&uf->flow.key), flow_cmp); + hash = flow_hash(&uf->flow.key); + table = get_table_protected(dp); + flow_node = tbl_lookup(table, &uf->flow.key, hash, flow_cmp); if (!flow_node) { /* No such flow. */ struct sw_flow_actions *acts; @@ -823,7 +835,7 @@ static int do_put_flow(struct datapath *dp, struct odp_flow_put *uf, error = expand_table(dp); if (error) goto error; - table = rcu_dereference(dp->table); + table = get_table_protected(dp); } /* Allocate flow. */ @@ -843,7 +855,7 @@ static int do_put_flow(struct datapath *dp, struct odp_flow_put *uf, rcu_assign_pointer(flow->sf_acts, acts); /* Put flow in bucket. */ - error = tbl_insert(table, &flow->tbl_node, flow_hash(&flow->key)); + error = tbl_insert(table, &flow->tbl_node, hash); if (error) goto error_free_flow_acts; @@ -864,7 +876,9 @@ static int do_put_flow(struct datapath *dp, struct odp_flow_put *uf, 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)) { @@ -913,7 +927,8 @@ static int put_flow(struct datapath *dp, struct odp_flow_put __user *ufp) 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) @@ -936,7 +951,8 @@ static int do_answer_query(struct sw_flow *flow, u32 query_flags, 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)))) @@ -945,21 +961,21 @@ static int do_answer_query(struct sw_flow *flow, u32 query_flags, 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); } static struct sw_flow *do_del_flow(struct datapath *dp, struct odp_flow_key *key) { - struct tbl *table = rcu_dereference(dp->table); + struct tbl *table = get_table_protected(dp); struct tbl_node *flow_node; int error; @@ -991,14 +1007,14 @@ static int del_flow(struct datapath *dp, struct odp_flow __user *ufp) 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; } static int do_query_flows(struct datapath *dp, const struct odp_flowvec *flowvec) { - struct tbl *table = rcu_dereference(dp->table); + struct tbl *table = get_table_protected(dp); u32 i; for (i = 0; i < flowvec->n_flows; i++) { @@ -1014,7 +1030,7 @@ static int do_query_flows(struct datapath *dp, const struct odp_flowvec *flowvec 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; } @@ -1022,6 +1038,7 @@ static int do_query_flows(struct datapath *dp, const struct odp_flowvec *flowvec } struct list_flows_cbdata { + struct datapath *dp; struct odp_flow __user *uflows; u32 n_flows; u32 listed_flows; @@ -1036,7 +1053,7 @@ static int list_flow(struct tbl_node *node, void *cbdata_) 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; @@ -1053,11 +1070,12 @@ static int do_list_flows(struct datapath *dp, const struct odp_flowvec *flowvec) 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; - error = tbl_foreach(rcu_dereference(dp->table), list_flow, &cbdata); + error = tbl_foreach(get_table_protected(dp), list_flow, &cbdata); return error ? error : cbdata.listed_flows; } @@ -1163,7 +1181,7 @@ static int execute_packet(struct datapath *dp, const struct odp_execute __user * static int get_dp_stats(struct datapath *dp, struct odp_stats __user *statsp) { - struct tbl *table = rcu_dereference(dp->table); + struct tbl *table = get_table_protected(dp); struct odp_stats stats; int i; @@ -1551,7 +1569,8 @@ static int compat_put_flow(struct datapath *dp, struct compat_odp_flow_put __use 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; @@ -1559,7 +1578,7 @@ static int compat_answer_query(struct sw_flow *flow, u32 query_flags, 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); } @@ -1576,7 +1595,7 @@ static int compat_del_flow(struct datapath *dp, struct compat_odp_flow __user *u 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; } @@ -1585,7 +1604,7 @@ static int compat_query_flows(struct datapath *dp, struct compat_odp_flow __user *flows, u32 n_flows) { - struct tbl *table = rcu_dereference(dp->table); + struct tbl *table = get_table_protected(dp); u32 i; for (i = 0; i < n_flows; i++) { @@ -1601,7 +1620,8 @@ static int compat_query_flows(struct datapath *dp, 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; } @@ -1609,6 +1629,7 @@ static int compat_query_flows(struct datapath *dp, } struct compat_list_flows_cbdata { + struct datapath *dp; struct compat_odp_flow __user *uflows; u32 n_flows; u32 listed_flows; @@ -1623,7 +1644,7 @@ static int compat_list_flow(struct tbl_node *node, void *cbdata_) 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; @@ -1641,11 +1662,12 @@ static int compat_list_flows(struct datapath *dp, if (!n_flows) return 0; + cbdata.dp = dp; cbdata.uflows = flows; cbdata.n_flows = n_flows; cbdata.listed_flows = 0; - error = tbl_foreach(rcu_dereference(dp->table), compat_list_flow, &cbdata); + error = tbl_foreach(get_table_protected(dp), compat_list_flow, &cbdata); return error ? error : cbdata.listed_flows; } @@ -1918,6 +1940,8 @@ success: u16 csum_start, csum_offset; get_skb_csum_pointers(skb, &csum_start, &csum_offset); + csum_start -= skb_headroom(skb); + BUG_ON(csum_start >= skb_headlen(skb)); retval = skb_copy_and_csum_datagram(skb, csum_start, buf + csum_start, copy_bytes - csum_start, &csum);