Debian: Update change log for 1.1.0~pre2.g2.ea763e0e-1 upload
[openvswitch] / datapath / datapath.c
index 0205fd267070760e91b67266486ba2c844801cb8..4117ba9d8c7d7ea9ad8d3266f7644f034809b915 100644 (file)
@@ -96,7 +96,14 @@ static struct datapath *get_dp_locked(int dp_idx)
 
 static struct tbl *get_table_protected(struct datapath *dp)
 {
-       return rcu_dereference_protected(dp->table, lockdep_is_held(&dp->mutex));
+       return rcu_dereference_protected(dp->table,
+                                        lockdep_is_held(&dp->mutex));
+}
+
+static struct vport *get_vport_protected(struct datapath *dp, u16 port_no)
+{
+       return rcu_dereference_protected(dp->ports[port_no],
+                                        lockdep_is_held(&dp->mutex));
 }
 
 /* Must be called with rcu_read_lock or RTNL lock. */
@@ -120,7 +127,7 @@ static int dp_fill_ifinfo(struct sk_buff *skb,
                          const struct vport *port,
                          int event, unsigned int flags)
 {
-       const struct datapath *dp = port->dp;
+       struct datapath *dp = port->dp;
        int ifindex = vport_get_ifindex(port);
        int iflink = vport_get_iflink(port);
        struct ifinfomsg *hdr;
@@ -146,7 +153,7 @@ static int dp_fill_ifinfo(struct sk_buff *skb,
 
        NLA_PUT_STRING(skb, IFLA_IFNAME, vport_get_name(port));
        NLA_PUT_U32(skb, IFLA_MASTER,
-               vport_get_ifindex(rtnl_dereference(dp->ports[ODPP_LOCAL])));
+               vport_get_ifindex(get_vport_protected(dp, ODPP_LOCAL)));
        NLA_PUT_U32(skb, IFLA_MTU, vport_get_mtu(port));
 #ifdef IFLA_OPERSTATE
        NLA_PUT_U8(skb, IFLA_OPERSTATE,
@@ -240,6 +247,7 @@ static int create_dp(int dp_idx, const char __user *devnamep)
                goto err_put_module;
        INIT_LIST_HEAD(&dp->port_list);
        mutex_init(&dp->mutex);
+       mutex_lock(&dp->mutex);
        dp->dp_idx = dp_idx;
        for (i = 0; i < DP_N_QUEUES; i++)
                skb_queue_head_init(&dp->queues[i]);
@@ -252,7 +260,7 @@ static int create_dp(int dp_idx, const char __user *devnamep)
 
        /* Allocate table. */
        err = -ENOMEM;
-       rcu_assign_pointer(dp->table, tbl_create(0));
+       rcu_assign_pointer(dp->table, tbl_create(TBL_MIN_BUCKETS));
        if (!dp->table)
                goto err_free_dp;
 
@@ -270,22 +278,26 @@ 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);
 
+       mutex_unlock(&dp->mutex);
        mutex_unlock(&dp_mutex);
        rtnl_unlock();
 
        return 0;
 
 err_destroy_local_port:
-       dp_detach_port(dp->ports[ODPP_LOCAL]);
+       dp_detach_port(get_vport_protected(dp, ODPP_LOCAL));
 err_destroy_table:
-       tbl_destroy(dp->table, NULL);
+       tbl_destroy(get_table_protected(dp), NULL);
 err_free_dp:
+       mutex_unlock(&dp->mutex);
        kfree(dp);
 err_put_module:
        module_put(THIS_MODULE);
@@ -296,52 +308,54 @@ err:
        return err;
 }
 
