diff options
author | Andrey Shvetsov <andrey.shvetsov@k2l.de> | 2017-06-20 17:11:51 +0200 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2017-06-24 00:32:46 +0800 |
commit | 4271eabb487d72d7818e273a6dbf44bfb4253a44 (patch) | |
tree | 5ddef14ea3821b8d35c9447ead16a1fc9757ee5f /drivers/staging/most | |
parent | 2338652c3346df68f5b95a42d41e021e2977ddf0 (diff) |
staging: most: net: hold used net device
This adds the dev_hold and dev_put calls to the functions
aim_resume_tx_channel, aim_rx_data and on_netinfo to postpone the
unregistration of the used net device.
Signed-off-by: Andrey Shvetsov <andrey.shvetsov@k2l.de>
Signed-off-by: Christian Gromm <christian.gromm@microchip.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/staging/most')
-rw-r--r-- | drivers/staging/most/aim-network/networking.c | 78 |
1 files changed, 55 insertions, 23 deletions
diff --git a/drivers/staging/most/aim-network/networking.c b/drivers/staging/most/aim-network/networking.c index 217265cbf03b..4c259c20048f 100644 --- a/drivers/staging/most/aim-network/networking.c +++ b/drivers/staging/most/aim-network/networking.c @@ -73,7 +73,7 @@ struct net_dev_context { static struct list_head net_devices = LIST_HEAD_INIT(net_devices); static struct mutex probe_disc_mt; /* ch->linked = true, most_nd_open */ -static struct spinlock list_lock; +static struct spinlock list_lock; /* list_head, ch->linked = false, dev_hold */ static struct most_aim aim; static int skb_to_mamac(const struct sk_buff *skb, struct mbo *mbo) @@ -271,21 +271,29 @@ static void most_nd_setup(struct net_device *dev) dev->netdev_ops = &most_nd_ops; } -static struct net_dev_context *get_net_dev_context( - struct most_interface *iface) +static struct net_dev_context *get_net_dev(struct most_interface *iface) +{ + struct net_dev_context *nd; + + list_for_each_entry(nd, &net_devices, list) + if (nd->iface == iface) + return nd; + return NULL; +} + +static struct net_dev_context *get_net_dev_hold(struct most_interface *iface) { struct net_dev_context *nd; unsigned long flags; spin_lock_irqsave(&list_lock, flags); - list_for_each_entry(nd, &net_devices, list) { - if (nd->iface == iface) { - spin_unlock_irqrestore(&list_lock, flags); - return nd; - } - } + nd = get_net_dev(iface); + if (nd && nd->rx.linked && nd->tx.linked) + dev_hold(nd->dev); + else + nd = NULL; spin_unlock_irqrestore(&list_lock, flags); - return NULL; + return nd; } static int aim_probe_channel(struct most_interface *iface, int channel_idx, @@ -305,7 +313,7 @@ static int aim_probe_channel(struct most_interface *iface, int channel_idx, return -EINVAL; mutex_lock(&probe_disc_mt); - nd = get_net_dev_context(iface); + nd = get_net_dev(iface); if (!nd) { dev = alloc_netdev(sizeof(struct net_dev_context), "meth%d", NET_NAME_UNKNOWN, most_nd_setup); @@ -354,7 +362,7 @@ static int aim_disconnect_channel(struct most_interface *iface, int ret = 0; mutex_lock(&probe_disc_mt); - nd = get_net_dev_context(iface); + nd = get_net_dev(iface); if (!nd) { ret = -EINVAL; goto unlock; @@ -370,12 +378,15 @@ static int aim_disconnect_channel(struct most_interface *iface, } if (nd->rx.linked && nd->tx.linked) { + spin_lock_irqsave(&list_lock, flags); + ch->linked = false; + spin_unlock_irqrestore(&list_lock, flags); + /* * do not call most_stop_channel() here, because channels are * going to be closed in ndo_stop() after unregister_netdev() */ unregister_netdev(nd->dev); - ch->linked = false; } else { spin_lock_irqsave(&list_lock, flags); list_del(&nd->list); @@ -394,11 +405,17 @@ static int aim_resume_tx_channel(struct most_interface *iface, { struct net_dev_context *nd; - nd = get_net_dev_context(iface); - if (!nd || nd->tx.ch_id != channel_idx) + nd = get_net_dev_hold(iface); + if (!nd) return 0; + if (nd->tx.ch_id != channel_idx) + goto put_nd; + netif_wake_queue(nd->dev); + +put_nd: + dev_put(nd->dev); return 0; } @@ -411,21 +428,31 @@ static int aim_rx_data(struct mbo *mbo) struct sk_buff *skb; struct net_device *dev; unsigned int skb_len; + int ret = 0; - nd = get_net_dev_context(mbo->ifp); - if (!nd || nd->rx.ch_id != mbo->hdm_channel_id) + nd = get_net_dev_hold(mbo->ifp); + if (!nd) return -EIO; + if (nd->rx.ch_id != mbo->hdm_channel_id) { + ret = -EIO; + goto put_nd; + } + dev = nd->dev; if (nd->is_mamac) { - if (!PMS_IS_MAMAC(buf, len)) - return -EIO; + if (!PMS_IS_MAMAC(buf, len)) { + ret = -EIO; + goto put_nd; + } skb = dev_alloc_skb(len - MDP_HDR_LEN + 2 * ETH_ALEN + 2); } else { - if (!PMS_IS_MEP(buf, len)) - return -EIO; + if (!PMS_IS_MEP(buf, len)) { + ret = -EIO; + goto put_nd; + } skb = dev_alloc_skb(len - MEP_HDR_LEN); } @@ -468,7 +495,10 @@ static int aim_rx_data(struct mbo *mbo) out: most_put_mbo(mbo); - return 0; + +put_nd: + dev_put(nd->dev); + return ret; } static struct most_aim aim = { @@ -504,7 +534,7 @@ static void on_netinfo(struct most_interface *iface, struct net_device *dev; const u8 *m = mac_addr; - nd = get_net_dev_context(iface); + nd = get_net_dev_hold(iface); if (!nd) return; @@ -526,6 +556,8 @@ static void on_netinfo(struct most_interface *iface, m[0], m[1], m[2], m[3], m[4], m[5]); } } + + dev_put(nd->dev); } module_init(most_net_init); |