[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>

authored by Ralph Metzler and committed by Linus Torvalds 1130ca45 9b9225f0

+20 -11
+20 -11
drivers/media/dvb/dvb-core/dvb_net.c
··· 151 151 unsigned char ule_bridged; /* Whether the ULE_BRIDGED extension header was found. */ 152 152 int ule_sndu_remain; /* Nr. of bytes still required for current ULE SNDU. */ 153 153 unsigned long ts_count; /* Current ts cell counter. */ 154 + 155 + struct semaphore mutex; 154 156 }; 155 157 156 158 ··· 883 881 884 882 static int dvb_net_feed_start(struct net_device *dev) 885 883 { 886 - int ret, i; 884 + int ret = 0, i; 887 885 struct dvb_net_priv *priv = dev->priv; 888 886 struct dmx_demux *demux = priv->demux; 889 887 unsigned char *mac = (unsigned char *) dev->dev_addr; 890 888 891 889 dprintk("%s: rx_mode %i\n", __FUNCTION__, priv->rx_mode); 890 + down(&priv->mutex); 892 891 if (priv->tsfeed || priv->secfeed || priv->secfilter || priv->multi_secfilter[0]) 893 892 printk("%s: BUG %d\n", __FUNCTION__, __LINE__); 894 893 ··· 903 900 dvb_net_sec_callback); 904 901 if (ret<0) { 905 902 printk("%s: could not allocate section feed\n", dev->name); 906 - return ret; 903 + goto error; 907 904 } 908 905 909 906 ret = priv->secfeed->set(priv->secfeed, priv->pid, 32768, 1); ··· 912 909 printk("%s: could not set section feed\n", dev->name); 913 910 priv->demux->release_section_feed(priv->demux, priv->secfeed); 914 911 priv->secfeed=NULL; 915 - return ret; 912 + goto error; 916 913 } 917 914 918 915 if (priv->rx_mode != RX_MODE_PROMISC) { ··· 951 948 ret = demux->allocate_ts_feed(demux, &priv->tsfeed, dvb_net_ts_callback); 952 949 if (ret < 0) { 953 950 printk("%s: could not allocate ts feed\n", dev->name); 954 - return ret; 951 + goto error; 955 952 } 956 953 957 954 /* Set netdevice pointer for ts decaps callback. */ ··· 965 962 printk("%s: could not set ts feed\n", dev->name); 966 963 priv->demux->release_ts_feed(priv->demux, priv->tsfeed); 967 964 priv->tsfeed = NULL; 968 - return ret; 965 + goto error; 969 966 } 970 967 971 968 dprintk("%s: start filtering\n", __FUNCTION__); 972 969 priv->tsfeed->start_filtering(priv->tsfeed); 973 970 } else 974 - return -EINVAL; 971 + ret = -EINVAL; 975 972 976 - return 0; 973 + error: 974 + up(&priv->mutex); 975 + return ret; 977 976 } 978 977 979 978 static int dvb_net_feed_stop(struct net_device *dev) 980 979 { 981 980 struct dvb_net_priv *priv = dev->priv; 982 - int i; 981 + int i, ret = 0; 983 982 984 983 dprintk("%s\n", __FUNCTION__); 984 + down(&priv->mutex); 985 985 if (priv->feedtype == DVB_NET_FEEDTYPE_MPE) { 986 986 if (priv->secfeed) { 987 987 if (priv->secfeed->is_filtering) { ··· 1025 1019 else 1026 1020 printk("%s: no ts feed to stop\n", dev->name); 1027 1021 } else 1028 - return -EINVAL; 1029 - return 0; 1022 + ret = -EINVAL; 1023 + up(&priv->mutex); 1024 + return ret; 1030 1025 } 1031 1026 1032 1027 ··· 1051 1044 struct dvb_net_priv *priv = dev->priv; 1052 1045 1053 1046 dvb_net_feed_stop(dev); 1054 - 1055 1047 priv->rx_mode = RX_MODE_UNI; 1048 + spin_lock_bh(&dev->xmit_lock); 1056 1049 1057 1050 if (dev->flags & IFF_PROMISC) { 1058 1051 dprintk("%s: promiscuous mode\n", dev->name); ··· 1077 1070 } 1078 1071 } 1079 1072 1073 + spin_unlock_bh(&dev->xmit_lock); 1080 1074 dvb_net_feed_start(dev); 1081 1075 } 1082 1076 ··· 1208 1200 1209 1201 INIT_WORK(&priv->set_multicast_list_wq, wq_set_multicast_list, net); 1210 1202 INIT_WORK(&priv->restart_net_feed_wq, wq_restart_net_feed, net); 1203 + init_MUTEX(&priv->mutex); 1211 1204 1212 1205 net->base_addr = pid; 1213 1206