-static void do_destroy_dp(struct datapath *dp)
+static void destroy_dp_rcu(struct rcu_head *rcu)
 {
-       struct vport *p, *n;
+       struct datapath *dp = container_of(rcu, struct datapath, rcu);
        int i;
 
-       list_for_each_entry_safe (p, n, &dp->port_list, node)
-               if (p->port_no != ODPP_LOCAL)
-                       dp_detach_port(p);
-
-       dp_sysfs_del_dp(dp);
-
-       rcu_assign_pointer(dps[dp->dp_idx], NULL);
-
-       dp_detach_port(dp->ports[ODPP_LOCAL]);
-
-       tbl_destroy(dp->table, flow_free_tbl);
-
        for (i = 0; i < DP_N_QUEUES; i++)
                skb_queue_purge(&dp->queues[i]);
+
+       tbl_destroy((struct tbl __force *)dp->table, flow_free_tbl);
        free_percpu(dp->stats_percpu);
        kobject_put(&dp->ifobj);
-       module_put(THIS_MODULE);
 }
 
 static int destroy_dp(int dp_idx)
 {
        struct datapath *dp;
-       int err;
+       int err = 0;
+       struct vport *p, *n;
 
        rtnl_lock();
        mutex_lock(&dp_mutex);
        dp = get_dp(dp_idx);
-       err = -ENODEV;
-       if (!dp)
-               goto err_unlock;
+       if (!dp) {
+               err = -ENODEV;
+               goto out;
+       }
 
-       do_destroy_dp(dp);
-       err = 0;
+       mutex_lock(&dp->mutex);
 
-err_unlock:
+       list_for_each_entry_safe (p, n, &dp->port_list, node)
+               if (p->port_no != ODPP_LOCAL)
+                       dp_detach_port(p);
+
+       dp_sysfs_del_dp(dp);
+       rcu_assign_pointer(dps[dp->dp_idx], NULL);
+       dp_detach_port(get_vport_protected(dp, ODPP_LOCAL));
+
+       mutex_unlock(&dp->mutex);
+       call_rcu(&dp->rcu, destroy_dp_rcu);
+       module_put(THIS_MODULE);
+
+out:
        mutex_unlock(&dp_mutex);
        rtnl_unlock();
        return err;
 }
 
