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

Reply via email to