diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c index 4b77819e9328..069e8824c264 100644 --- a/drivers/net/macvlan.c +++ b/drivers/net/macvlan.c @@ -889,7 +889,7 @@ static void macvlan_set_lockdep_class(struct net_device *dev) static int macvlan_init(struct net_device *dev) { struct macvlan_dev *vlan = netdev_priv(dev); - const struct net_device *lowerdev = vlan->lowerdev; + struct net_device *lowerdev = vlan->lowerdev; struct macvlan_port *port = vlan->port; dev->state = (dev->state & ~MACVLAN_STATE_MASK) | @@ -911,6 +911,9 @@ static int macvlan_init(struct net_device *dev) port->count += 1; + /* Get macvlan's reference to lowerdev */ + dev_hold_track(lowerdev, &vlan->dev_tracker, GFP_KERNEL); + return 0; } @@ -1173,6 +1176,14 @@ static const struct net_device_ops macvlan_netdev_ops = { .ndo_features_check = passthru_features_check, }; +static void macvlan_dev_free(struct net_device *dev) +{ + struct macvlan_dev *vlan = netdev_priv(dev); + + /* Get rid of the macvlan's reference to lowerdev */ + dev_put_track(vlan->lowerdev, &vlan->dev_tracker); +} + void macvlan_common_setup(struct net_device *dev) { ether_setup(dev); @@ -1184,6 +1195,7 @@ void macvlan_common_setup(struct net_device *dev) dev->priv_flags |= IFF_UNICAST_FLT | IFF_CHANGE_PROTO_DOWN; dev->netdev_ops = &macvlan_netdev_ops; dev->needs_free_netdev = true; + dev->priv_destructor = macvlan_dev_free; dev->header_ops = &macvlan_hard_header_ops; dev->ethtool_ops = &macvlan_ethtool_ops; } diff --git a/include/linux/if_macvlan.h b/include/linux/if_macvlan.h index 10c94a3936ca..b42294739063 100644 --- a/include/linux/if_macvlan.h +++ b/include/linux/if_macvlan.h @@ -21,6 +21,7 @@ struct macvlan_dev { struct hlist_node hlist; struct macvlan_port *port; struct net_device *lowerdev; + netdevice_tracker dev_tracker; void *accel_priv; struct vlan_pcpu_stats __percpu *pcpu_stats;