On 20/04/2016 07:21, "Ilya Maximets" <i.maxim...@samsung.com> wrote:
>On 20.04.2016 01:28, diproiettod at vmware.com (Daniele Di Proietto) >wrote: >> netdev objects are hard to use with RCU, because it's not possible to >> split removal and reclamation. Postponing the removal means that the >> port is not removed and cannot be readded immediately. Waiting for >> reclamation means introducing a quiescent state, and that may introduce >> subtle bugs, due to the RCU model we use in userspace. >> >> This commit changes the port container from cmap to hmap. 'port_mutex' >> must be held by readers and writers. This shouldn't have performace >> impact, as readers in the fast path use a thread local cache. >> >> Signed-off-by: Daniele Di Proietto <diproiettod at vmware.com> >> --- >> lib/dpif-netdev.c | 96 >>+++++++++++++++++++++++++++++++++---------------------- >> 1 file changed, 57 insertions(+), 39 deletions(-) >> >> diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c >> index bd2249e..8cc37e2 100644 >> --- a/lib/dpif-netdev.c >> +++ b/lib/dpif-netdev.c >> @@ -195,9 +195,10 @@ struct dp_netdev { >> >> /* Ports. >> * >> - * Protected by RCU. Take the mutex to add or remove ports. */ >> + * Any lookup into 'ports' or any access to the dp_netdev_ports >>found >> + * through 'ports' requires taking 'port_mutex'. */ >> struct ovs_mutex port_mutex; >> - struct cmap ports; >> + struct hmap ports; >> struct seq *port_seq; /* Incremented whenever a port >>changes. */ >> >> /* Protects access to ofproto-dpif-upcall interface during >>revalidator >> @@ -228,7 +229,8 @@ struct dp_netdev { >> }; >> >> static struct dp_netdev_port *dp_netdev_lookup_port(const struct >>dp_netdev *dp, >> - odp_port_t); >> + odp_port_t) >> + OVS_REQUIRES(&dp->port_mutex); > >OVS_REQUIRES(dp->port_mutex); >here and 2 times more below. I've changed them, thanks. I think the analyzer accepts both (a pointer or the object itself), but I prefer the syntax you suggested. > >> >> enum dp_stat_type { >> DP_STAT_EXACT_HIT, /* Packets that had an exact match >>(emc). */ >> @@ -248,7 +250,7 @@ enum pmd_cycles_counter_type { >> struct dp_netdev_port { >> odp_port_t port_no; >> struct netdev *netdev; >> - struct cmap_node node; /* Node in dp_netdev's 'ports'. */ >> + struct hmap_node node; /* Node in dp_netdev's 'ports'. */ >> struct netdev_saved_flags *sf; >> unsigned n_rxq; /* Number of elements in 'rxq' */ >> struct netdev_rxq **rxq; >> @@ -476,9 +478,11 @@ struct dpif_netdev { >> }; >> >> static int get_port_by_number(struct dp_netdev *dp, odp_port_t port_no, >> - struct dp_netdev_port **portp); >> + struct dp_netdev_port **portp) >> + OVS_REQUIRES(dp->port_mutex); >> static int get_port_by_name(struct dp_netdev *dp, const char *devname, >> - struct dp_netdev_port **portp); >> + struct dp_netdev_port **portp) >> + OVS_REQUIRES(dp->port_mutex); >> static void dp_netdev_free(struct dp_netdev *) >> OVS_REQUIRES(dp_netdev_mutex); >> static int do_add_port(struct dp_netdev *dp, const char *devname, >> @@ -522,7 +526,8 @@ dp_netdev_add_rxq_to_pmd(struct >>dp_netdev_pmd_thread *pmd, >> struct dp_netdev_port *port, struct >>netdev_rxq *rx); >> static struct dp_netdev_pmd_thread * >> dp_netdev_less_loaded_pmd_on_numa(struct dp_netdev *dp, int numa_id); >> -static void dp_netdev_reset_pmd_threads(struct dp_netdev *dp); >> +static void dp_netdev_reset_pmd_threads(struct dp_netdev *dp) >> + OVS_REQUIRES(dp->port_mutex); >> static bool dp_netdev_pmd_try_ref(struct dp_netdev_pmd_thread *pmd); >> static void dp_netdev_pmd_unref(struct dp_netdev_pmd_thread *pmd); >> static void dp_netdev_pmd_flow_flush(struct dp_netdev_pmd_thread *pmd); >> @@ -913,7 +918,7 @@ create_dp_netdev(const char *name, const struct >>dpif_class *class, >> atomic_flag_clear(&dp->destroyed); >> >> ovs_mutex_init(&dp->port_mutex); >> - cmap_init(&dp->ports); >> + hmap_init(&dp->ports); >> dp->port_seq = seq_create(); >> fat_rwlock_init(&dp->upcall_rwlock); >> >> @@ -984,7 +989,7 @@ static void >> dp_netdev_free(struct dp_netdev *dp) >> OVS_REQUIRES(dp_netdev_mutex) >> { >> - struct dp_netdev_port *port; >> + struct dp_netdev_port *port, *next; >> >> shash_find_and_delete(&dp_netdevs, dp->name); >> >> @@ -993,15 +998,14 @@ dp_netdev_free(struct dp_netdev *dp) >> ovsthread_key_delete(dp->per_pmd_key); >> >> ovs_mutex_lock(&dp->port_mutex); >> - CMAP_FOR_EACH (port, node, &dp->ports) { >> - /* PMD threads are destroyed here. do_del_port() cannot >>quiesce */ >> + HMAP_FOR_EACH_SAFE (port, next, node, &dp->ports) { >> do_del_port(dp, port); >> } >> ovs_mutex_unlock(&dp->port_mutex); >> cmap_destroy(&dp->poll_threads); >> >> seq_destroy(dp->port_seq); >> - cmap_destroy(&dp->ports); >> + hmap_destroy(&dp->ports); >> ovs_mutex_destroy(&dp->port_mutex); >> >> /* Upcalls must be disabled at this point */ >> @@ -1222,7 +1226,7 @@ do_add_port(struct dp_netdev *dp, const char >>*devname, const char *type, >> return error; >> } >> >> - cmap_insert(&dp->ports, &port->node, hash_port_no(port_no)); >> + hmap_insert(&dp->ports, &port->node, hash_port_no(port_no)); >> >> dp_netdev_add_port_to_pmds(dp, port); >> seq_change(dp->port_seq); >> @@ -1288,10 +1292,11 @@ is_valid_port_number(odp_port_t port_no) >> >> static struct dp_netdev_port * >> dp_netdev_lookup_port(const struct dp_netdev *dp, odp_port_t port_no) >> + OVS_REQUIRES(&dp->port_mutex) > >here > >> { >> struct dp_netdev_port *port; >> >> - CMAP_FOR_EACH_WITH_HASH (port, node, hash_port_no(port_no), >>&dp->ports) { >> + HMAP_FOR_EACH_WITH_HASH (port, node, hash_port_no(port_no), >>&dp->ports) { >> if (port->port_no == port_no) { >> return port; >> } >> @@ -1302,6 +1307,7 @@ dp_netdev_lookup_port(const struct dp_netdev *dp, >>odp_port_t port_no) >> static int >> get_port_by_number(struct dp_netdev *dp, >> odp_port_t port_no, struct dp_netdev_port **portp) >> + OVS_REQUIRES(&dp->port_mutex) > >and here. > >> { >> if (!is_valid_port_number(port_no)) { >> *portp = NULL; >> @@ -1338,7 +1344,7 @@ get_port_by_name(struct dp_netdev *dp, >> { >> struct dp_netdev_port *port; >> >> - CMAP_FOR_EACH (port, node, &dp->ports) { >> + HMAP_FOR_EACH (port, node, &dp->ports) { >> if (!strcmp(netdev_get_name(port->netdev), devname)) { >> *portp = port; >> return 0; >> @@ -1373,10 +1379,11 @@ get_n_pmd_threads_on_numa(struct dp_netdev *dp, >>int numa_id) >> * is on numa node 'numa_id'. */ >> static bool >> has_pmd_port_for_numa(struct dp_netdev *dp, int numa_id) >> + OVS_REQUIRES(dp->port_mutex) >> { >> struct dp_netdev_port *port; >> >> - CMAP_FOR_EACH (port, node, &dp->ports) { >> + HMAP_FOR_EACH (port, node, &dp->ports) { >> if (netdev_is_pmd(port->netdev) >> && netdev_get_numa_id(port->netdev) == numa_id) { >> return true; >> @@ -1391,7 +1398,7 @@ static void >> do_del_port(struct dp_netdev *dp, struct dp_netdev_port *port) >> OVS_REQUIRES(dp->port_mutex) >> { >> - cmap_remove(&dp->ports, &port->node, hash_odp_port(port->port_no)); >> + hmap_remove(&dp->ports, &port->node); >> seq_change(dp->port_seq); >> >> dp_netdev_del_port_from_all_pmds(dp, port); >> @@ -1428,10 +1435,12 @@ dpif_netdev_port_query_by_number(const struct >>dpif *dpif, odp_port_t port_no, >> struct dp_netdev_port *port; >> int error; >> >> + ovs_mutex_lock(&dp->port_mutex); >> error = get_port_by_number(dp, port_no, &port); >> if (!error && dpif_port) { >> answer_port_query(port, dpif_port); >> } >> + ovs_mutex_unlock(&dp->port_mutex); >> >> return error; >> } >> @@ -1516,7 +1525,7 @@ dpif_netdev_flow_flush(struct dpif *dpif) >> } >> >> struct dp_netdev_port_state { >> - struct cmap_position position; >> + struct hmap_position position; >> char *name; >> }; >> >> @@ -1533,10 +1542,11 @@ dpif_netdev_port_dump_next(const struct dpif >>*dpif, void *state_, >> { >> struct dp_netdev_port_state *state = state_; >> struct dp_netdev *dp = get_dp_netdev(dpif); >> - struct cmap_node *node; >> + struct hmap_node *node; >> int retval; >> >> - node = cmap_next_position(&dp->ports, &state->position); >> + ovs_mutex_lock(&dp->port_mutex); >> + node = hmap_at_position(&dp->ports, &state->position); >> if (node) { >> struct dp_netdev_port *port; >> >> @@ -1552,6 +1562,7 @@ dpif_netdev_port_dump_next(const struct dpif >>*dpif, void *state_, >> } else { >> retval = EOF; >> } >> + ovs_mutex_unlock(&dp->port_mutex); >> >> return retval; >> } >> @@ -2407,8 +2418,8 @@ dpif_netdev_execute(struct dpif *dpif, struct >>dpif_execute *execute) >> dp_netdev_execute_actions(pmd, &pp, 1, false, execute->actions, >> execute->actions_len); >> if (pmd->core_id == NON_PMD_CORE_ID) { >> - dp_netdev_pmd_unref(pmd); >> ovs_mutex_unlock(&dp->non_pmd_mutex); >> + dp_netdev_pmd_unref(pmd); >> } >> >> return 0; >> @@ -2449,14 +2460,17 @@ pmd_config_changed(const struct dp_netdev *dp, >>const char *cmask) >> { >> struct dp_netdev_port *port; >> >> - CMAP_FOR_EACH (port, node, &dp->ports) { >> + ovs_mutex_lock(&dp->port_mutex); >> + HMAP_FOR_EACH (port, node, &dp->ports) { >> struct netdev *netdev = port->netdev; >> int requested_n_rxq = netdev_requested_n_rxq(netdev); >> if (netdev_is_pmd(netdev) >> && port->latest_requested_n_rxq != requested_n_rxq) { >> + ovs_mutex_unlock(&dp->port_mutex); >> return true; >> } >> } >> + ovs_mutex_unlock(&dp->port_mutex); >> >> if (dp->pmd_cmask != NULL && cmask != NULL) { >> return strcmp(dp->pmd_cmask, cmask); >> @@ -2476,7 +2490,8 @@ dpif_netdev_pmd_set(struct dpif *dpif, const char >>*cmask) >> >> dp_netdev_destroy_all_pmds(dp); >> >> - CMAP_FOR_EACH (port, node, &dp->ports) { >> + ovs_mutex_lock(&dp->port_mutex); >> + HMAP_FOR_EACH (port, node, &dp->ports) { >> struct netdev *netdev = port->netdev; >> int requested_n_rxq = netdev_requested_n_rxq(netdev); >> if (netdev_is_pmd(port->netdev) >> @@ -2498,6 +2513,7 @@ dpif_netdev_pmd_set(struct dpif *dpif, const char >>*cmask) >> VLOG_ERR("Failed to set dpdk interface %s rx_queue >>to:" >> " %u", netdev_get_name(port->netdev), >> requested_n_rxq); >> + ovs_mutex_unlock(&dp->port_mutex); >> return err; >> } >> port->latest_requested_n_rxq = requested_n_rxq; >> @@ -2518,6 +2534,7 @@ dpif_netdev_pmd_set(struct dpif *dpif, const char >>*cmask) >> dp_netdev_set_nonpmd(dp); >> /* Restores all pmd threads. */ >> dp_netdev_reset_pmd_threads(dp); >> + ovs_mutex_unlock(&dp->port_mutex); >> } >> >> return 0; >> @@ -2627,8 +2644,9 @@ dpif_netdev_run(struct dpif *dpif) >> >>NON_PMD_CORE_ID); >> uint64_t new_tnl_seq; >> >> + ovs_mutex_lock(&dp->port_mutex); >> ovs_mutex_lock(&dp->non_pmd_mutex); >> - CMAP_FOR_EACH (port, node, &dp->ports) { >> + HMAP_FOR_EACH (port, node, &dp->ports) { >> if (!netdev_is_pmd(port->netdev)) { >> int i; >> >> @@ -2638,6 +2656,7 @@ dpif_netdev_run(struct dpif *dpif) >> } >> } >> ovs_mutex_unlock(&dp->non_pmd_mutex); >> + ovs_mutex_unlock(&dp->port_mutex); >> dp_netdev_pmd_unref(non_pmd); >> >> tnl_neigh_cache_run(); >> @@ -2658,7 +2677,8 @@ dpif_netdev_wait(struct dpif *dpif) >> struct dp_netdev *dp = get_dp_netdev(dpif); >> >> ovs_mutex_lock(&dp_netdev_mutex); >> - CMAP_FOR_EACH (port, node, &dp->ports) { >> + ovs_mutex_lock(&dp->port_mutex); >> + HMAP_FOR_EACH (port, node, &dp->ports) { >> if (!netdev_is_pmd(port->netdev)) { >> int i; >> >> @@ -2667,6 +2687,7 @@ dpif_netdev_wait(struct dpif *dpif) >> } >> } >> } >> + ovs_mutex_unlock(&dp->port_mutex); >> ovs_mutex_unlock(&dp_netdev_mutex); >> seq_wait(tnl_conf_seq, dp->last_tnl_conf_seq); >> } >> @@ -3296,12 +3317,13 @@ dp_netdev_set_pmds_on_numa(struct dp_netdev >>*dp, int numa_id) >> * new configuration. */ >> static void >> dp_netdev_reset_pmd_threads(struct dp_netdev *dp) >> + OVS_REQUIRES(dp->port_mutex) >> { >> struct dp_netdev_port *port; >> struct hmapx to_reload = HMAPX_INITIALIZER(&to_reload); >> struct hmapx_node *node; >> >> - CMAP_FOR_EACH (port, node, &dp->ports) { >> + HMAP_FOR_EACH (port, node, &dp->ports) { >> if (netdev_is_pmd(port->netdev)) { >> dp_netdev_add_port_to_pmds__(dp, port, &to_reload); >> } >> @@ -3857,7 +3879,6 @@ dp_netdev_clone_pkt_batch(struct dp_packet >>**dst_pkts, >> static void >> dp_execute_cb(void *aux_, struct dp_packet **packets, int cnt, >> const struct nlattr *a, bool may_steal) >> - OVS_NO_THREAD_SAFETY_ANALYSIS >> { >> struct dp_netdev_execute_aux *aux = aux_; >> uint32_t *depth = recirc_depth_get(); >> @@ -4076,8 +4097,7 @@ static void >> dpif_dummy_change_port_number(struct unixctl_conn *conn, int argc >>OVS_UNUSED, >> const char *argv[], void *aux OVS_UNUSED) >> { >> - struct dp_netdev_port *old_port; >> - struct dp_netdev_port *new_port; >> + struct dp_netdev_port *port; >> struct dp_netdev *dp; >> odp_port_t port_no; >> >> @@ -4092,7 +4112,7 @@ dpif_dummy_change_port_number(struct unixctl_conn >>*conn, int argc OVS_UNUSED, >> ovs_mutex_unlock(&dp_netdev_mutex); >> >> ovs_mutex_lock(&dp->port_mutex); >> - if (get_port_by_name(dp, argv[2], &old_port)) { >> + if (get_port_by_name(dp, argv[2], &port)) { >> unixctl_command_reply_error(conn, "unknown port"); >> goto exit; >> } >> @@ -4107,16 +4127,14 @@ dpif_dummy_change_port_number(struct >>unixctl_conn *conn, int argc OVS_UNUSED, >> goto exit; >> } >> >> - /* Remove old port. */ >> - cmap_remove(&dp->ports, &old_port->node, >>hash_port_no(old_port->port_no)); >> - dp_netdev_del_port_from_all_pmds(dp, old_port); >> - ovsrcu_postpone(free, old_port); >> + /* Remove port. */ >> + hmap_remove(&dp->ports, &port->node); >> + dp_netdev_del_port_from_all_pmds(dp, port); >> >> - /* Insert new port (cmap semantics mean we cannot re-insert >>'old_port'). */ >> - new_port = xmemdup(old_port, sizeof *old_port); >> - new_port->port_no = port_no; >> - cmap_insert(&dp->ports, &new_port->node, hash_port_no(port_no)); >> - dp_netdev_add_port_to_pmds(dp, new_port); >> + /* Reinsert with new port number. */ >> + port->port_no = port_no; >> + hmap_insert(&dp->ports, &port->node, hash_port_no(port_no)); >> + dp_netdev_add_port_to_pmds(dp, port); >> >> seq_change(dp->port_seq); >> unixctl_command_reply(conn, NULL); >> _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev