net: use batched device unregister in veth and macvlan
veth devices dont use the batched device unregisters yet. Since veth are a pair of devices, it makes sense to use a batch of two unregisters, this roughly divides dismantle time by two. Fix this by changing dellink() callers to always provide a non NULL head. (Idea from Michał Mirosław) This patch also handles macvlan case : We now dismantle all macvlans on top of a lower dev at once. Reported-by: Alex Bligh <alex@alex.org.uk> Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com> Cc: Michał Mirosław <mirqus@gmail.com> Cc: Jesse Gross <jesse@nicira.com> Cc: Paul E. McKenney <paulmck@linux.vnet.ibm.com> Cc: Ben Greear <greearb@candelatech.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
		
					parent
					
						
							
								7ef73bca73
							
						
					
				
			
			
				commit
				
					
						226bd34114
					
				
			
		
					 2 changed files with 8 additions and 2 deletions
				
			
		| 
						 | 
					@ -785,6 +785,7 @@ static int macvlan_device_event(struct notifier_block *unused,
 | 
				
			||||||
	struct net_device *dev = ptr;
 | 
						struct net_device *dev = ptr;
 | 
				
			||||||
	struct macvlan_dev *vlan, *next;
 | 
						struct macvlan_dev *vlan, *next;
 | 
				
			||||||
	struct macvlan_port *port;
 | 
						struct macvlan_port *port;
 | 
				
			||||||
 | 
						LIST_HEAD(list_kill);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!macvlan_port_exists(dev))
 | 
						if (!macvlan_port_exists(dev))
 | 
				
			||||||
		return NOTIFY_DONE;
 | 
							return NOTIFY_DONE;
 | 
				
			||||||
| 
						 | 
					@ -810,7 +811,9 @@ static int macvlan_device_event(struct notifier_block *unused,
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		list_for_each_entry_safe(vlan, next, &port->vlans, list)
 | 
							list_for_each_entry_safe(vlan, next, &port->vlans, list)
 | 
				
			||||||
			vlan->dev->rtnl_link_ops->dellink(vlan->dev, NULL);
 | 
								vlan->dev->rtnl_link_ops->dellink(vlan->dev, &list_kill);
 | 
				
			||||||
 | 
							unregister_netdevice_many(&list_kill);
 | 
				
			||||||
 | 
							list_del(&list_kill);
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
	case NETDEV_PRE_TYPE_CHANGE:
 | 
						case NETDEV_PRE_TYPE_CHANGE:
 | 
				
			||||||
		/* Forbid underlaying device to change its type. */
 | 
							/* Forbid underlaying device to change its type. */
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1501,6 +1501,7 @@ static int rtnl_dellink(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
 | 
				
			||||||
	char ifname[IFNAMSIZ];
 | 
						char ifname[IFNAMSIZ];
 | 
				
			||||||
	struct nlattr *tb[IFLA_MAX+1];
 | 
						struct nlattr *tb[IFLA_MAX+1];
 | 
				
			||||||
	int err;
 | 
						int err;
 | 
				
			||||||
 | 
						LIST_HEAD(list_kill);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFLA_MAX, ifla_policy);
 | 
						err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFLA_MAX, ifla_policy);
 | 
				
			||||||
	if (err < 0)
 | 
						if (err < 0)
 | 
				
			||||||
| 
						 | 
					@ -1524,7 +1525,9 @@ static int rtnl_dellink(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
 | 
				
			||||||
	if (!ops)
 | 
						if (!ops)
 | 
				
			||||||
		return -EOPNOTSUPP;
 | 
							return -EOPNOTSUPP;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ops->dellink(dev, NULL);
 | 
						ops->dellink(dev, &list_kill);
 | 
				
			||||||
 | 
						unregister_netdevice_many(&list_kill);
 | 
				
			||||||
 | 
						list_del(&list_kill);
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue