diff options
author | Andrey Shvetsov <andrey.shvetsov@k2l.de> | 2017-06-20 18:11:50 +0300 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2017-06-23 19:32:46 +0300 |
commit | 2338652c3346df68f5b95a42d41e021e2977ddf0 (patch) | |
tree | f0595218827e117b4cc9c6cc3b00869d203753d4 /drivers/staging/most | |
parent | 606c21759774a6694d4219d5bb96704ab13e20a0 (diff) | |
download | linux-2338652c3346df68f5b95a42d41e021e2977ddf0.tar.xz |
staging: most: net: protect consistency of the state
This introduces the mutex that protects the consistency between the
tx.linked, rx.linked and the presence of the net divice.
Additionally, this patch optimizes the setup of the ch->linked in the
function aim_probe_channel.
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 | 64 |
1 files changed, 42 insertions, 22 deletions
diff --git a/drivers/staging/most/aim-network/networking.c b/drivers/staging/most/aim-network/networking.c index 750652de90a8..217265cbf03b 100644 --- a/drivers/staging/most/aim-network/networking.c +++ b/drivers/staging/most/aim-network/networking.c @@ -72,6 +72,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 most_aim aim; @@ -179,18 +180,21 @@ static void on_netinfo(struct most_interface *iface, static int most_nd_open(struct net_device *dev) { struct net_dev_context *nd = netdev_priv(dev); + int ret = 0; - BUG_ON(!nd->tx.linked || !nd->rx.linked); + mutex_lock(&probe_disc_mt); if (most_start_channel(nd->iface, nd->rx.ch_id, &aim)) { netdev_err(dev, "most_start_channel() failed\n"); - return -EBUSY; + ret = -EBUSY; + goto unlock; } if (most_start_channel(nd->iface, nd->tx.ch_id, &aim)) { netdev_err(dev, "most_start_channel() failed\n"); most_stop_channel(nd->iface, nd->rx.ch_id, &aim); - return -EBUSY; + ret = -EBUSY; + goto unlock; } netif_carrier_off(dev); @@ -201,7 +205,10 @@ static int most_nd_open(struct net_device *dev) netif_wake_queue(dev); if (nd->iface->request_netinfo) nd->iface->request_netinfo(nd->iface, nd->tx.ch_id, on_netinfo); - return 0; + +unlock: + mutex_unlock(&probe_disc_mt); + return ret; } static int most_nd_stop(struct net_device *dev) @@ -289,6 +296,7 @@ static int aim_probe_channel(struct most_interface *iface, int channel_idx, struct net_dev_channel *ch; struct net_device *dev; unsigned long flags; + int ret = 0; if (!iface) return -EINVAL; @@ -296,13 +304,15 @@ static int aim_probe_channel(struct most_interface *iface, int channel_idx, if (ccfg->data_type != MOST_CH_ASYNC) return -EINVAL; + mutex_lock(&probe_disc_mt); nd = get_net_dev_context(iface); - if (!nd) { dev = alloc_netdev(sizeof(struct net_dev_context), "meth%d", NET_NAME_UNKNOWN, most_nd_setup); - if (!dev) - return -ENOMEM; + if (!dev) { + ret = -ENOMEM; + goto unlock; + } nd = netdev_priv(dev); nd->iface = iface; @@ -313,25 +323,26 @@ static int aim_probe_channel(struct most_interface *iface, int channel_idx, spin_unlock_irqrestore(&list_lock, flags); ch = ccfg->direction == MOST_CH_TX ? &nd->tx : &nd->rx; - ch->ch_id = channel_idx; - ch->linked = true; } else { ch = ccfg->direction == MOST_CH_TX ? &nd->tx : &nd->rx; if (ch->linked) { pr_err("direction is allocated\n"); - return -EINVAL; + ret = -EINVAL; + goto unlock; } - ch->ch_id = channel_idx; - ch->linked = true; if (register_netdev(nd->dev)) { pr_err("register_netdev() failed\n"); - ch->linked = false; - return -EINVAL; + ret = -EINVAL; + goto unlock; } } + ch->ch_id = channel_idx; + ch->linked = true; - return 0; +unlock: + mutex_unlock(&probe_disc_mt); + return ret; } static int aim_disconnect_channel(struct most_interface *iface, @@ -340,17 +351,23 @@ static int aim_disconnect_channel(struct most_interface *iface, struct net_dev_context *nd; struct net_dev_channel *ch; unsigned long flags; + int ret = 0; + mutex_lock(&probe_disc_mt); nd = get_net_dev_context(iface); - if (!nd) - return -EINVAL; + if (!nd) { + ret = -EINVAL; + goto unlock; + } - if (nd->rx.linked && channel_idx == nd->rx.ch_id) + if (nd->rx.linked && channel_idx == nd->rx.ch_id) { ch = &nd->rx; - else if (nd->tx.linked && channel_idx == nd->tx.ch_id) + } else if (nd->tx.linked && channel_idx == nd->tx.ch_id) { ch = &nd->tx; - else - return -EINVAL; + } else { + ret = -EINVAL; + goto unlock; + } if (nd->rx.linked && nd->tx.linked) { /* @@ -367,7 +384,9 @@ static int aim_disconnect_channel(struct most_interface *iface, free_netdev(nd->dev); } - return 0; +unlock: + mutex_unlock(&probe_disc_mt); + return ret; } static int aim_resume_tx_channel(struct most_interface *iface, @@ -463,6 +482,7 @@ static struct most_aim aim = { static int __init most_net_init(void) { spin_lock_init(&list_lock); + mutex_init(&probe_disc_mt); return most_register_aim(&aim); } |