Fix locking to prevent Oops on SMP systems when starting/stopping dvb network
interfaces.
Signed-off-by: Ralph Metzler <rjkm@metzlerbros.de>
Signed-off-by: Mauro Carvalho Chehab <mchehab@brturbo.com.br>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
unsigned char ule_bridged; /* Whether the ULE_BRIDGED extension header was found. */
int ule_sndu_remain; /* Nr. of bytes still required for current ULE SNDU. */
unsigned long ts_count; /* Current ts cell counter. */
unsigned char ule_bridged; /* Whether the ULE_BRIDGED extension header was found. */
int ule_sndu_remain; /* Nr. of bytes still required for current ULE SNDU. */
unsigned long ts_count; /* Current ts cell counter. */
+
+ struct semaphore mutex;
static int dvb_net_feed_start(struct net_device *dev)
{
static int dvb_net_feed_start(struct net_device *dev)
{
struct dvb_net_priv *priv = dev->priv;
struct dmx_demux *demux = priv->demux;
unsigned char *mac = (unsigned char *) dev->dev_addr;
dprintk("%s: rx_mode %i\n", __FUNCTION__, priv->rx_mode);
struct dvb_net_priv *priv = dev->priv;
struct dmx_demux *demux = priv->demux;
unsigned char *mac = (unsigned char *) dev->dev_addr;
dprintk("%s: rx_mode %i\n", __FUNCTION__, priv->rx_mode);
if (priv->tsfeed || priv->secfeed || priv->secfilter || priv->multi_secfilter[0])
printk("%s: BUG %d\n", __FUNCTION__, __LINE__);
if (priv->tsfeed || priv->secfeed || priv->secfilter || priv->multi_secfilter[0])
printk("%s: BUG %d\n", __FUNCTION__, __LINE__);
dvb_net_sec_callback);
if (ret<0) {
printk("%s: could not allocate section feed\n", dev->name);
dvb_net_sec_callback);
if (ret<0) {
printk("%s: could not allocate section feed\n", dev->name);
}
ret = priv->secfeed->set(priv->secfeed, priv->pid, 32768, 1);
}
ret = priv->secfeed->set(priv->secfeed, priv->pid, 32768, 1);
printk("%s: could not set section feed\n", dev->name);
priv->demux->release_section_feed(priv->demux, priv->secfeed);
priv->secfeed=NULL;
printk("%s: could not set section feed\n", dev->name);
priv->demux->release_section_feed(priv->demux, priv->secfeed);
priv->secfeed=NULL;
}
if (priv->rx_mode != RX_MODE_PROMISC) {
}
if (priv->rx_mode != RX_MODE_PROMISC) {
ret = demux->allocate_ts_feed(demux, &priv->tsfeed, dvb_net_ts_callback);
if (ret < 0) {
printk("%s: could not allocate ts feed\n", dev->name);
ret = demux->allocate_ts_feed(demux, &priv->tsfeed, dvb_net_ts_callback);
if (ret < 0) {
printk("%s: could not allocate ts feed\n", dev->name);
}
/* Set netdevice pointer for ts decaps callback. */
}
/* Set netdevice pointer for ts decaps callback. */
printk("%s: could not set ts feed\n", dev->name);
priv->demux->release_ts_feed(priv->demux, priv->tsfeed);
priv->tsfeed = NULL;
printk("%s: could not set ts feed\n", dev->name);
priv->demux->release_ts_feed(priv->demux, priv->tsfeed);
priv->tsfeed = NULL;
}
dprintk("%s: start filtering\n", __FUNCTION__);
priv->tsfeed->start_filtering(priv->tsfeed);
} else
}
dprintk("%s: start filtering\n", __FUNCTION__);
priv->tsfeed->start_filtering(priv->tsfeed);
} else
+error:
+ up(&priv->mutex);
+ return ret;
}
static int dvb_net_feed_stop(struct net_device *dev)
{
struct dvb_net_priv *priv = dev->priv;
}
static int dvb_net_feed_stop(struct net_device *dev)
{
struct dvb_net_priv *priv = dev->priv;
dprintk("%s\n", __FUNCTION__);
dprintk("%s\n", __FUNCTION__);
if (priv->feedtype == DVB_NET_FEEDTYPE_MPE) {
if (priv->secfeed) {
if (priv->secfeed->is_filtering) {
if (priv->feedtype == DVB_NET_FEEDTYPE_MPE) {
if (priv->secfeed) {
if (priv->secfeed->is_filtering) {
else
printk("%s: no ts feed to stop\n", dev->name);
} else
else
printk("%s: no ts feed to stop\n", dev->name);
} else
- return -EINVAL;
- return 0;
+ ret = -EINVAL;
+ up(&priv->mutex);
+ return ret;
struct dvb_net_priv *priv = dev->priv;
dvb_net_feed_stop(dev);
struct dvb_net_priv *priv = dev->priv;
dvb_net_feed_stop(dev);
priv->rx_mode = RX_MODE_UNI;
priv->rx_mode = RX_MODE_UNI;
+ spin_lock_bh(&dev->xmit_lock);
if (dev->flags & IFF_PROMISC) {
dprintk("%s: promiscuous mode\n", dev->name);
if (dev->flags & IFF_PROMISC) {
dprintk("%s: promiscuous mode\n", dev->name);
+ spin_unlock_bh(&dev->xmit_lock);
dvb_net_feed_start(dev);
}
dvb_net_feed_start(dev);
}
INIT_WORK(&priv->set_multicast_list_wq, wq_set_multicast_list, net);
INIT_WORK(&priv->restart_net_feed_wq, wq_restart_net_feed, net);
INIT_WORK(&priv->set_multicast_list_wq, wq_set_multicast_list, net);
INIT_WORK(&priv->restart_net_feed_wq, wq_restart_net_feed, net);
+ init_MUTEX(&priv->mutex);