瀏覽代碼

driver: macvlan: Destroy new macvlan port if macvlan_common_newlink failed.

When there is no existing macvlan port in lowdev, one new macvlan port
would be created. But it doesn't be destoried when something failed later.
It casues some memleak.

Now add one flag to indicate if new macvlan port is created.

Signed-off-by: Gao Feng <fgao@ikuai8.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Gao Feng 9 年之前
父節點
當前提交
aa5fd0fb77
共有 1 個文件被更改,包括 22 次插入9 次删除
  1. 22 9
      drivers/net/macvlan.c

+ 22 - 9
drivers/net/macvlan.c

@@ -1278,6 +1278,7 @@ int macvlan_common_newlink(struct net *src_net, struct net_device *dev,
 	struct net_device *lowerdev;
 	struct net_device *lowerdev;
 	int err;
 	int err;
 	int macmode;
 	int macmode;
+	bool create = false;
 
 
 	if (!tb[IFLA_LINK])
 	if (!tb[IFLA_LINK])
 		return -EINVAL;
 		return -EINVAL;
@@ -1304,12 +1305,18 @@ int macvlan_common_newlink(struct net *src_net, struct net_device *dev,
 		err = macvlan_port_create(lowerdev);
 		err = macvlan_port_create(lowerdev);
 		if (err < 0)
 		if (err < 0)
 			return err;
 			return err;
+		create = true;
 	}
 	}
 	port = macvlan_port_get_rtnl(lowerdev);
 	port = macvlan_port_get_rtnl(lowerdev);
 
 
 	/* Only 1 macvlan device can be created in passthru mode */
 	/* Only 1 macvlan device can be created in passthru mode */
-	if (port->passthru)
-		return -EINVAL;
+	if (port->passthru) {
+		/* The macvlan port must be not created this time,
+		 * still goto destroy_macvlan_port for readability.
+		 */
+		err = -EINVAL;
+		goto destroy_macvlan_port;
+	}
 
 
 	vlan->lowerdev = lowerdev;
 	vlan->lowerdev = lowerdev;
 	vlan->dev      = dev;
 	vlan->dev      = dev;
@@ -1325,24 +1332,28 @@ int macvlan_common_newlink(struct net *src_net, struct net_device *dev,
 		vlan->flags = nla_get_u16(data[IFLA_MACVLAN_FLAGS]);
 		vlan->flags = nla_get_u16(data[IFLA_MACVLAN_FLAGS]);
 
 
 	if (vlan->mode == MACVLAN_MODE_PASSTHRU) {
 	if (vlan->mode == MACVLAN_MODE_PASSTHRU) {
-		if (port->count)
-			return -EINVAL;
+		if (port->count) {
+			err = -EINVAL;
+			goto destroy_macvlan_port;
+		}
 		port->passthru = true;
 		port->passthru = true;
 		eth_hw_addr_inherit(dev, lowerdev);
 		eth_hw_addr_inherit(dev, lowerdev);
 	}
 	}
 
 
 	if (data && data[IFLA_MACVLAN_MACADDR_MODE]) {
 	if (data && data[IFLA_MACVLAN_MACADDR_MODE]) {
-		if (vlan->mode != MACVLAN_MODE_SOURCE)
-			return -EINVAL;
+		if (vlan->mode != MACVLAN_MODE_SOURCE) {
+			err = -EINVAL;
+			goto destroy_macvlan_port;
+		}
 		macmode = nla_get_u32(data[IFLA_MACVLAN_MACADDR_MODE]);
 		macmode = nla_get_u32(data[IFLA_MACVLAN_MACADDR_MODE]);
 		err = macvlan_changelink_sources(vlan, macmode, data);
 		err = macvlan_changelink_sources(vlan, macmode, data);
 		if (err)
 		if (err)
-			return err;
+			goto destroy_macvlan_port;
 	}
 	}
 
 
 	err = register_netdevice(dev);
 	err = register_netdevice(dev);
 	if (err < 0)
 	if (err < 0)
-		return err;
+		goto destroy_macvlan_port;
 
 
 	dev->priv_flags |= IFF_MACVLAN;
 	dev->priv_flags |= IFF_MACVLAN;
 	err = netdev_upper_dev_link(lowerdev, dev);
 	err = netdev_upper_dev_link(lowerdev, dev);
@@ -1357,7 +1368,9 @@ int macvlan_common_newlink(struct net *src_net, struct net_device *dev,
 
 
 unregister_netdev:
 unregister_netdev:
 	unregister_netdevice(dev);
 	unregister_netdevice(dev);
-
+destroy_macvlan_port:
+	if (create)
+		macvlan_port_destroy(port->dev);
 	return err;
 	return err;
 }
 }
 EXPORT_SYMBOL_GPL(macvlan_common_newlink);
 EXPORT_SYMBOL_GPL(macvlan_common_newlink);