diff options
| author | Ralph Metzler <rjkm@metzlerbros.de> | 2005-12-01 03:51:54 -0500 |
|---|---|---|
| committer | Linus Torvalds <torvalds@g5.osdl.org> | 2005-12-01 18:48:59 -0500 |
| commit | 1130ca45c719fe788fa544a54a82ea53ef5ea87a (patch) | |
| tree | 423a0eb692c0e14a8b1c6462a8dfdfc402e93753 | |
| parent | 9b9225f0f002c39f340da2ed1e7efec6885ca312 (diff) | |
[PATCH] DVB: Fix locking to prevent Oops on SMP systems
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>
| -rw-r--r-- | drivers/media/dvb/dvb-core/dvb_net.c | 31 |
1 files changed, 20 insertions, 11 deletions
diff --git a/drivers/media/dvb/dvb-core/dvb_net.c b/drivers/media/dvb/dvb-core/dvb_net.c index 87935490bfb2..df536bd2e103 100644 --- a/drivers/media/dvb/dvb-core/dvb_net.c +++ b/drivers/media/dvb/dvb-core/dvb_net.c | |||
| @@ -151,6 +151,8 @@ struct dvb_net_priv { | |||
| 151 | unsigned char ule_bridged; /* Whether the ULE_BRIDGED extension header was found. */ | 151 | unsigned char ule_bridged; /* Whether the ULE_BRIDGED extension header was found. */ |
| 152 | int ule_sndu_remain; /* Nr. of bytes still required for current ULE SNDU. */ | 152 | int ule_sndu_remain; /* Nr. of bytes still required for current ULE SNDU. */ |
| 153 | unsigned long ts_count; /* Current ts cell counter. */ | 153 | unsigned long ts_count; /* Current ts cell counter. */ |
| 154 | |||
| 155 | struct semaphore mutex; | ||
| 154 | }; | 156 | }; |
| 155 | 157 | ||
| 156 | 158 | ||
| @@ -881,12 +883,13 @@ static int dvb_net_filter_sec_set(struct net_device *dev, | |||
| 881 | 883 | ||
| 882 | static int dvb_net_feed_start(struct net_device *dev) | 884 | static int dvb_net_feed_start(struct net_device *dev) |
| 883 | { | 885 | { |
| 884 | int ret, i; | 886 | int ret = 0, i; |
| 885 | struct dvb_net_priv *priv = dev->priv; | 887 | struct dvb_net_priv *priv = dev->priv; |
| 886 | struct dmx_demux *demux = priv->demux; | 888 | struct dmx_demux *demux = priv->demux; |
| 887 | unsigned char *mac = (unsigned char *) dev->dev_addr; | 889 | unsigned char *mac = (unsigned char *) dev->dev_addr; |
| 888 | 890 | ||
| 889 | dprintk("%s: rx_mode %i\n", __FUNCTION__, priv->rx_mode); | 891 | dprintk("%s: rx_mode %i\n", __FUNCTION__, priv->rx_mode); |
| 892 | down(&priv->mutex); | ||
| 890 | if (priv->tsfeed || priv->secfeed || priv->secfilter || priv->multi_secfilter[0]) | 893 | if (priv->tsfeed || priv->secfeed || priv->secfilter || priv->multi_secfilter[0]) |
| 891 | printk("%s: BUG %d\n", __FUNCTION__, __LINE__); | 894 | printk("%s: BUG %d\n", __FUNCTION__, __LINE__); |
| 892 | 895 | ||
| @@ -900,7 +903,7 @@ static int dvb_net_feed_start(struct net_device *dev) | |||
| 900 | dvb_net_sec_callback); | 903 | dvb_net_sec_callback); |
| 901 | if (ret<0) { | 904 | if (ret<0) { |
| 902 | printk("%s: could not allocate section feed\n", dev->name); | 905 | printk("%s: could not allocate section feed\n", dev->name); |
| 903 | return ret; | 906 | goto error; |
| 904 | } | 907 | } |
| 905 | 908 | ||
| 906 | ret = priv->secfeed->set(priv->secfeed, priv->pid, 32768, 1); | 909 | ret = priv->secfeed->set(priv->secfeed, priv->pid, 32768, 1); |
| @@ -909,7 +912,7 @@ static int dvb_net_feed_start(struct net_device *dev) | |||
| 909 | printk("%s: could not set section feed\n", dev->name); | 912 | printk("%s: could not set section feed\n", dev->name); |
| 910 | priv->demux->release_section_feed(priv->demux, priv->secfeed); | 913 | priv->demux->release_section_feed(priv->demux, priv->secfeed); |
| 911 | priv->secfeed=NULL; | 914 | priv->secfeed=NULL; |
| 912 | return ret; | 915 | goto error; |
| 913 | } | 916 | } |
| 914 | 917 | ||
| 915 | if (priv->rx_mode != RX_MODE_PROMISC) { | 918 | if (priv->rx_mode != RX_MODE_PROMISC) { |
| @@ -948,7 +951,7 @@ static int dvb_net_feed_start(struct net_device *dev) | |||
| 948 | ret = demux->allocate_ts_feed(demux, &priv->tsfeed, dvb_net_ts_callback); | 951 | ret = demux->allocate_ts_feed(demux, &priv->tsfeed, dvb_net_ts_callback); |
| 949 | if (ret < 0) { | 952 | if (ret < 0) { |
| 950 | printk("%s: could not allocate ts feed\n", dev->name); | 953 | printk("%s: could not allocate ts feed\n", dev->name); |
| 951 | return ret; | 954 | goto error; |
| 952 | } | 955 | } |
| 953 | 956 | ||
| 954 | /* Set netdevice pointer for ts decaps callback. */ | 957 | /* Set netdevice pointer for ts decaps callback. */ |
| @@ -962,23 +965,26 @@ static int dvb_net_feed_start(struct net_device *dev) | |||
| 962 | printk("%s: could not set ts feed\n", dev->name); | 965 | printk("%s: could not set ts feed\n", dev->name); |
| 963 | priv->demux->release_ts_feed(priv->demux, priv->tsfeed); | 966 | priv->demux->release_ts_feed(priv->demux, priv->tsfeed); |
| 964 | priv->tsfeed = NULL; | 967 | priv->tsfeed = NULL; |
| 965 | return ret; | 968 | goto error; |
| 966 | } | 969 | } |
| 967 | 970 | ||
| 968 | dprintk("%s: start filtering\n", __FUNCTION__); | 971 | dprintk("%s: start filtering\n", __FUNCTION__); |
| 969 | priv->tsfeed->start_filtering(priv->tsfeed); | 972 | priv->tsfeed->start_filtering(priv->tsfeed); |
| 970 | } else | 973 | } else |
| 971 | return -EINVAL; | 974 | ret = -EINVAL; |
| 972 | 975 | ||
| 973 | return 0; | 976 | error: |
| 977 | up(&priv->mutex); | ||
| 978 | return ret; | ||
| 974 | } | 979 | } |
| 975 | 980 | ||
| 976 | static int dvb_net_feed_stop(struct net_device *dev) | 981 | static int dvb_net_feed_stop(struct net_device *dev) |
| 977 | { | 982 | { |
| 978 | struct dvb_net_priv *priv = dev->priv; | 983 | struct dvb_net_priv *priv = dev->priv; |
| 979 | int i; | 984 | int i, ret = 0; |
| 980 | 985 | ||
| 981 | dprintk("%s\n", __FUNCTION__); | 986 | dprintk("%s\n", __FUNCTION__); |
| 987 | down(&priv->mutex); | ||
| 982 | if (priv->feedtype == DVB_NET_FEEDTYPE_MPE) { | 988 | if (priv->feedtype == DVB_NET_FEEDTYPE_MPE) { |
| 983 | if (priv->secfeed) { | 989 | if (priv->secfeed) { |
| 984 | if (priv->secfeed->is_filtering) { | 990 | if (priv->secfeed->is_filtering) { |
| @@ -1019,8 +1025,9 @@ static int dvb_net_feed_stop(struct net_device *dev) | |||
| 1019 | else | 1025 | else |
| 1020 | printk("%s: no ts feed to stop\n", dev->name); | 1026 | printk("%s: no ts feed to stop\n", dev->name); |
| 1021 | } else | 1027 | } else |
| 1022 | return -EINVAL; | 1028 | ret = -EINVAL; |
| 1023 | return 0; | 1029 | up(&priv->mutex); |
| 1030 | return ret; | ||
| 1024 | } | 1031 | } |
| 1025 | 1032 | ||
| 1026 | 1033 | ||
| @@ -1044,8 +1051,8 @@ static void wq_set_multicast_list (void *data) | |||
| 1044 | struct dvb_net_priv *priv = dev->priv; | 1051 | struct dvb_net_priv *priv = dev->priv; |
| 1045 | 1052 | ||
| 1046 | dvb_net_feed_stop(dev); | 1053 | dvb_net_feed_stop(dev); |
| 1047 | |||
| 1048 | priv->rx_mode = RX_MODE_UNI; | 1054 | priv->rx_mode = RX_MODE_UNI; |
| 1055 | spin_lock_bh(&dev->xmit_lock); | ||
| 1049 | 1056 | ||
| 1050 | if (dev->flags & IFF_PROMISC) { | 1057 | if (dev->flags & IFF_PROMISC) { |
| 1051 | dprintk("%s: promiscuous mode\n", dev->name); | 1058 | dprintk("%s: promiscuous mode\n", dev->name); |
| @@ -1070,6 +1077,7 @@ static void wq_set_multicast_list (void *data) | |||
| 1070 | } | 1077 | } |
| 1071 | } | 1078 | } |
| 1072 | 1079 | ||
| 1080 | spin_unlock_bh(&dev->xmit_lock); | ||
| 1073 | dvb_net_feed_start(dev); | 1081 | dvb_net_feed_start(dev); |
| 1074 | } | 1082 | } |
| 1075 | 1083 | ||
| @@ -1200,6 +1208,7 @@ static int dvb_net_add_if(struct dvb_net *dvbnet, u16 pid, u8 feedtype) | |||
| 1200 | 1208 | ||
| 1201 | INIT_WORK(&priv->set_multicast_list_wq, wq_set_multicast_list, net); | 1209 | INIT_WORK(&priv->set_multicast_list_wq, wq_set_multicast_list, net); |
| 1202 | INIT_WORK(&priv->restart_net_feed_wq, wq_restart_net_feed, net); | 1210 | INIT_WORK(&priv->restart_net_feed_wq, wq_restart_net_feed, net); |
| 1211 | init_MUTEX(&priv->mutex); | ||
| 1203 | 1212 | ||
| 1204 | net->base_addr = pid; | 1213 | net->base_addr = pid; |
| 1205 | 1214 | ||
