diff options
author | Mahesh Bandewar <maheshb@google.com> | 2016-04-27 17:59:27 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2016-04-28 17:23:08 -0400 |
commit | 494e8489db50157637d146ee377991ed6f0018f1 (patch) | |
tree | b4caedab38388527503bb7d2ddeb857774411b81 /drivers/net/ipvlan/ipvlan_main.c | |
parent | 222e4d0b13c674b28a562d67c270367d45d0a53d (diff) |
ipvlan: Fix failure path in dev registration during link creation
When newlink creation fails at device-registration, the port->count
is decremented twice. Francesco Ruggeri (fruggeri@arista.com) found
this issue in Macvlan and the same exists in IPvlan driver too.
While fixing this issue I noticed another issue of missing unregister
in case of failure, so adding it to the fix which is similar to the
macvlan fix by Francesco in commit 308379607548 ("macvlan: fix failure
during registration v3")
Reported-by: Francesco Ruggeri <fruggeri@arista.com>
Signed-off-by: Mahesh Bandewar <maheshb@google.com>
CC: Eric Dumazet <edumazet@google.com>
CC: Eric W. Biederman <ebiederm@xmission.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/ipvlan/ipvlan_main.c')
-rw-r--r-- | drivers/net/ipvlan/ipvlan_main.c | 19 |
1 files changed, 8 insertions, 11 deletions
diff --git a/drivers/net/ipvlan/ipvlan_main.c b/drivers/net/ipvlan/ipvlan_main.c index 57941d3f4227..1c4d395fbd49 100644 --- a/drivers/net/ipvlan/ipvlan_main.c +++ b/drivers/net/ipvlan/ipvlan_main.c | |||
@@ -113,6 +113,7 @@ static int ipvlan_init(struct net_device *dev) | |||
113 | { | 113 | { |
114 | struct ipvl_dev *ipvlan = netdev_priv(dev); | 114 | struct ipvl_dev *ipvlan = netdev_priv(dev); |
115 | const struct net_device *phy_dev = ipvlan->phy_dev; | 115 | const struct net_device *phy_dev = ipvlan->phy_dev; |
116 | struct ipvl_port *port = ipvlan->port; | ||
116 | 117 | ||
117 | dev->state = (dev->state & ~IPVLAN_STATE_MASK) | | 118 | dev->state = (dev->state & ~IPVLAN_STATE_MASK) | |
118 | (phy_dev->state & IPVLAN_STATE_MASK); | 119 | (phy_dev->state & IPVLAN_STATE_MASK); |
@@ -128,6 +129,8 @@ static int ipvlan_init(struct net_device *dev) | |||
128 | if (!ipvlan->pcpu_stats) | 129 | if (!ipvlan->pcpu_stats) |
129 | return -ENOMEM; | 130 | return -ENOMEM; |
130 | 131 | ||
132 | port->count += 1; | ||
133 | |||
131 | return 0; | 134 | return 0; |
132 | } | 135 | } |
133 | 136 | ||
@@ -481,27 +484,21 @@ static int ipvlan_link_new(struct net *src_net, struct net_device *dev, | |||
481 | 484 | ||
482 | dev->priv_flags |= IFF_IPVLAN_SLAVE; | 485 | dev->priv_flags |= IFF_IPVLAN_SLAVE; |
483 | 486 | ||
484 | port->count += 1; | ||
485 | err = register_netdevice(dev); | 487 | err = register_netdevice(dev); |
486 | if (err < 0) | 488 | if (err < 0) |
487 | goto ipvlan_destroy_port; | 489 | return err; |
488 | 490 | ||
489 | err = netdev_upper_dev_link(phy_dev, dev); | 491 | err = netdev_upper_dev_link(phy_dev, dev); |
490 | if (err) | 492 | if (err) { |
491 | goto ipvlan_destroy_port; | 493 | unregister_netdevice(dev); |
494 | return err; | ||
495 | } | ||
492 | 496 | ||
493 | list_add_tail_rcu(&ipvlan->pnode, &port->ipvlans); | 497 | list_add_tail_rcu(&ipvlan->pnode, &port->ipvlans); |
494 | ipvlan_set_port_mode(port, mode); | 498 | ipvlan_set_port_mode(port, mode); |
495 | 499 | ||
496 | netif_stacked_transfer_operstate(phy_dev, dev); | 500 | netif_stacked_transfer_operstate(phy_dev, dev); |
497 | return 0; | 501 | return 0; |
498 | |||
499 | ipvlan_destroy_port: | ||
500 | port->count -= 1; | ||
501 | if (!port->count) | ||
502 | ipvlan_port_destroy(phy_dev); | ||
503 | |||
504 | return err; | ||
505 | } | 502 | } |
506 | 503 | ||
507 | static void ipvlan_link_delete(struct net_device *dev, struct list_head *head) | 504 | static void ipvlan_link_delete(struct net_device *dev, struct list_head *head) |