net: openvswitch: fix upcall counter access before allocation
[platform/kernel/linux-starfive.git] / net / openvswitch / vport.c
index 7e0f5c4..972ae01 100644 (file)
@@ -124,6 +124,7 @@ struct vport *ovs_vport_alloc(int priv_size, const struct vport_ops *ops,
 {
        struct vport *vport;
        size_t alloc_size;
+       int err;
 
        alloc_size = sizeof(struct vport);
        if (priv_size) {
@@ -135,17 +136,29 @@ struct vport *ovs_vport_alloc(int priv_size, const struct vport_ops *ops,
        if (!vport)
                return ERR_PTR(-ENOMEM);
 
+       vport->upcall_stats = netdev_alloc_pcpu_stats(struct vport_upcall_stats_percpu);
+       if (!vport->upcall_stats) {
+               err = -ENOMEM;
+               goto err_kfree_vport;
+       }
+
        vport->dp = parms->dp;
        vport->port_no = parms->port_no;
        vport->ops = ops;
        INIT_HLIST_NODE(&vport->dp_hash_node);
 
        if (ovs_vport_set_upcall_portids(vport, parms->upcall_portids)) {
-               kfree(vport);
-               return ERR_PTR(-EINVAL);
+               err = -EINVAL;
+               goto err_free_percpu;
        }
 
        return vport;
+
+err_free_percpu:
+       free_percpu(vport->upcall_stats);
+err_kfree_vport:
+       kfree(vport);
+       return ERR_PTR(err);
 }
 EXPORT_SYMBOL_GPL(ovs_vport_alloc);
 
@@ -165,6 +178,7 @@ void ovs_vport_free(struct vport *vport)
         * it is safe to use raw dereference.
         */
        kfree(rcu_dereference_raw(vport->upcall_portids));
+       free_percpu(vport->upcall_stats);
        kfree(vport);
 }
 EXPORT_SYMBOL_GPL(ovs_vport_free);