Mailing List archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[linux-dvb] Re: [PATCH] fix oops from removing running dvb_net



> Thanks!
> 
> I just tried the joint patch and unfortunately it has the same problems 
> as the last version from Jon Burgess.

!!! There must be some systematic error maybe

> Steps to reproduce it:
> - apply the joint patch to current dvb-kernel, resolve the one
> conflict in av7110 manually (no big deal)

> - recompile & load the driver
> 
> Now "szap" a channel, the usage count of "dvb-ttpci" stays 0! If you 
> stop "szap", then the usage count drops to "-3" (ie. the number of 
> filters that were set by "szap".)

I can't reproduce it this way! Do you use special szap or some
particular channel with certain properties (low/no signal)?

If I szap to some normal and active channel, the dvb-ttpci
usage count rises to 3 and after ctrl-c stopping szap it drops to 0
as it is expected. I will inspect the code for possible leakages

here is attached joint05a.patch, that should differ to the previous
patch only with the av7110 minor issue, however the -3 usagecount
fix you observed isn't attempted there but still we can try it 
just to sync to the latest code

> Apparently the setting of the filters does not increase the usage counr. 8-/

that's right, filter usage is no more increasing count number, but the
true module inter-dependency as seen from dvb-core is used, following 
the Jon's approach   

Emard
diff -pur dvb-kernel.orig/linux/drivers/media/dvb/b2c2/skystar2.c dvb-kernel/linux/drivers/media/dvb/b2c2/skystar2.c
--- dvb-kernel.orig/linux/drivers/media/dvb/b2c2/skystar2.c	Sun Dec 28 01:30:31 2003
+++ dvb-kernel/linux/drivers/media/dvb/b2c2/skystar2.c	Sun Dec 28 01:27:58 2003
@@ -2243,7 +2243,7 @@ static int skystar2_probe(struct pci_dev
 	if (driver_initialize(pdev) != 0)
 		return -ENODEV;
 
-	dvb_register_adapter(&dvb_adapter, skystar2_pci_driver.name);
+	dvb_register_adapter(&dvb_adapter, skystar2_pci_driver.name, THIS_MODULE);
 
 	if (dvb_adapter == NULL) {
 		printk("%s: Error registering DVB adapter\n", __FUNCTION__);
diff -pur dvb-kernel.orig/linux/drivers/media/dvb/bt8xx/dvb-bt8xx.c dvb-kernel/linux/drivers/media/dvb/bt8xx/dvb-bt8xx.c
--- dvb-kernel.orig/linux/drivers/media/dvb/bt8xx/dvb-bt8xx.c	Sun Dec 28 01:30:31 2003
+++ dvb-kernel/linux/drivers/media/dvb/bt8xx/dvb-bt8xx.c	Sun Dec 28 01:27:58 2003
@@ -321,7 +321,7 @@ static int __init dvb_bt8xx_load_card( s
 	
 	}
 
-	if ((result = dvb_register_adapter(&card->dvb_adapter, card->card_name)) < 0) {
+	if ((result = dvb_register_adapter(&card->dvb_adapter, card->card_name, THIS_MODULE)) < 0) {
 	
 		printk("dvb_bt8xx: dvb_register_adapter failed (errno = %d)\n", result);
 		
diff -pur dvb-kernel.orig/linux/drivers/media/dvb/dvb-core/dmxdev.c dvb-kernel/linux/drivers/media/dvb/dvb-core/dmxdev.c
--- dvb-kernel.orig/linux/drivers/media/dvb/dvb-core/dmxdev.c	Sun Dec 28 01:30:31 2003
+++ dvb-kernel/linux/drivers/media/dvb/dvb-core/dmxdev.c	Sun Dec 28 01:27:58 2003
@@ -250,6 +250,7 @@ static int dvb_dvr_release(struct inode 
 		}
 	}
 	up(&dmxdev->mutex);
+	dvb_device_release(dvbdev);
 	return 0;
 }
 
@@ -992,8 +993,14 @@ static int dvb_demux_release(struct inod
 {
 	struct dmxdev_filter *dmxdevfilter = dvb_dmxdev_file_to_filter(file);
 	struct dmxdev *dmxdev = dmxdevfilter->dev;
+	struct dvb_device *dvbdev= dmxdev->dvbdev;
+	int ret;
 
-	return dvb_dmxdev_filter_free(dmxdev, dmxdevfilter);
+	ret = dvb_dmxdev_filter_free(dmxdev, dmxdevfilter);
+	if (!ret) {
+	        dvb_device_release(dvbdev);
+	}
+	return ret;
 }
 
 
diff -pur dvb-kernel.orig/linux/drivers/media/dvb/dvb-core/dvb_net.c dvb-kernel/linux/drivers/media/dvb/dvb-core/dvb_net.c
--- dvb-kernel.orig/linux/drivers/media/dvb/dvb-core/dvb_net.c	Sun Dec 28 01:30:31 2003
+++ dvb-kernel/linux/drivers/media/dvb/dvb-core/dvb_net.c	Sun Dec 28 01:27:58 2003
@@ -306,7 +306,7 @@ static int dvb_net_feed_start(struct net
 	return 0;
 }
 
-static void dvb_net_feed_stop(struct net_device *dev)
+static int dvb_net_feed_stop(struct net_device *dev)
 {
 	struct dvb_net_priv *priv = (struct dvb_net_priv*) dev->priv;
 	int i;
@@ -337,7 +337,11 @@ static void dvb_net_feed_stop(struct net
 		priv->demux->release_section_feed(priv->demux, priv->secfeed);
 		priv->secfeed=0;
 	} else
+	{
 		printk("%s: no feed to stop\n", dev->name);
+		return -1;
+	}
+	return 0;
 }
 
 
@@ -360,7 +364,8 @@ static void wq_set_multicast_list (void 
 	struct net_device *dev = data;
 	struct dvb_net_priv *priv = (struct dvb_net_priv*) dev->priv;
 
-	dvb_net_feed_stop(dev);
+	if(dvb_net_feed_stop(dev))
+		return; // no feed to stop
 
 	priv->rx_mode = RX_MODE_UNI;
 	
@@ -387,8 +392,8 @@ static void wq_set_multicast_list (void 
 		}
 	}
 
-		dvb_net_feed_start(dev);
-	}
+	dvb_net_feed_start(dev);
+}
 
 
 static void dvb_net_set_multicast_list (struct net_device *dev)
@@ -592,6 +597,11 @@ static int dvb_net_remove_if(struct dvb_
 	if (priv->in_use)
 		return -EBUSY;
 
+	if (netif_running(&dvbnet->device[num]))
+	{
+		printk("dvb_net.c: WARNING attempt to remove netif in use\n");
+		return -EBUSY;
+	}
 	dvb_net_stop(&dvbnet->device[num]);
 	flush_scheduled_work();
 	kfree(priv);
@@ -637,9 +647,18 @@ static int dvb_net_do_ioctl(struct inode
 		
 		if (!capable(CAP_SYS_ADMIN))
 			return -EPERM;
+		if (!dvbdev)
+			return -ENODEV;
+		if (!dvbdev->adapter)
+			return -ENODEV;
+		if (!try_module_get(dvbdev->adapter->module))
+			return -ENODEV;
 		result=dvb_net_add_if(dvbnet, dvbnetif->pid);
 		if (result<0)
+		{
+			module_put(dvbdev->adapter->module);
 			return result;
+		}
 		dvbnetif->if_num=result;
 		break;
 	}
@@ -649,19 +668,46 @@ static int dvb_net_do_ioctl(struct inode
 		struct dvb_net_priv *priv_data;
 		struct dvb_net_if *dvbnetif=(struct dvb_net_if *)parg;
 
-		if (dvbnetif->if_num >= DVB_NET_DEVICES_MAX ||
-		    !dvbnet->state[dvbnetif->if_num])
+		if(dvbnetif->if_num >= DVB_NET_DEVICES_MAX)
 			return -EFAULT;
-
+		if(!dvbnet)
+			return -EFAULT;
+		if(!dvbnet->state)
+			return -EFAULT;
+		if(!dvbnet->state[dvbnetif->if_num])
+			return -EFAULT;
+		if(!dvbnet->device)
+			return -EFAULT;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
 		netdev=(struct net_device*)&dvbnet->device[dvbnetif->if_num];
+#else
+		netdev=(struct net_device*)dvbnet->device[dvbnetif->if_num];
+#endif
+		if(!netdev)
+			return -EFAULT;		
 		priv_data=(struct dvb_net_priv*)netdev->priv;
 		dvbnetif->pid=priv_data->pid;
 		break;
 	}
 	case NET_REMOVE_IF:
+	{
+		unsigned int deviceno = (unsigned int) (long) parg;
+		int result;
+
 		if (!capable(CAP_SYS_ADMIN))
 			return -EPERM;
-		return dvb_net_remove_if(dvbnet, (int) (long) parg);
+
+		if(deviceno >= DVB_NET_DEVICES_MAX)
+			return -EFAULT;
+
+		if(!dvbnet->state[deviceno])
+			return -EFAULT;
+
+		result = dvb_net_remove_if(dvbnet, deviceno);
+		if(result == 0)
+			module_put(dvbdev->adapter->module);
+		return result;
+	}
 	default:
 		return -EINVAL;
 	}
diff -pur dvb-kernel.orig/linux/drivers/media/dvb/dvb-core/dvbdev.c dvb-kernel/linux/drivers/media/dvb/dvb-core/dvbdev.c
--- dvb-kernel.orig/linux/drivers/media/dvb/dvb-core/dvbdev.c	Sun Dec 28 01:30:31 2003
+++ dvb-kernel/linux/drivers/media/dvb/dvb-core/dvbdev.c	Sun Dec 28 01:27:58 2003
@@ -79,26 +79,42 @@ static struct dvb_device* dvbdev_find_de
 static int dvb_device_open(struct inode *inode, struct file *file)
 {
 	struct dvb_device *dvbdev;
+	struct file_operations *old_fops;
+	int err = -EOPNOTSUPP;
 	
 	dvbdev = dvbdev_find_device (iminor(inode));
 
-	if (dvbdev && dvbdev->fops) {
-		int err = 0;
-		struct file_operations *old_fops;
-
-		file->private_data = dvbdev;
-		old_fops = file->f_op;
-                file->f_op = fops_get(dvbdev->fops);
-                if(file->f_op->open)
-                        err = file->f_op->open(inode,file);
-                if (err) {
-                        fops_put(file->f_op);
-                        file->f_op = fops_get(old_fops);
-                }
-                fops_put(old_fops);
-                return err;
+	if (!dvbdev)
+		return -ENODEV;
+	if (!dvbdev->fops)
+		return -ENODEV;
+	if (!dvbdev->adapter)
+		return -ENODEV;
+	if (!try_module_get(dvbdev->adapter->module))
+	        return -ENODEV;
+
+	file->private_data = dvbdev;
+	old_fops = file->f_op;
+	file->f_op = fops_get(dvbdev->fops);
+	if(file->f_op->open)
+	       err = file->f_op->open(inode,file);
+	if (err) {
+	        fops_put(file->f_op);
+	        file->f_op = fops_get(old_fops);
+	        module_put(dvbdev->adapter->module);
 	}
-	return -ENODEV;
+	fops_put(old_fops);
+	return err;
+}
+
+/* Needs to be to drop module count when not 
+ * using dvb_generic_release.
+ */
+void dvb_device_release(struct dvb_device *dvbdev)
+{
+        if (dvbdev && dvbdev->adapter) {
+	        module_put(dvbdev->adapter->module);        
+        }
 }
 
 
@@ -150,6 +166,7 @@ int dvb_generic_release(struct inode *in
 	}
 	
 	dvbdev->users++;
+	dvb_device_release(dvbdev);
 	return 0;
 }
 
@@ -287,7 +304,8 @@ skip:
 }
 
 