-/* Called with RTNL lock and dp_mutex. */
+/* Called with RTNL lock and dp->mutex. */
 static int new_vport(struct datapath *dp, struct odp_port *odp_port, int port_no)
 {
        struct vport_parms parms;
@@ -400,7 +414,7 @@ got_port_no:
                goto out_unlock_dp;
 
        set_internal_devs_mtu(dp);
-       dp_sysfs_add_if(dp->ports[port_no]);
+       dp_sysfs_add_if(get_vport_protected(dp, port_no));
 
        err = put_user(port_no, &portp->port);
 
@@ -451,7 +465,7 @@ static int detach_port(int dp_idx, int port_no)
        if (!dp)
                goto out_unlock_rtnl;
 
-       p = dp->ports[port_no];
+       p = get_vport_protected(dp, port_no);
        err = -ENOENT;
        if (!p)
                goto out_unlock_dp;
@@ -651,7 +665,7 @@ static int flush_flows(struct datapath *dp)
        struct tbl *old_table = get_table_protected(dp);
        struct tbl *new_table;
 
-       new_table = tbl_create(0);
+       new_table = tbl_create(TBL_MIN_BUCKETS);
        if (!new_table)
                return -ENOMEM;
 
@@ -746,7 +760,7 @@ static struct sw_flow_actions *get_actions(const struct odp_flow *flow)
 
        error = -EFAULT;
        if (copy_from_user(actions->actions,
-                          (struct nlattr __user *)flow->actions,
+                          (struct nlattr __user __force *)flow->actions,
                           flow->actions_len))
                goto error_free_actions;
        error = validate_actions(actions->actions, actions->actions_len);
@@ -814,14 +828,15 @@ static int do_put_flow(struct datapath *dp, struct odp_flow_put *uf,
        struct tbl_node *flow_node;
        struct sw_flow *flow;
        struct tbl *table;
+       struct sw_flow_actions *acts = NULL;
        int error;
+       u32 hash;
 
+       hash = flow_hash(&uf->flow.key);
        table = get_table_protected(dp);
-       flow_node = tbl_lookup(table, &uf->flow.key, flow_hash(&uf->flow.key), flow_cmp);
+       flow_node = tbl_lookup(table, &uf->flow.key, hash, flow_cmp);
        if (!flow_node) {
                /* No such flow. */
-               struct sw_flow_actions *acts;
-
                error = -ENOENT;
                if (!(uf->flags & ODPPF_CREATE))
                        goto error;
@@ -851,7 +866,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;
 
@@ -895,7 +910,7 @@ static int do_put_flow(struct datapath *dp, struct odp_flow_put *uf,
        return 0;
 
 error_free_flow_acts:
-       kfree(flow->sf_acts);
+       kfree(acts);
 error_free_flow:
        flow->sf_acts = NULL;
        flow_put(flow);
@@ -1014,7 +1029,7 @@ static int do_query_flows(struct datapath *dp, const struct odp_flowvec *flowvec
        u32 i;
 
        for (i = 0; i < flowvec->n_flows; i++) {
-               struct odp_flow __user *ufp = (struct odp_flow __user *)&flowvec->flows[i];
+               struct odp_flow __user *ufp = (struct odp_flow __user __force *)&flowvec->flows[i];
                struct odp_flow uf;
                struct tbl_node *flow_node;
                int error;
@@ -1067,7 +1082,7 @@ static int do_list_flows(struct datapath *dp, const struct odp_flowvec *flowvec)
                return 0;
 
        cbdata.dp = dp;
-       cbdata.uflows = (struct odp_flow __user *)flowvec->flows;
+       cbdata.uflows = (struct odp_flow __user __force*)flowvec->flows;
        cbdata.n_flows = flowvec->n_flows;
        cbdata.listed_flows = 0;
 
@@ -1117,7 +1132,7 @@ static int do_execute(struct datapath *dp, const struct odp_execute *execute)
 
        err = -EFAULT;
        if (copy_from_user(actions->actions,
-           (struct nlattr __user *)execute->actions, execute->actions_len))
+           (struct nlattr __user __force *)execute->actions, execute->actions_len))
                goto error_free_actions;
 
        err = validate_actions(actions->actions, execute->actions_len);
@@ -1131,7 +1146,7 @@ static int do_execute(struct datapath *dp, const struct odp_execute *execute)
 
        err = -EFAULT;
        if (copy_from_user(skb_put(skb, execute->length),
-                          (const void __user *)execute->data,
+                          (const void __user __force *)execute->data,
                           execute->length))
                goto error_free_skb;
 
@@ -1259,6 +1274,7 @@ static int put_port(const struct vport *p, struct odp_port __user *uop)
        rcu_read_lock();
        strncpy(op.devname, vport_get_name(p), sizeof op.devname);
        strncpy(op.type, vport_get_type(p), sizeof op.type);
+       vport_get_config(p, op.config);
        rcu_read_unlock();
 
        op.port = p->port_no;
@@ -1269,45 +1285,32 @@ static int put_port(const struct vport *p, struct odp_port __user *uop)
 static int query_port(struct datapath *dp, struct odp_port __user *uport)
 {
        struct odp_port port;
+       struct vport *vport;
 
        if (copy_from_user(&port, uport, sizeof port))
                return -EFAULT;
 
        if (port.devname[0]) {
-               struct vport *vport;
-               int err = 0;
-
                port.devname[IFNAMSIZ - 1] = '\0';
 
                vport_lock();
-               rcu_read_lock();
-
                vport = vport_locate(port.devname);
-               if (!vport) {
-                       err = -ENODEV;
-                       goto error_unlock;
-               }
-               if (vport->dp != dp) {
-                       err = -ENOENT;
-                       goto error_unlock;
-               }
-
-               port.port = vport->port_no;
-
-error_unlock:
-               rcu_read_unlock();
                vport_unlock();
 
-               if (err)
-                       return err;
+               if (!vport)
+                       return -ENODEV;
+               if (vport->dp != dp)
+                       return -ENOENT;
        } else {
                if (port.port >= DP_MAX_PORTS)
                        return -EINVAL;
-               if (!dp->ports[port.port])
+
+               vport = get_vport_protected(dp, port.port);
+               if (!vport)
                        return -ENOENT;
        }
 
-       return put_port(dp->ports[port.port], uport);
+       return put_port(vport, uport);
 }
 
 static int do_list_ports(struct datapath *dp, struct odp_port __user *uports,
@@ -1335,7 +1338,7 @@ static int list_ports(struct datapath *dp, struct odp_portvec __user *upv)
        if (copy_from_user(&pv, upv, sizeof pv))
                return -EFAULT;
 
-       retval = do_list_ports(dp, (struct odp_port __user *)pv.ports,
+       retval = do_list_ports(dp, (struct odp_port __user __force *)pv.ports,
                               pv.n_ports);
        if (retval < 0)
                return retval;
@@ -1936,6 +1939,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);
@@ -1991,6 +1996,7 @@ static unsigned int openvswitch_poll(struct file *file, poll_table *wait)
 }
 
 static struct file_operations openvswitch_fops = {
+       .owner = THIS_MODULE,
        .read  = openvswitch_read,
        .poll  = openvswitch_poll,
        .unlocked_ioctl = openvswitch_ioctl,