datapath: Allocate vports in more RCU friendly manner.
authorJesse Gross <jesse@nicira.com>
Fri, 24 Dec 2010 00:36:26 +0000 (16:36 -0800)
committerJesse Gross <jesse@nicira.com>
Wed, 29 Dec 2010 18:42:47 +0000 (10:42 -0800)
In a few places, when creating a new vport we also need to allocate
some memory for configuration that can change.  This data is protected
by RCU but we directly access the memory when initializing it.  This
is fine, since the vport has not yet been published and we use the
apropriate memory barriers when doing so.  However, it makes tools
like sparse unhappy and is also asymmetric since we use RCU to
dereference the pointers but not to assign them.  This cleans that
up somewhat by initializing the memory first and then using RCU
to assign it, which makes everyone happy.

Found with sparse.

Signed-off-by: Jesse Gross <jesse@nicira.com>
Acked-by: Ben Pfaff <blp@nicira.com>
datapath/tunnel.c
datapath/vport-patch.c

index d49d928cc42db5318622a6a361836cfafd00cc41..e42e0e361fbf562a36ac0149dfc037cd8dccfe7e 100644 (file)
@@ -1372,6 +1372,7 @@ struct vport *tnl_create(const struct vport_parms *parms,
 {
        struct vport *vport;
        struct tnl_vport *tnl_vport;
+       struct tnl_mutable_config *mutable;
        int initial_frag_id;
        int err;
 
@@ -1386,19 +1387,19 @@ struct vport *tnl_create(const struct vport_parms *parms,
        strcpy(tnl_vport->name, parms->name);
        tnl_vport->tnl_ops = tnl_ops;
 
-       tnl_vport->mutable = kzalloc(sizeof(struct tnl_mutable_config), GFP_KERNEL);
-       if (!tnl_vport->mutable) {
+       mutable = kzalloc(sizeof(struct tnl_mutable_config), GFP_KERNEL);
+       if (!mutable) {
                err = -ENOMEM;
                goto error_free_vport;
        }
 
-       vport_gen_rand_ether_addr(tnl_vport->mutable->eth_addr);
-       tnl_vport->mutable->mtu = ETH_DATA_LEN;
+       vport_gen_rand_ether_addr(mutable->eth_addr);
+       mutable->mtu = ETH_DATA_LEN;
 
        get_random_bytes(&initial_frag_id, sizeof(int));
        atomic_set(&tnl_vport->frag_id, initial_frag_id);
 
-       err = set_config(parms->config, tnl_ops, NULL, tnl_vport->mutable);
+       err = set_config(parms->config, tnl_ops, NULL, mutable);
        if (err)
                goto error_free_mutable;
 
@@ -1406,9 +1407,11 @@ struct vport *tnl_create(const struct vport_parms *parms,
 
 #ifdef NEED_CACHE_TIMEOUT
        tnl_vport->cache_exp_interval = MAX_CACHE_EXP -
-                                       (net_random() % (MAX_CACHE_EXP / 2));
+                                      (net_random() % (MAX_CACHE_EXP / 2));
 #endif
 
+       rcu_assign_pointer(tnl_vport->mutable, mutable);
+
        err = add_port(vport);
        if (err)
                goto error_free_mutable;
@@ -1416,7 +1419,7 @@ struct vport *tnl_create(const struct vport_parms *parms,
        return vport;
 
 error_free_mutable:
-       kfree(tnl_vport->mutable);
+       kfree(mutable);
 error_free_vport:
        vport_free(vport);
 error:
index 67b68a367757ed8758b21ffb24c25d3acf7503a7..8a3b46552fd302f438fef4e5ac47204549d9fe29 100644 (file)
@@ -106,6 +106,7 @@ static struct vport *patch_create(const struct vport_parms *parms)
        struct vport *vport;
        struct patch_vport *patch_vport;
        const char *peer_name;
+       struct device_config *devconf;
        int err;
 
        vport = vport_alloc(sizeof(struct patch_vport), &patch_vport_ops, parms);
@@ -118,32 +119,33 @@ static struct vport *patch_create(const struct vport_parms *parms)
 
        strcpy(patch_vport->name, parms->name);
 
-       patch_vport->devconf = kmalloc(sizeof(struct device_config), GFP_KERNEL);
-       if (!patch_vport->devconf) {
+       devconf = kmalloc(sizeof(struct device_config), GFP_KERNEL);
+       if (!devconf) {
                err = -ENOMEM;
                goto error_free_vport;
        }
 
-       err = set_config(vport, parms->config, patch_vport->devconf);
+       err = set_config(vport, parms->config, devconf);
        if (err)
                goto error_free_devconf;
 
-       vport_gen_rand_ether_addr(patch_vport->devconf->eth_addr);
+       vport_gen_rand_ether_addr(devconf->eth_addr);
 
        /* Make the default MTU fairly large so that it doesn't become the
         * bottleneck on systems using jumbo frames. */
-       patch_vport->devconf->mtu = 65535;
+       devconf->mtu = 65535;
 
-       peer_name = patch_vport->devconf->peer_name;
-       hlist_add_head(&patch_vport->hash_node, hash_bucket(peer_name));
+       rcu_assign_pointer(patch_vport->devconf, devconf);
 
+       peer_name = devconf->peer_name;
+       hlist_add_head(&patch_vport->hash_node, hash_bucket(peer_name));
        rcu_assign_pointer(patch_vport->peer, vport_locate(peer_name));
        update_peers(patch_vport->name, vport);
 
        return vport;
 
 error_free_devconf:
-       kfree(patch_vport->devconf);
+       kfree(devconf);
 error_free_vport:
        vport_free(vport);
 error: