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