-int dvb_register_adapter(struct dvb_adapter **padap, const char *name)
+int dvb_register_adapter(struct dvb_adapter **padap, const char *name,
+			 struct module *module)
 {
 	struct dvb_adapter *adap;
 	int num;
@@ -321,6 +339,7 @@ int dvb_register_adapter(struct dvb_adap
 #endif
 	adap->num = num;
 	adap->name = name;
+	adap->module = module;
 
 	list_add_tail (&adap->list_head, &dvb_adapter_list);
 
diff -pur dvb-kernel.orig/linux/drivers/media/dvb/dvb-core/dvbdev.h dvb-kernel/linux/drivers/media/dvb/dvb-core/dvbdev.h
--- dvb-kernel.orig/linux/drivers/media/dvb/dvb-core/dvbdev.h	Sun Dec 28 01:30:31 2003
+++ dvb-kernel/linux/drivers/media/dvb/dvb-core/dvbdev.h	Sun Dec 28 01:27:58 2003
@@ -52,6 +52,7 @@ struct dvb_adapter {
 	struct list_head device_list;
 	const char *name;
 	u8 proposed_mac [6];
+	struct module *module;
 };
 
 
@@ -79,7 +80,10 @@ struct dvb_device {
 };
 
 
-extern int dvb_register_adapter (struct dvb_adapter **padap, const char *name);
+extern int dvb_register_adapter (struct dvb_adapter **padap, 
+				 const char *name,
+				 struct module *module);
+
 extern int dvb_unregister_adapter (struct dvb_adapter *adap);
 
 extern int dvb_register_device (struct dvb_adapter *adap,
@@ -92,6 +96,7 @@ extern void dvb_unregister_device (struc
 
 extern int dvb_generic_open (struct inode *inode, struct file *file);
 extern int dvb_generic_release (struct inode *inode, struct file *file);
+extern void dvb_device_release(struct dvb_device *dvbdev);
 extern int dvb_generic_ioctl (struct inode *inode, struct file *file,
 			      unsigned int cmd, unsigned long arg);
 #endif /* #ifndef _DVBDEV_H_ */
diff -pur dvb-kernel.orig/linux/drivers/media/dvb/ttpci/av7110.c dvb-kernel/linux/drivers/media/dvb/ttpci/av7110.c
--- dvb-kernel.orig/linux/drivers/media/dvb/ttpci/av7110.c	Sun Dec 28 01:30:31 2003
+++ dvb-kernel/linux/drivers/media/dvb/ttpci/av7110.c	Sun Dec 28 01:30:04 2003
@@ -4604,7 +4604,7 @@ static int av7110_attach (struct saa7146
 	av7110->dev=(struct saa7146_dev *)dev;
 	(struct av7110*)dev->ext_priv = av7110;
 
-	dvb_register_adapter(&av7110->dvb_adapter, av7110->card_name);
+	dvb_register_adapter(&av7110->dvb_adapter, av7110->card_name, THIS_MODULE);
 
 	/* the Siemens DVB needs this if you want to have the i2c chips
 	   get recognized before the main driver is fully loaded */
Only in dvb-kernel/linux/drivers/media/dvb/ttpci: av7110.c.orig
Only in dvb-kernel/linux/drivers/media/dvb/ttpci: av7110.c.rej
Only in dvb-kernel/linux/drivers/media/dvb/ttpci: av7110.c~
diff -pur dvb-kernel.orig/linux/drivers/media/dvb/ttpci/budget-av.c dvb-kernel/linux/drivers/media/dvb/ttpci/budget-av.c
--- dvb-kernel.orig/linux/drivers/media/dvb/ttpci/budget-av.c	Sun Dec 28 01:30:31 2003
+++ dvb-kernel/linux/drivers/media/dvb/ttpci/budget-av.c	Sun Dec 28 01:27:58 2003
@@ -204,7 +204,7 @@ static int budget_av_attach (struct saa7
 
 	memset(budget_av, 0, sizeof(struct budget_av));
 
-	if ((err = ttpci_budget_init(&budget_av->budget, dev, info))) {
+	if ((err = ttpci_budget_init(&budget_av->budget, dev, info, THIS_MODULE))) {
 		kfree(budget_av);
 		return err;
 	}
diff -pur dvb-kernel.orig/linux/drivers/media/dvb/ttpci/budget-ci.c dvb-kernel/linux/drivers/media/dvb/ttpci/budget-ci.c
--- dvb-kernel.orig/linux/drivers/media/dvb/ttpci/budget-ci.c	Sun Dec 28 01:30:31 2003
+++ dvb-kernel/linux/drivers/media/dvb/ttpci/budget-ci.c	Sun Dec 28 01:27:58 2003
@@ -250,7 +250,7 @@ static int budget_ci_attach (struct saa7
 
 	DEB_EE(("budget_ci: %p\n", budget_ci));
 
-	if ((err = ttpci_budget_init (&budget_ci->budget, dev, info))) {
+	if ((err = ttpci_budget_init (&budget_ci->budget, dev, info, THIS_MODULE))) {
 		kfree (budget_ci);
 		return err;
 	}
diff -pur dvb-kernel.orig/linux/drivers/media/dvb/ttpci/budget-core.c dvb-kernel/linux/drivers/media/dvb/ttpci/budget-core.c
--- dvb-kernel.orig/linux/drivers/media/dvb/ttpci/budget-core.c	Sun Dec 28 01:30:31 2003
+++ dvb-kernel/linux/drivers/media/dvb/ttpci/budget-core.c	Sun Dec 28 01:27:58 2003
@@ -195,7 +195,8 @@ static int master_xfer (struct dvb_i2c_b
 
 int ttpci_budget_init (struct budget *budget,
 		       struct saa7146_dev* dev,
-		       struct saa7146_pci_extension_data *info)
+		       struct saa7146_pci_extension_data *info,
+		       struct module *module)
 {
 	int length = TS_WIDTH*TS_HEIGHT;
 	int ret = 0;
@@ -208,7 +209,7 @@ int ttpci_budget_init (struct budget *bu
 	budget->card = bi;
 	budget->dev = (struct saa7146_dev *) dev;
 
-	dvb_register_adapter(&budget->dvb_adapter, budget->card->name);
+	dvb_register_adapter(&budget->dvb_adapter, budget->card->name, module);
 
 	/* set dd1 stream a & b */
       	saa7146_write(dev, DD1_STREAM_B, 0x00000000);
diff -pur dvb-kernel.orig/linux/drivers/media/dvb/ttpci/budget-patch.c dvb-kernel/linux/drivers/media/dvb/ttpci/budget-patch.c
--- dvb-kernel.orig/linux/drivers/media/dvb/ttpci/budget-patch.c	Sun Dec 28 01:30:31 2003
+++ dvb-kernel/linux/drivers/media/dvb/ttpci/budget-patch.c	Sun Dec 28 01:27:58 2003
@@ -172,7 +172,7 @@ static int budget_patch_attach (struct s
 
         DEB_EE(("budget: %p\n",budget));
 
-        if ((err = ttpci_budget_init (budget, dev, info))) {
+        if ((err = ttpci_budget_init (budget, dev, info, THIS_MODULE))) {
                 kfree (budget);
                 return err;
         }
diff -pur dvb-kernel.orig/linux/drivers/media/dvb/ttpci/budget.c dvb-kernel/linux/drivers/media/dvb/ttpci/budget.c
--- dvb-kernel.orig/linux/drivers/media/dvb/ttpci/budget.c	Sun Dec 28 01:30:31 2003
+++ dvb-kernel/linux/drivers/media/dvb/ttpci/budget.c	Sun Dec 28 01:27:58 2003
@@ -154,7 +154,7 @@ static int budget_attach (struct saa7146
 
 	DEB_EE(("dev:%p, info:%p, budget:%p\n",dev,info,budget));
 
-	if ((err = ttpci_budget_init (budget, dev, info))) {
+	if ((err = ttpci_budget_init (budget, dev, info, THIS_MODULE))) {
 		printk("==> failed\n");
 		kfree (budget);
 		return err;
diff -pur dvb-kernel.orig/linux/drivers/media/dvb/ttpci/budget.h dvb-kernel/linux/drivers/media/dvb/ttpci/budget.h
--- dvb-kernel.orig/linux/drivers/media/dvb/ttpci/budget.h	Sun Dec 28 01:30:31 2003
+++ dvb-kernel/linux/drivers/media/dvb/ttpci/budget.h	Sun Dec 28 01:27:58 2003
@@ -77,7 +77,9 @@ static struct saa7146_pci_extension_data
 
 extern int ttpci_budget_init (struct budget *budget,
 			      struct saa7146_dev* dev,
-			      struct saa7146_pci_extension_data *info);
+			      struct saa7146_pci_extension_data *info,
+			      struct module *module);
+
 extern int ttpci_budget_deinit (struct budget *budget);
 extern void ttpci_budget_irq10_handler (struct saa7146_dev* dev, u32 *isr);
 
diff -pur dvb-kernel.orig/linux/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c dvb-kernel/linux/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c
--- dvb-kernel.orig/linux/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c	Sun Dec 28 01:30:31 2003
+++ dvb-kernel/linux/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c	Sun Dec 28 01:27:58 2003
@@ -1130,7 +1130,8 @@ static int ttusb_probe(struct usb_interf
 	up(&ttusb->sem);
 
 	dvb_register_adapter(&ttusb->adapter,
-			     "Technotrend/Hauppauge Nova-USB");
+			     "Technotrend/Hauppauge Nova-USB", 
+			     THIS_MODULE);
 
 	dvb_register_i2c_bus(ttusb_i2c_xfer, ttusb, ttusb->adapter, 0);
 	dvb_add_frontend_ioctls(ttusb->adapter, ttusb_lnb_ioctl, NULL,
diff -pur dvb-kernel.orig/linux/drivers/media/dvb/ttusb-dec/ttusb_dec.c dvb-kernel/linux/drivers/media/dvb/ttusb-dec/ttusb_dec.c
--- dvb-kernel.orig/linux/drivers/media/dvb/ttusb-dec/ttusb_dec.c	Sun Dec 28 01:30:31 2003
+++ dvb-kernel/linux/drivers/media/dvb/ttusb-dec/ttusb_dec.c	Sun Dec 28 01:27:58 2003
@@ -1149,7 +1149,7 @@ static int ttusb_dec_init_dvb(struct ttu
 
 	dprintk("%s\n", __FUNCTION__);
 
-	if ((result = dvb_register_adapter(&dec->adapter, dec->model_name)) < 0) {
+	if ((result = dvb_register_adapter(&dec->adapter, dec->model_name, THIS_MODULE)) < 0) {
 		printk("%s: dvb_register_adapter failed: error %d\n",
 		       __FUNCTION__, result);
 
Only in dvb-kernel/linux/drivers/media/dvb/ttusb-dec: ttusb_dec.c.orig

Home | Main Index | Thread Index