Commit 912df262 authored by David S. Miller's avatar David S. Miller

net: introduce upper device lists and remove dev->master

Jiri Pirko says:

====================
This is a V6 of a repost of my previous patchset:
"[patch net-next v2 00/15] net: introduce upper device lists and remove dev->master" from Aug 14

The discussion around
"[net-next] bonding: don't allow the master to become its slave"
forced me to think about upper<->lower device connections.

This patchset adds a possibility to record upper device linkage.
All upper<->lower devices are converted to use this mechanism right after.
That leads to dev->master removal because this info becomes redundant since
"master links" have the same value.

After all changes, there is no longer possible to do things as:
"bond->someotherdevice->samebond"

Also I think that drivers like cxgb3, qlcnic, qeth would benefit by this
in future by being able to get more appropriate info about l3 addresses.

v5->v6:
- netdev_has_upper_dev() - added statement to comment that this is looking at
  the immediate upper devices only.
- renamed "RTNL semaphore" -> "RTNL lock" in all comments
- renamed __netdev_has_upper_dev() to __netdev_search_upper_dev() to emhasize
  the difference to netdev_has_upper_dev()

v4->v5:
- fixed missed typo in drivers/infiniband/hw/nes/nes_cm.c

v3->v4:
- comments in __netdev_upper_dev_link() squashed into one line
- kfree_rcu used instead of call_rcu in netdev_upper_dev_unlink()

v2->v3:
- removed recursion in __netdev_has_upper_dev()
- refreshed bits to be applicable on current net-next

v1->v2:
- s/unique/master/ better naming + stays closer to the past
- fixed vlan err goto
- original patch 15 (WARN_ON change) is squashed into the first patch
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 04e406dc 85464ef2
......@@ -135,6 +135,7 @@ static int nes_inetaddr_event(struct notifier_block *notifier,
struct net_device *event_netdev = ifa->ifa_dev->dev;
struct nes_device *nesdev;
struct net_device *netdev;
struct net_device *upper_dev;
struct nes_vnic *nesvnic;
unsigned int is_bonded;
......@@ -145,8 +146,9 @@ static int nes_inetaddr_event(struct notifier_block *notifier,
nesdev, nesdev->netdev[0]->name);
netdev = nesdev->netdev[0];
nesvnic = netdev_priv(netdev);
upper_dev = netdev_master_upper_dev_get(netdev);
is_bonded = netif_is_bond_slave(netdev) &&
(netdev->master == event_netdev);
(upper_dev == event_netdev);
if ((netdev == event_netdev) || is_bonded) {
if (nesvnic->rdma_enabled == 0) {
nes_debug(NES_DBG_NETDEV, "Returning without processing event for %s since"
......@@ -179,9 +181,9 @@ static int nes_inetaddr_event(struct notifier_block *notifier,
/* fall through */
case NETDEV_CHANGEADDR:
/* Add the address to the IP table */
if (netdev->master)
if (upper_dev)
nesvnic->local_ipaddr =
((struct in_device *)netdev->master->ip_ptr)->ifa_list->ifa_address;
((struct in_device *)upper_dev->ip_ptr)->ifa_list->ifa_address;
else
nesvnic->local_ipaddr = ifa->ifa_address;
......
......@@ -1340,7 +1340,7 @@ static int nes_addr_resolve_neigh(struct nes_vnic *nesvnic, u32 dst_ip, int arpi
}
if (netif_is_bond_slave(nesvnic->netdev))
netdev = nesvnic->netdev->master;
netdev = netdev_master_upper_dev_get(nesvnic->netdev);
else
netdev = nesvnic->netdev;
......
......@@ -1127,7 +1127,7 @@ static void ad_rx_machine(struct lacpdu *lacpdu, struct port *port)
// INFO_RECEIVED_LOOPBACK_FRAMES
pr_err("%s: An illegal loopback occurred on adapter (%s).\n"
"Check the configuration to verify that all adapters are connected to 802.3ad compliant switch ports\n",
port->slave->dev->master->name, port->slave->dev->name);
port->slave->bond->dev->name, port->slave->dev->name);
return;
}
__update_selected(lacpdu, port);
......@@ -1306,7 +1306,7 @@ static void ad_port_selection_logic(struct port *port)
}
if (!curr_port) { // meaning: the port was related to an aggregator but was not on the aggregator port list
pr_warning("%s: Warning: Port %d (on %s) was related to aggregator %d but was not on its port list\n",
port->slave->dev->master->name,
port->slave->bond->dev->name,
port->actor_port_number,
port->slave->dev->name,
port->aggregator->aggregator_identifier);
......@@ -1386,7 +1386,7 @@ static void ad_port_selection_logic(struct port *port)
port->aggregator->aggregator_identifier);
} else {
pr_err("%s: Port %d (on %s) did not find a suitable aggregator\n",
port->slave->dev->master->name,
port->slave->bond->dev->name,
port->actor_port_number, port->slave->dev->name);
}
}
......@@ -1463,7 +1463,7 @@ static struct aggregator *ad_agg_selection_test(struct aggregator *best,
default:
pr_warning("%s: Impossible agg select mode %d\n",
curr->slave->dev->master->name,
curr->slave->bond->dev->name,
__get_agg_selection_mode(curr->lag_ports));
break;
}
......@@ -1571,7 +1571,7 @@ static void ad_agg_selection_logic(struct aggregator *agg)
// check if any partner replys
if (best->is_individual) {
pr_warning("%s: Warning: No 802.3ad response from the link partner for any adapters in the bond\n",
best->slave ? best->slave->dev->master->name : "NULL");
best->slave ? best->slave->bond->dev->name : "NULL");
}
best->is_active = 1;
......@@ -1898,7 +1898,7 @@ int bond_3ad_bind_slave(struct slave *slave)
if (bond == NULL) {
pr_err("%s: The slave %s is not attached to its bond\n",
slave->dev->master->name, slave->dev->name);
slave->bond->dev->name, slave->dev->name);
return -1;
}
......@@ -1973,7 +1973,7 @@ void bond_3ad_unbind_slave(struct slave *slave)
// if slave is null, the whole port is not initialized
if (!port->slave) {
pr_warning("Warning: %s: Trying to unbind an uninitialized port on %s\n",
slave->dev->master->name, slave->dev->name);
slave->bond->dev->name, slave->dev->name);
return;
}
......@@ -2009,7 +2009,7 @@ void bond_3ad_unbind_slave(struct slave *slave)
if ((new_aggregator->lag_ports == port) && new_aggregator->is_active) {
pr_info("%s: Removing an active aggregator\n",
aggregator->slave->dev->master->name);
aggregator->slave->bond->dev->name);
// select new active aggregator
select_new_active_agg = 1;
}
......@@ -2040,7 +2040,7 @@ void bond_3ad_unbind_slave(struct slave *slave)
ad_agg_selection_logic(__get_first_agg(port));
} else {
pr_warning("%s: Warning: unbinding aggregator, and could not find a new aggregator for its ports\n",
slave->dev->master->name);
slave->bond->dev->name);
}
} else { // in case that the only port related to this aggregator is the one we want to remove
select_new_active_agg = aggregator->is_active;
......@@ -2048,7 +2048,7 @@ void bond_3ad_unbind_slave(struct slave *slave)
ad_clear_agg(aggregator);
if (select_new_active_agg) {
pr_info("%s: Removing an active aggregator\n",
slave->dev->master->name);
slave->bond->dev->name);
// select new active aggregator
ad_agg_selection_logic(__get_first_agg(port));
}
......@@ -2076,7 +2076,7 @@ void bond_3ad_unbind_slave(struct slave *slave)
ad_clear_agg(temp_aggregator);
if (select_new_active_agg) {
pr_info("%s: Removing an active aggregator\n",
slave->dev->master->name);
slave->bond->dev->name);
// select new active aggregator
ad_agg_selection_logic(__get_first_agg(port));
}
......@@ -2184,7 +2184,7 @@ static int bond_3ad_rx_indication(struct lacpdu *lacpdu, struct slave *slave, u1
if (!port->slave) {
pr_warning("%s: Warning: port of slave %s is uninitialized\n",
slave->dev->name, slave->dev->master->name);
slave->dev->name, slave->bond->dev->name);
return ret;
}
......@@ -2240,7 +2240,7 @@ void bond_3ad_adapter_speed_changed(struct slave *slave)
// if slave is null, the whole port is not initialized
if (!port->slave) {
pr_warning("Warning: %s: speed changed for uninitialized port on %s\n",
slave->dev->master->name, slave->dev->name);
slave->bond->dev->name, slave->dev->name);
return;
}
......@@ -2268,7 +2268,7 @@ void bond_3ad_adapter_duplex_changed(struct slave *slave)
// if slave is null, the whole port is not initialized
if (!port->slave) {
pr_warning("%s: Warning: duplex changed for uninitialized port on %s\n",
slave->dev->master->name, slave->dev->name);
slave->bond->dev->name, slave->dev->name);
return;
}
......@@ -2297,7 +2297,7 @@ void bond_3ad_handle_link_change(struct slave *slave, char link)
// if slave is null, the whole port is not initialized
if (!port->slave) {
pr_warning("Warning: %s: link status changed for uninitialized port on %s\n",
slave->dev->master->name, slave->dev->name);
slave->bond->dev->name, slave->dev->name);
return;
}
......
......@@ -507,7 +507,7 @@ static void rlb_update_client(struct rlb_client_info *client_info)
client_info->mac_dst);
if (!skb) {
pr_err("%s: Error: failed to create an ARP packet\n",
client_info->slave->dev->master->name);
client_info->slave->bond->dev->name);
continue;
}
......@@ -517,7 +517,7 @@ static void rlb_update_client(struct rlb_client_info *client_info)
skb = vlan_put_tag(skb, client_info->vlan_id);
if (!skb) {
pr_err("%s: Error: failed to insert VLAN tag\n",
client_info->slave->dev->master->name);
client_info->slave->bond->dev->name);
continue;
}
}
......@@ -1043,7 +1043,7 @@ static int alb_set_slave_mac_addr(struct slave *slave, u8 addr[])
if (dev_set_mac_address(dev, &s_addr)) {
pr_err("%s: Error: dev_set_mac_address of dev %s failed!\n"
"ALB mode requires that the base driver support setting the hw address also when the network device's interface is open\n",
dev->master->name, dev->name);
slave->bond->dev->name, dev->name);
return -EOPNOTSUPP;
}
return 0;
......
......@@ -746,11 +746,9 @@ static void __bond_resend_igmp_join_requests(struct net_device *dev)
{
struct in_device *in_dev;
rcu_read_lock();
in_dev = __in_dev_get_rcu(dev);
if (in_dev)
ip_mc_rejoin_groups(in_dev);
rcu_read_unlock();
}
/*
......@@ -760,9 +758,10 @@ static void __bond_resend_igmp_join_requests(struct net_device *dev)
*/
static void bond_resend_igmp_join_requests(struct bonding *bond)
{
struct net_device *bond_dev, *vlan_dev, *master_dev;
struct net_device *bond_dev, *vlan_dev, *upper_dev;
struct vlan_entry *vlan;
rcu_read_lock();
read_lock(&bond->lock);
bond_dev = bond->dev;
......@@ -774,18 +773,14 @@ static void bond_resend_igmp_join_requests(struct bonding *bond)
* if bond is enslaved to a bridge,
* then rejoin all groups on its master
*/
master_dev = bond_dev->master;
if (master_dev)
if ((master_dev->priv_flags & IFF_EBRIDGE)
&& (bond_dev->priv_flags & IFF_BRIDGE_PORT))
__bond_resend_igmp_join_requests(master_dev);
upper_dev = netdev_master_upper_dev_get_rcu(bond_dev);
if (upper_dev && upper_dev->priv_flags & IFF_EBRIDGE)
__bond_resend_igmp_join_requests(upper_dev);
/* rejoin all groups on vlan devices */
list_for_each_entry(vlan, &bond->vlan_list, vlan_list) {
rcu_read_lock();
vlan_dev = __vlan_find_dev_deep(bond_dev,
vlan->vlan_id);
rcu_read_unlock();
if (vlan_dev)
__bond_resend_igmp_join_requests(vlan_dev);
}
......@@ -794,13 +789,16 @@ static void bond_resend_igmp_join_requests(struct bonding *bond)
queue_delayed_work(bond->wq, &bond->mcast_work, HZ/5);
read_unlock(&bond->lock);
rcu_read_unlock();
}
static void bond_resend_igmp_join_requests_delayed(struct work_struct *work)
{
struct bonding *bond = container_of(work, struct bonding,
mcast_work.work);
rcu_read_lock();
bond_resend_igmp_join_requests(bond);
rcu_read_unlock();
}
/*
......@@ -1493,6 +1491,27 @@ static rx_handler_result_t bond_handle_frame(struct sk_buff **pskb)
return ret;
}
static int bond_master_upper_dev_link(struct net_device *bond_dev,
struct net_device *slave_dev)
{
int err;
err = netdev_master_upper_dev_link(slave_dev, bond_dev);
if (err)
return err;
slave_dev->flags |= IFF_SLAVE;
rtmsg_ifinfo(RTM_NEWLINK, slave_dev, IFF_SLAVE);
return 0;
}
static void bond_upper_dev_unlink(struct net_device *bond_dev,
struct net_device *slave_dev)
{
netdev_upper_dev_unlink(slave_dev, bond_dev);
slave_dev->flags &= ~IFF_SLAVE;
rtmsg_ifinfo(RTM_NEWLINK, slave_dev, IFF_SLAVE);
}
/* enslave device <slave> to bond device <master> */
int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
{
......@@ -1655,9 +1674,9 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
}
}
res = netdev_set_bond_master(slave_dev, bond_dev);
res = bond_master_upper_dev_link(bond_dev, slave_dev);
if (res) {
pr_debug("Error %d calling netdev_set_bond_master\n", res);
pr_debug("Error %d calling bond_master_upper_dev_link\n", res);
goto err_restore_mac;
}
......@@ -1891,7 +1910,7 @@ err_close:
dev_close(slave_dev);
err_unset_master:
netdev_set_bond_master(slave_dev, NULL);
bond_upper_dev_unlink(bond_dev, slave_dev);
err_restore_mac:
if (!bond->params.fail_over_mac) {
......@@ -1936,7 +1955,7 @@ int bond_release(struct net_device *bond_dev, struct net_device *slave_dev)
/* slave is not a slave or master is not master of this slave */
if (!(slave_dev->flags & IFF_SLAVE) ||
(slave_dev->master != bond_dev)) {
!netdev_has_upper_dev(slave_dev, bond_dev)) {
pr_err("%s: Error: cannot release %s.\n",
bond_dev->name, slave_dev->name);
return -EINVAL;
......@@ -2080,7 +2099,7 @@ int bond_release(struct net_device *bond_dev, struct net_device *slave_dev)
netif_addr_unlock_bh(bond_dev);
}
netdev_set_bond_master(slave_dev, NULL);
bond_upper_dev_unlink(bond_dev, slave_dev);
slave_disable_netpoll(slave);
......@@ -2195,7 +2214,7 @@ static int bond_release_all(struct net_device *bond_dev)
netif_addr_unlock_bh(bond_dev);
}
netdev_set_bond_master(slave_dev, NULL);
bond_upper_dev_unlink(bond_dev, slave_dev);
slave_disable_netpoll(slave);
......@@ -2259,8 +2278,9 @@ static int bond_ioctl_change_active(struct net_device *bond_dev, struct net_devi
if (!USES_PRIMARY(bond->params.mode))
return -EINVAL;
/* Verify that master_dev is indeed the master of slave_dev */
if (!(slave_dev->flags & IFF_SLAVE) || (slave_dev->master != bond_dev))
/* Verify that bond_dev is indeed the master of slave_dev */
if (!(slave_dev->flags & IFF_SLAVE) ||
!netdev_has_upper_dev(slave_dev, bond_dev))
return -EINVAL;
read_lock(&bond->lock);
......@@ -3258,36 +3278,32 @@ static int bond_master_netdev_event(unsigned long event,
static int bond_slave_netdev_event(unsigned long event,
struct net_device *slave_dev)
{
struct net_device *bond_dev = slave_dev->master;
struct bonding *bond = netdev_priv(bond_dev);
struct slave *slave = NULL;
struct slave *slave = bond_slave_get_rtnl(slave_dev);
struct bonding *bond = slave->bond;
struct net_device *bond_dev = slave->bond->dev;
u32 old_speed;
u8 old_duplex;
switch (event) {
case NETDEV_UNREGISTER:
if (bond_dev) {
if (bond->setup_by_slave)
bond_release_and_destroy(bond_dev, slave_dev);
else
bond_release(bond_dev, slave_dev);
}
if (bond->setup_by_slave)
bond_release_and_destroy(bond_dev, slave_dev);
else
bond_release(bond_dev, slave_dev);
break;
case NETDEV_UP:
case NETDEV_CHANGE:
slave = bond_get_slave_by_dev(bond, slave_dev);
if (slave) {
u32 old_speed = slave->speed;
u8 old_duplex = slave->duplex;
old_speed = slave->speed;
old_duplex = slave->duplex;
bond_update_speed_duplex(slave);
bond_update_speed_duplex(slave);
if (bond->params.mode == BOND_MODE_8023AD) {
if (old_speed != slave->speed)
bond_3ad_adapter_speed_changed(slave);
if (old_duplex != slave->duplex)
bond_3ad_adapter_duplex_changed(slave);
}
if (bond->params.mode == BOND_MODE_8023AD) {
if (old_speed != slave->speed)
bond_3ad_adapter_speed_changed(slave);
if (old_duplex != slave->duplex)
bond_3ad_adapter_duplex_changed(slave);
}
break;
case NETDEV_DOWN:
/*
......
......@@ -258,6 +258,9 @@ static inline bool bond_vlan_used(struct bonding *bond)
#define bond_slave_get_rcu(dev) \
((struct slave *) rcu_dereference(dev->rx_handler_data))
#define bond_slave_get_rtnl(dev) \
((struct slave *) rtnl_dereference(dev->rx_handler_data))
/**
* Returns NULL if the net_device does not belong to any of the bond's slaves
*
......@@ -280,11 +283,9 @@ static inline struct slave *bond_get_slave_by_dev(struct bonding *bond,
static inline struct bonding *bond_get_bond_by_slave(struct slave *slave)
{
if (!slave || !slave->dev->master) {
if (!slave || !slave->bond)
return NULL;
}
return netdev_priv(slave->dev->master);
return slave->bond;
}
static inline bool bond_is_lb(const struct bonding *bond)
......@@ -360,10 +361,9 @@ static inline void bond_netpoll_send_skb(const struct slave *slave,
static inline void bond_set_slave_inactive_flags(struct slave *slave)
{
struct bonding *bond = netdev_priv(slave->dev->master);
if (!bond_is_lb(bond))
if (!bond_is_lb(slave->bond))
bond_set_backup_slave(slave);
if (!bond->params.all_slaves_active)
if (!slave->bond->params.all_slaves_active)
slave->inactive = 1;
}
......
......@@ -182,14 +182,17 @@ static struct net_device *get_iff_from_mac(struct adapter *adapter,
struct net_device *dev = adapter->port[i];
if (!memcmp(dev->dev_addr, mac, ETH_ALEN)) {
rcu_read_lock();
if (vlan && vlan != VLAN_VID_MASK) {
rcu_read_lock();
dev = __vlan_find_dev_deep(dev, vlan);
rcu_read_unlock();
} else if (netif_is_bond_slave(dev)) {
while (dev->master)
dev = dev->master;
struct net_device *upper_dev;
while ((upper_dev =
netdev_master_upper_dev_get_rcu(dev)))
dev = upper_dev;
}
rcu_read_unlock();
return dev;
}
}
......
......@@ -3186,12 +3186,14 @@ void qlcnic_restore_indev_addr(struct net_device *netdev, unsigned long event)
qlcnic_config_indev_addr(adapter, netdev, event);
rcu_read_lock();
for_each_set_bit(vid, adapter->vlans, VLAN_N_VID) {
dev = __vlan_find_dev_deep(netdev, vid);
if (!dev)
continue;
qlcnic_config_indev_addr(adapter, dev, event);
}
rcu_read_unlock();
}
static int qlcnic_netdev_event(struct notifier_block *this,
......
......@@ -764,16 +764,22 @@ int macvlan_common_newlink(struct net *src_net, struct net_device *dev,
memcpy(dev->dev_addr, lowerdev->dev_addr, ETH_ALEN);
}
err = netdev_upper_dev_link(lowerdev, dev);
if (err)
goto destroy_port;
port->count += 1;
err = register_netdevice(dev);
if (err < 0)
goto destroy_port;
goto upper_dev_unlink;
list_add_tail(&vlan->list, &port->vlans);
netif_stacked_transfer_operstate(lowerdev, dev);
return 0;
upper_dev_unlink:
netdev_upper_dev_unlink(lowerdev, dev);
destroy_port:
port->count -= 1;
if (!port->count)
......@@ -797,6 +803,7 @@ void macvlan_dellink(struct net_device *dev, struct list_head *head)
list_del(&vlan->list);
unregister_netdevice_queue(dev, head);
netdev_upper_dev_unlink(vlan->lowerdev, dev);
}
EXPORT_SYMBOL_GPL(macvlan_dellink);
......
......@@ -1055,10 +1055,11 @@ static int team_port_add(struct team *team, struct net_device *port_dev)
}
}
err = netdev_set_master(port_dev, dev);
err = netdev_master_upper_dev_link(port_dev, dev);
if (err) {
netdev_err(dev, "Device %s failed to set master\n", portname);
goto err_set_master;
netdev_err(dev, "Device %s failed to set upper link\n",
portname);
goto err_set_upper_link;
}
err = netdev_rx_handler_register(port_dev, team_handle_frame,
......@@ -1091,9 +1092,9 @@ err_option_port_add:
netdev_rx_handler_unregister(port_dev);
err_handler_register:
netdev_set_master(port_dev, NULL);
netdev_upper_dev_unlink(port_dev, dev);
err_set_master:
err_set_upper_link:
team_port_disable_netpoll(port);
err_enable_netpoll:
......@@ -1137,7 +1138,7 @@ static int team_port_del(struct team *team, struct net_device *port_dev)
team_port_disable(team, port);
list_del_rcu(&port->list);
netdev_rx_handler_unregister(port_dev);
netdev_set_master(port_dev, NULL);
netdev_upper_dev_unlink(port_dev, dev);
team_port_disable_netpoll(port);
vlan_vids_del_by_dev(port_dev, dev);
dev_close(port_dev);
......
......@@ -1640,6 +1640,7 @@ static void qeth_l3_add_mc(struct qeth_card *card, struct in_device *in4_dev)
}
}
/* called with rcu_read_lock */
static void qeth_l3_add_vlan_mc(struct qeth_card *card)
{
struct in_device *in_dev;
......@@ -1652,19 +1653,14 @@ static void qeth_l3_add_vlan_mc(struct qeth_card *card)
for_each_set_bit(vid, card->active_vlans, VLAN_N_VID) {
struct net_device *netdev;
rcu_read_lock();
netdev = __vlan_find_dev_deep(card->dev, vid);
rcu_read_unlock();
if (netdev == NULL ||
!(netdev->flags & IFF_UP))
continue;
in_dev = in_dev_get(netdev);
in_dev = __in_dev_get_rcu(netdev);
if (!in_dev)
continue;
rcu_read_lock();
qeth_l3_add_mc(card, in_dev);
rcu_read_unlock();
in_dev_put(in_dev);
}
}
......@@ -1673,14 +1669,14 @@ static void qeth_l3_add_multicast_ipv4(struct qeth_card *card)
struct in_device *in4_dev;
QETH_CARD_TEXT(card, 4, "chkmcv4");
in4_dev = in_dev_get(card->dev);
if (in4_dev == NULL)
return;
rcu_read_lock();
in4_dev = __in_dev_get_rcu(card->dev);
if (in4_dev == NULL)
goto unlock;
qeth_l3_add_mc(card, in4_dev);
qeth_l3_add_vlan_mc(card);
unlock:
rcu_read_unlock();
in_dev_put(in4_dev);
}
#ifdef CONFIG_QETH_IPV6
......@@ -1705,6 +1701,7 @@ static void qeth_l3_add_mc6(struct qeth_card *card, struct inet6_dev *in6_dev)
}
}
/* called with rcu_read_lock */
static void qeth_l3_add_vlan_mc6(struct qeth_card *card)
{
struct inet6_dev *in_dev;
......@@ -1741,10 +1738,12 @@ static void qeth_l3_add_multicast_ipv6(struct qeth_card *card)
in6_dev = in6_dev_get(card->dev);
if (in6_dev == NULL)
return;
rcu_read_lock();
read_lock_bh(&in6_dev->lock);
qeth_l3_add_mc6(card, in6_dev);
qeth_l3_add_vlan_mc6(card);
read_unlock_bh(&in6_dev->lock);
rcu_read_unlock();
in6_dev_put(in6_dev);
}
#endif /* CONFIG_QETH_IPV6 */
......@@ -1813,8 +1812,10 @@ static void qeth_l3_free_vlan_addresses6(struct qeth_card *card,
static void qeth_l3_free_vlan_addresses(struct qeth_card *card,
unsigned short vid)
{