linux-media.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/7] Fix remaining issues with em28xx device removal
@ 2014-01-12 23:00 Mauro Carvalho Chehab
  2014-01-12 23:00 ` [PATCH 1/7] em28xx-audio: fix return code on device disconnect Mauro Carvalho Chehab
                   ` (7 more replies)
  0 siblings, 8 replies; 40+ messages in thread
From: Mauro Carvalho Chehab @ 2014-01-12 23:00 UTC (permalink / raw)
  Cc: Mauro Carvalho Chehab, Linux Media Mailing List,
	Mauro Carvalho Chehab

Even after Frank's series, there are several issues with device module
removal.

This series fix those issues, by use kref to deallocate the common
data (struct em28xx *dev).

It also fixes a circular deppendency inside em28xx-audio.

Mauro Carvalho Chehab (7):
  em28xx-audio: fix return code on device disconnect
  em28xx-audio: simplify error handling
  em28xx: Only deallocate struct em28xx after finishing all extensions
  em28xx-audio: disconnect before freeing URBs
  em28xx-audio: remove a deplock circular dependency
  em28xx: print a message at disconnect
  em28xx: Fix usb diconnect logic

 drivers/media/usb/em28xx/em28xx-audio.c | 47 ++++++++++++++++++++-------------
 drivers/media/usb/em28xx/em28xx-cards.c | 41 +++++++++++++---------------
 drivers/media/usb/em28xx/em28xx-dvb.c   |  7 ++++-
 drivers/media/usb/em28xx/em28xx-input.c | 10 ++++++-
 drivers/media/usb/em28xx/em28xx-video.c | 13 ++++-----
 drivers/media/usb/em28xx/em28xx.h       |  9 +++++--
 6 files changed, 76 insertions(+), 51 deletions(-)

-- 
1.8.3.1


^ permalink raw reply	[flat|nested] 40+ messages in thread

* [PATCH 1/7] em28xx-audio: fix return code on device disconnect
  2014-01-12 23:00 [PATCH 0/7] Fix remaining issues with em28xx device removal Mauro Carvalho Chehab
@ 2014-01-12 23:00 ` Mauro Carvalho Chehab
  2014-01-13 18:38   ` Frank Schäfer
  2014-01-12 23:00 ` [PATCH 2/7] em28xx-audio: simplify error handling Mauro Carvalho Chehab
                   ` (6 subsequent siblings)
  7 siblings, 1 reply; 40+ messages in thread
From: Mauro Carvalho Chehab @ 2014-01-12 23:00 UTC (permalink / raw)
  Cc: Mauro Carvalho Chehab, Linux Media Mailing List,
	Mauro Carvalho Chehab

Alsa has an special non-negative return code to indicate device removal
at snd_em28xx_capture_pointer(). Use it, instead of an error code.

Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
---
 drivers/media/usb/em28xx/em28xx-audio.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/media/usb/em28xx/em28xx-audio.c b/drivers/media/usb/em28xx/em28xx-audio.c
index f3e320098f79..47766b796acb 100644
--- a/drivers/media/usb/em28xx/em28xx-audio.c
+++ b/drivers/media/usb/em28xx/em28xx-audio.c
@@ -434,7 +434,7 @@ static snd_pcm_uframes_t snd_em28xx_capture_pointer(struct snd_pcm_substream
 
 	dev = snd_pcm_substream_chip(substream);
 	if (dev->disconnected)
-		return -ENODEV;
+		return SNDRV_PCM_POS_XRUN;
 
 	spin_lock_irqsave(&dev->adev.slock, flags);
 	hwptr_done = dev->adev.hwptr_done_capture;
-- 
1.8.3.1


^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [PATCH 2/7] em28xx-audio: simplify error handling
  2014-01-12 23:00 [PATCH 0/7] Fix remaining issues with em28xx device removal Mauro Carvalho Chehab
  2014-01-12 23:00 ` [PATCH 1/7] em28xx-audio: fix return code on device disconnect Mauro Carvalho Chehab
@ 2014-01-12 23:00 ` Mauro Carvalho Chehab
  2014-01-13 18:41   ` Frank Schäfer
  2014-01-12 23:00 ` [PATCH 3/7] em28xx: Only deallocate struct em28xx after finishing all extensions Mauro Carvalho Chehab
                   ` (5 subsequent siblings)
  7 siblings, 1 reply; 40+ messages in thread
From: Mauro Carvalho Chehab @ 2014-01-12 23:00 UTC (permalink / raw)
  Cc: Mauro Carvalho Chehab, Linux Media Mailing List,
	Mauro Carvalho Chehab

Cleanup the error handling code at em28xx-audio init.

Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
---
 drivers/media/usb/em28xx/em28xx-audio.c | 27 ++++++++++++++-------------
 1 file changed, 14 insertions(+), 13 deletions(-)

diff --git a/drivers/media/usb/em28xx/em28xx-audio.c b/drivers/media/usb/em28xx/em28xx-audio.c
index 47766b796acb..97d9105e6830 100644
--- a/drivers/media/usb/em28xx/em28xx-audio.c
+++ b/drivers/media/usb/em28xx/em28xx-audio.c
@@ -893,10 +893,8 @@ static int em28xx_audio_init(struct em28xx *dev)
 	adev->udev = dev->udev;
 
 	err = snd_pcm_new(card, "Em28xx Audio", 0, 0, 1, &pcm);
-	if (err < 0) {
-		snd_card_free(card);
-		return err;
-	}
+	if (err < 0)
+		goto card_free;
 
 	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_em28xx_pcm_capture);
 	pcm->info_flags = 0;
@@ -927,20 +925,23 @@ static int em28xx_audio_init(struct em28xx *dev)
 	}
 
 	err = em28xx_audio_urb_init(dev);
-	if (err) {
-		snd_card_free(card);
-		return -ENODEV;
-	}
+	if (err)
+		goto card_free;
 
 	err = snd_card_register(card);
-	if (err < 0) {
-		em28xx_audio_free_urb(dev);
-		snd_card_free(card);
-		return err;
-	}
+	if (err < 0)
+		goto urb_free;
 
 	em28xx_info("Audio extension successfully initialized\n");
 	return 0;
+
+urb_free:
+	em28xx_audio_free_urb(dev);
+
+card_free:
+	snd_card_free(card);
+
+	return err;
 }
 
 static int em28xx_audio_fini(struct em28xx *dev)
-- 
1.8.3.1


^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [PATCH 3/7] em28xx: Only deallocate struct em28xx after finishing all extensions
  2014-01-12 23:00 [PATCH 0/7] Fix remaining issues with em28xx device removal Mauro Carvalho Chehab
  2014-01-12 23:00 ` [PATCH 1/7] em28xx-audio: fix return code on device disconnect Mauro Carvalho Chehab
  2014-01-12 23:00 ` [PATCH 2/7] em28xx-audio: simplify error handling Mauro Carvalho Chehab
@ 2014-01-12 23:00 ` Mauro Carvalho Chehab
  2014-01-13 19:02   ` Frank Schäfer
  2014-01-14 17:36   ` [PATCH v2] " Mauro Carvalho Chehab
  2014-01-12 23:00 ` [PATCH 4/7] em28xx-audio: disconnect before freeing URBs Mauro Carvalho Chehab
                   ` (4 subsequent siblings)
  7 siblings, 2 replies; 40+ messages in thread
From: Mauro Carvalho Chehab @ 2014-01-12 23:00 UTC (permalink / raw)
  Cc: Mauro Carvalho Chehab, Linux Media Mailing List,
	Mauro Carvalho Chehab

We can't free struct em28xx while one of the extensions is still
using it.

So, add a kref() to control it, freeing it only after the
extensions fini calls.

Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
---
 drivers/media/usb/em28xx/em28xx-audio.c |  5 ++++-
 drivers/media/usb/em28xx/em28xx-cards.c | 34 ++++++++++++++++-----------------
 drivers/media/usb/em28xx/em28xx-dvb.c   |  5 ++++-
 drivers/media/usb/em28xx/em28xx-input.c |  8 +++++++-
 drivers/media/usb/em28xx/em28xx-video.c | 11 +++++------
 drivers/media/usb/em28xx/em28xx.h       |  9 +++++++--
 6 files changed, 44 insertions(+), 28 deletions(-)

diff --git a/drivers/media/usb/em28xx/em28xx-audio.c b/drivers/media/usb/em28xx/em28xx-audio.c
index 97d9105e6830..8e959dae8358 100644
--- a/drivers/media/usb/em28xx/em28xx-audio.c
+++ b/drivers/media/usb/em28xx/em28xx-audio.c
@@ -878,6 +878,8 @@ static int em28xx_audio_init(struct em28xx *dev)
 
 	em28xx_info("Binding audio extension\n");
 
+	kref_get(&dev->ref);
+
 	printk(KERN_INFO "em28xx-audio.c: Copyright (C) 2006 Markus "
 			 "Rechberger\n");
 	printk(KERN_INFO
@@ -949,7 +951,7 @@ static int em28xx_audio_fini(struct em28xx *dev)
 	if (dev == NULL)
 		return 0;
 
-	if (dev->has_alsa_audio != 1) {
+	if (!dev->has_alsa_audio) {
 		/* This device does not support the extension (in this case
 		   the device is expecting the snd-usb-audio module or
 		   doesn't have analog audio support at all) */
@@ -963,6 +965,7 @@ static int em28xx_audio_fini(struct em28xx *dev)
 		dev->adev.sndcard = NULL;
 	}
 
+	kref_put(&dev->ref, em28xx_free_device);
 	return 0;
 }
 
diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c
index 3b332d527ccb..df92f417634a 100644
--- a/drivers/media/usb/em28xx/em28xx-cards.c
+++ b/drivers/media/usb/em28xx/em28xx-cards.c
@@ -2867,16 +2867,18 @@ static void flush_request_modules(struct em28xx *dev)
 	flush_work(&dev->request_module_wk);
 }
 
-/*
- * em28xx_release_resources()
- * unregisters the v4l2,i2c and usb devices
- * called when the device gets disconnected or at module unload
-*/
-void em28xx_release_resources(struct em28xx *dev)
+/**
+ * em28xx_release_resources() -  unregisters the v4l2,i2c and usb devices
+ *
+ * @ref: struct kref for em28xx device
+ *
+ * This is called when all extensions and em28xx core unregisters a device
+ */
+void em28xx_free_device(struct kref *ref)
 {
-	/*FIXME: I2C IR should be disconnected */
+	struct em28xx *dev = kref_to_dev(ref);
 
-	mutex_lock(&dev->lock);
+	em28xx_info("Freeing device\n");
 
 	if (dev->def_i2c_bus)
 		em28xx_i2c_unregister(dev, 1);
@@ -2887,9 +2889,10 @@ void em28xx_release_resources(struct em28xx *dev)
 	/* Mark device as unused */
 	clear_bit(dev->devno, &em28xx_devused);
 
-	mutex_unlock(&dev->lock);
-};
-EXPORT_SYMBOL_GPL(em28xx_release_resources);
+	kfree(dev->alt_max_pkt_size_isoc);
+	kfree(dev);
+}
+EXPORT_SYMBOL_GPL(em28xx_free_device);
 
 /*
  * em28xx_init_dev()
@@ -3342,6 +3345,8 @@ static int em28xx_usb_probe(struct usb_interface *interface,
 			    dev->dvb_xfer_bulk ? "bulk" : "isoc");
 	}
 
+	kref_init(&dev->ref);
+
 	request_modules(dev);
 
 	/* Should be the last thing to do, to avoid newer udev's to
@@ -3390,12 +3395,7 @@ static void em28xx_usb_disconnect(struct usb_interface *interface)
 
 	em28xx_close_extension(dev);
 
-	em28xx_release_resources(dev);
-
-	if (!dev->users) {
-		kfree(dev->alt_max_pkt_size_isoc);
-		kfree(dev);
-	}
+	kref_put(&dev->ref, em28xx_free_device);
 }
 
 static struct usb_driver em28xx_usb_driver = {
diff --git a/drivers/media/usb/em28xx/em28xx-dvb.c b/drivers/media/usb/em28xx/em28xx-dvb.c
index 5ea563e3f0e4..8674ae5fce06 100644
--- a/drivers/media/usb/em28xx/em28xx-dvb.c
+++ b/drivers/media/usb/em28xx/em28xx-dvb.c
@@ -1010,11 +1010,11 @@ static int em28xx_dvb_init(struct em28xx *dev)
 	em28xx_info("Binding DVB extension\n");
 
 	dvb = kzalloc(sizeof(struct em28xx_dvb), GFP_KERNEL);
-
 	if (dvb == NULL) {
 		em28xx_info("em28xx_dvb: memory allocation failed\n");
 		return -ENOMEM;
 	}
+	kref_get(&dev->ref);
 	dev->dvb = dvb;
 	dvb->fe[0] = dvb->fe[1] = NULL;
 
@@ -1442,6 +1442,7 @@ static int em28xx_dvb_init(struct em28xx *dev)
 	dvb->adapter.mfe_shared = mfe_shared;
 
 	em28xx_info("DVB extension successfully initialized\n");
+
 ret:
 	em28xx_set_mode(dev, EM28XX_SUSPEND);
 	mutex_unlock(&dev->lock);
@@ -1492,6 +1493,8 @@ static int em28xx_dvb_fini(struct em28xx *dev)
 		dev->dvb = NULL;
 	}
 
+	kref_put(&dev->ref, em28xx_free_device);
+
 	return 0;
 }
 
diff --git a/drivers/media/usb/em28xx/em28xx-input.c b/drivers/media/usb/em28xx/em28xx-input.c
index 61c061f3a476..33388b5922a0 100644
--- a/drivers/media/usb/em28xx/em28xx-input.c
+++ b/drivers/media/usb/em28xx/em28xx-input.c
@@ -676,6 +676,8 @@ static int em28xx_ir_init(struct em28xx *dev)
 		return 0;
 	}
 
+	kref_get(&dev->ref);
+
 	if (dev->board.buttons)
 		em28xx_init_buttons(dev);
 
@@ -814,7 +816,7 @@ static int em28xx_ir_fini(struct em28xx *dev)
 
 	/* skip detach on non attached boards */
 	if (!ir)
-		return 0;
+		goto ref_put;
 
 	if (ir->rc)
 		rc_unregister_device(ir->rc);
@@ -822,6 +824,10 @@ static int em28xx_ir_fini(struct em28xx *dev)
 	/* done */
 	kfree(ir);
 	dev->ir = NULL;
+
+ref_put:
+	kref_put(&dev->ref, em28xx_free_device);
+
 	return 0;
 }
 
diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c
index 587ff3fe9402..dc10cec772ba 100644
--- a/drivers/media/usb/em28xx/em28xx-video.c
+++ b/drivers/media/usb/em28xx/em28xx-video.c
@@ -1922,8 +1922,7 @@ static int em28xx_v4l2_fini(struct em28xx *dev)
 	v4l2_ctrl_handler_free(&dev->ctrl_handler);
 	v4l2_device_unregister(&dev->v4l2_dev);
 
-	if (dev->users)
-		em28xx_warn("Device is open ! Memory deallocation is deferred on last close.\n");
+	kref_put(&dev->ref, em28xx_free_device);
 
 	return 0;
 }
@@ -1945,11 +1944,9 @@ static int em28xx_v4l2_close(struct file *filp)
 	mutex_lock(&dev->lock);
 
 	if (dev->users == 1) {
-		/* free the remaining resources if device is disconnected */
-		if (dev->disconnected) {
-			kfree(dev->alt_max_pkt_size_isoc);
+		/* No sense to try to write to the device */
+		if (dev->disconnected)
 			goto exit;
-		}
 
 		/* Save some power by putting tuner to sleep */
 		v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_power, 0);
@@ -2201,6 +2198,8 @@ static int em28xx_v4l2_init(struct em28xx *dev)
 
 	em28xx_info("Registering V4L2 extension\n");
 
+	kref_get(&dev->ref);
+
 	mutex_lock(&dev->lock);
 
 	ret = v4l2_device_register(&dev->udev->dev, &dev->v4l2_dev);
diff --git a/drivers/media/usb/em28xx/em28xx.h b/drivers/media/usb/em28xx/em28xx.h
index 5d5d1b6f0294..d38c08e4da60 100644
--- a/drivers/media/usb/em28xx/em28xx.h
+++ b/drivers/media/usb/em28xx/em28xx.h
@@ -32,6 +32,7 @@
 #include <linux/workqueue.h>
 #include <linux/i2c.h>
 #include <linux/mutex.h>
+#include <linux/kref.h>
 #include <linux/videodev2.h>
 
 #include <media/videobuf2-vmalloc.h>
@@ -531,9 +532,11 @@ struct em28xx_i2c_bus {
 	enum em28xx_i2c_algo_type algo_type;
 };
 
-
 /* main device struct */
 struct em28xx {
+	struct kref ref;
+
+
 	/* generic device properties */
 	char name[30];		/* name (including minor) of the device */
 	int model;		/* index in the device_data struct */
@@ -706,6 +709,8 @@ struct em28xx {
 	struct em28xx_dvb *dvb;
 };
 
+#define kref_to_dev(d) container_of(d, struct em28xx, ref)
+
 struct em28xx_ops {
 	struct list_head next;
 	char *name;
@@ -763,7 +768,7 @@ extern struct em28xx_board em28xx_boards[];
 extern struct usb_device_id em28xx_id_table[];
 int em28xx_tuner_callback(void *ptr, int component, int command, int arg);
 void em28xx_setup_xc3028(struct em28xx *dev, struct xc2028_ctrl *ctl);
-void em28xx_release_resources(struct em28xx *dev);
+void em28xx_free_device(struct kref *ref);
 
 /* Provided by em28xx-camera.c */
 int em28xx_detect_sensor(struct em28xx *dev);
-- 
1.8.3.1


^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [PATCH 4/7] em28xx-audio: disconnect before freeing URBs
  2014-01-12 23:00 [PATCH 0/7] Fix remaining issues with em28xx device removal Mauro Carvalho Chehab
                   ` (2 preceding siblings ...)
  2014-01-12 23:00 ` [PATCH 3/7] em28xx: Only deallocate struct em28xx after finishing all extensions Mauro Carvalho Chehab
@ 2014-01-12 23:00 ` Mauro Carvalho Chehab
  2014-01-13 18:47   ` Frank Schäfer
  2014-01-12 23:00 ` [PATCH 5/7] em28xx-audio: remove a deplock circular dependency Mauro Carvalho Chehab
                   ` (3 subsequent siblings)
  7 siblings, 1 reply; 40+ messages in thread
From: Mauro Carvalho Chehab @ 2014-01-12 23:00 UTC (permalink / raw)
  Cc: Mauro Carvalho Chehab, Linux Media Mailing List,
	Mauro Carvalho Chehab

URBs might be in usage. Disconnect the device before freeing
them.

Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
---
 drivers/media/usb/em28xx/em28xx-audio.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/media/usb/em28xx/em28xx-audio.c b/drivers/media/usb/em28xx/em28xx-audio.c
index 8e959dae8358..cdc2fcf3e05e 100644
--- a/drivers/media/usb/em28xx/em28xx-audio.c
+++ b/drivers/media/usb/em28xx/em28xx-audio.c
@@ -958,6 +958,7 @@ static int em28xx_audio_fini(struct em28xx *dev)
 		return 0;
 	}
 
+	snd_card_disconnect(dev->adev.sndcard);
 	em28xx_audio_free_urb(dev);
 
 	if (dev->adev.sndcard) {
-- 
1.8.3.1


^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [PATCH 5/7] em28xx-audio: remove a deplock circular dependency
  2014-01-12 23:00 [PATCH 0/7] Fix remaining issues with em28xx device removal Mauro Carvalho Chehab
                   ` (3 preceding siblings ...)
  2014-01-12 23:00 ` [PATCH 4/7] em28xx-audio: disconnect before freeing URBs Mauro Carvalho Chehab
@ 2014-01-12 23:00 ` Mauro Carvalho Chehab
  2014-01-13 21:51   ` Frank Schäfer
  2014-01-12 23:00 ` [PATCH 6/7] em28xx: print a message at disconnect Mauro Carvalho Chehab
                   ` (2 subsequent siblings)
  7 siblings, 1 reply; 40+ messages in thread
From: Mauro Carvalho Chehab @ 2014-01-12 23:00 UTC (permalink / raw)
  Cc: Mauro Carvalho Chehab, Linux Media Mailing List,
	Mauro Carvalho Chehab

We can't lock at pcm close, as it causes circular dependency
lock issues with .init and .fini callbacks. So, move the code
that puts the device on mute to the kthread.

    [  322.026316] ======================================================
    [  322.026356] [ INFO: possible circular locking dependency detected ]
    [  322.026397] 3.13.0-rc1+ #24 Not tainted
    [  322.026437] -------------------------------------------------------
    [  322.026476] khubd/54 is trying to acquire lock:
    [  322.026516]  (&pcm->open_mutex){+.+.+.}, at: [<ffffffffa04819e6>] snd_pcm_dev_disconnect+0x46/0x1e0 [snd_pcm]
    [  322.026727]
    but task is already holding lock:
    [  322.026767]  (register_mutex#3){+.+.+.}, at: [<ffffffffa04819c4>] snd_pcm_dev_disconnect+0x24/0x1e0 [snd_pcm]
    [  322.027005]
    which lock already depends on the new lock.

    [  322.027045]
    the existing dependency chain (in reverse order) is:
    [  322.027084]
    -> #2 (register_mutex#3){+.+.+.}:
    [  322.027318]        [<ffffffff810b8fa3>] __lock_acquire+0xb43/0x1330
    [  322.027401]        [<ffffffff810b9f82>] lock_acquire+0xa2/0x120
    [  322.027479]        [<ffffffff816a5b6c>] mutex_lock_nested+0x5c/0x3c0
    [  322.027559]        [<ffffffffa04819c4>] snd_pcm_dev_disconnect+0x24/0x1e0 [snd_pcm]
    [  322.027642]        [<ffffffffa02e855a>] snd_device_disconnect+0x6a/0xf0 [snd]
    [  322.027727]        [<ffffffffa02e86ac>] snd_device_disconnect_all+0x4c/0x90 [snd]
    [  322.027814]        [<ffffffffa02e1876>] snd_card_disconnect+0x126/0x1d0 [snd]
    [  322.027898]        [<ffffffffa02e1ea8>] snd_card_free+0x18/0x90 [snd]
    [  322.027982]        [<ffffffffa087235f>] em28xx_audio_fini+0x8f/0xa0 [em28xx_alsa]
    [  322.028063]        [<ffffffffa085cba6>] em28xx_close_extension+0x56/0x90 [em28xx]
    [  322.028143]        [<ffffffffa085e639>] em28xx_usb_disconnect+0x79/0x90 [em28xx]
    [  322.028222]        [<ffffffff814a06e7>] usb_unbind_interface+0x67/0x1d0
    [  322.028302]        [<ffffffff8142920f>] __device_release_driver+0x7f/0xf0
    [  322.028381]        [<ffffffff814292a5>] device_release_driver+0x25/0x40
    [  322.028462]        [<ffffffff81428b0c>] bus_remove_device+0x11c/0x1a0
    [  322.028540]        [<ffffffff81425536>] device_del+0x136/0x1d0
    [  322.028619]        [<ffffffff8149e0c0>] usb_disable_device+0xb0/0x290
    [  322.028698]        [<ffffffff814930c5>] usb_disconnect+0xb5/0x1d0
    [  322.028779]        [<ffffffff81495ab6>] hub_port_connect_change+0xd6/0xad0
    [  322.028859]        [<ffffffff814967c3>] hub_events+0x313/0x9b0
    [  322.028940]        [<ffffffff81496e95>] hub_thread+0x35/0x170
    [  322.029019]        [<ffffffff8108ea2f>] kthread+0xff/0x120
    [  322.029099]        [<ffffffff816b187c>] ret_from_fork+0x7c/0xb0
    [  322.029179]
    -> #1 (&dev->lock#2){+.+.+.}:
    [  322.029414]        [<ffffffff810b8fa3>] __lock_acquire+0xb43/0x1330
    [  322.029494]        [<ffffffff810b9f82>] lock_acquire+0xa2/0x120
    [  322.029572]        [<ffffffff816a5b6c>] mutex_lock_nested+0x5c/0x3c0
    [  322.029651]        [<ffffffffa087122e>] snd_em28xx_pcm_close+0x3e/0x100 [em28xx_alsa]
    [  322.029732]        [<ffffffffa048620f>] snd_pcm_release_substream.part.29+0x3f/0x90 [snd_pcm]
    [  322.029816]        [<ffffffffa0486340>] snd_pcm_release+0xb0/0xd0 [snd_pcm]
    [  322.029900]        [<ffffffff811c9752>] __fput+0xe2/0x230
    [  322.029979]        [<ffffffff811c98ee>] ____fput+0xe/0x10
    [  322.030057]        [<ffffffff8108b64f>] task_work_run+0x9f/0xe0
    [  322.030135]        [<ffffffff81013a81>] do_notify_resume+0x61/0xa0
    [  322.030223]        [<ffffffff816b1c62>] int_signal+0x12/0x17
    [  322.030294]
    -> #0 (&pcm->open_mutex){+.+.+.}:
    [  322.030473]        [<ffffffff810b7a47>] check_prevs_add+0x947/0x950
    [  322.030546]        [<ffffffff810b8fa3>] __lock_acquire+0xb43/0x1330
    [  322.030618]        [<ffffffff810b9f82>] lock_acquire+0xa2/0x120
    [  322.030689]        [<ffffffff816a5b6c>] mutex_lock_nested+0x5c/0x3c0
    [  322.030760]        [<ffffffffa04819e6>] snd_pcm_dev_disconnect+0x46/0x1e0 [snd_pcm]
    [  322.030835]        [<ffffffffa02e855a>] snd_device_disconnect+0x6a/0xf0 [snd]
    [  322.030913]        [<ffffffffa02e86ac>] snd_device_disconnect_all+0x4c/0x90 [snd]
    [  322.030988]        [<ffffffffa02e1876>] snd_card_disconnect+0x126/0x1d0 [snd]
    [  322.031067]        [<ffffffffa02e1ea8>] snd_card_free+0x18/0x90 [snd]
    [  322.031146]        [<ffffffffa087235f>] em28xx_audio_fini+0x8f/0xa0 [em28xx_alsa]
    [  322.031220]        [<ffffffffa085cba6>] em28xx_close_extension+0x56/0x90 [em28xx]
    [  322.031292]        [<ffffffffa085e639>] em28xx_usb_disconnect+0x79/0x90 [em28xx]
    [  322.031363]        [<ffffffff814a06e7>] usb_unbind_interface+0x67/0x1d0
    [  322.031433]        [<ffffffff8142920f>] __device_release_driver+0x7f/0xf0
    [  322.031503]        [<ffffffff814292a5>] device_release_driver+0x25/0x40
    [  322.031573]        [<ffffffff81428b0c>] bus_remove_device+0x11c/0x1a0
    [  322.031643]        [<ffffffff81425536>] device_del+0x136/0x1d0
    [  322.031714]        [<ffffffff8149e0c0>] usb_disable_device+0xb0/0x290
    [  322.031784]        [<ffffffff814930c5>] usb_disconnect+0xb5/0x1d0
    [  322.031853]        [<ffffffff81495ab6>] hub_port_connect_change+0xd6/0xad0
    [  322.031922]        [<ffffffff814967c3>] hub_events+0x313/0x9b0
    [  322.031992]        [<ffffffff81496e95>] hub_thread+0x35/0x170
    [  322.032062]        [<ffffffff8108ea2f>] kthread+0xff/0x120
    [  322.032135]        [<ffffffff816b187c>] ret_from_fork+0x7c/0xb0
    [  322.032205]
    other info that might help us debug this:

    [  322.032240] Chain exists of:
      &pcm->open_mutex --> &dev->lock#2 --> register_mutex#3

    [  322.032547]  Possible unsafe locking scenario:

    [  322.032582]        CPU0                    CPU1
    [  322.032616]        ----                    ----
    [  322.032654]   lock(register_mutex#3);
    [  322.032793]                                lock(&dev->lock#2);
    [  322.032929]                                lock(register_mutex#3);
    [  322.033064]   lock(&pcm->open_mutex);
    [  322.033168]
     *** DEADLOCK ***

    [  322.033204] 6 locks held by khubd/54:
    [  322.033239]  #0:  (&__lockdep_no_validate__){......}, at: [<ffffffff81496564>] hub_events+0xb4/0x9b0
    [  322.033446]  #1:  (&__lockdep_no_validate__){......}, at: [<ffffffff81493076>] usb_disconnect+0x66/0x1d0
    [  322.033655]  #2:  (&__lockdep_no_validate__){......}, at: [<ffffffff8142929d>] device_release_driver+0x1d/0x40
    [  322.033859]  #3:  (em28xx_devlist_mutex){+.+.+.}, at: [<ffffffffa085cb77>] em28xx_close_extension+0x27/0x90 [em28xx]
    [  322.034067]  #4:  (&dev->lock#2){+.+.+.}, at: [<ffffffffa085cb81>] em28xx_close_extension+0x31/0x90 [em28xx]
    [  322.034307]  #5:  (register_mutex#3){+.+.+.}, at: [<ffffffffa04819c4>] snd_pcm_dev_disconnect+0x24/0x1e0 [snd_pcm]
    [  322.034552]
    stack backtrace:
    [  322.034588] CPU: 3 PID: 54 Comm: khubd Not tainted 3.13.0-rc1+ #24
    [  322.034624] Hardware name: SAMSUNG ELECTRONICS CO., LTD. 550P5C/550P7C/SAMSUNG_NP1234567890, BIOS P04ABI.013.130220.dg 02/20/2013
    [  322.034659]  ffffffff82513770 ffff880221bcd7c8 ffffffff816a03c6 ffffffff8250a810
    [  322.034832]  ffff880221bcd808 ffffffff8169a203 ffff880221bcd830 0000000000000005
    [  322.035004]  ffff8802222b2880 ffff8802222b3020 ffff8802222b3020 0000000000000006
    [  322.035187] Call Trace:
    [  322.035230]  [<ffffffff816a03c6>] dump_stack+0x45/0x56
    [  322.035276]  [<ffffffff8169a203>] print_circular_bug+0x200/0x20e
    [  322.035320]  [<ffffffff810b7a47>] check_prevs_add+0x947/0x950
    [  322.035365]  [<ffffffff8101b303>] ? native_sched_clock+0x13/0x80
    [  322.035409]  [<ffffffff810b8fa3>] __lock_acquire+0xb43/0x1330
    [  322.035454]  [<ffffffff810b9f82>] lock_acquire+0xa2/0x120
    [  322.035500]  [<ffffffffa04819e6>] ? snd_pcm_dev_disconnect+0x46/0x1e0 [snd_pcm]
    [  322.035550]  [<ffffffff816a5b6c>] mutex_lock_nested+0x5c/0x3c0
    [  322.035596]  [<ffffffffa04819e6>] ? snd_pcm_dev_disconnect+0x46/0x1e0 [snd_pcm]
    [  322.035648]  [<ffffffffa04819e6>] ? snd_pcm_dev_disconnect+0x46/0x1e0 [snd_pcm]
    [  322.035697]  [<ffffffff810b8045>] ? trace_hardirqs_on_caller+0x105/0x1d0
    [  322.035744]  [<ffffffffa04819e6>] snd_pcm_dev_disconnect+0x46/0x1e0 [snd_pcm]
    [  322.035797]  [<ffffffffa02e855a>] snd_device_disconnect+0x6a/0xf0 [snd]
    [  322.035852]  [<ffffffffa02e86ac>] snd_device_disconnect_all+0x4c/0x90 [snd]
    [  322.035904]  [<ffffffffa02e1876>] snd_card_disconnect+0x126/0x1d0 [snd]
    [  322.035957]  [<ffffffffa02e1ea8>] snd_card_free+0x18/0x90 [snd]
    [  322.036008]  [<ffffffffa087235f>] em28xx_audio_fini+0x8f/0xa0 [em28xx_alsa]
    [  322.036054]  [<ffffffffa085cba6>] em28xx_close_extension+0x56/0x90 [em28xx]
    [  322.036100]  [<ffffffffa085e639>] em28xx_usb_disconnect+0x79/0x90 [em28xx]
    [  322.036144]  [<ffffffff814a06e7>] usb_unbind_interface+0x67/0x1d0
    [  322.036188]  [<ffffffff8142920f>] __device_release_driver+0x7f/0xf0
    [  322.036231]  [<ffffffff814292a5>] device_release_driver+0x25/0x40
    [  322.036274]  [<ffffffff81428b0c>] bus_remove_device+0x11c/0x1a0
    [  322.036318]  [<ffffffff81425536>] device_del+0x136/0x1d0
    [  322.036361]  [<ffffffff8149e0c0>] usb_disable_device+0xb0/0x290
    [  322.036404]  [<ffffffff814930c5>] usb_disconnect+0xb5/0x1d0
    [  322.036447]  [<ffffffff81495ab6>] hub_port_connect_change+0xd6/0xad0
    [  322.036492]  [<ffffffff8149cb04>] ? usb_control_msg+0xd4/0x110
    [  322.036535]  [<ffffffff814967c3>] hub_events+0x313/0x9b0
    [  322.036579]  [<ffffffff810b8045>] ? trace_hardirqs_on_caller+0x105/0x1d0
    [  322.036623]  [<ffffffff81496e95>] hub_thread+0x35/0x170
    [  322.036667]  [<ffffffff810af310>] ? abort_exclusive_wait+0xb0/0xb0
    [  322.036711]  [<ffffffff81496e60>] ? hub_events+0x9b0/0x9b0
    [  322.036756]  [<ffffffff8108ea2f>] kthread+0xff/0x120
    [  322.036802]  [<ffffffff8108e930>] ? kthread_create_on_node+0x250/0x250
    [  322.036846]  [<ffffffff816b187c>] ret_from_fork+0x7c/0xb0
    [  322.036890]  [<ffffffff8108e930>] ? kthread_create_on_node+0x250/0x250

Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
---
 drivers/media/usb/em28xx/em28xx-audio.c | 10 +++++++---
 1 file changed, 7 insertions(+), 3 deletions(-)

diff --git a/drivers/media/usb/em28xx/em28xx-audio.c b/drivers/media/usb/em28xx/em28xx-audio.c
index cdc2fcf3e05e..5e16fcf18cac 100644
--- a/drivers/media/usb/em28xx/em28xx-audio.c
+++ b/drivers/media/usb/em28xx/em28xx-audio.c
@@ -311,20 +311,17 @@ static int snd_em28xx_pcm_close(struct snd_pcm_substream *substream)
 	dprintk("closing device\n");
 
 	dev->mute = 1;
-	mutex_lock(&dev->lock);
 	dev->adev.users--;
 	if (atomic_read(&dev->stream_started) > 0) {
 		atomic_set(&dev->stream_started, 0);
 		schedule_work(&dev->wq_trigger);
 	}
 
-	em28xx_audio_analog_set(dev);
 	if (substream->runtime->dma_area) {
 		dprintk("freeing\n");
 		vfree(substream->runtime->dma_area);
 		substream->runtime->dma_area = NULL;
 	}
-	mutex_unlock(&dev->lock);
 
 	return 0;
 }
@@ -395,6 +392,13 @@ static void audio_trigger(struct work_struct *work)
 	} else {
 		dprintk("stopping capture");
 		em28xx_deinit_isoc_audio(dev);
+
+		/* Mute device if needed */
+		if (dev->mute) {
+			mutex_lock(&dev->lock);
+			em28xx_audio_analog_set(dev);
+			mutex_unlock(&dev->lock);
+		}
 	}
 }
 
-- 
1.8.3.1


^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [PATCH 6/7] em28xx: print a message at disconnect
  2014-01-12 23:00 [PATCH 0/7] Fix remaining issues with em28xx device removal Mauro Carvalho Chehab
                   ` (4 preceding siblings ...)
  2014-01-12 23:00 ` [PATCH 5/7] em28xx-audio: remove a deplock circular dependency Mauro Carvalho Chehab
@ 2014-01-12 23:00 ` Mauro Carvalho Chehab
  2014-01-13 18:51   ` Frank Schäfer
  2014-01-12 23:00 ` [PATCH 7/7] em28xx: Fix usb diconnect logic Mauro Carvalho Chehab
  2014-01-13 17:30 ` [PATCH 0/7] Fix remaining issues with em28xx device removal Antti Palosaari
  7 siblings, 1 reply; 40+ messages in thread
From: Mauro Carvalho Chehab @ 2014-01-12 23:00 UTC (permalink / raw)
  Cc: Mauro Carvalho Chehab, Linux Media Mailing List,
	Mauro Carvalho Chehab

That helps to identify if something fails and explain why em28xx
struct is not freed (if it ever happens).

Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
---
 drivers/media/usb/em28xx/em28xx-audio.c | 2 ++
 drivers/media/usb/em28xx/em28xx-dvb.c   | 2 ++
 drivers/media/usb/em28xx/em28xx-input.c | 2 ++
 drivers/media/usb/em28xx/em28xx-video.c | 2 ++
 4 files changed, 8 insertions(+)

diff --git a/drivers/media/usb/em28xx/em28xx-audio.c b/drivers/media/usb/em28xx/em28xx-audio.c
index 5e16fcf18cac..0ec4742c3ab0 100644
--- a/drivers/media/usb/em28xx/em28xx-audio.c
+++ b/drivers/media/usb/em28xx/em28xx-audio.c
@@ -962,6 +962,8 @@ static int em28xx_audio_fini(struct em28xx *dev)
 		return 0;
 	}
 
+	em28xx_info("Disconnecting audio extension");
+
 	snd_card_disconnect(dev->adev.sndcard);
 	em28xx_audio_free_urb(dev);
 
diff --git a/drivers/media/usb/em28xx/em28xx-dvb.c b/drivers/media/usb/em28xx/em28xx-dvb.c
index 8674ae5fce06..7ba209de57dd 100644
--- a/drivers/media/usb/em28xx/em28xx-dvb.c
+++ b/drivers/media/usb/em28xx/em28xx-dvb.c
@@ -1473,6 +1473,8 @@ static int em28xx_dvb_fini(struct em28xx *dev)
 		return 0;
 	}
 
+	em28xx_info("Disconnecting DVB extension");
+
 	if (dev->dvb) {
 		struct em28xx_dvb *dvb = dev->dvb;
 
diff --git a/drivers/media/usb/em28xx/em28xx-input.c b/drivers/media/usb/em28xx/em28xx-input.c
index 33388b5922a0..bf04c5e1bd2a 100644
--- a/drivers/media/usb/em28xx/em28xx-input.c
+++ b/drivers/media/usb/em28xx/em28xx-input.c
@@ -812,6 +812,8 @@ static int em28xx_ir_fini(struct em28xx *dev)
 		return 0;
 	}
 
+	em28xx_info("Disconnecting input extension");
+
 	em28xx_shutdown_buttons(dev);
 
 	/* skip detach on non attached boards */
diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c
index dc10cec772ba..004fe12ceec7 100644
--- a/drivers/media/usb/em28xx/em28xx-video.c
+++ b/drivers/media/usb/em28xx/em28xx-video.c
@@ -1894,6 +1894,8 @@ static int em28xx_v4l2_fini(struct em28xx *dev)
 		return 0;
 	}
 
+	em28xx_info("Disconnecting video extension");
+
 	v4l2_device_disconnect(&dev->v4l2_dev);
 
 	em28xx_uninit_usb_xfer(dev, EM28XX_ANALOG_MODE);
-- 
1.8.3.1


^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [PATCH 7/7] em28xx: Fix usb diconnect logic
  2014-01-12 23:00 [PATCH 0/7] Fix remaining issues with em28xx device removal Mauro Carvalho Chehab
                   ` (5 preceding siblings ...)
  2014-01-12 23:00 ` [PATCH 6/7] em28xx: print a message at disconnect Mauro Carvalho Chehab
@ 2014-01-12 23:00 ` Mauro Carvalho Chehab
  2014-01-13 18:53   ` Frank Schäfer
  2014-01-13 17:30 ` [PATCH 0/7] Fix remaining issues with em28xx device removal Antti Palosaari
  7 siblings, 1 reply; 40+ messages in thread
From: Mauro Carvalho Chehab @ 2014-01-12 23:00 UTC (permalink / raw)
  Cc: Mauro Carvalho Chehab, Linux Media Mailing List,
	Mauro Carvalho Chehab

Now that everything is extension, the usb disconnect logic should
be the same.

While here, fix the device name.

Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
---
 drivers/media/usb/em28xx/em28xx-cards.c | 7 +------
 1 file changed, 1 insertion(+), 6 deletions(-)

diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c
index df92f417634a..8fc0a437054e 100644
--- a/drivers/media/usb/em28xx/em28xx-cards.c
+++ b/drivers/media/usb/em28xx/em28xx-cards.c
@@ -3384,12 +3384,7 @@ static void em28xx_usb_disconnect(struct usb_interface *interface)
 
 	dev->disconnected = 1;
 
-	if (dev->is_audio_only) {
-		em28xx_close_extension(dev);
-		return;
-	}
-
-	em28xx_info("disconnecting %s\n", dev->vdev->name);
+	em28xx_info("Disconnecting %s\n", dev->name);
 
 	flush_request_modules(dev);
 
-- 
1.8.3.1


^ permalink raw reply related	[flat|nested] 40+ messages in thread

* Re: [PATCH 0/7] Fix remaining issues with em28xx device removal
  2014-01-12 23:00 [PATCH 0/7] Fix remaining issues with em28xx device removal Mauro Carvalho Chehab
                   ` (6 preceding siblings ...)
  2014-01-12 23:00 ` [PATCH 7/7] em28xx: Fix usb diconnect logic Mauro Carvalho Chehab
@ 2014-01-13 17:30 ` Antti Palosaari
  2014-01-13 17:50   ` Mauro Carvalho Chehab
  7 siblings, 1 reply; 40+ messages in thread
From: Antti Palosaari @ 2014-01-13 17:30 UTC (permalink / raw)
  To: Mauro Carvalho Chehab; +Cc: Linux Media Mailing List, Mauro Carvalho Chehab

On 13.01.2014 01:00, Mauro Carvalho Chehab wrote:
> Even after Frank's series, there are several issues with device module
> removal.
>
> This series fix those issues, by use kref to deallocate the common
> data (struct em28xx *dev).
>
> It also fixes a circular deppendency inside em28xx-audio.
>
> Mauro Carvalho Chehab (7):
>    em28xx-audio: fix return code on device disconnect
>    em28xx-audio: simplify error handling
>    em28xx: Only deallocate struct em28xx after finishing all extensions
>    em28xx-audio: disconnect before freeing URBs
>    em28xx-audio: remove a deplock circular dependency
>    em28xx: print a message at disconnect
>    em28xx: Fix usb diconnect logic
>
>   drivers/media/usb/em28xx/em28xx-audio.c | 47 ++++++++++++++++++++-------------
>   drivers/media/usb/em28xx/em28xx-cards.c | 41 +++++++++++++---------------
>   drivers/media/usb/em28xx/em28xx-dvb.c   |  7 ++++-
>   drivers/media/usb/em28xx/em28xx-input.c | 10 ++++++-
>   drivers/media/usb/em28xx/em28xx-video.c | 13 ++++-----
>   drivers/media/usb/em28xx/em28xx.h       |  9 +++++--
>   6 files changed, 76 insertions(+), 51 deletions(-)
>



Tested-by: Antti Palosaari <crope@iki.fi>


I tested quite many em28xx devices and it seems to work very well.

However, there is that (it looks new) error dump coming after device is 
unplugged.

tammi 13 18:50:56 localhost.localdomain kernel: usb 8-2: USB disconnect, 
device number 2
tammi 13 18:50:56 localhost.localdomain kernel: em2884 #0: Disconnecting 
em2884 #0
tammi 13 18:50:56 localhost.localdomain kernel: em2884 #0: Disconnecting 
video extension
tammi 13 18:50:56 localhost.localdomain kernel: em2884 #0: V4L2 device 
video0 deregistered
tammi 13 18:50:56 localhost.localdomain kernel: em2884 #0: Disconnecting 
audio extension
tammi 13 18:50:56 localhost.localdomain kernel: em2884 #0: Disconnecting 
DVB extension
tammi 13 18:50:56 localhost.localdomain kernel: xc5000 6-0061: 
destroying instance
tammi 13 18:50:56 localhost.localdomain kernel: em2884 #0: Disconnecting 
input extensionINFO: trying to register non-static key.
tammi 13 18:50:56 localhost.localdomain kernel: the code is fine but 
needs lockdep annotation.
tammi 13 18:50:56 localhost.localdomain kernel: turning off the locking 
correctness validator.
tammi 13 18:50:56 localhost.localdomain kernel: CPU: 3 PID: 34 Comm: 
khubd Tainted: G           O 3.13.0-rc1+ #79
tammi 13 18:50:56 localhost.localdomain kernel: Hardware name: System 
manufacturer System Product Name/M5A78L-M/USB3, BIOS 1801    11/12/2013
tammi 13 18:50:56 localhost.localdomain kernel:  ffff88030da1a8a0 
ffff88030dbb99a8 ffffffff816b8da9 0000000000000002
tammi 13 18:50:56 localhost.localdomain kernel:  ffff88030dbb99b8 
ffffffff816b285c ffff88030dbb9a28 ffffffff810bb9ae
tammi 13 18:50:56 localhost.localdomain kernel:  ffffffff810b9bc9 
00000007810b648d ffff88030da1a8a0 ffffffff810cbe27
tammi 13 18:50:56 localhost.localdomain kernel: Call Trace:
tammi 13 18:50:56 localhost.localdomain kernel:  [<ffffffff816b8da9>] 
dump_stack+0x4d/0x66
tammi 13 18:50:56 localhost.localdomain kernel:  [<ffffffff816b285c>] 
register_lock_class.part.40+0x38/0x3c
tammi 13 18:50:56 localhost.localdomain kernel:  [<ffffffff810bb9ae>] 
__lock_acquire+0x9fe/0xc40
tammi 13 18:50:56 localhost.localdomain kernel:  [<ffffffff810b9bc9>] ? 
mark_held_locks+0xb9/0x140
tammi 13 18:50:56 localhost.localdomain kernel:  [<ffffffff810cbe27>] ? 
vprintk_emit+0x1d7/0x5e0
tammi 13 18:50:56 localhost.localdomain kernel:  [<ffffffff810bbca0>] 
lock_acquire+0xb0/0x150
tammi 13 18:50:56 localhost.localdomain kernel:  [<ffffffff81087f75>] ? 
flush_work+0x5/0x60
tammi 13 18:50:56 localhost.localdomain kernel:  [<ffffffff81087fa6>] 
flush_work+0x36/0x60
tammi 13 18:50:56 localhost.localdomain kernel:  [<ffffffff81087f75>] ? 
flush_work+0x5/0x60
tammi 13 18:50:56 localhost.localdomain kernel:  [<ffffffff8108858a>] 
__cancel_work_timer+0x8a/0x120
tammi 13 18:50:56 localhost.localdomain kernel:  [<ffffffff81088653>] 
cancel_delayed_work_sync+0x13/0x20
tammi 13 18:50:56 localhost.localdomain kernel:  [<ffffffffa0839ba8>] 
em28xx_ir_fini+0x48/0xc0 [em28xx_rc]
tammi 13 18:50:56 localhost.localdomain kernel:  [<ffffffffa07a4b8e>] 
em28xx_close_extension+0x3e/0x70 [em28xx]
tammi 13 18:50:56 localhost.localdomain kernel:  [<ffffffffa07a6600>] 
em28xx_usb_disconnect+0x60/0x80 [em28xx]
tammi 13 18:50:56 localhost.localdomain kernel:  [<ffffffff814b7c87>] 
usb_unbind_interface+0x67/0x1d0
tammi 13 18:50:56 localhost.localdomain kernel:  [<ffffffff814378ff>] 
__device_release_driver+0x7f/0xf0
tammi 13 18:50:56 localhost.localdomain kernel:  [<ffffffff81437995>] 
device_release_driver+0x25/0x40
tammi 13 18:50:56 localhost.localdomain kernel:  [<ffffffff814371fc>] 
bus_remove_device+0x11c/0x1a0
tammi 13 18:50:56 localhost.localdomain kernel:  [<ffffffff81433c26>] 
device_del+0x136/0x1d0
tammi 13 18:50:56 localhost.localdomain kernel:  [<ffffffff814b5660>] 
usb_disable_device+0xb0/0x290
tammi 13 18:50:56 localhost.localdomain kernel:  [<ffffffff814aa5f5>] 
usb_disconnect+0xb5/0x1d0
tammi 13 18:50:56 localhost.localdomain kernel:  [<ffffffff814acfe6>] 
hub_port_connect_change+0xd6/0xad0
tammi 13 18:50:56 localhost.localdomain kernel:  [<ffffffff814b40a4>] ? 
usb_control_msg+0xd4/0x110
tammi 13 18:50:56 localhost.localdomain kernel:  [<ffffffff814adcf3>] 
hub_events+0x313/0x9b0
tammi 13 18:50:56 localhost.localdomain kernel:  [<ffffffff814ae3c5>] 
hub_thread+0x35/0x190
tammi 13 18:50:56 localhost.localdomain kernel:  [<ffffffff810b12d0>] ? 
abort_exclusive_wait+0xb0/0xb0
tammi 13 18:50:56 localhost.localdomain kernel:  [<ffffffff814ae390>] ? 
hub_events+0x9b0/0x9b0
tammi 13 18:50:56 localhost.localdomain kernel:  [<ffffffff8109044f>] 
kthread+0xff/0x120
tammi 13 18:50:56 localhost.localdomain kernel:  [<ffffffff81090350>] ? 
kthread_create_on_node+0x250/0x250
tammi 13 18:50:56 localhost.localdomain kernel:  [<ffffffff816ca67c>] 
ret_from_fork+0x7c/0xb0
tammi 13 18:50:56 localhost.localdomain kernel:  [<ffffffff81090350>] ? 
kthread_create_on_node+0x250/0x250
tammi 13 18:50:56 localhost.localdomain kernel: em2884 #0: Freeing device

regards
Antti



-- 
http://palosaari.fi/

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 0/7] Fix remaining issues with em28xx device removal
  2014-01-13 17:30 ` [PATCH 0/7] Fix remaining issues with em28xx device removal Antti Palosaari
@ 2014-01-13 17:50   ` Mauro Carvalho Chehab
  0 siblings, 0 replies; 40+ messages in thread
From: Mauro Carvalho Chehab @ 2014-01-13 17:50 UTC (permalink / raw)
  To: Antti Palosaari; +Cc: Linux Media Mailing List, Mauro Carvalho Chehab

Em Mon, 13 Jan 2014 19:30:24 +0200
Antti Palosaari <crope@iki.fi> escreveu:

> On 13.01.2014 01:00, Mauro Carvalho Chehab wrote:
> > Even after Frank's series, there are several issues with device module
> > removal.
> >
> > This series fix those issues, by use kref to deallocate the common
> > data (struct em28xx *dev).
> >
> > It also fixes a circular deppendency inside em28xx-audio.
> >
> > Mauro Carvalho Chehab (7):
> >    em28xx-audio: fix return code on device disconnect
> >    em28xx-audio: simplify error handling
> >    em28xx: Only deallocate struct em28xx after finishing all extensions
> >    em28xx-audio: disconnect before freeing URBs
> >    em28xx-audio: remove a deplock circular dependency
> >    em28xx: print a message at disconnect
> >    em28xx: Fix usb diconnect logic
> >
> >   drivers/media/usb/em28xx/em28xx-audio.c | 47 ++++++++++++++++++++-------------
> >   drivers/media/usb/em28xx/em28xx-cards.c | 41 +++++++++++++---------------
> >   drivers/media/usb/em28xx/em28xx-dvb.c   |  7 ++++-
> >   drivers/media/usb/em28xx/em28xx-input.c | 10 ++++++-
> >   drivers/media/usb/em28xx/em28xx-video.c | 13 ++++-----
> >   drivers/media/usb/em28xx/em28xx.h       |  9 +++++--
> >   6 files changed, 76 insertions(+), 51 deletions(-)
> >
> 
> 
> 
> Tested-by: Antti Palosaari <crope@iki.fi>
> 
> 
> I tested quite many em28xx devices and it seems to work very well.
> 
> However, there is that (it looks new) error dump coming after device is 
> unplugged.

That's likely because now the lockdep code is able to go one step further
on their tests.

> tammi 13 18:50:56 localhost.localdomain kernel: usb 8-2: USB disconnect, 
> device number 2
> tammi 13 18:50:56 localhost.localdomain kernel: em2884 #0: Disconnecting 
> em2884 #0
> tammi 13 18:50:56 localhost.localdomain kernel: em2884 #0: Disconnecting 
> video extension
> tammi 13 18:50:56 localhost.localdomain kernel: em2884 #0: V4L2 device 
> video0 deregistered
> tammi 13 18:50:56 localhost.localdomain kernel: em2884 #0: Disconnecting 
> audio extension
> tammi 13 18:50:56 localhost.localdomain kernel: em2884 #0: Disconnecting 
> DVB extension
> tammi 13 18:50:56 localhost.localdomain kernel: xc5000 6-0061: 
> destroying instance
> tammi 13 18:50:56 localhost.localdomain kernel: em2884 #0: Disconnecting 
> input extensionINFO: trying to register non-static key.
> tammi 13 18:50:56 localhost.localdomain kernel: the code is fine but 
> needs lockdep annotation.
> tammi 13 18:50:56 localhost.localdomain kernel: turning off the locking 
> correctness validator.

I suspect that the reason is because we're not flushing/canceling the
pending work on em28xx-alsa and em28xx-rc.

I can't reproduce it here, but could you please check if this patch fixes
it?
	http://git.linuxtv.org/mchehab/experimental.git/commitdiff/144f41066bdab280869e309f76f7a42ad5b2be72

> tammi 13 18:50:56 localhost.localdomain kernel: CPU: 3 PID: 34 Comm: 
> khubd Tainted: G           O 3.13.0-rc1+ #79
> tammi 13 18:50:56 localhost.localdomain kernel: Hardware name: System 
> manufacturer System Product Name/M5A78L-M/USB3, BIOS 1801    11/12/2013
> tammi 13 18:50:56 localhost.localdomain kernel:  ffff88030da1a8a0 
> ffff88030dbb99a8 ffffffff816b8da9 0000000000000002
> tammi 13 18:50:56 localhost.localdomain kernel:  ffff88030dbb99b8 
> ffffffff816b285c ffff88030dbb9a28 ffffffff810bb9ae
> tammi 13 18:50:56 localhost.localdomain kernel:  ffffffff810b9bc9 
> 00000007810b648d ffff88030da1a8a0 ffffffff810cbe27
> tammi 13 18:50:56 localhost.localdomain kernel: Call Trace:
> tammi 13 18:50:56 localhost.localdomain kernel:  [<ffffffff816b8da9>] 
> dump_stack+0x4d/0x66
> tammi 13 18:50:56 localhost.localdomain kernel:  [<ffffffff816b285c>] 
> register_lock_class.part.40+0x38/0x3c
> tammi 13 18:50:56 localhost.localdomain kernel:  [<ffffffff810bb9ae>] 
> __lock_acquire+0x9fe/0xc40
> tammi 13 18:50:56 localhost.localdomain kernel:  [<ffffffff810b9bc9>] ? 
> mark_held_locks+0xb9/0x140
> tammi 13 18:50:56 localhost.localdomain kernel:  [<ffffffff810cbe27>] ? 
> vprintk_emit+0x1d7/0x5e0
> tammi 13 18:50:56 localhost.localdomain kernel:  [<ffffffff810bbca0>] 
> lock_acquire+0xb0/0x150
> tammi 13 18:50:56 localhost.localdomain kernel:  [<ffffffff81087f75>] ? 
> flush_work+0x5/0x60
> tammi 13 18:50:56 localhost.localdomain kernel:  [<ffffffff81087fa6>] 
> flush_work+0x36/0x60
> tammi 13 18:50:56 localhost.localdomain kernel:  [<ffffffff81087f75>] ? 
> flush_work+0x5/0x60
> tammi 13 18:50:56 localhost.localdomain kernel:  [<ffffffff8108858a>] 
> __cancel_work_timer+0x8a/0x120
> tammi 13 18:50:56 localhost.localdomain kernel:  [<ffffffff81088653>] 
> cancel_delayed_work_sync+0x13/0x20
> tammi 13 18:50:56 localhost.localdomain kernel:  [<ffffffffa0839ba8>] 
> em28xx_ir_fini+0x48/0xc0 [em28xx_rc]
> tammi 13 18:50:56 localhost.localdomain kernel:  [<ffffffffa07a4b8e>] 
> em28xx_close_extension+0x3e/0x70 [em28xx]
> tammi 13 18:50:56 localhost.localdomain kernel:  [<ffffffffa07a6600>] 
> em28xx_usb_disconnect+0x60/0x80 [em28xx]
> tammi 13 18:50:56 localhost.localdomain kernel:  [<ffffffff814b7c87>] 
> usb_unbind_interface+0x67/0x1d0
> tammi 13 18:50:56 localhost.localdomain kernel:  [<ffffffff814378ff>] 
> __device_release_driver+0x7f/0xf0
> tammi 13 18:50:56 localhost.localdomain kernel:  [<ffffffff81437995>] 
> device_release_driver+0x25/0x40
> tammi 13 18:50:56 localhost.localdomain kernel:  [<ffffffff814371fc>] 
> bus_remove_device+0x11c/0x1a0
> tammi 13 18:50:56 localhost.localdomain kernel:  [<ffffffff81433c26>] 
> device_del+0x136/0x1d0
> tammi 13 18:50:56 localhost.localdomain kernel:  [<ffffffff814b5660>] 
> usb_disable_device+0xb0/0x290
> tammi 13 18:50:56 localhost.localdomain kernel:  [<ffffffff814aa5f5>] 
> usb_disconnect+0xb5/0x1d0
> tammi 13 18:50:56 localhost.localdomain kernel:  [<ffffffff814acfe6>] 
> hub_port_connect_change+0xd6/0xad0
> tammi 13 18:50:56 localhost.localdomain kernel:  [<ffffffff814b40a4>] ? 
> usb_control_msg+0xd4/0x110
> tammi 13 18:50:56 localhost.localdomain kernel:  [<ffffffff814adcf3>] 
> hub_events+0x313/0x9b0
> tammi 13 18:50:56 localhost.localdomain kernel:  [<ffffffff814ae3c5>] 
> hub_thread+0x35/0x190
> tammi 13 18:50:56 localhost.localdomain kernel:  [<ffffffff810b12d0>] ? 
> abort_exclusive_wait+0xb0/0xb0
> tammi 13 18:50:56 localhost.localdomain kernel:  [<ffffffff814ae390>] ? 
> hub_events+0x9b0/0x9b0
> tammi 13 18:50:56 localhost.localdomain kernel:  [<ffffffff8109044f>] 
> kthread+0xff/0x120
> tammi 13 18:50:56 localhost.localdomain kernel:  [<ffffffff81090350>] ? 
> kthread_create_on_node+0x250/0x250
> tammi 13 18:50:56 localhost.localdomain kernel:  [<ffffffff816ca67c>] 
> ret_from_fork+0x7c/0xb0
> tammi 13 18:50:56 localhost.localdomain kernel:  [<ffffffff81090350>] ? 
> kthread_create_on_node+0x250/0x250
> tammi 13 18:50:56 localhost.localdomain kernel: em2884 #0: Freeing device
> 
> regards
> Antti
> 
> 
> 


-- 

Cheers,
Mauro

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 1/7] em28xx-audio: fix return code on device disconnect
  2014-01-12 23:00 ` [PATCH 1/7] em28xx-audio: fix return code on device disconnect Mauro Carvalho Chehab
@ 2014-01-13 18:38   ` Frank Schäfer
  0 siblings, 0 replies; 40+ messages in thread
From: Frank Schäfer @ 2014-01-13 18:38 UTC (permalink / raw)
  To: Mauro Carvalho Chehab; +Cc: Linux Media Mailing List, Mauro Carvalho Chehab

On 13.01.2014 00:00, Mauro Carvalho Chehab wrote:
> Alsa has an special non-negative return code to indicate device removal
> at snd_em28xx_capture_pointer(). Use it, instead of an error code.
>
> Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
> ---
>   drivers/media/usb/em28xx/em28xx-audio.c | 2 +-
>   1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/drivers/media/usb/em28xx/em28xx-audio.c b/drivers/media/usb/em28xx/em28xx-audio.c
> index f3e320098f79..47766b796acb 100644
> --- a/drivers/media/usb/em28xx/em28xx-audio.c
> +++ b/drivers/media/usb/em28xx/em28xx-audio.c
> @@ -434,7 +434,7 @@ static snd_pcm_uframes_t snd_em28xx_capture_pointer(struct snd_pcm_substream
>   
>   	dev = snd_pcm_substream_chip(substream);
>   	if (dev->disconnected)
> -		return -ENODEV;
> +		return SNDRV_PCM_POS_XRUN;
>   
>   	spin_lock_irqsave(&dev->adev.slock, flags);
>   	hwptr_done = dev->adev.hwptr_done_capture;

Reviewed-by: Frank Schäfer <fschaefer.oss@googlemail.com>

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 2/7] em28xx-audio: simplify error handling
  2014-01-12 23:00 ` [PATCH 2/7] em28xx-audio: simplify error handling Mauro Carvalho Chehab
@ 2014-01-13 18:41   ` Frank Schäfer
  0 siblings, 0 replies; 40+ messages in thread
From: Frank Schäfer @ 2014-01-13 18:41 UTC (permalink / raw)
  To: Mauro Carvalho Chehab; +Cc: Linux Media Mailing List, Mauro Carvalho Chehab

On 13.01.2014 00:00, Mauro Carvalho Chehab wrote:
> Cleanup the error handling code at em28xx-audio init.
>
> Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
> ---
>   drivers/media/usb/em28xx/em28xx-audio.c | 27 ++++++++++++++-------------
>   1 file changed, 14 insertions(+), 13 deletions(-)
>
> diff --git a/drivers/media/usb/em28xx/em28xx-audio.c b/drivers/media/usb/em28xx/em28xx-audio.c
> index 47766b796acb..97d9105e6830 100644
> --- a/drivers/media/usb/em28xx/em28xx-audio.c
> +++ b/drivers/media/usb/em28xx/em28xx-audio.c
> @@ -893,10 +893,8 @@ static int em28xx_audio_init(struct em28xx *dev)
>   	adev->udev = dev->udev;
>   
>   	err = snd_pcm_new(card, "Em28xx Audio", 0, 0, 1, &pcm);
> -	if (err < 0) {
> -		snd_card_free(card);
> -		return err;
> -	}
> +	if (err < 0)
> +		goto card_free;
>   
>   	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_em28xx_pcm_capture);
>   	pcm->info_flags = 0;
> @@ -927,20 +925,23 @@ static int em28xx_audio_init(struct em28xx *dev)
>   	}
>   
>   	err = em28xx_audio_urb_init(dev);
> -	if (err) {
> -		snd_card_free(card);
> -		return -ENODEV;
> -	}
> +	if (err)
> +		goto card_free;
>   
>   	err = snd_card_register(card);
> -	if (err < 0) {
> -		em28xx_audio_free_urb(dev);
> -		snd_card_free(card);
> -		return err;
> -	}
> +	if (err < 0)
> +		goto urb_free;
>   
>   	em28xx_info("Audio extension successfully initialized\n");
>   	return 0;
> +
> +urb_free:
> +	em28xx_audio_free_urb(dev);
> +
> +card_free:
> +	snd_card_free(card);
> +
> +	return err;
>   }
>   
>   static int em28xx_audio_fini(struct em28xx *dev)
Reviewed-by: Frank Schäfer <fschaefer.oss@googlemail.com>


^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 4/7] em28xx-audio: disconnect before freeing URBs
  2014-01-12 23:00 ` [PATCH 4/7] em28xx-audio: disconnect before freeing URBs Mauro Carvalho Chehab
@ 2014-01-13 18:47   ` Frank Schäfer
  0 siblings, 0 replies; 40+ messages in thread
From: Frank Schäfer @ 2014-01-13 18:47 UTC (permalink / raw)
  To: Mauro Carvalho Chehab; +Cc: Linux Media Mailing List, Mauro Carvalho Chehab

On 13.01.2014 00:00, Mauro Carvalho Chehab wrote:
> URBs might be in usage. Disconnect the device before freeing
> them.
>
> Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
> ---
>   drivers/media/usb/em28xx/em28xx-audio.c | 1 +
>   1 file changed, 1 insertion(+)
>
> diff --git a/drivers/media/usb/em28xx/em28xx-audio.c b/drivers/media/usb/em28xx/em28xx-audio.c
> index 8e959dae8358..cdc2fcf3e05e 100644
> --- a/drivers/media/usb/em28xx/em28xx-audio.c
> +++ b/drivers/media/usb/em28xx/em28xx-audio.c
> @@ -958,6 +958,7 @@ static int em28xx_audio_fini(struct em28xx *dev)
>   		return 0;
>   	}
>   
> +	snd_card_disconnect(dev->adev.sndcard);
>   	em28xx_audio_free_urb(dev);
>   
>   	if (dev->adev.sndcard) {

Reviewed-by: Frank Schäfer <fschaefer.oss@googlemail.com>


^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 6/7] em28xx: print a message at disconnect
  2014-01-12 23:00 ` [PATCH 6/7] em28xx: print a message at disconnect Mauro Carvalho Chehab
@ 2014-01-13 18:51   ` Frank Schäfer
  0 siblings, 0 replies; 40+ messages in thread
From: Frank Schäfer @ 2014-01-13 18:51 UTC (permalink / raw)
  To: Mauro Carvalho Chehab; +Cc: Linux Media Mailing List, Mauro Carvalho Chehab

On 13.01.2014 00:00, Mauro Carvalho Chehab wrote:
> That helps to identify if something fails and explain why em28xx
> struct is not freed (if it ever happens).
>
> Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
> ---
>   drivers/media/usb/em28xx/em28xx-audio.c | 2 ++
>   drivers/media/usb/em28xx/em28xx-dvb.c   | 2 ++
>   drivers/media/usb/em28xx/em28xx-input.c | 2 ++
>   drivers/media/usb/em28xx/em28xx-video.c | 2 ++
>   4 files changed, 8 insertions(+)
>
> diff --git a/drivers/media/usb/em28xx/em28xx-audio.c b/drivers/media/usb/em28xx/em28xx-audio.c
> index 5e16fcf18cac..0ec4742c3ab0 100644
> --- a/drivers/media/usb/em28xx/em28xx-audio.c
> +++ b/drivers/media/usb/em28xx/em28xx-audio.c
> @@ -962,6 +962,8 @@ static int em28xx_audio_fini(struct em28xx *dev)
>   		return 0;
>   	}
>   
> +	em28xx_info("Disconnecting audio extension");
> +
>   	snd_card_disconnect(dev->adev.sndcard);
>   	em28xx_audio_free_urb(dev);
>   
> diff --git a/drivers/media/usb/em28xx/em28xx-dvb.c b/drivers/media/usb/em28xx/em28xx-dvb.c
> index 8674ae5fce06..7ba209de57dd 100644
> --- a/drivers/media/usb/em28xx/em28xx-dvb.c
> +++ b/drivers/media/usb/em28xx/em28xx-dvb.c
> @@ -1473,6 +1473,8 @@ static int em28xx_dvb_fini(struct em28xx *dev)
>   		return 0;
>   	}
>   
> +	em28xx_info("Disconnecting DVB extension");
> +
>   	if (dev->dvb) {
>   		struct em28xx_dvb *dvb = dev->dvb;
>   
> diff --git a/drivers/media/usb/em28xx/em28xx-input.c b/drivers/media/usb/em28xx/em28xx-input.c
> index 33388b5922a0..bf04c5e1bd2a 100644
> --- a/drivers/media/usb/em28xx/em28xx-input.c
> +++ b/drivers/media/usb/em28xx/em28xx-input.c
> @@ -812,6 +812,8 @@ static int em28xx_ir_fini(struct em28xx *dev)
>   		return 0;
>   	}
>   
> +	em28xx_info("Disconnecting input extension");
> +
>   	em28xx_shutdown_buttons(dev);
>   
>   	/* skip detach on non attached boards */
> diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c
> index dc10cec772ba..004fe12ceec7 100644
> --- a/drivers/media/usb/em28xx/em28xx-video.c
> +++ b/drivers/media/usb/em28xx/em28xx-video.c
> @@ -1894,6 +1894,8 @@ static int em28xx_v4l2_fini(struct em28xx *dev)
>   		return 0;
>   	}
>   
> +	em28xx_info("Disconnecting video extension");
> +
>   	v4l2_device_disconnect(&dev->v4l2_dev);
>   
>   	em28xx_uninit_usb_xfer(dev, EM28XX_ANALOG_MODE);

I would say "Closing" instead of "Disconnecting". That's also how we 
call the function that calls the extensions fini() methods.

Reviewed-by: Frank Schäfer <fschaefer.oss@googlemail.com>



^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 7/7] em28xx: Fix usb diconnect logic
  2014-01-12 23:00 ` [PATCH 7/7] em28xx: Fix usb diconnect logic Mauro Carvalho Chehab
@ 2014-01-13 18:53   ` Frank Schäfer
  0 siblings, 0 replies; 40+ messages in thread
From: Frank Schäfer @ 2014-01-13 18:53 UTC (permalink / raw)
  To: Mauro Carvalho Chehab; +Cc: Linux Media Mailing List, Mauro Carvalho Chehab

On 13.01.2014 00:00, Mauro Carvalho Chehab wrote:
> Now that everything is extension, the usb disconnect logic should
> be the same.
>
> While here, fix the device name.
>
> Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
> ---
>   drivers/media/usb/em28xx/em28xx-cards.c | 7 +------
>   1 file changed, 1 insertion(+), 6 deletions(-)
>
> diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c
> index df92f417634a..8fc0a437054e 100644
> --- a/drivers/media/usb/em28xx/em28xx-cards.c
> +++ b/drivers/media/usb/em28xx/em28xx-cards.c
> @@ -3384,12 +3384,7 @@ static void em28xx_usb_disconnect(struct usb_interface *interface)
>   
>   	dev->disconnected = 1;
>   
> -	if (dev->is_audio_only) {
> -		em28xx_close_extension(dev);
> -		return;
> -	}
> -
> -	em28xx_info("disconnecting %s\n", dev->vdev->name);
> +	em28xx_info("Disconnecting %s\n", dev->name);
>   
>   	flush_request_modules(dev);
Great.
I noticed this buggy section but finally forgot to remove it.

Reviewed-by: Frank Schäfer <fschaefer.oss@googlemail.com>

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 3/7] em28xx: Only deallocate struct em28xx after finishing all extensions
  2014-01-12 23:00 ` [PATCH 3/7] em28xx: Only deallocate struct em28xx after finishing all extensions Mauro Carvalho Chehab
@ 2014-01-13 19:02   ` Frank Schäfer
  2014-01-13 19:23     ` Mauro Carvalho Chehab
  2014-01-14 17:36   ` [PATCH v2] " Mauro Carvalho Chehab
  1 sibling, 1 reply; 40+ messages in thread
From: Frank Schäfer @ 2014-01-13 19:02 UTC (permalink / raw)
  To: Mauro Carvalho Chehab; +Cc: Linux Media Mailing List, Mauro Carvalho Chehab

On 13.01.2014 00:00, Mauro Carvalho Chehab wrote:
> We can't free struct em28xx while one of the extensions is still
> using it.
>
> So, add a kref() to control it, freeing it only after the
> extensions fini calls.
>
> Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
> ---
>   drivers/media/usb/em28xx/em28xx-audio.c |  5 ++++-
>   drivers/media/usb/em28xx/em28xx-cards.c | 34 ++++++++++++++++-----------------
>   drivers/media/usb/em28xx/em28xx-dvb.c   |  5 ++++-
>   drivers/media/usb/em28xx/em28xx-input.c |  8 +++++++-
>   drivers/media/usb/em28xx/em28xx-video.c | 11 +++++------
>   drivers/media/usb/em28xx/em28xx.h       |  9 +++++++--
>   6 files changed, 44 insertions(+), 28 deletions(-)
>
> diff --git a/drivers/media/usb/em28xx/em28xx-audio.c b/drivers/media/usb/em28xx/em28xx-audio.c
> index 97d9105e6830..8e959dae8358 100644
> --- a/drivers/media/usb/em28xx/em28xx-audio.c
> +++ b/drivers/media/usb/em28xx/em28xx-audio.c
> @@ -878,6 +878,8 @@ static int em28xx_audio_init(struct em28xx *dev)
>   
>   	em28xx_info("Binding audio extension\n");
>   
> +	kref_get(&dev->ref);
> +
>   	printk(KERN_INFO "em28xx-audio.c: Copyright (C) 2006 Markus "
>   			 "Rechberger\n");
>   	printk(KERN_INFO
> @@ -949,7 +951,7 @@ static int em28xx_audio_fini(struct em28xx *dev)
>   	if (dev == NULL)
>   		return 0;
>   
> -	if (dev->has_alsa_audio != 1) {
> +	if (!dev->has_alsa_audio) {
>   		/* This device does not support the extension (in this case
>   		   the device is expecting the snd-usb-audio module or
>   		   doesn't have analog audio support at all) */
> @@ -963,6 +965,7 @@ static int em28xx_audio_fini(struct em28xx *dev)
>   		dev->adev.sndcard = NULL;
>   	}
>   
> +	kref_put(&dev->ref, em28xx_free_device);
>   	return 0;
>   }
>   
> diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c
> index 3b332d527ccb..df92f417634a 100644
> --- a/drivers/media/usb/em28xx/em28xx-cards.c
> +++ b/drivers/media/usb/em28xx/em28xx-cards.c
> @@ -2867,16 +2867,18 @@ static void flush_request_modules(struct em28xx *dev)
>   	flush_work(&dev->request_module_wk);
>   }
>   
> -/*
> - * em28xx_release_resources()
> - * unregisters the v4l2,i2c and usb devices
> - * called when the device gets disconnected or at module unload
> -*/
> -void em28xx_release_resources(struct em28xx *dev)
> +/**
> + * em28xx_release_resources() -  unregisters the v4l2,i2c and usb devices
> + *
> + * @ref: struct kref for em28xx device
> + *
> + * This is called when all extensions and em28xx core unregisters a device
> + */
> +void em28xx_free_device(struct kref *ref)
>   {
> -	/*FIXME: I2C IR should be disconnected */
> +	struct em28xx *dev = kref_to_dev(ref);
>   
> -	mutex_lock(&dev->lock);
> +	em28xx_info("Freeing device\n");
>   
>   	if (dev->def_i2c_bus)
>   		em28xx_i2c_unregister(dev, 1);
> @@ -2887,9 +2889,10 @@ void em28xx_release_resources(struct em28xx *dev)
>   	/* Mark device as unused */
>   	clear_bit(dev->devno, &em28xx_devused);
>   
> -	mutex_unlock(&dev->lock);
> -};
> -EXPORT_SYMBOL_GPL(em28xx_release_resources);
> +	kfree(dev->alt_max_pkt_size_isoc);
> +	kfree(dev);
> +}
> +EXPORT_SYMBOL_GPL(em28xx_free_device);
>   
>   /*
>    * em28xx_init_dev()
> @@ -3342,6 +3345,8 @@ static int em28xx_usb_probe(struct usb_interface *interface,
>   			    dev->dvb_xfer_bulk ? "bulk" : "isoc");
>   	}
>   
> +	kref_init(&dev->ref);
> +
>   	request_modules(dev);
>   
>   	/* Should be the last thing to do, to avoid newer udev's to
> @@ -3390,12 +3395,7 @@ static void em28xx_usb_disconnect(struct usb_interface *interface)
>   
>   	em28xx_close_extension(dev);
>   
> -	em28xx_release_resources(dev);
> -
> -	if (!dev->users) {
> -		kfree(dev->alt_max_pkt_size_isoc);
> -		kfree(dev);
> -	}
> +	kref_put(&dev->ref, em28xx_free_device);
>   }
>   
>   static struct usb_driver em28xx_usb_driver = {
> diff --git a/drivers/media/usb/em28xx/em28xx-dvb.c b/drivers/media/usb/em28xx/em28xx-dvb.c
> index 5ea563e3f0e4..8674ae5fce06 100644
> --- a/drivers/media/usb/em28xx/em28xx-dvb.c
> +++ b/drivers/media/usb/em28xx/em28xx-dvb.c
> @@ -1010,11 +1010,11 @@ static int em28xx_dvb_init(struct em28xx *dev)
>   	em28xx_info("Binding DVB extension\n");
>   
>   	dvb = kzalloc(sizeof(struct em28xx_dvb), GFP_KERNEL);
> -
>   	if (dvb == NULL) {
>   		em28xx_info("em28xx_dvb: memory allocation failed\n");
>   		return -ENOMEM;
>   	}
> +	kref_get(&dev->ref);
>   	dev->dvb = dvb;
>   	dvb->fe[0] = dvb->fe[1] = NULL;
>   
> @@ -1442,6 +1442,7 @@ static int em28xx_dvb_init(struct em28xx *dev)
>   	dvb->adapter.mfe_shared = mfe_shared;
>   
>   	em28xx_info("DVB extension successfully initialized\n");
> +
>   ret:
>   	em28xx_set_mode(dev, EM28XX_SUSPEND);
>   	mutex_unlock(&dev->lock);
> @@ -1492,6 +1493,8 @@ static int em28xx_dvb_fini(struct em28xx *dev)
>   		dev->dvb = NULL;
>   	}
>   
> +	kref_put(&dev->ref, em28xx_free_device);
> +
>   	return 0;
>   }
>   
> diff --git a/drivers/media/usb/em28xx/em28xx-input.c b/drivers/media/usb/em28xx/em28xx-input.c
> index 61c061f3a476..33388b5922a0 100644
> --- a/drivers/media/usb/em28xx/em28xx-input.c
> +++ b/drivers/media/usb/em28xx/em28xx-input.c
> @@ -676,6 +676,8 @@ static int em28xx_ir_init(struct em28xx *dev)
>   		return 0;
>   	}
>   
> +	kref_get(&dev->ref);
> +
>   	if (dev->board.buttons)
>   		em28xx_init_buttons(dev);
>   
> @@ -814,7 +816,7 @@ static int em28xx_ir_fini(struct em28xx *dev)
>   
>   	/* skip detach on non attached boards */
>   	if (!ir)
> -		return 0;
> +		goto ref_put;
>   
>   	if (ir->rc)
>   		rc_unregister_device(ir->rc);
> @@ -822,6 +824,10 @@ static int em28xx_ir_fini(struct em28xx *dev)
>   	/* done */
>   	kfree(ir);
>   	dev->ir = NULL;
> +
> +ref_put:
> +	kref_put(&dev->ref, em28xx_free_device);
> +
>   	return 0;
>   }
>   
> diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c
> index 587ff3fe9402..dc10cec772ba 100644
> --- a/drivers/media/usb/em28xx/em28xx-video.c
> +++ b/drivers/media/usb/em28xx/em28xx-video.c
> @@ -1922,8 +1922,7 @@ static int em28xx_v4l2_fini(struct em28xx *dev)
>   	v4l2_ctrl_handler_free(&dev->ctrl_handler);
>   	v4l2_device_unregister(&dev->v4l2_dev);
>   
> -	if (dev->users)
> -		em28xx_warn("Device is open ! Memory deallocation is deferred on last close.\n");
> +	kref_put(&dev->ref, em28xx_free_device);
>   
>   	return 0;
>   }
> @@ -1945,11 +1944,9 @@ static int em28xx_v4l2_close(struct file *filp)
>   	mutex_lock(&dev->lock);
>   
>   	if (dev->users == 1) {
> -		/* free the remaining resources if device is disconnected */
> -		if (dev->disconnected) {
> -			kfree(dev->alt_max_pkt_size_isoc);
> +		/* No sense to try to write to the device */
> +		if (dev->disconnected)
>   			goto exit;
> -		}
>   
>   		/* Save some power by putting tuner to sleep */
>   		v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_power, 0);
> @@ -2201,6 +2198,8 @@ static int em28xx_v4l2_init(struct em28xx *dev)
>   
>   	em28xx_info("Registering V4L2 extension\n");
>   
> +	kref_get(&dev->ref);
> +
>   	mutex_lock(&dev->lock);
>   
>   	ret = v4l2_device_register(&dev->udev->dev, &dev->v4l2_dev);
> diff --git a/drivers/media/usb/em28xx/em28xx.h b/drivers/media/usb/em28xx/em28xx.h
> index 5d5d1b6f0294..d38c08e4da60 100644
> --- a/drivers/media/usb/em28xx/em28xx.h
> +++ b/drivers/media/usb/em28xx/em28xx.h
> @@ -32,6 +32,7 @@
>   #include <linux/workqueue.h>
>   #include <linux/i2c.h>
>   #include <linux/mutex.h>
> +#include <linux/kref.h>
>   #include <linux/videodev2.h>
>   
>   #include <media/videobuf2-vmalloc.h>
> @@ -531,9 +532,11 @@ struct em28xx_i2c_bus {
>   	enum em28xx_i2c_algo_type algo_type;
>   };
>   
> -
>   /* main device struct */
>   struct em28xx {
> +	struct kref ref;
> +
> +
>   	/* generic device properties */
>   	char name[30];		/* name (including minor) of the device */
>   	int model;		/* index in the device_data struct */
> @@ -706,6 +709,8 @@ struct em28xx {
>   	struct em28xx_dvb *dvb;
>   };
>   
> +#define kref_to_dev(d) container_of(d, struct em28xx, ref)
> +
>   struct em28xx_ops {
>   	struct list_head next;
>   	char *name;
> @@ -763,7 +768,7 @@ extern struct em28xx_board em28xx_boards[];
>   extern struct usb_device_id em28xx_id_table[];
>   int em28xx_tuner_callback(void *ptr, int component, int command, int arg);
>   void em28xx_setup_xc3028(struct em28xx *dev, struct xc2028_ctrl *ctl);
> -void em28xx_release_resources(struct em28xx *dev);
> +void em28xx_free_device(struct kref *ref);
>   
>   /* Provided by em28xx-camera.c */
>   int em28xx_detect_sensor(struct em28xx *dev);
I welcome this patch and the general approach looks good.
I had started working on the same issue, but it's not that trivial.

At first glance there seem to be several issues, but I will need to 
review this patch in more detail and also make some tests.
Unfortunately, I don't have much time this evening, So could you please 
hold it back another day ?
I hope I can review the other remaining patch of this series (patch 5/7) 
later this evening.

Regards,
Frank

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 3/7] em28xx: Only deallocate struct em28xx after finishing all extensions
  2014-01-13 19:02   ` Frank Schäfer
@ 2014-01-13 19:23     ` Mauro Carvalho Chehab
  2014-01-13 21:55       ` Frank Schäfer
  0 siblings, 1 reply; 40+ messages in thread
From: Mauro Carvalho Chehab @ 2014-01-13 19:23 UTC (permalink / raw)
  To: Frank Schäfer; +Cc: Linux Media Mailing List, Mauro Carvalho Chehab

Em Mon, 13 Jan 2014 20:02:19 +0100
Frank Schäfer <fschaefer.oss@googlemail.com> escreveu:

> On 13.01.2014 00:00, Mauro Carvalho Chehab wrote:
> > We can't free struct em28xx while one of the extensions is still
> > using it.
> >
> > So, add a kref() to control it, freeing it only after the
> > extensions fini calls.
> >
> > Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
> > ---
> >   drivers/media/usb/em28xx/em28xx-audio.c |  5 ++++-
> >   drivers/media/usb/em28xx/em28xx-cards.c | 34 ++++++++++++++++-----------------
> >   drivers/media/usb/em28xx/em28xx-dvb.c   |  5 ++++-
> >   drivers/media/usb/em28xx/em28xx-input.c |  8 +++++++-
> >   drivers/media/usb/em28xx/em28xx-video.c | 11 +++++------
> >   drivers/media/usb/em28xx/em28xx.h       |  9 +++++++--
> >   6 files changed, 44 insertions(+), 28 deletions(-)
> >
> > diff --git a/drivers/media/usb/em28xx/em28xx-audio.c b/drivers/media/usb/em28xx/em28xx-audio.c
> > index 97d9105e6830..8e959dae8358 100644
> > --- a/drivers/media/usb/em28xx/em28xx-audio.c
> > +++ b/drivers/media/usb/em28xx/em28xx-audio.c
> > @@ -878,6 +878,8 @@ static int em28xx_audio_init(struct em28xx *dev)
> >   
> >   	em28xx_info("Binding audio extension\n");
> >   
> > +	kref_get(&dev->ref);
> > +
> >   	printk(KERN_INFO "em28xx-audio.c: Copyright (C) 2006 Markus "
> >   			 "Rechberger\n");
> >   	printk(KERN_INFO
> > @@ -949,7 +951,7 @@ static int em28xx_audio_fini(struct em28xx *dev)
> >   	if (dev == NULL)
> >   		return 0;
> >   
> > -	if (dev->has_alsa_audio != 1) {
> > +	if (!dev->has_alsa_audio) {
> >   		/* This device does not support the extension (in this case
> >   		   the device is expecting the snd-usb-audio module or
> >   		   doesn't have analog audio support at all) */
> > @@ -963,6 +965,7 @@ static int em28xx_audio_fini(struct em28xx *dev)
> >   		dev->adev.sndcard = NULL;
> >   	}
> >   
> > +	kref_put(&dev->ref, em28xx_free_device);
> >   	return 0;
> >   }
> >   
> > diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c
> > index 3b332d527ccb..df92f417634a 100644
> > --- a/drivers/media/usb/em28xx/em28xx-cards.c
> > +++ b/drivers/media/usb/em28xx/em28xx-cards.c
> > @@ -2867,16 +2867,18 @@ static void flush_request_modules(struct em28xx *dev)
> >   	flush_work(&dev->request_module_wk);
> >   }
> >   
> > -/*
> > - * em28xx_release_resources()
> > - * unregisters the v4l2,i2c and usb devices
> > - * called when the device gets disconnected or at module unload
> > -*/
> > -void em28xx_release_resources(struct em28xx *dev)
> > +/**
> > + * em28xx_release_resources() -  unregisters the v4l2,i2c and usb devices
> > + *
> > + * @ref: struct kref for em28xx device
> > + *
> > + * This is called when all extensions and em28xx core unregisters a device
> > + */
> > +void em28xx_free_device(struct kref *ref)
> >   {
> > -	/*FIXME: I2C IR should be disconnected */
> > +	struct em28xx *dev = kref_to_dev(ref);
> >   
> > -	mutex_lock(&dev->lock);
> > +	em28xx_info("Freeing device\n");
> >   
> >   	if (dev->def_i2c_bus)
> >   		em28xx_i2c_unregister(dev, 1);
> > @@ -2887,9 +2889,10 @@ void em28xx_release_resources(struct em28xx *dev)
> >   	/* Mark device as unused */
> >   	clear_bit(dev->devno, &em28xx_devused);
> >   
> > -	mutex_unlock(&dev->lock);
> > -};
> > -EXPORT_SYMBOL_GPL(em28xx_release_resources);
> > +	kfree(dev->alt_max_pkt_size_isoc);
> > +	kfree(dev);
> > +}
> > +EXPORT_SYMBOL_GPL(em28xx_free_device);
> >   
> >   /*
> >    * em28xx_init_dev()
> > @@ -3342,6 +3345,8 @@ static int em28xx_usb_probe(struct usb_interface *interface,
> >   			    dev->dvb_xfer_bulk ? "bulk" : "isoc");
> >   	}
> >   
> > +	kref_init(&dev->ref);
> > +
> >   	request_modules(dev);
> >   
> >   	/* Should be the last thing to do, to avoid newer udev's to
> > @@ -3390,12 +3395,7 @@ static void em28xx_usb_disconnect(struct usb_interface *interface)
> >   
> >   	em28xx_close_extension(dev);
> >   
> > -	em28xx_release_resources(dev);
> > -
> > -	if (!dev->users) {
> > -		kfree(dev->alt_max_pkt_size_isoc);
> > -		kfree(dev);
> > -	}
> > +	kref_put(&dev->ref, em28xx_free_device);
> >   }
> >   
> >   static struct usb_driver em28xx_usb_driver = {
> > diff --git a/drivers/media/usb/em28xx/em28xx-dvb.c b/drivers/media/usb/em28xx/em28xx-dvb.c
> > index 5ea563e3f0e4..8674ae5fce06 100644
> > --- a/drivers/media/usb/em28xx/em28xx-dvb.c
> > +++ b/drivers/media/usb/em28xx/em28xx-dvb.c
> > @@ -1010,11 +1010,11 @@ static int em28xx_dvb_init(struct em28xx *dev)
> >   	em28xx_info("Binding DVB extension\n");
> >   
> >   	dvb = kzalloc(sizeof(struct em28xx_dvb), GFP_KERNEL);
> > -
> >   	if (dvb == NULL) {
> >   		em28xx_info("em28xx_dvb: memory allocation failed\n");
> >   		return -ENOMEM;
> >   	}
> > +	kref_get(&dev->ref);
> >   	dev->dvb = dvb;
> >   	dvb->fe[0] = dvb->fe[1] = NULL;
> >   
> > @@ -1442,6 +1442,7 @@ static int em28xx_dvb_init(struct em28xx *dev)
> >   	dvb->adapter.mfe_shared = mfe_shared;
> >   
> >   	em28xx_info("DVB extension successfully initialized\n");
> > +
> >   ret:
> >   	em28xx_set_mode(dev, EM28XX_SUSPEND);
> >   	mutex_unlock(&dev->lock);
> > @@ -1492,6 +1493,8 @@ static int em28xx_dvb_fini(struct em28xx *dev)
> >   		dev->dvb = NULL;
> >   	}
> >   
> > +	kref_put(&dev->ref, em28xx_free_device);
> > +
> >   	return 0;
> >   }
> >   
> > diff --git a/drivers/media/usb/em28xx/em28xx-input.c b/drivers/media/usb/em28xx/em28xx-input.c
> > index 61c061f3a476..33388b5922a0 100644
> > --- a/drivers/media/usb/em28xx/em28xx-input.c
> > +++ b/drivers/media/usb/em28xx/em28xx-input.c
> > @@ -676,6 +676,8 @@ static int em28xx_ir_init(struct em28xx *dev)
> >   		return 0;
> >   	}
> >   
> > +	kref_get(&dev->ref);
> > +
> >   	if (dev->board.buttons)
> >   		em28xx_init_buttons(dev);
> >   
> > @@ -814,7 +816,7 @@ static int em28xx_ir_fini(struct em28xx *dev)
> >   
> >   	/* skip detach on non attached boards */
> >   	if (!ir)
> > -		return 0;
> > +		goto ref_put;
> >   
> >   	if (ir->rc)
> >   		rc_unregister_device(ir->rc);
> > @@ -822,6 +824,10 @@ static int em28xx_ir_fini(struct em28xx *dev)
> >   	/* done */
> >   	kfree(ir);
> >   	dev->ir = NULL;
> > +
> > +ref_put:
> > +	kref_put(&dev->ref, em28xx_free_device);
> > +
> >   	return 0;
> >   }
> >   
> > diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c
> > index 587ff3fe9402..dc10cec772ba 100644
> > --- a/drivers/media/usb/em28xx/em28xx-video.c
> > +++ b/drivers/media/usb/em28xx/em28xx-video.c
> > @@ -1922,8 +1922,7 @@ static int em28xx_v4l2_fini(struct em28xx *dev)
> >   	v4l2_ctrl_handler_free(&dev->ctrl_handler);
> >   	v4l2_device_unregister(&dev->v4l2_dev);
> >   
> > -	if (dev->users)
> > -		em28xx_warn("Device is open ! Memory deallocation is deferred on last close.\n");
> > +	kref_put(&dev->ref, em28xx_free_device);
> >   
> >   	return 0;
> >   }
> > @@ -1945,11 +1944,9 @@ static int em28xx_v4l2_close(struct file *filp)
> >   	mutex_lock(&dev->lock);
> >   
> >   	if (dev->users == 1) {
> > -		/* free the remaining resources if device is disconnected */
> > -		if (dev->disconnected) {
> > -			kfree(dev->alt_max_pkt_size_isoc);
> > +		/* No sense to try to write to the device */
> > +		if (dev->disconnected)
> >   			goto exit;
> > -		}
> >   
> >   		/* Save some power by putting tuner to sleep */
> >   		v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_power, 0);
> > @@ -2201,6 +2198,8 @@ static int em28xx_v4l2_init(struct em28xx *dev)
> >   
> >   	em28xx_info("Registering V4L2 extension\n");
> >   
> > +	kref_get(&dev->ref);
> > +
> >   	mutex_lock(&dev->lock);
> >   
> >   	ret = v4l2_device_register(&dev->udev->dev, &dev->v4l2_dev);
> > diff --git a/drivers/media/usb/em28xx/em28xx.h b/drivers/media/usb/em28xx/em28xx.h
> > index 5d5d1b6f0294..d38c08e4da60 100644
> > --- a/drivers/media/usb/em28xx/em28xx.h
> > +++ b/drivers/media/usb/em28xx/em28xx.h
> > @@ -32,6 +32,7 @@
> >   #include <linux/workqueue.h>
> >   #include <linux/i2c.h>
> >   #include <linux/mutex.h>
> > +#include <linux/kref.h>
> >   #include <linux/videodev2.h>
> >   
> >   #include <media/videobuf2-vmalloc.h>
> > @@ -531,9 +532,11 @@ struct em28xx_i2c_bus {
> >   	enum em28xx_i2c_algo_type algo_type;
> >   };
> >   
> > -
> >   /* main device struct */
> >   struct em28xx {
> > +	struct kref ref;
> > +
> > +
> >   	/* generic device properties */
> >   	char name[30];		/* name (including minor) of the device */
> >   	int model;		/* index in the device_data struct */
> > @@ -706,6 +709,8 @@ struct em28xx {
> >   	struct em28xx_dvb *dvb;
> >   };
> >   
> > +#define kref_to_dev(d) container_of(d, struct em28xx, ref)
> > +
> >   struct em28xx_ops {
> >   	struct list_head next;
> >   	char *name;
> > @@ -763,7 +768,7 @@ extern struct em28xx_board em28xx_boards[];
> >   extern struct usb_device_id em28xx_id_table[];
> >   int em28xx_tuner_callback(void *ptr, int component, int command, int arg);
> >   void em28xx_setup_xc3028(struct em28xx *dev, struct xc2028_ctrl *ctl);
> > -void em28xx_release_resources(struct em28xx *dev);
> > +void em28xx_free_device(struct kref *ref);
> >   
> >   /* Provided by em28xx-camera.c */
> >   int em28xx_detect_sensor(struct em28xx *dev);
> I welcome this patch and the general approach looks good.
> I had started working on the same issue, but it's not that trivial.
> 
> At first glance there seem to be several issues, but I will need to 
> review this patch in more detail and also make some tests.
> Unfortunately, I don't have much time this evening, So could you please 
> hold it back another day ?
> I hope I can review the other remaining patch of this series (patch 5/7) 
> later this evening.

We're running out of time for 3.14. I think we should merge this patch
series, and your patch series for 3.14, to be together with the em28xx-v4l
split.

My plan is to merge the remaining patches for 3.14 today or, in the worse
case, tomorrow.

If we slip on some bug, we'll still have the 3.14-rc cycle to fix, if the
series gets merged, but, if we miss the bus, I'm afraid that we'll end
by having more problems that will be hard to fix with trivial patches, due
to em28xx-v4l split changes that also affected the driver removal and device
close code.

FYI, I tested this code and also Antti with our devices, randomly removing
the devices while streaming, and this is now finally working.

I won't doubt that there are some cases that require fixes (and
it seems that em28xx-rc has one of such corner cases), but they'll likely
can be solved with somewhat short and trivial patches.

Cheers,
Mauro

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 5/7] em28xx-audio: remove a deplock circular dependency
  2014-01-12 23:00 ` [PATCH 5/7] em28xx-audio: remove a deplock circular dependency Mauro Carvalho Chehab
@ 2014-01-13 21:51   ` Frank Schäfer
  2014-01-14 15:45     ` Mauro Carvalho Chehab
  0 siblings, 1 reply; 40+ messages in thread
From: Frank Schäfer @ 2014-01-13 21:51 UTC (permalink / raw)
  To: Mauro Carvalho Chehab; +Cc: Linux Media Mailing List, Mauro Carvalho Chehab

Am 13.01.2014 00:00, schrieb Mauro Carvalho Chehab:
> We can't lock at pcm close, as it causes circular dependency
> lock issues with .init and .fini callbacks. So, move the code
> that puts the device on mute to the kthread.
>
>     [  322.026316] ======================================================
>     [  322.026356] [ INFO: possible circular locking dependency detected ]
>     [  322.026397] 3.13.0-rc1+ #24 Not tainted
>     [  322.026437] -------------------------------------------------------
>     [  322.026476] khubd/54 is trying to acquire lock:
>     [  322.026516]  (&pcm->open_mutex){+.+.+.}, at: [<ffffffffa04819e6>] snd_pcm_dev_disconnect+0x46/0x1e0 [snd_pcm]
>     [  322.026727]
>     but task is already holding lock:
>     [  322.026767]  (register_mutex#3){+.+.+.}, at: [<ffffffffa04819c4>] snd_pcm_dev_disconnect+0x24/0x1e0 [snd_pcm]
>     [  322.027005]
>     which lock already depends on the new lock.
>
>     [  322.027045]
>     the existing dependency chain (in reverse order) is:
>     [  322.027084]
>     -> #2 (register_mutex#3){+.+.+.}:
>     [  322.027318]        [<ffffffff810b8fa3>] __lock_acquire+0xb43/0x1330
>     [  322.027401]        [<ffffffff810b9f82>] lock_acquire+0xa2/0x120
>     [  322.027479]        [<ffffffff816a5b6c>] mutex_lock_nested+0x5c/0x3c0
>     [  322.027559]        [<ffffffffa04819c4>] snd_pcm_dev_disconnect+0x24/0x1e0 [snd_pcm]
>     [  322.027642]        [<ffffffffa02e855a>] snd_device_disconnect+0x6a/0xf0 [snd]
>     [  322.027727]        [<ffffffffa02e86ac>] snd_device_disconnect_all+0x4c/0x90 [snd]
>     [  322.027814]        [<ffffffffa02e1876>] snd_card_disconnect+0x126/0x1d0 [snd]
>     [  322.027898]        [<ffffffffa02e1ea8>] snd_card_free+0x18/0x90 [snd]
>     [  322.027982]        [<ffffffffa087235f>] em28xx_audio_fini+0x8f/0xa0 [em28xx_alsa]
>     [  322.028063]        [<ffffffffa085cba6>] em28xx_close_extension+0x56/0x90 [em28xx]
>     [  322.028143]        [<ffffffffa085e639>] em28xx_usb_disconnect+0x79/0x90 [em28xx]
>     [  322.028222]        [<ffffffff814a06e7>] usb_unbind_interface+0x67/0x1d0
>     [  322.028302]        [<ffffffff8142920f>] __device_release_driver+0x7f/0xf0
>     [  322.028381]        [<ffffffff814292a5>] device_release_driver+0x25/0x40
>     [  322.028462]        [<ffffffff81428b0c>] bus_remove_device+0x11c/0x1a0
>     [  322.028540]        [<ffffffff81425536>] device_del+0x136/0x1d0
>     [  322.028619]        [<ffffffff8149e0c0>] usb_disable_device+0xb0/0x290
>     [  322.028698]        [<ffffffff814930c5>] usb_disconnect+0xb5/0x1d0
>     [  322.028779]        [<ffffffff81495ab6>] hub_port_connect_change+0xd6/0xad0
>     [  322.028859]        [<ffffffff814967c3>] hub_events+0x313/0x9b0
>     [  322.028940]        [<ffffffff81496e95>] hub_thread+0x35/0x170
>     [  322.029019]        [<ffffffff8108ea2f>] kthread+0xff/0x120
>     [  322.029099]        [<ffffffff816b187c>] ret_from_fork+0x7c/0xb0
>     [  322.029179]
>     -> #1 (&dev->lock#2){+.+.+.}:
>     [  322.029414]        [<ffffffff810b8fa3>] __lock_acquire+0xb43/0x1330
>     [  322.029494]        [<ffffffff810b9f82>] lock_acquire+0xa2/0x120
>     [  322.029572]        [<ffffffff816a5b6c>] mutex_lock_nested+0x5c/0x3c0
>     [  322.029651]        [<ffffffffa087122e>] snd_em28xx_pcm_close+0x3e/0x100 [em28xx_alsa]
>     [  322.029732]        [<ffffffffa048620f>] snd_pcm_release_substream.part.29+0x3f/0x90 [snd_pcm]
>     [  322.029816]        [<ffffffffa0486340>] snd_pcm_release+0xb0/0xd0 [snd_pcm]
>     [  322.029900]        [<ffffffff811c9752>] __fput+0xe2/0x230
>     [  322.029979]        [<ffffffff811c98ee>] ____fput+0xe/0x10
>     [  322.030057]        [<ffffffff8108b64f>] task_work_run+0x9f/0xe0
>     [  322.030135]        [<ffffffff81013a81>] do_notify_resume+0x61/0xa0
>     [  322.030223]        [<ffffffff816b1c62>] int_signal+0x12/0x17
>     [  322.030294]
>     -> #0 (&pcm->open_mutex){+.+.+.}:
>     [  322.030473]        [<ffffffff810b7a47>] check_prevs_add+0x947/0x950
>     [  322.030546]        [<ffffffff810b8fa3>] __lock_acquire+0xb43/0x1330
>     [  322.030618]        [<ffffffff810b9f82>] lock_acquire+0xa2/0x120
>     [  322.030689]        [<ffffffff816a5b6c>] mutex_lock_nested+0x5c/0x3c0
>     [  322.030760]        [<ffffffffa04819e6>] snd_pcm_dev_disconnect+0x46/0x1e0 [snd_pcm]
>     [  322.030835]        [<ffffffffa02e855a>] snd_device_disconnect+0x6a/0xf0 [snd]
>     [  322.030913]        [<ffffffffa02e86ac>] snd_device_disconnect_all+0x4c/0x90 [snd]
>     [  322.030988]        [<ffffffffa02e1876>] snd_card_disconnect+0x126/0x1d0 [snd]
>     [  322.031067]        [<ffffffffa02e1ea8>] snd_card_free+0x18/0x90 [snd]
>     [  322.031146]        [<ffffffffa087235f>] em28xx_audio_fini+0x8f/0xa0 [em28xx_alsa]
>     [  322.031220]        [<ffffffffa085cba6>] em28xx_close_extension+0x56/0x90 [em28xx]
>     [  322.031292]        [<ffffffffa085e639>] em28xx_usb_disconnect+0x79/0x90 [em28xx]
>     [  322.031363]        [<ffffffff814a06e7>] usb_unbind_interface+0x67/0x1d0
>     [  322.031433]        [<ffffffff8142920f>] __device_release_driver+0x7f/0xf0
>     [  322.031503]        [<ffffffff814292a5>] device_release_driver+0x25/0x40
>     [  322.031573]        [<ffffffff81428b0c>] bus_remove_device+0x11c/0x1a0
>     [  322.031643]        [<ffffffff81425536>] device_del+0x136/0x1d0
>     [  322.031714]        [<ffffffff8149e0c0>] usb_disable_device+0xb0/0x290
>     [  322.031784]        [<ffffffff814930c5>] usb_disconnect+0xb5/0x1d0
>     [  322.031853]        [<ffffffff81495ab6>] hub_port_connect_change+0xd6/0xad0
>     [  322.031922]        [<ffffffff814967c3>] hub_events+0x313/0x9b0
>     [  322.031992]        [<ffffffff81496e95>] hub_thread+0x35/0x170
>     [  322.032062]        [<ffffffff8108ea2f>] kthread+0xff/0x120
>     [  322.032135]        [<ffffffff816b187c>] ret_from_fork+0x7c/0xb0
>     [  322.032205]
>     other info that might help us debug this:
>
>     [  322.032240] Chain exists of:
>       &pcm->open_mutex --> &dev->lock#2 --> register_mutex#3
>
>     [  322.032547]  Possible unsafe locking scenario:
>
>     [  322.032582]        CPU0                    CPU1
>     [  322.032616]        ----                    ----
>     [  322.032654]   lock(register_mutex#3);
>     [  322.032793]                                lock(&dev->lock#2);
>     [  322.032929]                                lock(register_mutex#3);
>     [  322.033064]   lock(&pcm->open_mutex);
>     [  322.033168]
>      *** DEADLOCK ***
>
>     [  322.033204] 6 locks held by khubd/54:
>     [  322.033239]  #0:  (&__lockdep_no_validate__){......}, at: [<ffffffff81496564>] hub_events+0xb4/0x9b0
>     [  322.033446]  #1:  (&__lockdep_no_validate__){......}, at: [<ffffffff81493076>] usb_disconnect+0x66/0x1d0
>     [  322.033655]  #2:  (&__lockdep_no_validate__){......}, at: [<ffffffff8142929d>] device_release_driver+0x1d/0x40
>     [  322.033859]  #3:  (em28xx_devlist_mutex){+.+.+.}, at: [<ffffffffa085cb77>] em28xx_close_extension+0x27/0x90 [em28xx]
>     [  322.034067]  #4:  (&dev->lock#2){+.+.+.}, at: [<ffffffffa085cb81>] em28xx_close_extension+0x31/0x90 [em28xx]
>     [  322.034307]  #5:  (register_mutex#3){+.+.+.}, at: [<ffffffffa04819c4>] snd_pcm_dev_disconnect+0x24/0x1e0 [snd_pcm]
>     [  322.034552]
>     stack backtrace:
>     [  322.034588] CPU: 3 PID: 54 Comm: khubd Not tainted 3.13.0-rc1+ #24
>     [  322.034624] Hardware name: SAMSUNG ELECTRONICS CO., LTD. 550P5C/550P7C/SAMSUNG_NP1234567890, BIOS P04ABI.013.130220.dg 02/20/2013
>     [  322.034659]  ffffffff82513770 ffff880221bcd7c8 ffffffff816a03c6 ffffffff8250a810
>     [  322.034832]  ffff880221bcd808 ffffffff8169a203 ffff880221bcd830 0000000000000005
>     [  322.035004]  ffff8802222b2880 ffff8802222b3020 ffff8802222b3020 0000000000000006
>     [  322.035187] Call Trace:
>     [  322.035230]  [<ffffffff816a03c6>] dump_stack+0x45/0x56
>     [  322.035276]  [<ffffffff8169a203>] print_circular_bug+0x200/0x20e
>     [  322.035320]  [<ffffffff810b7a47>] check_prevs_add+0x947/0x950
>     [  322.035365]  [<ffffffff8101b303>] ? native_sched_clock+0x13/0x80
>     [  322.035409]  [<ffffffff810b8fa3>] __lock_acquire+0xb43/0x1330
>     [  322.035454]  [<ffffffff810b9f82>] lock_acquire+0xa2/0x120
>     [  322.035500]  [<ffffffffa04819e6>] ? snd_pcm_dev_disconnect+0x46/0x1e0 [snd_pcm]
>     [  322.035550]  [<ffffffff816a5b6c>] mutex_lock_nested+0x5c/0x3c0
>     [  322.035596]  [<ffffffffa04819e6>] ? snd_pcm_dev_disconnect+0x46/0x1e0 [snd_pcm]
>     [  322.035648]  [<ffffffffa04819e6>] ? snd_pcm_dev_disconnect+0x46/0x1e0 [snd_pcm]
>     [  322.035697]  [<ffffffff810b8045>] ? trace_hardirqs_on_caller+0x105/0x1d0
>     [  322.035744]  [<ffffffffa04819e6>] snd_pcm_dev_disconnect+0x46/0x1e0 [snd_pcm]
>     [  322.035797]  [<ffffffffa02e855a>] snd_device_disconnect+0x6a/0xf0 [snd]
>     [  322.035852]  [<ffffffffa02e86ac>] snd_device_disconnect_all+0x4c/0x90 [snd]
>     [  322.035904]  [<ffffffffa02e1876>] snd_card_disconnect+0x126/0x1d0 [snd]
>     [  322.035957]  [<ffffffffa02e1ea8>] snd_card_free+0x18/0x90 [snd]
>     [  322.036008]  [<ffffffffa087235f>] em28xx_audio_fini+0x8f/0xa0 [em28xx_alsa]
>     [  322.036054]  [<ffffffffa085cba6>] em28xx_close_extension+0x56/0x90 [em28xx]
>     [  322.036100]  [<ffffffffa085e639>] em28xx_usb_disconnect+0x79/0x90 [em28xx]
>     [  322.036144]  [<ffffffff814a06e7>] usb_unbind_interface+0x67/0x1d0
>     [  322.036188]  [<ffffffff8142920f>] __device_release_driver+0x7f/0xf0
>     [  322.036231]  [<ffffffff814292a5>] device_release_driver+0x25/0x40
>     [  322.036274]  [<ffffffff81428b0c>] bus_remove_device+0x11c/0x1a0
>     [  322.036318]  [<ffffffff81425536>] device_del+0x136/0x1d0
>     [  322.036361]  [<ffffffff8149e0c0>] usb_disable_device+0xb0/0x290
>     [  322.036404]  [<ffffffff814930c5>] usb_disconnect+0xb5/0x1d0
>     [  322.036447]  [<ffffffff81495ab6>] hub_port_connect_change+0xd6/0xad0
>     [  322.036492]  [<ffffffff8149cb04>] ? usb_control_msg+0xd4/0x110
>     [  322.036535]  [<ffffffff814967c3>] hub_events+0x313/0x9b0
>     [  322.036579]  [<ffffffff810b8045>] ? trace_hardirqs_on_caller+0x105/0x1d0
>     [  322.036623]  [<ffffffff81496e95>] hub_thread+0x35/0x170
>     [  322.036667]  [<ffffffff810af310>] ? abort_exclusive_wait+0xb0/0xb0
>     [  322.036711]  [<ffffffff81496e60>] ? hub_events+0x9b0/0x9b0
>     [  322.036756]  [<ffffffff8108ea2f>] kthread+0xff/0x120
>     [  322.036802]  [<ffffffff8108e930>] ? kthread_create_on_node+0x250/0x250
>     [  322.036846]  [<ffffffff816b187c>] ret_from_fork+0x7c/0xb0
>     [  322.036890]  [<ffffffff8108e930>] ? kthread_create_on_node+0x250/0x250
>
> Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
> ---
>  drivers/media/usb/em28xx/em28xx-audio.c | 10 +++++++---
>  1 file changed, 7 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/media/usb/em28xx/em28xx-audio.c b/drivers/media/usb/em28xx/em28xx-audio.c
> index cdc2fcf3e05e..5e16fcf18cac 100644
> --- a/drivers/media/usb/em28xx/em28xx-audio.c
> +++ b/drivers/media/usb/em28xx/em28xx-audio.c
> @@ -311,20 +311,17 @@ static int snd_em28xx_pcm_close(struct snd_pcm_substream *substream)
>  	dprintk("closing device\n");
>  
>  	dev->mute = 1;
> -	mutex_lock(&dev->lock);
>  	dev->adev.users--;
>  	if (atomic_read(&dev->stream_started) > 0) {
>  		atomic_set(&dev->stream_started, 0);
>  		schedule_work(&dev->wq_trigger);
>  	}
>  
> -	em28xx_audio_analog_set(dev);
>  	if (substream->runtime->dma_area) {
>  		dprintk("freeing\n");
>  		vfree(substream->runtime->dma_area);
>  		substream->runtime->dma_area = NULL;
>  	}
> -	mutex_unlock(&dev->lock);
>  
>  	return 0;
>  }
> @@ -395,6 +392,13 @@ static void audio_trigger(struct work_struct *work)
>  	} else {
>  		dprintk("stopping capture");
>  		em28xx_deinit_isoc_audio(dev);
> +
> +		/* Mute device if needed */
> +		if (dev->mute) {
> +			mutex_lock(&dev->lock);
> +			em28xx_audio_analog_set(dev);
> +			mutex_unlock(&dev->lock);
> +		}
>  	}
>  }
It's already late and I don't understand this deadlock yet completely,
but are you sure this is the proper fix for this issue ?
What happens when capturing is restarted ? Shouldn't the device then be
unmuted again ?
How often does the start/stop/resume happen ?




^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 3/7] em28xx: Only deallocate struct em28xx after finishing all extensions
  2014-01-13 19:23     ` Mauro Carvalho Chehab
@ 2014-01-13 21:55       ` Frank Schäfer
  2014-01-14 13:10         ` Mauro Carvalho Chehab
  0 siblings, 1 reply; 40+ messages in thread
From: Frank Schäfer @ 2014-01-13 21:55 UTC (permalink / raw)
  To: Mauro Carvalho Chehab; +Cc: Linux Media Mailing List, Mauro Carvalho Chehab

Am 13.01.2014 20:23, schrieb Mauro Carvalho Chehab:
> Em Mon, 13 Jan 2014 20:02:19 +0100
> Frank Schäfer <fschaefer.oss@googlemail.com> escreveu:
>
>> On 13.01.2014 00:00, Mauro Carvalho Chehab wrote:
>>> We can't free struct em28xx while one of the extensions is still
>>> using it.
>>>
>>> So, add a kref() to control it, freeing it only after the
>>> extensions fini calls.
>>>
>>> Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
>>> ---
>>>   drivers/media/usb/em28xx/em28xx-audio.c |  5 ++++-
>>>   drivers/media/usb/em28xx/em28xx-cards.c | 34 ++++++++++++++++-----------------
>>>   drivers/media/usb/em28xx/em28xx-dvb.c   |  5 ++++-
>>>   drivers/media/usb/em28xx/em28xx-input.c |  8 +++++++-
>>>   drivers/media/usb/em28xx/em28xx-video.c | 11 +++++------
>>>   drivers/media/usb/em28xx/em28xx.h       |  9 +++++++--
>>>   6 files changed, 44 insertions(+), 28 deletions(-)
>>>
>>> diff --git a/drivers/media/usb/em28xx/em28xx-audio.c b/drivers/media/usb/em28xx/em28xx-audio.c
>>> index 97d9105e6830..8e959dae8358 100644
>>> --- a/drivers/media/usb/em28xx/em28xx-audio.c
>>> +++ b/drivers/media/usb/em28xx/em28xx-audio.c
>>> @@ -878,6 +878,8 @@ static int em28xx_audio_init(struct em28xx *dev)
>>>   
>>>   	em28xx_info("Binding audio extension\n");
>>>   
>>> +	kref_get(&dev->ref);
>>> +
>>>   	printk(KERN_INFO "em28xx-audio.c: Copyright (C) 2006 Markus "
>>>   			 "Rechberger\n");
>>>   	printk(KERN_INFO
>>> @@ -949,7 +951,7 @@ static int em28xx_audio_fini(struct em28xx *dev)
>>>   	if (dev == NULL)
>>>   		return 0;
>>>   
>>> -	if (dev->has_alsa_audio != 1) {
>>> +	if (!dev->has_alsa_audio) {
>>>   		/* This device does not support the extension (in this case
>>>   		   the device is expecting the snd-usb-audio module or
>>>   		   doesn't have analog audio support at all) */
>>> @@ -963,6 +965,7 @@ static int em28xx_audio_fini(struct em28xx *dev)
>>>   		dev->adev.sndcard = NULL;
>>>   	}
>>>   
>>> +	kref_put(&dev->ref, em28xx_free_device);
>>>   	return 0;
>>>   }
>>>   
>>> diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c
>>> index 3b332d527ccb..df92f417634a 100644
>>> --- a/drivers/media/usb/em28xx/em28xx-cards.c
>>> +++ b/drivers/media/usb/em28xx/em28xx-cards.c
>>> @@ -2867,16 +2867,18 @@ static void flush_request_modules(struct em28xx *dev)
>>>   	flush_work(&dev->request_module_wk);
>>>   }
>>>   
>>> -/*
>>> - * em28xx_release_resources()
>>> - * unregisters the v4l2,i2c and usb devices
>>> - * called when the device gets disconnected or at module unload
>>> -*/
>>> -void em28xx_release_resources(struct em28xx *dev)
>>> +/**
>>> + * em28xx_release_resources() -  unregisters the v4l2,i2c and usb devices
>>> + *
>>> + * @ref: struct kref for em28xx device
>>> + *
>>> + * This is called when all extensions and em28xx core unregisters a device
>>> + */
>>> +void em28xx_free_device(struct kref *ref)
>>>   {
>>> -	/*FIXME: I2C IR should be disconnected */
>>> +	struct em28xx *dev = kref_to_dev(ref);
>>>   
>>> -	mutex_lock(&dev->lock);
>>> +	em28xx_info("Freeing device\n");
>>>   
>>>   	if (dev->def_i2c_bus)
>>>   		em28xx_i2c_unregister(dev, 1);
>>> @@ -2887,9 +2889,10 @@ void em28xx_release_resources(struct em28xx *dev)
>>>   	/* Mark device as unused */
>>>   	clear_bit(dev->devno, &em28xx_devused);
>>>   
>>> -	mutex_unlock(&dev->lock);
>>> -};
>>> -EXPORT_SYMBOL_GPL(em28xx_release_resources);
>>> +	kfree(dev->alt_max_pkt_size_isoc);
>>> +	kfree(dev);
>>> +}
>>> +EXPORT_SYMBOL_GPL(em28xx_free_device);
>>>   
>>>   /*
>>>    * em28xx_init_dev()
>>> @@ -3342,6 +3345,8 @@ static int em28xx_usb_probe(struct usb_interface *interface,
>>>   			    dev->dvb_xfer_bulk ? "bulk" : "isoc");
>>>   	}
>>>   
>>> +	kref_init(&dev->ref);
>>> +
>>>   	request_modules(dev);
>>>   
>>>   	/* Should be the last thing to do, to avoid newer udev's to
>>> @@ -3390,12 +3395,7 @@ static void em28xx_usb_disconnect(struct usb_interface *interface)
>>>   
>>>   	em28xx_close_extension(dev);
>>>   
>>> -	em28xx_release_resources(dev);
>>> -
>>> -	if (!dev->users) {
>>> -		kfree(dev->alt_max_pkt_size_isoc);
>>> -		kfree(dev);
>>> -	}
>>> +	kref_put(&dev->ref, em28xx_free_device);
>>>   }
>>>   
>>>   static struct usb_driver em28xx_usb_driver = {
>>> diff --git a/drivers/media/usb/em28xx/em28xx-dvb.c b/drivers/media/usb/em28xx/em28xx-dvb.c
>>> index 5ea563e3f0e4..8674ae5fce06 100644
>>> --- a/drivers/media/usb/em28xx/em28xx-dvb.c
>>> +++ b/drivers/media/usb/em28xx/em28xx-dvb.c
>>> @@ -1010,11 +1010,11 @@ static int em28xx_dvb_init(struct em28xx *dev)
>>>   	em28xx_info("Binding DVB extension\n");
>>>   
>>>   	dvb = kzalloc(sizeof(struct em28xx_dvb), GFP_KERNEL);
>>> -
>>>   	if (dvb == NULL) {
>>>   		em28xx_info("em28xx_dvb: memory allocation failed\n");
>>>   		return -ENOMEM;
>>>   	}
>>> +	kref_get(&dev->ref);
>>>   	dev->dvb = dvb;
>>>   	dvb->fe[0] = dvb->fe[1] = NULL;
>>>   
>>> @@ -1442,6 +1442,7 @@ static int em28xx_dvb_init(struct em28xx *dev)
>>>   	dvb->adapter.mfe_shared = mfe_shared;
>>>   
>>>   	em28xx_info("DVB extension successfully initialized\n");
>>> +
>>>   ret:
>>>   	em28xx_set_mode(dev, EM28XX_SUSPEND);
>>>   	mutex_unlock(&dev->lock);
>>> @@ -1492,6 +1493,8 @@ static int em28xx_dvb_fini(struct em28xx *dev)
>>>   		dev->dvb = NULL;
>>>   	}
>>>   
>>> +	kref_put(&dev->ref, em28xx_free_device);
>>> +
>>>   	return 0;
>>>   }
>>>   
>>> diff --git a/drivers/media/usb/em28xx/em28xx-input.c b/drivers/media/usb/em28xx/em28xx-input.c
>>> index 61c061f3a476..33388b5922a0 100644
>>> --- a/drivers/media/usb/em28xx/em28xx-input.c
>>> +++ b/drivers/media/usb/em28xx/em28xx-input.c
>>> @@ -676,6 +676,8 @@ static int em28xx_ir_init(struct em28xx *dev)
>>>   		return 0;
>>>   	}
>>>   
>>> +	kref_get(&dev->ref);
>>> +
>>>   	if (dev->board.buttons)
>>>   		em28xx_init_buttons(dev);
>>>   
>>> @@ -814,7 +816,7 @@ static int em28xx_ir_fini(struct em28xx *dev)
>>>   
>>>   	/* skip detach on non attached boards */
>>>   	if (!ir)
>>> -		return 0;
>>> +		goto ref_put;
>>>   
>>>   	if (ir->rc)
>>>   		rc_unregister_device(ir->rc);
>>> @@ -822,6 +824,10 @@ static int em28xx_ir_fini(struct em28xx *dev)
>>>   	/* done */
>>>   	kfree(ir);
>>>   	dev->ir = NULL;
>>> +
>>> +ref_put:
>>> +	kref_put(&dev->ref, em28xx_free_device);
>>> +
>>>   	return 0;
>>>   }
>>>   
>>> diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c
>>> index 587ff3fe9402..dc10cec772ba 100644
>>> --- a/drivers/media/usb/em28xx/em28xx-video.c
>>> +++ b/drivers/media/usb/em28xx/em28xx-video.c
>>> @@ -1922,8 +1922,7 @@ static int em28xx_v4l2_fini(struct em28xx *dev)
>>>   	v4l2_ctrl_handler_free(&dev->ctrl_handler);
>>>   	v4l2_device_unregister(&dev->v4l2_dev);
>>>   
>>> -	if (dev->users)
>>> -		em28xx_warn("Device is open ! Memory deallocation is deferred on last close.\n");
>>> +	kref_put(&dev->ref, em28xx_free_device);
>>>   
>>>   	return 0;
>>>   }
>>> @@ -1945,11 +1944,9 @@ static int em28xx_v4l2_close(struct file *filp)
>>>   	mutex_lock(&dev->lock);
>>>   
>>>   	if (dev->users == 1) {
>>> -		/* free the remaining resources if device is disconnected */
>>> -		if (dev->disconnected) {
>>> -			kfree(dev->alt_max_pkt_size_isoc);
>>> +		/* No sense to try to write to the device */
>>> +		if (dev->disconnected)
>>>   			goto exit;
>>> -		}
>>>   
>>>   		/* Save some power by putting tuner to sleep */
>>>   		v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_power, 0);
>>> @@ -2201,6 +2198,8 @@ static int em28xx_v4l2_init(struct em28xx *dev)
>>>   
>>>   	em28xx_info("Registering V4L2 extension\n");
>>>   
>>> +	kref_get(&dev->ref);
>>> +
>>>   	mutex_lock(&dev->lock);
>>>   
>>>   	ret = v4l2_device_register(&dev->udev->dev, &dev->v4l2_dev);
>>> diff --git a/drivers/media/usb/em28xx/em28xx.h b/drivers/media/usb/em28xx/em28xx.h
>>> index 5d5d1b6f0294..d38c08e4da60 100644
>>> --- a/drivers/media/usb/em28xx/em28xx.h
>>> +++ b/drivers/media/usb/em28xx/em28xx.h
>>> @@ -32,6 +32,7 @@
>>>   #include <linux/workqueue.h>
>>>   #include <linux/i2c.h>
>>>   #include <linux/mutex.h>
>>> +#include <linux/kref.h>
>>>   #include <linux/videodev2.h>
>>>   
>>>   #include <media/videobuf2-vmalloc.h>
>>> @@ -531,9 +532,11 @@ struct em28xx_i2c_bus {
>>>   	enum em28xx_i2c_algo_type algo_type;
>>>   };
>>>   
>>> -
>>>   /* main device struct */
>>>   struct em28xx {
>>> +	struct kref ref;
>>> +
>>> +
>>>   	/* generic device properties */
>>>   	char name[30];		/* name (including minor) of the device */
>>>   	int model;		/* index in the device_data struct */
>>> @@ -706,6 +709,8 @@ struct em28xx {
>>>   	struct em28xx_dvb *dvb;
>>>   };
>>>   
>>> +#define kref_to_dev(d) container_of(d, struct em28xx, ref)
>>> +
>>>   struct em28xx_ops {
>>>   	struct list_head next;
>>>   	char *name;
>>> @@ -763,7 +768,7 @@ extern struct em28xx_board em28xx_boards[];
>>>   extern struct usb_device_id em28xx_id_table[];
>>>   int em28xx_tuner_callback(void *ptr, int component, int command, int arg);
>>>   void em28xx_setup_xc3028(struct em28xx *dev, struct xc2028_ctrl *ctl);
>>> -void em28xx_release_resources(struct em28xx *dev);
>>> +void em28xx_free_device(struct kref *ref);
>>>   
>>>   /* Provided by em28xx-camera.c */
>>>   int em28xx_detect_sensor(struct em28xx *dev);
>> I welcome this patch and the general approach looks good.
>> I had started working on the same issue, but it's not that trivial.
>>
>> At first glance there seem to be several issues, but I will need to 
>> review this patch in more detail and also make some tests.
>> Unfortunately, I don't have much time this evening, So could you please 
>> hold it back another day ?
>> I hope I can review the other remaining patch of this series (patch 5/7) 
>> later this evening.
> We're running out of time for 3.14. I think we should merge this patch
> series, and your patch series for 3.14, to be together with the em28xx-v4l
> split.
>
> My plan is to merge the remaining patches for 3.14 today or, in the worse
> case, tomorrow.
>
> If we slip on some bug, we'll still have the 3.14-rc cycle to fix, if the
> series gets merged, but, if we miss the bus, I'm afraid that we'll end
> by having more problems that will be hard to fix with trivial patches, due
> to em28xx-v4l split changes that also affected the driver removal and device
> close code.
>
> FYI, I tested this code and also Antti with our devices, randomly removing
> the devices while streaming, and this is now finally working.
>
> I won't doubt that there are some cases that require fixes (and
> it seems that em28xx-rc has one of such corner cases), but they'll likely
> can be solved with somewhat short and trivial patches.
>
> Cheers,
> Mauro

This is a very critical patch and exactly the kind of change that should
_never_ be hurried !
FAICS it has some severe issues and it's not clear how easy it will be
to fix it within the the 3.14-rc cycle.
As long as it's not ready, don't merge it for 3.14.

em28xx resources releasing is broken since ... well... at least 2 years.
3.14 will already be much better and nobody will care if this remaining
issue is addressed a kernel release later.

Be warned !



^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 3/7] em28xx: Only deallocate struct em28xx after finishing all extensions
  2014-01-13 21:55       ` Frank Schäfer
@ 2014-01-14 13:10         ` Mauro Carvalho Chehab
  2014-01-14 18:13           ` Frank Schäfer
  0 siblings, 1 reply; 40+ messages in thread
From: Mauro Carvalho Chehab @ 2014-01-14 13:10 UTC (permalink / raw)
  To: Frank Schäfer; +Cc: Linux Media Mailing List, Mauro Carvalho Chehab

Em Mon, 13 Jan 2014 22:55:36 +0100
Frank Schäfer <fschaefer.oss@googlemail.com> escreveu:

> Am 13.01.2014 20:23, schrieb Mauro Carvalho Chehab:
> > Em Mon, 13 Jan 2014 20:02:19 +0100
> > Frank Schäfer <fschaefer.oss@googlemail.com> escreveu:
> >
> >> On 13.01.2014 00:00, Mauro Carvalho Chehab wrote:
> >>> We can't free struct em28xx while one of the extensions is still
> >>> using it.
> >>>
> >>> So, add a kref() to control it, freeing it only after the
> >>> extensions fini calls.
> >>>
> >>> Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
> >>> ---
> >>>   drivers/media/usb/em28xx/em28xx-audio.c |  5 ++++-
> >>>   drivers/media/usb/em28xx/em28xx-cards.c | 34 ++++++++++++++++-----------------
> >>>   drivers/media/usb/em28xx/em28xx-dvb.c   |  5 ++++-
> >>>   drivers/media/usb/em28xx/em28xx-input.c |  8 +++++++-
> >>>   drivers/media/usb/em28xx/em28xx-video.c | 11 +++++------
> >>>   drivers/media/usb/em28xx/em28xx.h       |  9 +++++++--
> >>>   6 files changed, 44 insertions(+), 28 deletions(-)
> >>>
> >>> diff --git a/drivers/media/usb/em28xx/em28xx-audio.c b/drivers/media/usb/em28xx/em28xx-audio.c
> >>> index 97d9105e6830..8e959dae8358 100644
> >>> --- a/drivers/media/usb/em28xx/em28xx-audio.c
> >>> +++ b/drivers/media/usb/em28xx/em28xx-audio.c
> >>> @@ -878,6 +878,8 @@ static int em28xx_audio_init(struct em28xx *dev)
> >>>   
> >>>   	em28xx_info("Binding audio extension\n");
> >>>   
> >>> +	kref_get(&dev->ref);
> >>> +
> >>>   	printk(KERN_INFO "em28xx-audio.c: Copyright (C) 2006 Markus "
> >>>   			 "Rechberger\n");
> >>>   	printk(KERN_INFO
> >>> @@ -949,7 +951,7 @@ static int em28xx_audio_fini(struct em28xx *dev)
> >>>   	if (dev == NULL)
> >>>   		return 0;
> >>>   
> >>> -	if (dev->has_alsa_audio != 1) {
> >>> +	if (!dev->has_alsa_audio) {
> >>>   		/* This device does not support the extension (in this case
> >>>   		   the device is expecting the snd-usb-audio module or
> >>>   		   doesn't have analog audio support at all) */
> >>> @@ -963,6 +965,7 @@ static int em28xx_audio_fini(struct em28xx *dev)
> >>>   		dev->adev.sndcard = NULL;
> >>>   	}
> >>>   
> >>> +	kref_put(&dev->ref, em28xx_free_device);
> >>>   	return 0;
> >>>   }
> >>>   
> >>> diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c
> >>> index 3b332d527ccb..df92f417634a 100644
> >>> --- a/drivers/media/usb/em28xx/em28xx-cards.c
> >>> +++ b/drivers/media/usb/em28xx/em28xx-cards.c
> >>> @@ -2867,16 +2867,18 @@ static void flush_request_modules(struct em28xx *dev)
> >>>   	flush_work(&dev->request_module_wk);
> >>>   }
> >>>   
> >>> -/*
> >>> - * em28xx_release_resources()
> >>> - * unregisters the v4l2,i2c and usb devices
> >>> - * called when the device gets disconnected or at module unload
> >>> -*/
> >>> -void em28xx_release_resources(struct em28xx *dev)
> >>> +/**
> >>> + * em28xx_release_resources() -  unregisters the v4l2,i2c and usb devices
> >>> + *
> >>> + * @ref: struct kref for em28xx device
> >>> + *
> >>> + * This is called when all extensions and em28xx core unregisters a device
> >>> + */
> >>> +void em28xx_free_device(struct kref *ref)
> >>>   {
> >>> -	/*FIXME: I2C IR should be disconnected */
> >>> +	struct em28xx *dev = kref_to_dev(ref);
> >>>   
> >>> -	mutex_lock(&dev->lock);
> >>> +	em28xx_info("Freeing device\n");
> >>>   
> >>>   	if (dev->def_i2c_bus)
> >>>   		em28xx_i2c_unregister(dev, 1);
> >>> @@ -2887,9 +2889,10 @@ void em28xx_release_resources(struct em28xx *dev)
> >>>   	/* Mark device as unused */
> >>>   	clear_bit(dev->devno, &em28xx_devused);
> >>>   
> >>> -	mutex_unlock(&dev->lock);
> >>> -};
> >>> -EXPORT_SYMBOL_GPL(em28xx_release_resources);
> >>> +	kfree(dev->alt_max_pkt_size_isoc);
> >>> +	kfree(dev);
> >>> +}
> >>> +EXPORT_SYMBOL_GPL(em28xx_free_device);
> >>>   
> >>>   /*
> >>>    * em28xx_init_dev()
> >>> @@ -3342,6 +3345,8 @@ static int em28xx_usb_probe(struct usb_interface *interface,
> >>>   			    dev->dvb_xfer_bulk ? "bulk" : "isoc");
> >>>   	}
> >>>   
> >>> +	kref_init(&dev->ref);
> >>> +
> >>>   	request_modules(dev);
> >>>   
> >>>   	/* Should be the last thing to do, to avoid newer udev's to
> >>> @@ -3390,12 +3395,7 @@ static void em28xx_usb_disconnect(struct usb_interface *interface)
> >>>   
> >>>   	em28xx_close_extension(dev);
> >>>   
> >>> -	em28xx_release_resources(dev);
> >>> -
> >>> -	if (!dev->users) {
> >>> -		kfree(dev->alt_max_pkt_size_isoc);
> >>> -		kfree(dev);
> >>> -	}
> >>> +	kref_put(&dev->ref, em28xx_free_device);
> >>>   }
> >>>   
> >>>   static struct usb_driver em28xx_usb_driver = {
> >>> diff --git a/drivers/media/usb/em28xx/em28xx-dvb.c b/drivers/media/usb/em28xx/em28xx-dvb.c
> >>> index 5ea563e3f0e4..8674ae5fce06 100644
> >>> --- a/drivers/media/usb/em28xx/em28xx-dvb.c
> >>> +++ b/drivers/media/usb/em28xx/em28xx-dvb.c
> >>> @@ -1010,11 +1010,11 @@ static int em28xx_dvb_init(struct em28xx *dev)
> >>>   	em28xx_info("Binding DVB extension\n");
> >>>   
> >>>   	dvb = kzalloc(sizeof(struct em28xx_dvb), GFP_KERNEL);
> >>> -
> >>>   	if (dvb == NULL) {
> >>>   		em28xx_info("em28xx_dvb: memory allocation failed\n");
> >>>   		return -ENOMEM;
> >>>   	}
> >>> +	kref_get(&dev->ref);
> >>>   	dev->dvb = dvb;
> >>>   	dvb->fe[0] = dvb->fe[1] = NULL;
> >>>   
> >>> @@ -1442,6 +1442,7 @@ static int em28xx_dvb_init(struct em28xx *dev)
> >>>   	dvb->adapter.mfe_shared = mfe_shared;
> >>>   
> >>>   	em28xx_info("DVB extension successfully initialized\n");
> >>> +
> >>>   ret:
> >>>   	em28xx_set_mode(dev, EM28XX_SUSPEND);
> >>>   	mutex_unlock(&dev->lock);
> >>> @@ -1492,6 +1493,8 @@ static int em28xx_dvb_fini(struct em28xx *dev)
> >>>   		dev->dvb = NULL;
> >>>   	}
> >>>   
> >>> +	kref_put(&dev->ref, em28xx_free_device);
> >>> +
> >>>   	return 0;
> >>>   }
> >>>   
> >>> diff --git a/drivers/media/usb/em28xx/em28xx-input.c b/drivers/media/usb/em28xx/em28xx-input.c
> >>> index 61c061f3a476..33388b5922a0 100644
> >>> --- a/drivers/media/usb/em28xx/em28xx-input.c
> >>> +++ b/drivers/media/usb/em28xx/em28xx-input.c
> >>> @@ -676,6 +676,8 @@ static int em28xx_ir_init(struct em28xx *dev)
> >>>   		return 0;
> >>>   	}
> >>>   
> >>> +	kref_get(&dev->ref);
> >>> +
> >>>   	if (dev->board.buttons)
> >>>   		em28xx_init_buttons(dev);
> >>>   
> >>> @@ -814,7 +816,7 @@ static int em28xx_ir_fini(struct em28xx *dev)
> >>>   
> >>>   	/* skip detach on non attached boards */
> >>>   	if (!ir)
> >>> -		return 0;
> >>> +		goto ref_put;
> >>>   
> >>>   	if (ir->rc)
> >>>   		rc_unregister_device(ir->rc);
> >>> @@ -822,6 +824,10 @@ static int em28xx_ir_fini(struct em28xx *dev)
> >>>   	/* done */
> >>>   	kfree(ir);
> >>>   	dev->ir = NULL;
> >>> +
> >>> +ref_put:
> >>> +	kref_put(&dev->ref, em28xx_free_device);
> >>> +
> >>>   	return 0;
> >>>   }
> >>>   
> >>> diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c
> >>> index 587ff3fe9402..dc10cec772ba 100644
> >>> --- a/drivers/media/usb/em28xx/em28xx-video.c
> >>> +++ b/drivers/media/usb/em28xx/em28xx-video.c
> >>> @@ -1922,8 +1922,7 @@ static int em28xx_v4l2_fini(struct em28xx *dev)
> >>>   	v4l2_ctrl_handler_free(&dev->ctrl_handler);
> >>>   	v4l2_device_unregister(&dev->v4l2_dev);
> >>>   
> >>> -	if (dev->users)
> >>> -		em28xx_warn("Device is open ! Memory deallocation is deferred on last close.\n");
> >>> +	kref_put(&dev->ref, em28xx_free_device);
> >>>   
> >>>   	return 0;
> >>>   }
> >>> @@ -1945,11 +1944,9 @@ static int em28xx_v4l2_close(struct file *filp)
> >>>   	mutex_lock(&dev->lock);
> >>>   
> >>>   	if (dev->users == 1) {
> >>> -		/* free the remaining resources if device is disconnected */
> >>> -		if (dev->disconnected) {
> >>> -			kfree(dev->alt_max_pkt_size_isoc);
> >>> +		/* No sense to try to write to the device */
> >>> +		if (dev->disconnected)
> >>>   			goto exit;
> >>> -		}
> >>>   
> >>>   		/* Save some power by putting tuner to sleep */
> >>>   		v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_power, 0);
> >>> @@ -2201,6 +2198,8 @@ static int em28xx_v4l2_init(struct em28xx *dev)
> >>>   
> >>>   	em28xx_info("Registering V4L2 extension\n");
> >>>   
> >>> +	kref_get(&dev->ref);
> >>> +
> >>>   	mutex_lock(&dev->lock);
> >>>   
> >>>   	ret = v4l2_device_register(&dev->udev->dev, &dev->v4l2_dev);
> >>> diff --git a/drivers/media/usb/em28xx/em28xx.h b/drivers/media/usb/em28xx/em28xx.h
> >>> index 5d5d1b6f0294..d38c08e4da60 100644
> >>> --- a/drivers/media/usb/em28xx/em28xx.h
> >>> +++ b/drivers/media/usb/em28xx/em28xx.h
> >>> @@ -32,6 +32,7 @@
> >>>   #include <linux/workqueue.h>
> >>>   #include <linux/i2c.h>
> >>>   #include <linux/mutex.h>
> >>> +#include <linux/kref.h>
> >>>   #include <linux/videodev2.h>
> >>>   
> >>>   #include <media/videobuf2-vmalloc.h>
> >>> @@ -531,9 +532,11 @@ struct em28xx_i2c_bus {
> >>>   	enum em28xx_i2c_algo_type algo_type;
> >>>   };
> >>>   
> >>> -
> >>>   /* main device struct */
> >>>   struct em28xx {
> >>> +	struct kref ref;
> >>> +
> >>> +
> >>>   	/* generic device properties */
> >>>   	char name[30];		/* name (including minor) of the device */
> >>>   	int model;		/* index in the device_data struct */
> >>> @@ -706,6 +709,8 @@ struct em28xx {
> >>>   	struct em28xx_dvb *dvb;
> >>>   };
> >>>   
> >>> +#define kref_to_dev(d) container_of(d, struct em28xx, ref)
> >>> +
> >>>   struct em28xx_ops {
> >>>   	struct list_head next;
> >>>   	char *name;
> >>> @@ -763,7 +768,7 @@ extern struct em28xx_board em28xx_boards[];
> >>>   extern struct usb_device_id em28xx_id_table[];
> >>>   int em28xx_tuner_callback(void *ptr, int component, int command, int arg);
> >>>   void em28xx_setup_xc3028(struct em28xx *dev, struct xc2028_ctrl *ctl);
> >>> -void em28xx_release_resources(struct em28xx *dev);
> >>> +void em28xx_free_device(struct kref *ref);
> >>>   
> >>>   /* Provided by em28xx-camera.c */
> >>>   int em28xx_detect_sensor(struct em28xx *dev);
> >> I welcome this patch and the general approach looks good.
> >> I had started working on the same issue, but it's not that trivial.
> >>
> >> At first glance there seem to be several issues, but I will need to 
> >> review this patch in more detail and also make some tests.
> >> Unfortunately, I don't have much time this evening, So could you please 
> >> hold it back another day ?
> >> I hope I can review the other remaining patch of this series (patch 5/7) 
> >> later this evening.
> > We're running out of time for 3.14. I think we should merge this patch
> > series, and your patch series for 3.14, to be together with the em28xx-v4l
> > split.
> >
> > My plan is to merge the remaining patches for 3.14 today or, in the worse
> > case, tomorrow.
> >
> > If we slip on some bug, we'll still have the 3.14-rc cycle to fix, if the
> > series gets merged, but, if we miss the bus, I'm afraid that we'll end
> > by having more problems that will be hard to fix with trivial patches, due
> > to em28xx-v4l split changes that also affected the driver removal and device
> > close code.
> >
> > FYI, I tested this code and also Antti with our devices, randomly removing
> > the devices while streaming, and this is now finally working.
> >
> > I won't doubt that there are some cases that require fixes (and
> > it seems that em28xx-rc has one of such corner cases), but they'll likely
> > can be solved with somewhat short and trivial patches.
> >
> > Cheers,
> > Mauro
> 
> This is a very critical patch and exactly the kind of change that should
> _never_ be hurried !
> FAICS it has some severe issues and it's not clear how easy it will be
> to fix it within the the 3.14-rc cycle.
> As long as it's not ready, don't merge it for 3.14.

What issues? So far, you didn't point any. On both my tests and Antti's one,
with this series, there were significant improvements on removing existing
bugs with device removal.

> em28xx resources releasing is broken since ... well... at least 2 years.
> 3.14 will already be much better and nobody will care if this remaining
> issue is addressed a kernel release later.

Although I think that we're properly releasing resources, I'm a way less
concerned about keeping some leaked memory while releasing them than I am 
concerned that a device removal that would cause an OOPS, or a deadly
crash at the USB or ALSA stack that prevents other devices to be probed.

Due to em28xx-v4l calling em28xx_release_resources(), now both the
USB and ALSA stacks crashes if you remove a device while ALSA is streaming.

That happens because em28xx, I2C, etc will be freed by em28xx-v4l, but
those resources are still needed by em28xx-alsa. That makes that the
.fini code there to cause crash at ALSA stack, and, sometimes, at the
USB stack.

As nowadays lots of components depend on pulseaudio, the ALSA crash
causes pulse to stop work, likely keeping it into some dead lock status.
This makes the entire machine to become really slow, when it doesn't
crash.

This is a serious regression that should be fixed.

This patch series for sure fixes it. As I said, there are two independent
series of tests verifying that (both using several different em28xx 
devices).

> 
> Be warned !
> 
> 


-- 

Cheers,
Mauro

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 5/7] em28xx-audio: remove a deplock circular dependency
  2014-01-13 21:51   ` Frank Schäfer
@ 2014-01-14 15:45     ` Mauro Carvalho Chehab
  2014-01-14 18:43       ` Frank Schäfer
  0 siblings, 1 reply; 40+ messages in thread
From: Mauro Carvalho Chehab @ 2014-01-14 15:45 UTC (permalink / raw)
  To: Frank Schäfer; +Cc: Linux Media Mailing List, Mauro Carvalho Chehab

Em Mon, 13 Jan 2014 22:51:00 +0100
Frank Schäfer <fschaefer.oss@googlemail.com> escreveu:

> Am 13.01.2014 00:00, schrieb Mauro Carvalho Chehab:
> > We can't lock at pcm close, as it causes circular dependency
> > lock issues with .init and .fini callbacks. So, move the code
> > that puts the device on mute to the kthread.
> >
> >     [  322.026316] ======================================================
> >     [  322.026356] [ INFO: possible circular locking dependency detected ]
> >     [  322.026397] 3.13.0-rc1+ #24 Not tainted
> >     [  322.026437] -------------------------------------------------------
> >     [  322.026476] khubd/54 is trying to acquire lock:
> >     [  322.026516]  (&pcm->open_mutex){+.+.+.}, at: [<ffffffffa04819e6>] snd_pcm_dev_disconnect+0x46/0x1e0 [snd_pcm]
> >     [  322.026727]
> >     but task is already holding lock:
> >     [  322.026767]  (register_mutex#3){+.+.+.}, at: [<ffffffffa04819c4>] snd_pcm_dev_disconnect+0x24/0x1e0 [snd_pcm]
> >     [  322.027005]
> >     which lock already depends on the new lock.
> >
> >     [  322.027045]
> >     the existing dependency chain (in reverse order) is:
> >     [  322.027084]
> >     -> #2 (register_mutex#3){+.+.+.}:
> >     [  322.027318]        [<ffffffff810b8fa3>] __lock_acquire+0xb43/0x1330
> >     [  322.027401]        [<ffffffff810b9f82>] lock_acquire+0xa2/0x120
> >     [  322.027479]        [<ffffffff816a5b6c>] mutex_lock_nested+0x5c/0x3c0
> >     [  322.027559]        [<ffffffffa04819c4>] snd_pcm_dev_disconnect+0x24/0x1e0 [snd_pcm]
> >     [  322.027642]        [<ffffffffa02e855a>] snd_device_disconnect+0x6a/0xf0 [snd]
> >     [  322.027727]        [<ffffffffa02e86ac>] snd_device_disconnect_all+0x4c/0x90 [snd]
> >     [  322.027814]        [<ffffffffa02e1876>] snd_card_disconnect+0x126/0x1d0 [snd]
> >     [  322.027898]        [<ffffffffa02e1ea8>] snd_card_free+0x18/0x90 [snd]
> >     [  322.027982]        [<ffffffffa087235f>] em28xx_audio_fini+0x8f/0xa0 [em28xx_alsa]
> >     [  322.028063]        [<ffffffffa085cba6>] em28xx_close_extension+0x56/0x90 [em28xx]
> >     [  322.028143]        [<ffffffffa085e639>] em28xx_usb_disconnect+0x79/0x90 [em28xx]
> >     [  322.028222]        [<ffffffff814a06e7>] usb_unbind_interface+0x67/0x1d0
> >     [  322.028302]        [<ffffffff8142920f>] __device_release_driver+0x7f/0xf0
> >     [  322.028381]        [<ffffffff814292a5>] device_release_driver+0x25/0x40
> >     [  322.028462]        [<ffffffff81428b0c>] bus_remove_device+0x11c/0x1a0
> >     [  322.028540]        [<ffffffff81425536>] device_del+0x136/0x1d0
> >     [  322.028619]        [<ffffffff8149e0c0>] usb_disable_device+0xb0/0x290
> >     [  322.028698]        [<ffffffff814930c5>] usb_disconnect+0xb5/0x1d0
> >     [  322.028779]        [<ffffffff81495ab6>] hub_port_connect_change+0xd6/0xad0
> >     [  322.028859]        [<ffffffff814967c3>] hub_events+0x313/0x9b0
> >     [  322.028940]        [<ffffffff81496e95>] hub_thread+0x35/0x170
> >     [  322.029019]        [<ffffffff8108ea2f>] kthread+0xff/0x120
> >     [  322.029099]        [<ffffffff816b187c>] ret_from_fork+0x7c/0xb0
> >     [  322.029179]
> >     -> #1 (&dev->lock#2){+.+.+.}:
> >     [  322.029414]        [<ffffffff810b8fa3>] __lock_acquire+0xb43/0x1330
> >     [  322.029494]        [<ffffffff810b9f82>] lock_acquire+0xa2/0x120
> >     [  322.029572]        [<ffffffff816a5b6c>] mutex_lock_nested+0x5c/0x3c0
> >     [  322.029651]        [<ffffffffa087122e>] snd_em28xx_pcm_close+0x3e/0x100 [em28xx_alsa]
> >     [  322.029732]        [<ffffffffa048620f>] snd_pcm_release_substream.part.29+0x3f/0x90 [snd_pcm]
> >     [  322.029816]        [<ffffffffa0486340>] snd_pcm_release+0xb0/0xd0 [snd_pcm]
> >     [  322.029900]        [<ffffffff811c9752>] __fput+0xe2/0x230
> >     [  322.029979]        [<ffffffff811c98ee>] ____fput+0xe/0x10
> >     [  322.030057]        [<ffffffff8108b64f>] task_work_run+0x9f/0xe0
> >     [  322.030135]        [<ffffffff81013a81>] do_notify_resume+0x61/0xa0
> >     [  322.030223]        [<ffffffff816b1c62>] int_signal+0x12/0x17
> >     [  322.030294]
> >     -> #0 (&pcm->open_mutex){+.+.+.}:
> >     [  322.030473]        [<ffffffff810b7a47>] check_prevs_add+0x947/0x950
> >     [  322.030546]        [<ffffffff810b8fa3>] __lock_acquire+0xb43/0x1330
> >     [  322.030618]        [<ffffffff810b9f82>] lock_acquire+0xa2/0x120
> >     [  322.030689]        [<ffffffff816a5b6c>] mutex_lock_nested+0x5c/0x3c0
> >     [  322.030760]        [<ffffffffa04819e6>] snd_pcm_dev_disconnect+0x46/0x1e0 [snd_pcm]
> >     [  322.030835]        [<ffffffffa02e855a>] snd_device_disconnect+0x6a/0xf0 [snd]
> >     [  322.030913]        [<ffffffffa02e86ac>] snd_device_disconnect_all+0x4c/0x90 [snd]
> >     [  322.030988]        [<ffffffffa02e1876>] snd_card_disconnect+0x126/0x1d0 [snd]
> >     [  322.031067]        [<ffffffffa02e1ea8>] snd_card_free+0x18/0x90 [snd]
> >     [  322.031146]        [<ffffffffa087235f>] em28xx_audio_fini+0x8f/0xa0 [em28xx_alsa]
> >     [  322.031220]        [<ffffffffa085cba6>] em28xx_close_extension+0x56/0x90 [em28xx]
> >     [  322.031292]        [<ffffffffa085e639>] em28xx_usb_disconnect+0x79/0x90 [em28xx]
> >     [  322.031363]        [<ffffffff814a06e7>] usb_unbind_interface+0x67/0x1d0
> >     [  322.031433]        [<ffffffff8142920f>] __device_release_driver+0x7f/0xf0
> >     [  322.031503]        [<ffffffff814292a5>] device_release_driver+0x25/0x40
> >     [  322.031573]        [<ffffffff81428b0c>] bus_remove_device+0x11c/0x1a0
> >     [  322.031643]        [<ffffffff81425536>] device_del+0x136/0x1d0
> >     [  322.031714]        [<ffffffff8149e0c0>] usb_disable_device+0xb0/0x290
> >     [  322.031784]        [<ffffffff814930c5>] usb_disconnect+0xb5/0x1d0
> >     [  322.031853]        [<ffffffff81495ab6>] hub_port_connect_change+0xd6/0xad0
> >     [  322.031922]        [<ffffffff814967c3>] hub_events+0x313/0x9b0
> >     [  322.031992]        [<ffffffff81496e95>] hub_thread+0x35/0x170
> >     [  322.032062]        [<ffffffff8108ea2f>] kthread+0xff/0x120
> >     [  322.032135]        [<ffffffff816b187c>] ret_from_fork+0x7c/0xb0
> >     [  322.032205]
> >     other info that might help us debug this:
> >
> >     [  322.032240] Chain exists of:
> >       &pcm->open_mutex --> &dev->lock#2 --> register_mutex#3
> >
> >     [  322.032547]  Possible unsafe locking scenario:
> >
> >     [  322.032582]        CPU0                    CPU1
> >     [  322.032616]        ----                    ----
> >     [  322.032654]   lock(register_mutex#3);
> >     [  322.032793]                                lock(&dev->lock#2);
> >     [  322.032929]                                lock(register_mutex#3);
> >     [  322.033064]   lock(&pcm->open_mutex);
> >     [  322.033168]
> >      *** DEADLOCK ***
> >
> >     [  322.033204] 6 locks held by khubd/54:
> >     [  322.033239]  #0:  (&__lockdep_no_validate__){......}, at: [<ffffffff81496564>] hub_events+0xb4/0x9b0
> >     [  322.033446]  #1:  (&__lockdep_no_validate__){......}, at: [<ffffffff81493076>] usb_disconnect+0x66/0x1d0
> >     [  322.033655]  #2:  (&__lockdep_no_validate__){......}, at: [<ffffffff8142929d>] device_release_driver+0x1d/0x40
> >     [  322.033859]  #3:  (em28xx_devlist_mutex){+.+.+.}, at: [<ffffffffa085cb77>] em28xx_close_extension+0x27/0x90 [em28xx]
> >     [  322.034067]  #4:  (&dev->lock#2){+.+.+.}, at: [<ffffffffa085cb81>] em28xx_close_extension+0x31/0x90 [em28xx]
> >     [  322.034307]  #5:  (register_mutex#3){+.+.+.}, at: [<ffffffffa04819c4>] snd_pcm_dev_disconnect+0x24/0x1e0 [snd_pcm]
> >     [  322.034552]
> >     stack backtrace:
> >     [  322.034588] CPU: 3 PID: 54 Comm: khubd Not tainted 3.13.0-rc1+ #24
> >     [  322.034624] Hardware name: SAMSUNG ELECTRONICS CO., LTD. 550P5C/550P7C/SAMSUNG_NP1234567890, BIOS P04ABI.013.130220.dg 02/20/2013
> >     [  322.034659]  ffffffff82513770 ffff880221bcd7c8 ffffffff816a03c6 ffffffff8250a810
> >     [  322.034832]  ffff880221bcd808 ffffffff8169a203 ffff880221bcd830 0000000000000005
> >     [  322.035004]  ffff8802222b2880 ffff8802222b3020 ffff8802222b3020 0000000000000006
> >     [  322.035187] Call Trace:
> >     [  322.035230]  [<ffffffff816a03c6>] dump_stack+0x45/0x56
> >     [  322.035276]  [<ffffffff8169a203>] print_circular_bug+0x200/0x20e
> >     [  322.035320]  [<ffffffff810b7a47>] check_prevs_add+0x947/0x950
> >     [  322.035365]  [<ffffffff8101b303>] ? native_sched_clock+0x13/0x80
> >     [  322.035409]  [<ffffffff810b8fa3>] __lock_acquire+0xb43/0x1330
> >     [  322.035454]  [<ffffffff810b9f82>] lock_acquire+0xa2/0x120
> >     [  322.035500]  [<ffffffffa04819e6>] ? snd_pcm_dev_disconnect+0x46/0x1e0 [snd_pcm]
> >     [  322.035550]  [<ffffffff816a5b6c>] mutex_lock_nested+0x5c/0x3c0
> >     [  322.035596]  [<ffffffffa04819e6>] ? snd_pcm_dev_disconnect+0x46/0x1e0 [snd_pcm]
> >     [  322.035648]  [<ffffffffa04819e6>] ? snd_pcm_dev_disconnect+0x46/0x1e0 [snd_pcm]
> >     [  322.035697]  [<ffffffff810b8045>] ? trace_hardirqs_on_caller+0x105/0x1d0
> >     [  322.035744]  [<ffffffffa04819e6>] snd_pcm_dev_disconnect+0x46/0x1e0 [snd_pcm]
> >     [  322.035797]  [<ffffffffa02e855a>] snd_device_disconnect+0x6a/0xf0 [snd]
> >     [  322.035852]  [<ffffffffa02e86ac>] snd_device_disconnect_all+0x4c/0x90 [snd]
> >     [  322.035904]  [<ffffffffa02e1876>] snd_card_disconnect+0x126/0x1d0 [snd]
> >     [  322.035957]  [<ffffffffa02e1ea8>] snd_card_free+0x18/0x90 [snd]
> >     [  322.036008]  [<ffffffffa087235f>] em28xx_audio_fini+0x8f/0xa0 [em28xx_alsa]
> >     [  322.036054]  [<ffffffffa085cba6>] em28xx_close_extension+0x56/0x90 [em28xx]
> >     [  322.036100]  [<ffffffffa085e639>] em28xx_usb_disconnect+0x79/0x90 [em28xx]
> >     [  322.036144]  [<ffffffff814a06e7>] usb_unbind_interface+0x67/0x1d0
> >     [  322.036188]  [<ffffffff8142920f>] __device_release_driver+0x7f/0xf0
> >     [  322.036231]  [<ffffffff814292a5>] device_release_driver+0x25/0x40
> >     [  322.036274]  [<ffffffff81428b0c>] bus_remove_device+0x11c/0x1a0
> >     [  322.036318]  [<ffffffff81425536>] device_del+0x136/0x1d0
> >     [  322.036361]  [<ffffffff8149e0c0>] usb_disable_device+0xb0/0x290
> >     [  322.036404]  [<ffffffff814930c5>] usb_disconnect+0xb5/0x1d0
> >     [  322.036447]  [<ffffffff81495ab6>] hub_port_connect_change+0xd6/0xad0
> >     [  322.036492]  [<ffffffff8149cb04>] ? usb_control_msg+0xd4/0x110
> >     [  322.036535]  [<ffffffff814967c3>] hub_events+0x313/0x9b0
> >     [  322.036579]  [<ffffffff810b8045>] ? trace_hardirqs_on_caller+0x105/0x1d0
> >     [  322.036623]  [<ffffffff81496e95>] hub_thread+0x35/0x170
> >     [  322.036667]  [<ffffffff810af310>] ? abort_exclusive_wait+0xb0/0xb0
> >     [  322.036711]  [<ffffffff81496e60>] ? hub_events+0x9b0/0x9b0
> >     [  322.036756]  [<ffffffff8108ea2f>] kthread+0xff/0x120
> >     [  322.036802]  [<ffffffff8108e930>] ? kthread_create_on_node+0x250/0x250
> >     [  322.036846]  [<ffffffff816b187c>] ret_from_fork+0x7c/0xb0
> >     [  322.036890]  [<ffffffff8108e930>] ? kthread_create_on_node+0x250/0x250
> >
> > Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
> > ---
> >  drivers/media/usb/em28xx/em28xx-audio.c | 10 +++++++---
> >  1 file changed, 7 insertions(+), 3 deletions(-)
> >
> > diff --git a/drivers/media/usb/em28xx/em28xx-audio.c b/drivers/media/usb/em28xx/em28xx-audio.c
> > index cdc2fcf3e05e..5e16fcf18cac 100644
> > --- a/drivers/media/usb/em28xx/em28xx-audio.c
> > +++ b/drivers/media/usb/em28xx/em28xx-audio.c
> > @@ -311,20 +311,17 @@ static int snd_em28xx_pcm_close(struct snd_pcm_substream *substream)
> >  	dprintk("closing device\n");
> >  
> >  	dev->mute = 1;
> > -	mutex_lock(&dev->lock);
> >  	dev->adev.users--;
> >  	if (atomic_read(&dev->stream_started) > 0) {
> >  		atomic_set(&dev->stream_started, 0);
> >  		schedule_work(&dev->wq_trigger);
> >  	}
> >  
> > -	em28xx_audio_analog_set(dev);
> >  	if (substream->runtime->dma_area) {
> >  		dprintk("freeing\n");
> >  		vfree(substream->runtime->dma_area);
> >  		substream->runtime->dma_area = NULL;
> >  	}
> > -	mutex_unlock(&dev->lock);
> >  
> >  	return 0;
> >  }
> > @@ -395,6 +392,13 @@ static void audio_trigger(struct work_struct *work)
> >  	} else {
> >  		dprintk("stopping capture");
> >  		em28xx_deinit_isoc_audio(dev);
> > +
> > +		/* Mute device if needed */
> > +		if (dev->mute) {
> > +			mutex_lock(&dev->lock);
> > +			em28xx_audio_analog_set(dev);
> > +			mutex_unlock(&dev->lock);
> > +		}
> >  	}
> >  }
> It's already late and I don't understand this deadlock yet completely,
> but are you sure this is the proper fix for this issue ?

This is one possible way to fix.

> What happens when capturing is restarted ? Shouldn't the device then be
> unmuted again ?

Please note that, inside em28xx-audio.c, only the open callback unmutes
the device, and only the close callback sets it to mute.

As the close callback ask the work tree to run, the above code will
defer mute to when the work queue runs.

So, the logic seems equivalent to the existing logic.

It should be noticed that we can change that code to always call 
em28xx_audio_analog_set() there, and remove the code that calls 
it from snd_em28xx_capture_open().

I can't see any functional changes with such changes.

That's said, I remember we spent lots of time at linux-media
discussing if the alsa start should automatically unmute a
device or just keep it as-is.

I don't remember the exact results, but I think we opted to put the
unmute code there due to pulseaudio bugs, as, without such code,
pulseaudio would change the mixers and make some mess.

> How often does the start/stop/resume happen ?

At device open, it starts. At device closes, it stops.

If a buffer underrun/overrun occurs, it will stop/start, but,
in that case, the dev->mute state won't change.

Regards,

Cheers,
Mauro

^ permalink raw reply	[flat|nested] 40+ messages in thread

* [PATCH v2] em28xx: Only deallocate struct em28xx after finishing all extensions
  2014-01-12 23:00 ` [PATCH 3/7] em28xx: Only deallocate struct em28xx after finishing all extensions Mauro Carvalho Chehab
  2014-01-13 19:02   ` Frank Schäfer
@ 2014-01-14 17:36   ` Mauro Carvalho Chehab
  2014-01-15 21:13     ` Frank Schäfer
  1 sibling, 1 reply; 40+ messages in thread
From: Mauro Carvalho Chehab @ 2014-01-14 17:36 UTC (permalink / raw)
  Cc: Mauro Carvalho Chehab, Linux Media Mailing List,
	Mauro Carvalho Chehab

We can't free struct em28xx while one of the extensions is still
using it.

So, add a kref() to control it, freeing it only after the
extensions fini calls.

Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
---

v2:
	- patch was rebased;
	- as em28xx-audio close uses struct em28xx dev, add a kref in order
	  to track audio open/close.

 drivers/media/usb/em28xx/em28xx-audio.c |  8 +++++++-
 drivers/media/usb/em28xx/em28xx-cards.c | 34 ++++++++++++++++-----------------
 drivers/media/usb/em28xx/em28xx-dvb.c   |  5 ++++-
 drivers/media/usb/em28xx/em28xx-input.c |  8 +++++++-
 drivers/media/usb/em28xx/em28xx-video.c | 14 ++++++++------
 drivers/media/usb/em28xx/em28xx.h       |  9 +++++++--
 6 files changed, 50 insertions(+), 28 deletions(-)

diff --git a/drivers/media/usb/em28xx/em28xx-audio.c b/drivers/media/usb/em28xx/em28xx-audio.c
index 45bea1adc11c..73eeeaf6551f 100644
--- a/drivers/media/usb/em28xx/em28xx-audio.c
+++ b/drivers/media/usb/em28xx/em28xx-audio.c
@@ -265,6 +265,8 @@ static int snd_em28xx_capture_open(struct snd_pcm_substream *substream)
 
 	dprintk("opening device and trying to acquire exclusive lock\n");
 
+	kref_get(&dev->ref);
+
 	runtime->hw = snd_em28xx_hw_capture;
 	if ((dev->alt == 0 || dev->audio_ifnum) && dev->adev.users == 0) {
 		int nonblock = !!(substream->f_flags & O_NONBLOCK);
@@ -330,6 +332,7 @@ static int snd_em28xx_pcm_close(struct snd_pcm_substream *substream)
 		substream->runtime->dma_area = NULL;
 	}
 	mutex_unlock(&dev->lock);
+	kref_put(&dev->ref, em28xx_free_device);
 
 	return 0;
 }
@@ -886,6 +889,8 @@ static int em28xx_audio_init(struct em28xx *dev)
 
 	em28xx_info("Binding audio extension\n");
 
+	kref_get(&dev->ref);
+
 	printk(KERN_INFO "em28xx-audio.c: Copyright (C) 2006 Markus "
 			 "Rechberger\n");
 	printk(KERN_INFO
@@ -958,7 +963,7 @@ static int em28xx_audio_fini(struct em28xx *dev)
 	if (dev == NULL)
 		return 0;
 
-	if (dev->has_alsa_audio != 1) {
+	if (!dev->has_alsa_audio) {
 		/* This device does not support the extension (in this case
 		   the device is expecting the snd-usb-audio module or
 		   doesn't have analog audio support at all) */
@@ -977,6 +982,7 @@ static int em28xx_audio_fini(struct em28xx *dev)
 		dev->adev.sndcard = NULL;
 	}
 
+	kref_put(&dev->ref, em28xx_free_device);
 	return 0;
 }
 
diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c
index e08d65b2e352..8fc0a437054e 100644
--- a/drivers/media/usb/em28xx/em28xx-cards.c
+++ b/drivers/media/usb/em28xx/em28xx-cards.c
@@ -2867,16 +2867,18 @@ static void flush_request_modules(struct em28xx *dev)
 	flush_work(&dev->request_module_wk);
 }
 
-/*
- * em28xx_release_resources()
- * unregisters the v4l2,i2c and usb devices
- * called when the device gets disconnected or at module unload
-*/
-void em28xx_release_resources(struct em28xx *dev)
+/**
+ * em28xx_release_resources() -  unregisters the v4l2,i2c and usb devices
+ *
+ * @ref: struct kref for em28xx device
+ *
+ * This is called when all extensions and em28xx core unregisters a device
+ */
+void em28xx_free_device(struct kref *ref)
 {
-	/*FIXME: I2C IR should be disconnected */
+	struct em28xx *dev = kref_to_dev(ref);
 
-	mutex_lock(&dev->lock);
+	em28xx_info("Freeing device\n");
 
 	if (dev->def_i2c_bus)
 		em28xx_i2c_unregister(dev, 1);
@@ -2887,9 +2889,10 @@ void em28xx_release_resources(struct em28xx *dev)
 	/* Mark device as unused */
 	clear_bit(dev->devno, &em28xx_devused);
 
-	mutex_unlock(&dev->lock);
-};
-EXPORT_SYMBOL_GPL(em28xx_release_resources);
+	kfree(dev->alt_max_pkt_size_isoc);
+	kfree(dev);
+}
+EXPORT_SYMBOL_GPL(em28xx_free_device);
 
 /*
  * em28xx_init_dev()
@@ -3342,6 +3345,8 @@ static int em28xx_usb_probe(struct usb_interface *interface,
 			    dev->dvb_xfer_bulk ? "bulk" : "isoc");
 	}
 
+	kref_init(&dev->ref);
+
 	request_modules(dev);
 
 	/* Should be the last thing to do, to avoid newer udev's to
@@ -3385,12 +3390,7 @@ static void em28xx_usb_disconnect(struct usb_interface *interface)
 
 	em28xx_close_extension(dev);
 
-	em28xx_release_resources(dev);
-
-	if (!dev->users) {
-		kfree(dev->alt_max_pkt_size_isoc);
-		kfree(dev);
-	}
+	kref_put(&dev->ref, em28xx_free_device);
 }
 
 static struct usb_driver em28xx_usb_driver = {
diff --git a/drivers/media/usb/em28xx/em28xx-dvb.c b/drivers/media/usb/em28xx/em28xx-dvb.c
index 881a813836eb..7df21e33a923 100644
--- a/drivers/media/usb/em28xx/em28xx-dvb.c
+++ b/drivers/media/usb/em28xx/em28xx-dvb.c
@@ -1005,11 +1005,11 @@ static int em28xx_dvb_init(struct em28xx *dev)
 	em28xx_info("Binding DVB extension\n");
 
 	dvb = kzalloc(sizeof(struct em28xx_dvb), GFP_KERNEL);
-
 	if (dvb == NULL) {
 		em28xx_info("em28xx_dvb: memory allocation failed\n");
 		return -ENOMEM;
 	}
+	kref_get(&dev->ref);
 	dev->dvb = dvb;
 	dvb->fe[0] = dvb->fe[1] = NULL;
 
@@ -1437,6 +1437,7 @@ static int em28xx_dvb_init(struct em28xx *dev)
 	dvb->adapter.mfe_shared = mfe_shared;
 
 	em28xx_info("DVB extension successfully initialized\n");
+
 ret:
 	em28xx_set_mode(dev, EM28XX_SUSPEND);
 	mutex_unlock(&dev->lock);
@@ -1489,6 +1490,8 @@ static int em28xx_dvb_fini(struct em28xx *dev)
 		dev->dvb = NULL;
 	}
 
+	kref_put(&dev->ref, em28xx_free_device);
+
 	return 0;
 }
 
diff --git a/drivers/media/usb/em28xx/em28xx-input.c b/drivers/media/usb/em28xx/em28xx-input.c
index 3d54c04e5230..c98d784a2772 100644
--- a/drivers/media/usb/em28xx/em28xx-input.c
+++ b/drivers/media/usb/em28xx/em28xx-input.c
@@ -675,6 +675,8 @@ static int em28xx_ir_init(struct em28xx *dev)
 		return 0;
 	}
 
+	kref_get(&dev->ref);
+
 	if (dev->board.buttons)
 		em28xx_init_buttons(dev);
 
@@ -817,7 +819,7 @@ static int em28xx_ir_fini(struct em28xx *dev)
 
 	/* skip detach on non attached boards */
 	if (!ir)
-		return 0;
+		goto ref_put;
 
 	if (ir->rc)
 		rc_unregister_device(ir->rc);
@@ -825,6 +827,10 @@ static int em28xx_ir_fini(struct em28xx *dev)
 	/* done */
 	kfree(ir);
 	dev->ir = NULL;
+
+ref_put:
+	kref_put(&dev->ref, em28xx_free_device);
+
 	return 0;
 }
 
diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c
index aabcafbdab46..f801af8d3f61 100644
--- a/drivers/media/usb/em28xx/em28xx-video.c
+++ b/drivers/media/usb/em28xx/em28xx-video.c
@@ -1837,6 +1837,7 @@ static int em28xx_v4l2_open(struct file *filp)
 			video_device_node_name(vdev), v4l2_type_names[fh_type],
 			dev->users);
 
+	kref_get(&dev->ref);
 
 	if (mutex_lock_interruptible(&dev->lock))
 		return -ERESTARTSYS;
@@ -1926,9 +1927,8 @@ static int em28xx_v4l2_fini(struct em28xx *dev)
 	v4l2_ctrl_handler_free(&dev->ctrl_handler);
 	v4l2_device_unregister(&dev->v4l2_dev);
 
-	if (dev->users)
-		em28xx_warn("Device is open ! Memory deallocation is deferred on last close.\n");
 	mutex_unlock(&dev->lock);
+	kref_put(&dev->ref, em28xx_free_device);
 
 	return 0;
 }
@@ -1950,11 +1950,9 @@ static int em28xx_v4l2_close(struct file *filp)
 	mutex_lock(&dev->lock);
 
 	if (dev->users == 1) {
-		/* free the remaining resources if device is disconnected */
-		if (dev->disconnected) {
-			kfree(dev->alt_max_pkt_size_isoc);
+		/* No sense to try to write to the device */
+		if (dev->disconnected)
 			goto exit;
-		}
 
 		/* Save some power by putting tuner to sleep */
 		v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_power, 0);
@@ -1975,6 +1973,8 @@ static int em28xx_v4l2_close(struct file *filp)
 exit:
 	dev->users--;
 	mutex_unlock(&dev->lock);
+	kref_put(&dev->ref, em28xx_free_device);
+
 	return 0;
 }
 
@@ -2206,6 +2206,8 @@ static int em28xx_v4l2_init(struct em28xx *dev)
 
 	em28xx_info("Registering V4L2 extension\n");
 
+	kref_get(&dev->ref);
+
 	mutex_lock(&dev->lock);
 
 	ret = v4l2_device_register(&dev->udev->dev, &dev->v4l2_dev);
diff --git a/drivers/media/usb/em28xx/em28xx.h b/drivers/media/usb/em28xx/em28xx.h
index 10b817245f7e..8b3438891bb3 100644
--- a/drivers/media/usb/em28xx/em28xx.h
+++ b/drivers/media/usb/em28xx/em28xx.h
@@ -32,6 +32,7 @@
 #include <linux/workqueue.h>
 #include <linux/i2c.h>
 #include <linux/mutex.h>
+#include <linux/kref.h>
 #include <linux/videodev2.h>
 
 #include <media/videobuf2-vmalloc.h>
@@ -533,9 +534,11 @@ struct em28xx_i2c_bus {
 	enum em28xx_i2c_algo_type algo_type;
 };
 
-
 /* main device struct */
 struct em28xx {
+	struct kref ref;
+
+
 	/* generic device properties */
 	char name[30];		/* name (including minor) of the device */
 	int model;		/* index in the device_data struct */
@@ -708,6 +711,8 @@ struct em28xx {
 	struct em28xx_dvb *dvb;
 };
 
+#define kref_to_dev(d) container_of(d, struct em28xx, ref)
+
 struct em28xx_ops {
 	struct list_head next;
 	char *name;
@@ -765,7 +770,7 @@ extern struct em28xx_board em28xx_boards[];
 extern struct usb_device_id em28xx_id_table[];
 int em28xx_tuner_callback(void *ptr, int component, int command, int arg);
 void em28xx_setup_xc3028(struct em28xx *dev, struct xc2028_ctrl *ctl);
-void em28xx_release_resources(struct em28xx *dev);
+void em28xx_free_device(struct kref *ref);
 
 /* Provided by em28xx-camera.c */
 int em28xx_detect_sensor(struct em28xx *dev);
-- 
1.8.3.1


^ permalink raw reply related	[flat|nested] 40+ messages in thread

* Re: [PATCH 3/7] em28xx: Only deallocate struct em28xx after finishing all extensions
  2014-01-14 13:10         ` Mauro Carvalho Chehab
@ 2014-01-14 18:13           ` Frank Schäfer
  2014-01-14 18:55             ` Mauro Carvalho Chehab
  0 siblings, 1 reply; 40+ messages in thread
From: Frank Schäfer @ 2014-01-14 18:13 UTC (permalink / raw)
  To: Mauro Carvalho Chehab; +Cc: Linux Media Mailing List, Mauro Carvalho Chehab

On 14.01.2014 14:10, Mauro Carvalho Chehab wrote:
> Em Mon, 13 Jan 2014 22:55:36 +0100
> Frank Schäfer <fschaefer.oss@googlemail.com> escreveu:
>
>> Am 13.01.2014 20:23, schrieb Mauro Carvalho Chehab:
>>> Em Mon, 13 Jan 2014 20:02:19 +0100
>>> Frank Schäfer <fschaefer.oss@googlemail.com> escreveu:
>>>
>>>> On 13.01.2014 00:00, Mauro Carvalho Chehab wrote:
>>>>> We can't free struct em28xx while one of the extensions is still
>>>>> using it.
>>>>>
>>>>> So, add a kref() to control it, freeing it only after the
>>>>> extensions fini calls.
>>>>>
>>>>> Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
>>>>> ---
>>>>>    drivers/media/usb/em28xx/em28xx-audio.c |  5 ++++-
>>>>>    drivers/media/usb/em28xx/em28xx-cards.c | 34 ++++++++++++++++-----------------
>>>>>    drivers/media/usb/em28xx/em28xx-dvb.c   |  5 ++++-
>>>>>    drivers/media/usb/em28xx/em28xx-input.c |  8 +++++++-
>>>>>    drivers/media/usb/em28xx/em28xx-video.c | 11 +++++------
>>>>>    drivers/media/usb/em28xx/em28xx.h       |  9 +++++++--
>>>>>    6 files changed, 44 insertions(+), 28 deletions(-)
>>>>>
>>>>> diff --git a/drivers/media/usb/em28xx/em28xx-audio.c b/drivers/media/usb/em28xx/em28xx-audio.c
>>>>> index 97d9105e6830..8e959dae8358 100644
>>>>> --- a/drivers/media/usb/em28xx/em28xx-audio.c
>>>>> +++ b/drivers/media/usb/em28xx/em28xx-audio.c
>>>>> @@ -878,6 +878,8 @@ static int em28xx_audio_init(struct em28xx *dev)
>>>>>    
>>>>>    	em28xx_info("Binding audio extension\n");
>>>>>    
>>>>> +	kref_get(&dev->ref);
>>>>> +
>>>>>    	printk(KERN_INFO "em28xx-audio.c: Copyright (C) 2006 Markus "
>>>>>    			 "Rechberger\n");
>>>>>    	printk(KERN_INFO
>>>>> @@ -949,7 +951,7 @@ static int em28xx_audio_fini(struct em28xx *dev)
>>>>>    	if (dev == NULL)
>>>>>    		return 0;
>>>>>    
>>>>> -	if (dev->has_alsa_audio != 1) {
>>>>> +	if (!dev->has_alsa_audio) {
>>>>>    		/* This device does not support the extension (in this case
>>>>>    		   the device is expecting the snd-usb-audio module or
>>>>>    		   doesn't have analog audio support at all) */
>>>>> @@ -963,6 +965,7 @@ static int em28xx_audio_fini(struct em28xx *dev)
>>>>>    		dev->adev.sndcard = NULL;
>>>>>    	}
>>>>>    
>>>>> +	kref_put(&dev->ref, em28xx_free_device);
>>>>>    	return 0;
>>>>>    }
>>>>>    
>>>>> diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c
>>>>> index 3b332d527ccb..df92f417634a 100644
>>>>> --- a/drivers/media/usb/em28xx/em28xx-cards.c
>>>>> +++ b/drivers/media/usb/em28xx/em28xx-cards.c
>>>>> @@ -2867,16 +2867,18 @@ static void flush_request_modules(struct em28xx *dev)
>>>>>    	flush_work(&dev->request_module_wk);
>>>>>    }
>>>>>    
>>>>> -/*
>>>>> - * em28xx_release_resources()
>>>>> - * unregisters the v4l2,i2c and usb devices
>>>>> - * called when the device gets disconnected or at module unload
>>>>> -*/
>>>>> -void em28xx_release_resources(struct em28xx *dev)
>>>>> +/**
>>>>> + * em28xx_release_resources() -  unregisters the v4l2,i2c and usb devices
>>>>> + *
>>>>> + * @ref: struct kref for em28xx device
>>>>> + *
>>>>> + * This is called when all extensions and em28xx core unregisters a device
>>>>> + */
>>>>> +void em28xx_free_device(struct kref *ref)
>>>>>    {
>>>>> -	/*FIXME: I2C IR should be disconnected */
>>>>> +	struct em28xx *dev = kref_to_dev(ref);
>>>>>    
>>>>> -	mutex_lock(&dev->lock);
>>>>> +	em28xx_info("Freeing device\n");
>>>>>    
>>>>>    	if (dev->def_i2c_bus)
>>>>>    		em28xx_i2c_unregister(dev, 1);
>>>>> @@ -2887,9 +2889,10 @@ void em28xx_release_resources(struct em28xx *dev)
>>>>>    	/* Mark device as unused */
>>>>>    	clear_bit(dev->devno, &em28xx_devused);
>>>>>    
>>>>> -	mutex_unlock(&dev->lock);
>>>>> -};
>>>>> -EXPORT_SYMBOL_GPL(em28xx_release_resources);
>>>>> +	kfree(dev->alt_max_pkt_size_isoc);
>>>>> +	kfree(dev);
>>>>> +}
>>>>> +EXPORT_SYMBOL_GPL(em28xx_free_device);
>>>>>    
>>>>>    /*
>>>>>     * em28xx_init_dev()
>>>>> @@ -3342,6 +3345,8 @@ static int em28xx_usb_probe(struct usb_interface *interface,
>>>>>    			    dev->dvb_xfer_bulk ? "bulk" : "isoc");
>>>>>    	}
>>>>>    
>>>>> +	kref_init(&dev->ref);
>>>>> +
>>>>>    	request_modules(dev);
>>>>>    
>>>>>    	/* Should be the last thing to do, to avoid newer udev's to
>>>>> @@ -3390,12 +3395,7 @@ static void em28xx_usb_disconnect(struct usb_interface *interface)
>>>>>    
>>>>>    	em28xx_close_extension(dev);
>>>>>    
>>>>> -	em28xx_release_resources(dev);
>>>>> -
>>>>> -	if (!dev->users) {
>>>>> -		kfree(dev->alt_max_pkt_size_isoc);
>>>>> -		kfree(dev);
>>>>> -	}
>>>>> +	kref_put(&dev->ref, em28xx_free_device);
>>>>>    }
>>>>>    
>>>>>    static struct usb_driver em28xx_usb_driver = {
>>>>> diff --git a/drivers/media/usb/em28xx/em28xx-dvb.c b/drivers/media/usb/em28xx/em28xx-dvb.c
>>>>> index 5ea563e3f0e4..8674ae5fce06 100644
>>>>> --- a/drivers/media/usb/em28xx/em28xx-dvb.c
>>>>> +++ b/drivers/media/usb/em28xx/em28xx-dvb.c
>>>>> @@ -1010,11 +1010,11 @@ static int em28xx_dvb_init(struct em28xx *dev)
>>>>>    	em28xx_info("Binding DVB extension\n");
>>>>>    
>>>>>    	dvb = kzalloc(sizeof(struct em28xx_dvb), GFP_KERNEL);
>>>>> -
>>>>>    	if (dvb == NULL) {
>>>>>    		em28xx_info("em28xx_dvb: memory allocation failed\n");
>>>>>    		return -ENOMEM;
>>>>>    	}
>>>>> +	kref_get(&dev->ref);
>>>>>    	dev->dvb = dvb;
>>>>>    	dvb->fe[0] = dvb->fe[1] = NULL;
>>>>>    
>>>>> @@ -1442,6 +1442,7 @@ static int em28xx_dvb_init(struct em28xx *dev)
>>>>>    	dvb->adapter.mfe_shared = mfe_shared;
>>>>>    
>>>>>    	em28xx_info("DVB extension successfully initialized\n");
>>>>> +
>>>>>    ret:
>>>>>    	em28xx_set_mode(dev, EM28XX_SUSPEND);
>>>>>    	mutex_unlock(&dev->lock);
>>>>> @@ -1492,6 +1493,8 @@ static int em28xx_dvb_fini(struct em28xx *dev)
>>>>>    		dev->dvb = NULL;
>>>>>    	}
>>>>>    
>>>>> +	kref_put(&dev->ref, em28xx_free_device);
>>>>> +
>>>>>    	return 0;
>>>>>    }
>>>>>    
>>>>> diff --git a/drivers/media/usb/em28xx/em28xx-input.c b/drivers/media/usb/em28xx/em28xx-input.c
>>>>> index 61c061f3a476..33388b5922a0 100644
>>>>> --- a/drivers/media/usb/em28xx/em28xx-input.c
>>>>> +++ b/drivers/media/usb/em28xx/em28xx-input.c
>>>>> @@ -676,6 +676,8 @@ static int em28xx_ir_init(struct em28xx *dev)
>>>>>    		return 0;
>>>>>    	}
>>>>>    
>>>>> +	kref_get(&dev->ref);
>>>>> +
>>>>>    	if (dev->board.buttons)
>>>>>    		em28xx_init_buttons(dev);
>>>>>    
>>>>> @@ -814,7 +816,7 @@ static int em28xx_ir_fini(struct em28xx *dev)
>>>>>    
>>>>>    	/* skip detach on non attached boards */
>>>>>    	if (!ir)
>>>>> -		return 0;
>>>>> +		goto ref_put;
>>>>>    
>>>>>    	if (ir->rc)
>>>>>    		rc_unregister_device(ir->rc);
>>>>> @@ -822,6 +824,10 @@ static int em28xx_ir_fini(struct em28xx *dev)
>>>>>    	/* done */
>>>>>    	kfree(ir);
>>>>>    	dev->ir = NULL;
>>>>> +
>>>>> +ref_put:
>>>>> +	kref_put(&dev->ref, em28xx_free_device);
>>>>> +
>>>>>    	return 0;
>>>>>    }
>>>>>    
>>>>> diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c
>>>>> index 587ff3fe9402..dc10cec772ba 100644
>>>>> --- a/drivers/media/usb/em28xx/em28xx-video.c
>>>>> +++ b/drivers/media/usb/em28xx/em28xx-video.c
>>>>> @@ -1922,8 +1922,7 @@ static int em28xx_v4l2_fini(struct em28xx *dev)
>>>>>    	v4l2_ctrl_handler_free(&dev->ctrl_handler);
>>>>>    	v4l2_device_unregister(&dev->v4l2_dev);
>>>>>    
>>>>> -	if (dev->users)
>>>>> -		em28xx_warn("Device is open ! Memory deallocation is deferred on last close.\n");
>>>>> +	kref_put(&dev->ref, em28xx_free_device);
>>>>>    
>>>>>    	return 0;
>>>>>    }
>>>>> @@ -1945,11 +1944,9 @@ static int em28xx_v4l2_close(struct file *filp)
>>>>>    	mutex_lock(&dev->lock);
>>>>>    
>>>>>    	if (dev->users == 1) {
>>>>> -		/* free the remaining resources if device is disconnected */
>>>>> -		if (dev->disconnected) {
>>>>> -			kfree(dev->alt_max_pkt_size_isoc);
>>>>> +		/* No sense to try to write to the device */
>>>>> +		if (dev->disconnected)
>>>>>    			goto exit;
>>>>> -		}
>>>>>    
>>>>>    		/* Save some power by putting tuner to sleep */
>>>>>    		v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_power, 0);
>>>>> @@ -2201,6 +2198,8 @@ static int em28xx_v4l2_init(struct em28xx *dev)
>>>>>    
>>>>>    	em28xx_info("Registering V4L2 extension\n");
>>>>>    
>>>>> +	kref_get(&dev->ref);
>>>>> +
>>>>>    	mutex_lock(&dev->lock);
>>>>>    
>>>>>    	ret = v4l2_device_register(&dev->udev->dev, &dev->v4l2_dev);
>>>>> diff --git a/drivers/media/usb/em28xx/em28xx.h b/drivers/media/usb/em28xx/em28xx.h
>>>>> index 5d5d1b6f0294..d38c08e4da60 100644
>>>>> --- a/drivers/media/usb/em28xx/em28xx.h
>>>>> +++ b/drivers/media/usb/em28xx/em28xx.h
>>>>> @@ -32,6 +32,7 @@
>>>>>    #include <linux/workqueue.h>
>>>>>    #include <linux/i2c.h>
>>>>>    #include <linux/mutex.h>
>>>>> +#include <linux/kref.h>
>>>>>    #include <linux/videodev2.h>
>>>>>    
>>>>>    #include <media/videobuf2-vmalloc.h>
>>>>> @@ -531,9 +532,11 @@ struct em28xx_i2c_bus {
>>>>>    	enum em28xx_i2c_algo_type algo_type;
>>>>>    };
>>>>>    
>>>>> -
>>>>>    /* main device struct */
>>>>>    struct em28xx {
>>>>> +	struct kref ref;
>>>>> +
>>>>> +
>>>>>    	/* generic device properties */
>>>>>    	char name[30];		/* name (including minor) of the device */
>>>>>    	int model;		/* index in the device_data struct */
>>>>> @@ -706,6 +709,8 @@ struct em28xx {
>>>>>    	struct em28xx_dvb *dvb;
>>>>>    };
>>>>>    
>>>>> +#define kref_to_dev(d) container_of(d, struct em28xx, ref)
>>>>> +
>>>>>    struct em28xx_ops {
>>>>>    	struct list_head next;
>>>>>    	char *name;
>>>>> @@ -763,7 +768,7 @@ extern struct em28xx_board em28xx_boards[];
>>>>>    extern struct usb_device_id em28xx_id_table[];
>>>>>    int em28xx_tuner_callback(void *ptr, int component, int command, int arg);
>>>>>    void em28xx_setup_xc3028(struct em28xx *dev, struct xc2028_ctrl *ctl);
>>>>> -void em28xx_release_resources(struct em28xx *dev);
>>>>> +void em28xx_free_device(struct kref *ref);
>>>>>    
>>>>>    /* Provided by em28xx-camera.c */
>>>>>    int em28xx_detect_sensor(struct em28xx *dev);
>>>> I welcome this patch and the general approach looks good.
>>>> I had started working on the same issue, but it's not that trivial.
>>>>
>>>> At first glance there seem to be several issues, but I will need to
>>>> review this patch in more detail and also make some tests.
>>>> Unfortunately, I don't have much time this evening, So could you please
>>>> hold it back another day ?
>>>> I hope I can review the other remaining patch of this series (patch 5/7)
>>>> later this evening.
>>> We're running out of time for 3.14. I think we should merge this patch
>>> series, and your patch series for 3.14, to be together with the em28xx-v4l
>>> split.
>>>
>>> My plan is to merge the remaining patches for 3.14 today or, in the worse
>>> case, tomorrow.
>>>
>>> If we slip on some bug, we'll still have the 3.14-rc cycle to fix, if the
>>> series gets merged, but, if we miss the bus, I'm afraid that we'll end
>>> by having more problems that will be hard to fix with trivial patches, due
>>> to em28xx-v4l split changes that also affected the driver removal and device
>>> close code.
>>>
>>> FYI, I tested this code and also Antti with our devices, randomly removing
>>> the devices while streaming, and this is now finally working.
>>>
>>> I won't doubt that there are some cases that require fixes (and
>>> it seems that em28xx-rc has one of such corner cases), but they'll likely
>>> can be solved with somewhat short and trivial patches.
>>>
>>> Cheers,
>>> Mauro
>> This is a very critical patch and exactly the kind of change that should
>> _never_ be hurried !
>> FAICS it has some severe issues and it's not clear how easy it will be
>> to fix it within the the 3.14-rc cycle.
>> As long as it's not ready, don't merge it for 3.14.
> What issues? So far, you didn't point any.
I already stated that I didn't have the time yet to review and test it 
in detail, but I'm going to do that as soon as possible.
If you can't wait, there's nothing I can do, sorry.

At first glance it seems there are at least 2 issues:
1.) use after freeing in v4l-extension (happens when the device is 
closed after the usb disconnect)
2.) error paths in the init() functions ?


> On both my tests and Antti's one,
> with this series, there were significant improvements on removing existing
> bugs with device removal.
I'm talking about this specific patch here, not the whole series.
I have no objections against the rest of the series (well, with the 
exception of patch 5 at the moment).

>
>> em28xx resources releasing is broken since ... well... at least 2 years.
>> 3.14 will already be much better and nobody will care if this remaining
>> issue is addressed a kernel release later.
> Although I think that we're properly releasing resources, I'm a way less
> concerned about keeping some leaked memory while releasing them than I am
> concerned that a device removal that would cause an OOPS, or a deadly
> crash at the USB or ALSA stack that prevents other devices to be probed.
>
> Due to em28xx-v4l calling em28xx_release_resources(), now both the
> USB and ALSA stacks crashes if you remove a device while ALSA is streaming.
>
> That happens because em28xx, I2C, etc will be freed by em28xx-v4l, but
> those resources are still needed by em28xx-alsa. That makes that the
> .fini code there to cause crash at ALSA stack, and, sometimes, at the
> USB stack.

That's not true anymore, em28xx_release_resources() is now only called 
by the usb disconnect handler in the core _after_ all fini() functions 
have been called.
Maybe you tested that without my patch series ? See patch 7/8.

> As nowadays lots of components depend on pulseaudio, the ALSA crash
> causes pulse to stop work, likely keeping it into some dead lock status.
> This makes the entire machine to become really slow, when it doesn't
> crash.
>
> This is a serious regression that should be fixed.
>
> This patch series for sure fixes it. As I said, there are two independent
> series of tests verifying that (both using several different em28xx
> devices).
>
>> Be warned !
>>
>>
>


^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 5/7] em28xx-audio: remove a deplock circular dependency
  2014-01-14 15:45     ` Mauro Carvalho Chehab
@ 2014-01-14 18:43       ` Frank Schäfer
  2014-01-14 19:59         ` Mauro Carvalho Chehab
  0 siblings, 1 reply; 40+ messages in thread
From: Frank Schäfer @ 2014-01-14 18:43 UTC (permalink / raw)
  To: Mauro Carvalho Chehab; +Cc: Linux Media Mailing List, Mauro Carvalho Chehab

On 14.01.2014 16:45, Mauro Carvalho Chehab wrote:
> Em Mon, 13 Jan 2014 22:51:00 +0100
> Frank Schäfer <fschaefer.oss@googlemail.com> escreveu:
>
>> Am 13.01.2014 00:00, schrieb Mauro Carvalho Chehab:
>>> We can't lock at pcm close, as it causes circular dependency
>>> lock issues with .init and .fini callbacks. So, move the code
>>> that puts the device on mute to the kthread.
>>>
>>>      [  322.026316] ======================================================
>>>      [  322.026356] [ INFO: possible circular locking dependency detected ]
>>>      [  322.026397] 3.13.0-rc1+ #24 Not tainted
>>>      [  322.026437] -------------------------------------------------------
>>>      [  322.026476] khubd/54 is trying to acquire lock:
>>>      [  322.026516]  (&pcm->open_mutex){+.+.+.}, at: [<ffffffffa04819e6>] snd_pcm_dev_disconnect+0x46/0x1e0 [snd_pcm]
>>>      [  322.026727]
>>>      but task is already holding lock:
>>>      [  322.026767]  (register_mutex#3){+.+.+.}, at: [<ffffffffa04819c4>] snd_pcm_dev_disconnect+0x24/0x1e0 [snd_pcm]
>>>      [  322.027005]
>>>      which lock already depends on the new lock.
>>>
>>>      [  322.027045]
>>>      the existing dependency chain (in reverse order) is:
>>>      [  322.027084]
>>>      -> #2 (register_mutex#3){+.+.+.}:
>>>      [  322.027318]        [<ffffffff810b8fa3>] __lock_acquire+0xb43/0x1330
>>>      [  322.027401]        [<ffffffff810b9f82>] lock_acquire+0xa2/0x120
>>>      [  322.027479]        [<ffffffff816a5b6c>] mutex_lock_nested+0x5c/0x3c0
>>>      [  322.027559]        [<ffffffffa04819c4>] snd_pcm_dev_disconnect+0x24/0x1e0 [snd_pcm]
>>>      [  322.027642]        [<ffffffffa02e855a>] snd_device_disconnect+0x6a/0xf0 [snd]
>>>      [  322.027727]        [<ffffffffa02e86ac>] snd_device_disconnect_all+0x4c/0x90 [snd]
>>>      [  322.027814]        [<ffffffffa02e1876>] snd_card_disconnect+0x126/0x1d0 [snd]
>>>      [  322.027898]        [<ffffffffa02e1ea8>] snd_card_free+0x18/0x90 [snd]
>>>      [  322.027982]        [<ffffffffa087235f>] em28xx_audio_fini+0x8f/0xa0 [em28xx_alsa]
>>>      [  322.028063]        [<ffffffffa085cba6>] em28xx_close_extension+0x56/0x90 [em28xx]
>>>      [  322.028143]        [<ffffffffa085e639>] em28xx_usb_disconnect+0x79/0x90 [em28xx]
>>>      [  322.028222]        [<ffffffff814a06e7>] usb_unbind_interface+0x67/0x1d0
>>>      [  322.028302]        [<ffffffff8142920f>] __device_release_driver+0x7f/0xf0
>>>      [  322.028381]        [<ffffffff814292a5>] device_release_driver+0x25/0x40
>>>      [  322.028462]        [<ffffffff81428b0c>] bus_remove_device+0x11c/0x1a0
>>>      [  322.028540]        [<ffffffff81425536>] device_del+0x136/0x1d0
>>>      [  322.028619]        [<ffffffff8149e0c0>] usb_disable_device+0xb0/0x290
>>>      [  322.028698]        [<ffffffff814930c5>] usb_disconnect+0xb5/0x1d0
>>>      [  322.028779]        [<ffffffff81495ab6>] hub_port_connect_change+0xd6/0xad0
>>>      [  322.028859]        [<ffffffff814967c3>] hub_events+0x313/0x9b0
>>>      [  322.028940]        [<ffffffff81496e95>] hub_thread+0x35/0x170
>>>      [  322.029019]        [<ffffffff8108ea2f>] kthread+0xff/0x120
>>>      [  322.029099]        [<ffffffff816b187c>] ret_from_fork+0x7c/0xb0
>>>      [  322.029179]
>>>      -> #1 (&dev->lock#2){+.+.+.}:
>>>      [  322.029414]        [<ffffffff810b8fa3>] __lock_acquire+0xb43/0x1330
>>>      [  322.029494]        [<ffffffff810b9f82>] lock_acquire+0xa2/0x120
>>>      [  322.029572]        [<ffffffff816a5b6c>] mutex_lock_nested+0x5c/0x3c0
>>>      [  322.029651]        [<ffffffffa087122e>] snd_em28xx_pcm_close+0x3e/0x100 [em28xx_alsa]
>>>      [  322.029732]        [<ffffffffa048620f>] snd_pcm_release_substream.part.29+0x3f/0x90 [snd_pcm]
>>>      [  322.029816]        [<ffffffffa0486340>] snd_pcm_release+0xb0/0xd0 [snd_pcm]
>>>      [  322.029900]        [<ffffffff811c9752>] __fput+0xe2/0x230
>>>      [  322.029979]        [<ffffffff811c98ee>] ____fput+0xe/0x10
>>>      [  322.030057]        [<ffffffff8108b64f>] task_work_run+0x9f/0xe0
>>>      [  322.030135]        [<ffffffff81013a81>] do_notify_resume+0x61/0xa0
>>>      [  322.030223]        [<ffffffff816b1c62>] int_signal+0x12/0x17
>>>      [  322.030294]
>>>      -> #0 (&pcm->open_mutex){+.+.+.}:
>>>      [  322.030473]        [<ffffffff810b7a47>] check_prevs_add+0x947/0x950
>>>      [  322.030546]        [<ffffffff810b8fa3>] __lock_acquire+0xb43/0x1330
>>>      [  322.030618]        [<ffffffff810b9f82>] lock_acquire+0xa2/0x120
>>>      [  322.030689]        [<ffffffff816a5b6c>] mutex_lock_nested+0x5c/0x3c0
>>>      [  322.030760]        [<ffffffffa04819e6>] snd_pcm_dev_disconnect+0x46/0x1e0 [snd_pcm]
>>>      [  322.030835]        [<ffffffffa02e855a>] snd_device_disconnect+0x6a/0xf0 [snd]
>>>      [  322.030913]        [<ffffffffa02e86ac>] snd_device_disconnect_all+0x4c/0x90 [snd]
>>>      [  322.030988]        [<ffffffffa02e1876>] snd_card_disconnect+0x126/0x1d0 [snd]
>>>      [  322.031067]        [<ffffffffa02e1ea8>] snd_card_free+0x18/0x90 [snd]
>>>      [  322.031146]        [<ffffffffa087235f>] em28xx_audio_fini+0x8f/0xa0 [em28xx_alsa]
>>>      [  322.031220]        [<ffffffffa085cba6>] em28xx_close_extension+0x56/0x90 [em28xx]
>>>      [  322.031292]        [<ffffffffa085e639>] em28xx_usb_disconnect+0x79/0x90 [em28xx]
>>>      [  322.031363]        [<ffffffff814a06e7>] usb_unbind_interface+0x67/0x1d0
>>>      [  322.031433]        [<ffffffff8142920f>] __device_release_driver+0x7f/0xf0
>>>      [  322.031503]        [<ffffffff814292a5>] device_release_driver+0x25/0x40
>>>      [  322.031573]        [<ffffffff81428b0c>] bus_remove_device+0x11c/0x1a0
>>>      [  322.031643]        [<ffffffff81425536>] device_del+0x136/0x1d0
>>>      [  322.031714]        [<ffffffff8149e0c0>] usb_disable_device+0xb0/0x290
>>>      [  322.031784]        [<ffffffff814930c5>] usb_disconnect+0xb5/0x1d0
>>>      [  322.031853]        [<ffffffff81495ab6>] hub_port_connect_change+0xd6/0xad0
>>>      [  322.031922]        [<ffffffff814967c3>] hub_events+0x313/0x9b0
>>>      [  322.031992]        [<ffffffff81496e95>] hub_thread+0x35/0x170
>>>      [  322.032062]        [<ffffffff8108ea2f>] kthread+0xff/0x120
>>>      [  322.032135]        [<ffffffff816b187c>] ret_from_fork+0x7c/0xb0
>>>      [  322.032205]
>>>      other info that might help us debug this:
>>>
>>>      [  322.032240] Chain exists of:
>>>        &pcm->open_mutex --> &dev->lock#2 --> register_mutex#3
>>>
>>>      [  322.032547]  Possible unsafe locking scenario:
>>>
>>>      [  322.032582]        CPU0                    CPU1
>>>      [  322.032616]        ----                    ----
>>>      [  322.032654]   lock(register_mutex#3);
>>>      [  322.032793]                                lock(&dev->lock#2);
>>>      [  322.032929]                                lock(register_mutex#3);
>>>      [  322.033064]   lock(&pcm->open_mutex);
>>>      [  322.033168]
>>>       *** DEADLOCK ***
I don't get it. Where is the deadlock here ???
Mauro, be honest: did you understand what's going on here ?

>>>
>>>      [  322.033204] 6 locks held by khubd/54:
>>>      [  322.033239]  #0:  (&__lockdep_no_validate__){......}, at: [<ffffffff81496564>] hub_events+0xb4/0x9b0
>>>      [  322.033446]  #1:  (&__lockdep_no_validate__){......}, at: [<ffffffff81493076>] usb_disconnect+0x66/0x1d0
>>>      [  322.033655]  #2:  (&__lockdep_no_validate__){......}, at: [<ffffffff8142929d>] device_release_driver+0x1d/0x40
>>>      [  322.033859]  #3:  (em28xx_devlist_mutex){+.+.+.}, at: [<ffffffffa085cb77>] em28xx_close_extension+0x27/0x90 [em28xx]
>>>      [  322.034067]  #4:  (&dev->lock#2){+.+.+.}, at: [<ffffffffa085cb81>] em28xx_close_extension+0x31/0x90 [em28xx]
>>>      [  322.034307]  #5:  (register_mutex#3){+.+.+.}, at: [<ffffffffa04819c4>] snd_pcm_dev_disconnect+0x24/0x1e0 [snd_pcm]
>>>      [  322.034552]
>>>      stack backtrace:
>>>      [  322.034588] CPU: 3 PID: 54 Comm: khubd Not tainted 3.13.0-rc1+ #24
>>>      [  322.034624] Hardware name: SAMSUNG ELECTRONICS CO., LTD. 550P5C/550P7C/SAMSUNG_NP1234567890, BIOS P04ABI.013.130220.dg 02/20/2013
>>>      [  322.034659]  ffffffff82513770 ffff880221bcd7c8 ffffffff816a03c6 ffffffff8250a810
>>>      [  322.034832]  ffff880221bcd808 ffffffff8169a203 ffff880221bcd830 0000000000000005
>>>      [  322.035004]  ffff8802222b2880 ffff8802222b3020 ffff8802222b3020 0000000000000006
>>>      [  322.035187] Call Trace:
>>>      [  322.035230]  [<ffffffff816a03c6>] dump_stack+0x45/0x56
>>>      [  322.035276]  [<ffffffff8169a203>] print_circular_bug+0x200/0x20e
>>>      [  322.035320]  [<ffffffff810b7a47>] check_prevs_add+0x947/0x950
>>>      [  322.035365]  [<ffffffff8101b303>] ? native_sched_clock+0x13/0x80
>>>      [  322.035409]  [<ffffffff810b8fa3>] __lock_acquire+0xb43/0x1330
>>>      [  322.035454]  [<ffffffff810b9f82>] lock_acquire+0xa2/0x120
>>>      [  322.035500]  [<ffffffffa04819e6>] ? snd_pcm_dev_disconnect+0x46/0x1e0 [snd_pcm]
>>>      [  322.035550]  [<ffffffff816a5b6c>] mutex_lock_nested+0x5c/0x3c0
>>>      [  322.035596]  [<ffffffffa04819e6>] ? snd_pcm_dev_disconnect+0x46/0x1e0 [snd_pcm]
>>>      [  322.035648]  [<ffffffffa04819e6>] ? snd_pcm_dev_disconnect+0x46/0x1e0 [snd_pcm]
>>>      [  322.035697]  [<ffffffff810b8045>] ? trace_hardirqs_on_caller+0x105/0x1d0
>>>      [  322.035744]  [<ffffffffa04819e6>] snd_pcm_dev_disconnect+0x46/0x1e0 [snd_pcm]
>>>      [  322.035797]  [<ffffffffa02e855a>] snd_device_disconnect+0x6a/0xf0 [snd]
>>>      [  322.035852]  [<ffffffffa02e86ac>] snd_device_disconnect_all+0x4c/0x90 [snd]
>>>      [  322.035904]  [<ffffffffa02e1876>] snd_card_disconnect+0x126/0x1d0 [snd]
>>>      [  322.035957]  [<ffffffffa02e1ea8>] snd_card_free+0x18/0x90 [snd]
>>>      [  322.036008]  [<ffffffffa087235f>] em28xx_audio_fini+0x8f/0xa0 [em28xx_alsa]
>>>      [  322.036054]  [<ffffffffa085cba6>] em28xx_close_extension+0x56/0x90 [em28xx]
>>>      [  322.036100]  [<ffffffffa085e639>] em28xx_usb_disconnect+0x79/0x90 [em28xx]
>>>      [  322.036144]  [<ffffffff814a06e7>] usb_unbind_interface+0x67/0x1d0
>>>      [  322.036188]  [<ffffffff8142920f>] __device_release_driver+0x7f/0xf0
>>>      [  322.036231]  [<ffffffff814292a5>] device_release_driver+0x25/0x40
>>>      [  322.036274]  [<ffffffff81428b0c>] bus_remove_device+0x11c/0x1a0
>>>      [  322.036318]  [<ffffffff81425536>] device_del+0x136/0x1d0
>>>      [  322.036361]  [<ffffffff8149e0c0>] usb_disable_device+0xb0/0x290
>>>      [  322.036404]  [<ffffffff814930c5>] usb_disconnect+0xb5/0x1d0
>>>      [  322.036447]  [<ffffffff81495ab6>] hub_port_connect_change+0xd6/0xad0
>>>      [  322.036492]  [<ffffffff8149cb04>] ? usb_control_msg+0xd4/0x110
>>>      [  322.036535]  [<ffffffff814967c3>] hub_events+0x313/0x9b0
>>>      [  322.036579]  [<ffffffff810b8045>] ? trace_hardirqs_on_caller+0x105/0x1d0
>>>      [  322.036623]  [<ffffffff81496e95>] hub_thread+0x35/0x170
>>>      [  322.036667]  [<ffffffff810af310>] ? abort_exclusive_wait+0xb0/0xb0
>>>      [  322.036711]  [<ffffffff81496e60>] ? hub_events+0x9b0/0x9b0
>>>      [  322.036756]  [<ffffffff8108ea2f>] kthread+0xff/0x120
>>>      [  322.036802]  [<ffffffff8108e930>] ? kthread_create_on_node+0x250/0x250
>>>      [  322.036846]  [<ffffffff816b187c>] ret_from_fork+0x7c/0xb0
>>>      [  322.036890]  [<ffffffff8108e930>] ? kthread_create_on_node+0x250/0x250
>>>
>>> Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
>>> ---
>>>   drivers/media/usb/em28xx/em28xx-audio.c | 10 +++++++---
>>>   1 file changed, 7 insertions(+), 3 deletions(-)
>>>
>>> diff --git a/drivers/media/usb/em28xx/em28xx-audio.c b/drivers/media/usb/em28xx/em28xx-audio.c
>>> index cdc2fcf3e05e..5e16fcf18cac 100644
>>> --- a/drivers/media/usb/em28xx/em28xx-audio.c
>>> +++ b/drivers/media/usb/em28xx/em28xx-audio.c
>>> @@ -311,20 +311,17 @@ static int snd_em28xx_pcm_close(struct snd_pcm_substream *substream)
>>>   	dprintk("closing device\n");
>>>   
>>>   	dev->mute = 1;
>>> -	mutex_lock(&dev->lock);
>>>   	dev->adev.users--;
>>>   	if (atomic_read(&dev->stream_started) > 0) {
>>>   		atomic_set(&dev->stream_started, 0);
>>>   		schedule_work(&dev->wq_trigger);
>>>   	}
>>>   
>>> -	em28xx_audio_analog_set(dev);
>>>   	if (substream->runtime->dma_area) {
>>>   		dprintk("freeing\n");
>>>   		vfree(substream->runtime->dma_area);
>>>   		substream->runtime->dma_area = NULL;
>>>   	}
>>> -	mutex_unlock(&dev->lock);
>>>   
>>>   	return 0;
>>>   }
>>> @@ -395,6 +392,13 @@ static void audio_trigger(struct work_struct *work)
>>>   	} else {
>>>   		dprintk("stopping capture");
>>>   		em28xx_deinit_isoc_audio(dev);
>>> +
>>> +		/* Mute device if needed */
>>> +		if (dev->mute) {
>>> +			mutex_lock(&dev->lock);
>>> +			em28xx_audio_analog_set(dev);
>>> +			mutex_unlock(&dev->lock);
>>> +		}
>>>   	}
>>>   }
After thinking about this for a while:
Does your patch

[PATCH] em28xx: push mutex down to extensions on .fini callback

which you've sent afterwards fix this warning, too ?

>> It's already late and I don't understand this deadlock yet completely,
>> but are you sure this is the proper fix for this issue ?
> This is one possible way to fix.
>
>> What happens when capturing is restarted ? Shouldn't the device then be
>> unmuted again ?
> Please note that, inside em28xx-audio.c, only the open callback unmutes
> the device, and only the close callback sets it to mute.
>
> As the close callback ask the work tree to run, the above code will
> defer mute to when the work queue runs.
>
> So, the logic seems equivalent to the existing logic.
>
> It should be noticed that we can change that code to always call
> em28xx_audio_analog_set() there, and remove the code that calls
> it from snd_em28xx_capture_open().
>
> I can't see any functional changes with such changes.
>
> That's said, I remember we spent lots of time at linux-media
> discussing if the alsa start should automatically unmute a
> device or just keep it as-is.
>
> I don't remember the exact results, but I think we opted to put the
> unmute code there due to pulseaudio bugs, as, without such code,
> pulseaudio would change the mixers and make some mess.
>>
>>
>> How often does the start/stop/resume happen ?
> At device open, it starts. At device closes, it stops.
>
> If a buffer underrun/overrun occurs, it will stop/start, but,
> in that case, the dev->mute state won't change.
True, but if dev->mute=1, you are calling em28xx_audio_analog_set(dev) 
again and again. That's crap.

Yes, Sometimes dirty workarounds are needed for the sake of fixing bugs.
But I prefer to understand what's wrong before coming up with solution.
Of course, I can't force anybody to spend more time on this and I don't 
have the hardware to reproduce/investigate this issue.
So it seems I lost.

Regards,
Frank

>
> Regards,
>
> Cheers,
> Mauro


^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 3/7] em28xx: Only deallocate struct em28xx after finishing all extensions
  2014-01-14 18:13           ` Frank Schäfer
@ 2014-01-14 18:55             ` Mauro Carvalho Chehab
  2014-01-14 19:31               ` Mauro Carvalho Chehab
  2014-01-14 20:48               ` Frank Schäfer
  0 siblings, 2 replies; 40+ messages in thread
From: Mauro Carvalho Chehab @ 2014-01-14 18:55 UTC (permalink / raw)
  To: Frank Schäfer; +Cc: Linux Media Mailing List, Mauro Carvalho Chehab

Em Tue, 14 Jan 2014 19:13:00 +0100
Frank Schäfer <fschaefer.oss@googlemail.com> escreveu:

> On 14.01.2014 14:10, Mauro Carvalho Chehab wrote:
> > Em Mon, 13 Jan 2014 22:55:36 +0100
> > Frank Schäfer <fschaefer.oss@googlemail.com> escreveu:
> >
> >> Am 13.01.2014 20:23, schrieb Mauro Carvalho Chehab:
> >>> Em Mon, 13 Jan 2014 20:02:19 +0100
> >>> Frank Schäfer <fschaefer.oss@googlemail.com> escreveu:
> >>>
> >>>> On 13.01.2014 00:00, Mauro Carvalho Chehab wrote:
> >>>>> We can't free struct em28xx while one of the extensions is still
> >>>>> using it.
> >>>>>
> >>>>> So, add a kref() to control it, freeing it only after the
> >>>>> extensions fini calls.
> >>>>>
> >>>>> Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
> >>>>> ---
> >>>>>    drivers/media/usb/em28xx/em28xx-audio.c |  5 ++++-
> >>>>>    drivers/media/usb/em28xx/em28xx-cards.c | 34 ++++++++++++++++-----------------
> >>>>>    drivers/media/usb/em28xx/em28xx-dvb.c   |  5 ++++-
> >>>>>    drivers/media/usb/em28xx/em28xx-input.c |  8 +++++++-
> >>>>>    drivers/media/usb/em28xx/em28xx-video.c | 11 +++++------
> >>>>>    drivers/media/usb/em28xx/em28xx.h       |  9 +++++++--
> >>>>>    6 files changed, 44 insertions(+), 28 deletions(-)
> >>>>>
> >>>>> diff --git a/drivers/media/usb/em28xx/em28xx-audio.c b/drivers/media/usb/em28xx/em28xx-audio.c
> >>>>> index 97d9105e6830..8e959dae8358 100644
> >>>>> --- a/drivers/media/usb/em28xx/em28xx-audio.c
> >>>>> +++ b/drivers/media/usb/em28xx/em28xx-audio.c
> >>>>> @@ -878,6 +878,8 @@ static int em28xx_audio_init(struct em28xx *dev)
> >>>>>    
> >>>>>    	em28xx_info("Binding audio extension\n");
> >>>>>    
> >>>>> +	kref_get(&dev->ref);
> >>>>> +
> >>>>>    	printk(KERN_INFO "em28xx-audio.c: Copyright (C) 2006 Markus "
> >>>>>    			 "Rechberger\n");
> >>>>>    	printk(KERN_INFO
> >>>>> @@ -949,7 +951,7 @@ static int em28xx_audio_fini(struct em28xx *dev)
> >>>>>    	if (dev == NULL)
> >>>>>    		return 0;
> >>>>>    
> >>>>> -	if (dev->has_alsa_audio != 1) {
> >>>>> +	if (!dev->has_alsa_audio) {
> >>>>>    		/* This device does not support the extension (in this case
> >>>>>    		   the device is expecting the snd-usb-audio module or
> >>>>>    		   doesn't have analog audio support at all) */
> >>>>> @@ -963,6 +965,7 @@ static int em28xx_audio_fini(struct em28xx *dev)
> >>>>>    		dev->adev.sndcard = NULL;
> >>>>>    	}
> >>>>>    
> >>>>> +	kref_put(&dev->ref, em28xx_free_device);
> >>>>>    	return 0;
> >>>>>    }
> >>>>>    
> >>>>> diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c
> >>>>> index 3b332d527ccb..df92f417634a 100644
> >>>>> --- a/drivers/media/usb/em28xx/em28xx-cards.c
> >>>>> +++ b/drivers/media/usb/em28xx/em28xx-cards.c
> >>>>> @@ -2867,16 +2867,18 @@ static void flush_request_modules(struct em28xx *dev)
> >>>>>    	flush_work(&dev->request_module_wk);
> >>>>>    }
> >>>>>    
> >>>>> -/*
> >>>>> - * em28xx_release_resources()
> >>>>> - * unregisters the v4l2,i2c and usb devices
> >>>>> - * called when the device gets disconnected or at module unload
> >>>>> -*/
> >>>>> -void em28xx_release_resources(struct em28xx *dev)
> >>>>> +/**
> >>>>> + * em28xx_release_resources() -  unregisters the v4l2,i2c and usb devices
> >>>>> + *
> >>>>> + * @ref: struct kref for em28xx device
> >>>>> + *
> >>>>> + * This is called when all extensions and em28xx core unregisters a device
> >>>>> + */
> >>>>> +void em28xx_free_device(struct kref *ref)
> >>>>>    {
> >>>>> -	/*FIXME: I2C IR should be disconnected */
> >>>>> +	struct em28xx *dev = kref_to_dev(ref);
> >>>>>    
> >>>>> -	mutex_lock(&dev->lock);
> >>>>> +	em28xx_info("Freeing device\n");
> >>>>>    
> >>>>>    	if (dev->def_i2c_bus)
> >>>>>    		em28xx_i2c_unregister(dev, 1);
> >>>>> @@ -2887,9 +2889,10 @@ void em28xx_release_resources(struct em28xx *dev)
> >>>>>    	/* Mark device as unused */
> >>>>>    	clear_bit(dev->devno, &em28xx_devused);
> >>>>>    
> >>>>> -	mutex_unlock(&dev->lock);
> >>>>> -};
> >>>>> -EXPORT_SYMBOL_GPL(em28xx_release_resources);
> >>>>> +	kfree(dev->alt_max_pkt_size_isoc);
> >>>>> +	kfree(dev);
> >>>>> +}
> >>>>> +EXPORT_SYMBOL_GPL(em28xx_free_device);
> >>>>>    
> >>>>>    /*
> >>>>>     * em28xx_init_dev()
> >>>>> @@ -3342,6 +3345,8 @@ static int em28xx_usb_probe(struct usb_interface *interface,
> >>>>>    			    dev->dvb_xfer_bulk ? "bulk" : "isoc");
> >>>>>    	}
> >>>>>    
> >>>>> +	kref_init(&dev->ref);
> >>>>> +
> >>>>>    	request_modules(dev);
> >>>>>    
> >>>>>    	/* Should be the last thing to do, to avoid newer udev's to
> >>>>> @@ -3390,12 +3395,7 @@ static void em28xx_usb_disconnect(struct usb_interface *interface)
> >>>>>    
> >>>>>    	em28xx_close_extension(dev);
> >>>>>    
> >>>>> -	em28xx_release_resources(dev);
> >>>>> -
> >>>>> -	if (!dev->users) {
> >>>>> -		kfree(dev->alt_max_pkt_size_isoc);
> >>>>> -		kfree(dev);
> >>>>> -	}
> >>>>> +	kref_put(&dev->ref, em28xx_free_device);
> >>>>>    }
> >>>>>    
> >>>>>    static struct usb_driver em28xx_usb_driver = {
> >>>>> diff --git a/drivers/media/usb/em28xx/em28xx-dvb.c b/drivers/media/usb/em28xx/em28xx-dvb.c
> >>>>> index 5ea563e3f0e4..8674ae5fce06 100644
> >>>>> --- a/drivers/media/usb/em28xx/em28xx-dvb.c
> >>>>> +++ b/drivers/media/usb/em28xx/em28xx-dvb.c
> >>>>> @@ -1010,11 +1010,11 @@ static int em28xx_dvb_init(struct em28xx *dev)
> >>>>>    	em28xx_info("Binding DVB extension\n");
> >>>>>    
> >>>>>    	dvb = kzalloc(sizeof(struct em28xx_dvb), GFP_KERNEL);
> >>>>> -
> >>>>>    	if (dvb == NULL) {
> >>>>>    		em28xx_info("em28xx_dvb: memory allocation failed\n");
> >>>>>    		return -ENOMEM;
> >>>>>    	}
> >>>>> +	kref_get(&dev->ref);
> >>>>>    	dev->dvb = dvb;
> >>>>>    	dvb->fe[0] = dvb->fe[1] = NULL;
> >>>>>    
> >>>>> @@ -1442,6 +1442,7 @@ static int em28xx_dvb_init(struct em28xx *dev)
> >>>>>    	dvb->adapter.mfe_shared = mfe_shared;
> >>>>>    
> >>>>>    	em28xx_info("DVB extension successfully initialized\n");
> >>>>> +
> >>>>>    ret:
> >>>>>    	em28xx_set_mode(dev, EM28XX_SUSPEND);
> >>>>>    	mutex_unlock(&dev->lock);
> >>>>> @@ -1492,6 +1493,8 @@ static int em28xx_dvb_fini(struct em28xx *dev)
> >>>>>    		dev->dvb = NULL;
> >>>>>    	}
> >>>>>    
> >>>>> +	kref_put(&dev->ref, em28xx_free_device);
> >>>>> +
> >>>>>    	return 0;
> >>>>>    }
> >>>>>    
> >>>>> diff --git a/drivers/media/usb/em28xx/em28xx-input.c b/drivers/media/usb/em28xx/em28xx-input.c
> >>>>> index 61c061f3a476..33388b5922a0 100644
> >>>>> --- a/drivers/media/usb/em28xx/em28xx-input.c
> >>>>> +++ b/drivers/media/usb/em28xx/em28xx-input.c
> >>>>> @@ -676,6 +676,8 @@ static int em28xx_ir_init(struct em28xx *dev)
> >>>>>    		return 0;
> >>>>>    	}
> >>>>>    
> >>>>> +	kref_get(&dev->ref);
> >>>>> +
> >>>>>    	if (dev->board.buttons)
> >>>>>    		em28xx_init_buttons(dev);
> >>>>>    
> >>>>> @@ -814,7 +816,7 @@ static int em28xx_ir_fini(struct em28xx *dev)
> >>>>>    
> >>>>>    	/* skip detach on non attached boards */
> >>>>>    	if (!ir)
> >>>>> -		return 0;
> >>>>> +		goto ref_put;
> >>>>>    
> >>>>>    	if (ir->rc)
> >>>>>    		rc_unregister_device(ir->rc);
> >>>>> @@ -822,6 +824,10 @@ static int em28xx_ir_fini(struct em28xx *dev)
> >>>>>    	/* done */
> >>>>>    	kfree(ir);
> >>>>>    	dev->ir = NULL;
> >>>>> +
> >>>>> +ref_put:
> >>>>> +	kref_put(&dev->ref, em28xx_free_device);
> >>>>> +
> >>>>>    	return 0;
> >>>>>    }
> >>>>>    
> >>>>> diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c
> >>>>> index 587ff3fe9402..dc10cec772ba 100644
> >>>>> --- a/drivers/media/usb/em28xx/em28xx-video.c
> >>>>> +++ b/drivers/media/usb/em28xx/em28xx-video.c
> >>>>> @@ -1922,8 +1922,7 @@ static int em28xx_v4l2_fini(struct em28xx *dev)
> >>>>>    	v4l2_ctrl_handler_free(&dev->ctrl_handler);
> >>>>>    	v4l2_device_unregister(&dev->v4l2_dev);
> >>>>>    
> >>>>> -	if (dev->users)
> >>>>> -		em28xx_warn("Device is open ! Memory deallocation is deferred on last close.\n");
> >>>>> +	kref_put(&dev->ref, em28xx_free_device);
> >>>>>    
> >>>>>    	return 0;
> >>>>>    }
> >>>>> @@ -1945,11 +1944,9 @@ static int em28xx_v4l2_close(struct file *filp)
> >>>>>    	mutex_lock(&dev->lock);
> >>>>>    
> >>>>>    	if (dev->users == 1) {
> >>>>> -		/* free the remaining resources if device is disconnected */
> >>>>> -		if (dev->disconnected) {
> >>>>> -			kfree(dev->alt_max_pkt_size_isoc);
> >>>>> +		/* No sense to try to write to the device */
> >>>>> +		if (dev->disconnected)
> >>>>>    			goto exit;
> >>>>> -		}
> >>>>>    
> >>>>>    		/* Save some power by putting tuner to sleep */
> >>>>>    		v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_power, 0);
> >>>>> @@ -2201,6 +2198,8 @@ static int em28xx_v4l2_init(struct em28xx *dev)
> >>>>>    
> >>>>>    	em28xx_info("Registering V4L2 extension\n");
> >>>>>    
> >>>>> +	kref_get(&dev->ref);
> >>>>> +
> >>>>>    	mutex_lock(&dev->lock);
> >>>>>    
> >>>>>    	ret = v4l2_device_register(&dev->udev->dev, &dev->v4l2_dev);
> >>>>> diff --git a/drivers/media/usb/em28xx/em28xx.h b/drivers/media/usb/em28xx/em28xx.h
> >>>>> index 5d5d1b6f0294..d38c08e4da60 100644
> >>>>> --- a/drivers/media/usb/em28xx/em28xx.h
> >>>>> +++ b/drivers/media/usb/em28xx/em28xx.h
> >>>>> @@ -32,6 +32,7 @@
> >>>>>    #include <linux/workqueue.h>
> >>>>>    #include <linux/i2c.h>
> >>>>>    #include <linux/mutex.h>
> >>>>> +#include <linux/kref.h>
> >>>>>    #include <linux/videodev2.h>
> >>>>>    
> >>>>>    #include <media/videobuf2-vmalloc.h>
> >>>>> @@ -531,9 +532,11 @@ struct em28xx_i2c_bus {
> >>>>>    	enum em28xx_i2c_algo_type algo_type;
> >>>>>    };
> >>>>>    
> >>>>> -
> >>>>>    /* main device struct */
> >>>>>    struct em28xx {
> >>>>> +	struct kref ref;
> >>>>> +
> >>>>> +
> >>>>>    	/* generic device properties */
> >>>>>    	char name[30];		/* name (including minor) of the device */
> >>>>>    	int model;		/* index in the device_data struct */
> >>>>> @@ -706,6 +709,8 @@ struct em28xx {
> >>>>>    	struct em28xx_dvb *dvb;
> >>>>>    };
> >>>>>    
> >>>>> +#define kref_to_dev(d) container_of(d, struct em28xx, ref)
> >>>>> +
> >>>>>    struct em28xx_ops {
> >>>>>    	struct list_head next;
> >>>>>    	char *name;
> >>>>> @@ -763,7 +768,7 @@ extern struct em28xx_board em28xx_boards[];
> >>>>>    extern struct usb_device_id em28xx_id_table[];
> >>>>>    int em28xx_tuner_callback(void *ptr, int component, int command, int arg);
> >>>>>    void em28xx_setup_xc3028(struct em28xx *dev, struct xc2028_ctrl *ctl);
> >>>>> -void em28xx_release_resources(struct em28xx *dev);
> >>>>> +void em28xx_free_device(struct kref *ref);
> >>>>>    
> >>>>>    /* Provided by em28xx-camera.c */
> >>>>>    int em28xx_detect_sensor(struct em28xx *dev);
> >>>> I welcome this patch and the general approach looks good.
> >>>> I had started working on the same issue, but it's not that trivial.
> >>>>
> >>>> At first glance there seem to be several issues, but I will need to
> >>>> review this patch in more detail and also make some tests.
> >>>> Unfortunately, I don't have much time this evening, So could you please
> >>>> hold it back another day ?
> >>>> I hope I can review the other remaining patch of this series (patch 5/7)
> >>>> later this evening.
> >>> We're running out of time for 3.14. I think we should merge this patch
> >>> series, and your patch series for 3.14, to be together with the em28xx-v4l
> >>> split.
> >>>
> >>> My plan is to merge the remaining patches for 3.14 today or, in the worse
> >>> case, tomorrow.
> >>>
> >>> If we slip on some bug, we'll still have the 3.14-rc cycle to fix, if the
> >>> series gets merged, but, if we miss the bus, I'm afraid that we'll end
> >>> by having more problems that will be hard to fix with trivial patches, due
> >>> to em28xx-v4l split changes that also affected the driver removal and device
> >>> close code.
> >>>
> >>> FYI, I tested this code and also Antti with our devices, randomly removing
> >>> the devices while streaming, and this is now finally working.
> >>>
> >>> I won't doubt that there are some cases that require fixes (and
> >>> it seems that em28xx-rc has one of such corner cases), but they'll likely
> >>> can be solved with somewhat short and trivial patches.
> >>>
> >>> Cheers,
> >>> Mauro
> >> This is a very critical patch and exactly the kind of change that should
> >> _never_ be hurried !
> >> FAICS it has some severe issues and it's not clear how easy it will be
> >> to fix it within the the 3.14-rc cycle.
> >> As long as it's not ready, don't merge it for 3.14.
> > What issues? So far, you didn't point any.
> I already stated that I didn't have the time yet to review and test it 
> in detail, but I'm going to do that as soon as possible.
> If you can't wait, there's nothing I can do, sorry.
> 
> At first glance it seems there are at least 2 issues:
> 1.) use after freeing in v4l-extension (happens when the device is 
> closed after the usb disconnect)

That's basically what this patch fixes. Both V4L2 and ALSA handles it
well, if you warn the subsystem that a device will be removed.

If are there still any issues, we may add a kref_get() at device open,
an a kref_put() at device close on the affected sub-driver.

> 2.) error paths in the init() functions ?

It should be ok. Basically, kref_get() is called even if an error
occurs, and kref_put() is called even if init fails. Ok, this is an
overkill, but makes the patch simpler to review. We may fine tune it
on a latter patch.

I opted to call kref_get() as soon as possible, to avoid the risk of
the device to be removed while the extension is still being
initialized (yes, if you remove a device too quick, even before pulseaudio
starts opening the device), it used to crash.

> > On both my tests and Antti's one,
> > with this series, there were significant improvements on removing existing
> > bugs with device removal.
> I'm talking about this specific patch here, not the whole series.
> I have no objections against the rest of the series (well, with the 
> exception of patch 5 at the moment).

I see. Well, let me do some tests with all patches except 3 and 5 applied,
to see how it behaves.

> >
> >> em28xx resources releasing is broken since ... well... at least 2 years.
> >> 3.14 will already be much better and nobody will care if this remaining
> >> issue is addressed a kernel release later.
> > Although I think that we're properly releasing resources, I'm a way less
> > concerned about keeping some leaked memory while releasing them than I am
> > concerned that a device removal that would cause an OOPS, or a deadly
> > crash at the USB or ALSA stack that prevents other devices to be probed.
> >
> > Due to em28xx-v4l calling em28xx_release_resources(), now both the
> > USB and ALSA stacks crashes if you remove a device while ALSA is streaming.
> >
> > That happens because em28xx, I2C, etc will be freed by em28xx-v4l, but
> > those resources are still needed by em28xx-alsa. That makes that the
> > .fini code there to cause crash at ALSA stack, and, sometimes, at the
> > USB stack.
> 
> That's not true anymore, em28xx_release_resources() is now only called 
> by the usb disconnect handler in the core _after_ all fini() functions 
> have been called.
> Maybe you tested that without my patch series ? See patch 7/8.

No, we tested it with your full series applied:
	http://git.linuxtv.org/mchehab/experimental.git/shortlog/refs/heads/em28xx

> 
> > As nowadays lots of components depend on pulseaudio, the ALSA crash
> > causes pulse to stop work, likely keeping it into some dead lock status.
> > This makes the entire machine to become really slow, when it doesn't
> > crash.
> >
> > This is a serious regression that should be fixed.
> >
> > This patch series for sure fixes it. As I said, there are two independent
> > series of tests verifying that (both using several different em28xx
> > devices).
> >
> >> Be warned !
> >>
> >>
> >
> 


-- 

Cheers,
Mauro

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 3/7] em28xx: Only deallocate struct em28xx after finishing all extensions
  2014-01-14 18:55             ` Mauro Carvalho Chehab
@ 2014-01-14 19:31               ` Mauro Carvalho Chehab
  2014-01-14 20:57                 ` Frank Schäfer
  2014-01-14 20:48               ` Frank Schäfer
  1 sibling, 1 reply; 40+ messages in thread
From: Mauro Carvalho Chehab @ 2014-01-14 19:31 UTC (permalink / raw)
  Cc: Frank Schäfer, Linux Media Mailing List

Em Tue, 14 Jan 2014 16:55:12 -0200
Mauro Carvalho Chehab <m.chehab@samsung.com> escreveu:

> Em Tue, 14 Jan 2014 19:13:00 +0100
> Frank Schäfer <fschaefer.oss@googlemail.com> escreveu:
> 
> > On 14.01.2014 14:10, Mauro Carvalho Chehab wrote:
> > > Em Mon, 13 Jan 2014 22:55:36 +0100
> > > Frank Schäfer <fschaefer.oss@googlemail.com> escreveu:
> > >
> > >> Am 13.01.2014 20:23, schrieb Mauro Carvalho Chehab:
> > >>> Em Mon, 13 Jan 2014 20:02:19 +0100
> > >>> Frank Schäfer <fschaefer.oss@googlemail.com> escreveu:
> > >>>
> > >>>> On 13.01.2014 00:00, Mauro Carvalho Chehab wrote:
> > >>>>> We can't free struct em28xx while one of the extensions is still
> > >>>>> using it.
> > >>>>>
> > >>>>> So, add a kref() to control it, freeing it only after the
> > >>>>> extensions fini calls.
> > >>>>>
> > >>>>> Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
> > >>>>> ---
> > >>>>>    drivers/media/usb/em28xx/em28xx-audio.c |  5 ++++-
> > >>>>>    drivers/media/usb/em28xx/em28xx-cards.c | 34 ++++++++++++++++-----------------
> > >>>>>    drivers/media/usb/em28xx/em28xx-dvb.c   |  5 ++++-
> > >>>>>    drivers/media/usb/em28xx/em28xx-input.c |  8 +++++++-
> > >>>>>    drivers/media/usb/em28xx/em28xx-video.c | 11 +++++------
> > >>>>>    drivers/media/usb/em28xx/em28xx.h       |  9 +++++++--
> > >>>>>    6 files changed, 44 insertions(+), 28 deletions(-)
> > >>>>>
> > >>>>> diff --git a/drivers/media/usb/em28xx/em28xx-audio.c b/drivers/media/usb/em28xx/em28xx-audio.c
> > >>>>> index 97d9105e6830..8e959dae8358 100644
> > >>>>> --- a/drivers/media/usb/em28xx/em28xx-audio.c
> > >>>>> +++ b/drivers/media/usb/em28xx/em28xx-audio.c
> > >>>>> @@ -878,6 +878,8 @@ static int em28xx_audio_init(struct em28xx *dev)
> > >>>>>    
> > >>>>>    	em28xx_info("Binding audio extension\n");
> > >>>>>    
> > >>>>> +	kref_get(&dev->ref);
> > >>>>> +
> > >>>>>    	printk(KERN_INFO "em28xx-audio.c: Copyright (C) 2006 Markus "
> > >>>>>    			 "Rechberger\n");
> > >>>>>    	printk(KERN_INFO
> > >>>>> @@ -949,7 +951,7 @@ static int em28xx_audio_fini(struct em28xx *dev)
> > >>>>>    	if (dev == NULL)
> > >>>>>    		return 0;
> > >>>>>    
> > >>>>> -	if (dev->has_alsa_audio != 1) {
> > >>>>> +	if (!dev->has_alsa_audio) {
> > >>>>>    		/* This device does not support the extension (in this case
> > >>>>>    		   the device is expecting the snd-usb-audio module or
> > >>>>>    		   doesn't have analog audio support at all) */
> > >>>>> @@ -963,6 +965,7 @@ static int em28xx_audio_fini(struct em28xx *dev)
> > >>>>>    		dev->adev.sndcard = NULL;
> > >>>>>    	}
> > >>>>>    
> > >>>>> +	kref_put(&dev->ref, em28xx_free_device);
> > >>>>>    	return 0;
> > >>>>>    }
> > >>>>>    
> > >>>>> diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c
> > >>>>> index 3b332d527ccb..df92f417634a 100644
> > >>>>> --- a/drivers/media/usb/em28xx/em28xx-cards.c
> > >>>>> +++ b/drivers/media/usb/em28xx/em28xx-cards.c
> > >>>>> @@ -2867,16 +2867,18 @@ static void flush_request_modules(struct em28xx *dev)
> > >>>>>    	flush_work(&dev->request_module_wk);
> > >>>>>    }
> > >>>>>    
> > >>>>> -/*
> > >>>>> - * em28xx_release_resources()
> > >>>>> - * unregisters the v4l2,i2c and usb devices
> > >>>>> - * called when the device gets disconnected or at module unload
> > >>>>> -*/
> > >>>>> -void em28xx_release_resources(struct em28xx *dev)
> > >>>>> +/**
> > >>>>> + * em28xx_release_resources() -  unregisters the v4l2,i2c and usb devices
> > >>>>> + *
> > >>>>> + * @ref: struct kref for em28xx device
> > >>>>> + *
> > >>>>> + * This is called when all extensions and em28xx core unregisters a device
> > >>>>> + */
> > >>>>> +void em28xx_free_device(struct kref *ref)
> > >>>>>    {
> > >>>>> -	/*FIXME: I2C IR should be disconnected */
> > >>>>> +	struct em28xx *dev = kref_to_dev(ref);
> > >>>>>    
> > >>>>> -	mutex_lock(&dev->lock);
> > >>>>> +	em28xx_info("Freeing device\n");
> > >>>>>    
> > >>>>>    	if (dev->def_i2c_bus)
> > >>>>>    		em28xx_i2c_unregister(dev, 1);
> > >>>>> @@ -2887,9 +2889,10 @@ void em28xx_release_resources(struct em28xx *dev)
> > >>>>>    	/* Mark device as unused */
> > >>>>>    	clear_bit(dev->devno, &em28xx_devused);
> > >>>>>    
> > >>>>> -	mutex_unlock(&dev->lock);
> > >>>>> -};
> > >>>>> -EXPORT_SYMBOL_GPL(em28xx_release_resources);
> > >>>>> +	kfree(dev->alt_max_pkt_size_isoc);
> > >>>>> +	kfree(dev);
> > >>>>> +}
> > >>>>> +EXPORT_SYMBOL_GPL(em28xx_free_device);
> > >>>>>    
> > >>>>>    /*
> > >>>>>     * em28xx_init_dev()
> > >>>>> @@ -3342,6 +3345,8 @@ static int em28xx_usb_probe(struct usb_interface *interface,
> > >>>>>    			    dev->dvb_xfer_bulk ? "bulk" : "isoc");
> > >>>>>    	}
> > >>>>>    
> > >>>>> +	kref_init(&dev->ref);
> > >>>>> +
> > >>>>>    	request_modules(dev);
> > >>>>>    
> > >>>>>    	/* Should be the last thing to do, to avoid newer udev's to
> > >>>>> @@ -3390,12 +3395,7 @@ static void em28xx_usb_disconnect(struct usb_interface *interface)
> > >>>>>    
> > >>>>>    	em28xx_close_extension(dev);
> > >>>>>    
> > >>>>> -	em28xx_release_resources(dev);
> > >>>>> -
> > >>>>> -	if (!dev->users) {
> > >>>>> -		kfree(dev->alt_max_pkt_size_isoc);
> > >>>>> -		kfree(dev);
> > >>>>> -	}
> > >>>>> +	kref_put(&dev->ref, em28xx_free_device);
> > >>>>>    }
> > >>>>>    
> > >>>>>    static struct usb_driver em28xx_usb_driver = {
> > >>>>> diff --git a/drivers/media/usb/em28xx/em28xx-dvb.c b/drivers/media/usb/em28xx/em28xx-dvb.c
> > >>>>> index 5ea563e3f0e4..8674ae5fce06 100644
> > >>>>> --- a/drivers/media/usb/em28xx/em28xx-dvb.c
> > >>>>> +++ b/drivers/media/usb/em28xx/em28xx-dvb.c
> > >>>>> @@ -1010,11 +1010,11 @@ static int em28xx_dvb_init(struct em28xx *dev)
> > >>>>>    	em28xx_info("Binding DVB extension\n");
> > >>>>>    
> > >>>>>    	dvb = kzalloc(sizeof(struct em28xx_dvb), GFP_KERNEL);
> > >>>>> -
> > >>>>>    	if (dvb == NULL) {
> > >>>>>    		em28xx_info("em28xx_dvb: memory allocation failed\n");
> > >>>>>    		return -ENOMEM;
> > >>>>>    	}
> > >>>>> +	kref_get(&dev->ref);
> > >>>>>    	dev->dvb = dvb;
> > >>>>>    	dvb->fe[0] = dvb->fe[1] = NULL;
> > >>>>>    
> > >>>>> @@ -1442,6 +1442,7 @@ static int em28xx_dvb_init(struct em28xx *dev)
> > >>>>>    	dvb->adapter.mfe_shared = mfe_shared;
> > >>>>>    
> > >>>>>    	em28xx_info("DVB extension successfully initialized\n");
> > >>>>> +
> > >>>>>    ret:
> > >>>>>    	em28xx_set_mode(dev, EM28XX_SUSPEND);
> > >>>>>    	mutex_unlock(&dev->lock);
> > >>>>> @@ -1492,6 +1493,8 @@ static int em28xx_dvb_fini(struct em28xx *dev)
> > >>>>>    		dev->dvb = NULL;
> > >>>>>    	}
> > >>>>>    
> > >>>>> +	kref_put(&dev->ref, em28xx_free_device);
> > >>>>> +
> > >>>>>    	return 0;
> > >>>>>    }
> > >>>>>    
> > >>>>> diff --git a/drivers/media/usb/em28xx/em28xx-input.c b/drivers/media/usb/em28xx/em28xx-input.c
> > >>>>> index 61c061f3a476..33388b5922a0 100644
> > >>>>> --- a/drivers/media/usb/em28xx/em28xx-input.c
> > >>>>> +++ b/drivers/media/usb/em28xx/em28xx-input.c
> > >>>>> @@ -676,6 +676,8 @@ static int em28xx_ir_init(struct em28xx *dev)
> > >>>>>    		return 0;
> > >>>>>    	}
> > >>>>>    
> > >>>>> +	kref_get(&dev->ref);
> > >>>>> +
> > >>>>>    	if (dev->board.buttons)
> > >>>>>    		em28xx_init_buttons(dev);
> > >>>>>    
> > >>>>> @@ -814,7 +816,7 @@ static int em28xx_ir_fini(struct em28xx *dev)
> > >>>>>    
> > >>>>>    	/* skip detach on non attached boards */
> > >>>>>    	if (!ir)
> > >>>>> -		return 0;
> > >>>>> +		goto ref_put;
> > >>>>>    
> > >>>>>    	if (ir->rc)
> > >>>>>    		rc_unregister_device(ir->rc);
> > >>>>> @@ -822,6 +824,10 @@ static int em28xx_ir_fini(struct em28xx *dev)
> > >>>>>    	/* done */
> > >>>>>    	kfree(ir);
> > >>>>>    	dev->ir = NULL;
> > >>>>> +
> > >>>>> +ref_put:
> > >>>>> +	kref_put(&dev->ref, em28xx_free_device);
> > >>>>> +
> > >>>>>    	return 0;
> > >>>>>    }
> > >>>>>    
> > >>>>> diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c
> > >>>>> index 587ff3fe9402..dc10cec772ba 100644
> > >>>>> --- a/drivers/media/usb/em28xx/em28xx-video.c
> > >>>>> +++ b/drivers/media/usb/em28xx/em28xx-video.c
> > >>>>> @@ -1922,8 +1922,7 @@ static int em28xx_v4l2_fini(struct em28xx *dev)
> > >>>>>    	v4l2_ctrl_handler_free(&dev->ctrl_handler);
> > >>>>>    	v4l2_device_unregister(&dev->v4l2_dev);
> > >>>>>    
> > >>>>> -	if (dev->users)
> > >>>>> -		em28xx_warn("Device is open ! Memory deallocation is deferred on last close.\n");
> > >>>>> +	kref_put(&dev->ref, em28xx_free_device);
> > >>>>>    
> > >>>>>    	return 0;
> > >>>>>    }
> > >>>>> @@ -1945,11 +1944,9 @@ static int em28xx_v4l2_close(struct file *filp)
> > >>>>>    	mutex_lock(&dev->lock);
> > >>>>>    
> > >>>>>    	if (dev->users == 1) {
> > >>>>> -		/* free the remaining resources if device is disconnected */
> > >>>>> -		if (dev->disconnected) {
> > >>>>> -			kfree(dev->alt_max_pkt_size_isoc);
> > >>>>> +		/* No sense to try to write to the device */
> > >>>>> +		if (dev->disconnected)
> > >>>>>    			goto exit;
> > >>>>> -		}
> > >>>>>    
> > >>>>>    		/* Save some power by putting tuner to sleep */
> > >>>>>    		v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_power, 0);
> > >>>>> @@ -2201,6 +2198,8 @@ static int em28xx_v4l2_init(struct em28xx *dev)
> > >>>>>    
> > >>>>>    	em28xx_info("Registering V4L2 extension\n");
> > >>>>>    
> > >>>>> +	kref_get(&dev->ref);
> > >>>>> +
> > >>>>>    	mutex_lock(&dev->lock);
> > >>>>>    
> > >>>>>    	ret = v4l2_device_register(&dev->udev->dev, &dev->v4l2_dev);
> > >>>>> diff --git a/drivers/media/usb/em28xx/em28xx.h b/drivers/media/usb/em28xx/em28xx.h
> > >>>>> index 5d5d1b6f0294..d38c08e4da60 100644
> > >>>>> --- a/drivers/media/usb/em28xx/em28xx.h
> > >>>>> +++ b/drivers/media/usb/em28xx/em28xx.h
> > >>>>> @@ -32,6 +32,7 @@
> > >>>>>    #include <linux/workqueue.h>
> > >>>>>    #include <linux/i2c.h>
> > >>>>>    #include <linux/mutex.h>
> > >>>>> +#include <linux/kref.h>
> > >>>>>    #include <linux/videodev2.h>
> > >>>>>    
> > >>>>>    #include <media/videobuf2-vmalloc.h>
> > >>>>> @@ -531,9 +532,11 @@ struct em28xx_i2c_bus {
> > >>>>>    	enum em28xx_i2c_algo_type algo_type;
> > >>>>>    };
> > >>>>>    
> > >>>>> -
> > >>>>>    /* main device struct */
> > >>>>>    struct em28xx {
> > >>>>> +	struct kref ref;
> > >>>>> +
> > >>>>> +
> > >>>>>    	/* generic device properties */
> > >>>>>    	char name[30];		/* name (including minor) of the device */
> > >>>>>    	int model;		/* index in the device_data struct */
> > >>>>> @@ -706,6 +709,8 @@ struct em28xx {
> > >>>>>    	struct em28xx_dvb *dvb;
> > >>>>>    };
> > >>>>>    
> > >>>>> +#define kref_to_dev(d) container_of(d, struct em28xx, ref)
> > >>>>> +
> > >>>>>    struct em28xx_ops {
> > >>>>>    	struct list_head next;
> > >>>>>    	char *name;
> > >>>>> @@ -763,7 +768,7 @@ extern struct em28xx_board em28xx_boards[];
> > >>>>>    extern struct usb_device_id em28xx_id_table[];
> > >>>>>    int em28xx_tuner_callback(void *ptr, int component, int command, int arg);
> > >>>>>    void em28xx_setup_xc3028(struct em28xx *dev, struct xc2028_ctrl *ctl);
> > >>>>> -void em28xx_release_resources(struct em28xx *dev);
> > >>>>> +void em28xx_free_device(struct kref *ref);
> > >>>>>    
> > >>>>>    /* Provided by em28xx-camera.c */
> > >>>>>    int em28xx_detect_sensor(struct em28xx *dev);
> > >>>> I welcome this patch and the general approach looks good.
> > >>>> I had started working on the same issue, but it's not that trivial.
> > >>>>
> > >>>> At first glance there seem to be several issues, but I will need to
> > >>>> review this patch in more detail and also make some tests.
> > >>>> Unfortunately, I don't have much time this evening, So could you please
> > >>>> hold it back another day ?
> > >>>> I hope I can review the other remaining patch of this series (patch 5/7)
> > >>>> later this evening.
> > >>> We're running out of time for 3.14. I think we should merge this patch
> > >>> series, and your patch series for 3.14, to be together with the em28xx-v4l
> > >>> split.
> > >>>
> > >>> My plan is to merge the remaining patches for 3.14 today or, in the worse
> > >>> case, tomorrow.
> > >>>
> > >>> If we slip on some bug, we'll still have the 3.14-rc cycle to fix, if the
> > >>> series gets merged, but, if we miss the bus, I'm afraid that we'll end
> > >>> by having more problems that will be hard to fix with trivial patches, due
> > >>> to em28xx-v4l split changes that also affected the driver removal and device
> > >>> close code.
> > >>>
> > >>> FYI, I tested this code and also Antti with our devices, randomly removing
> > >>> the devices while streaming, and this is now finally working.
> > >>>
> > >>> I won't doubt that there are some cases that require fixes (and
> > >>> it seems that em28xx-rc has one of such corner cases), but they'll likely
> > >>> can be solved with somewhat short and trivial patches.
> > >>>
> > >>> Cheers,
> > >>> Mauro
> > >> This is a very critical patch and exactly the kind of change that should
> > >> _never_ be hurried !
> > >> FAICS it has some severe issues and it's not clear how easy it will be
> > >> to fix it within the the 3.14-rc cycle.
> > >> As long as it's not ready, don't merge it for 3.14.
> > > What issues? So far, you didn't point any.
> > I already stated that I didn't have the time yet to review and test it 
> > in detail, but I'm going to do that as soon as possible.
> > If you can't wait, there's nothing I can do, sorry.
> > 
> > At first glance it seems there are at least 2 issues:
> > 1.) use after freeing in v4l-extension (happens when the device is 
> > closed after the usb disconnect)
> 
> That's basically what this patch fixes. Both V4L2 and ALSA handles it
> well, if you warn the subsystem that a device will be removed.
> 
> If are there still any issues, we may add a kref_get() at device open,
> an a kref_put() at device close on the affected sub-driver.
> 
> > 2.) error paths in the init() functions ?
> 
> It should be ok. Basically, kref_get() is called even if an error
> occurs, and kref_put() is called even if init fails. Ok, this is an
> overkill, but makes the patch simpler to review. We may fine tune it
> on a latter patch.
> 
> I opted to call kref_get() as soon as possible, to avoid the risk of
> the device to be removed while the extension is still being
> initialized (yes, if you remove a device too quick, even before pulseaudio
> starts opening the device), it used to crash.
> 
> > > On both my tests and Antti's one,
> > > with this series, there were significant improvements on removing existing
> > > bugs with device removal.
> > I'm talking about this specific patch here, not the whole series.
> > I have no objections against the rest of the series (well, with the 
> > exception of patch 5 at the moment).
> 
> I see. Well, let me do some tests with all patches except 3 and 5 applied,
> to see how it behaves.

Ok, patch 5 is not needed anymore.

However, after a series of removals and re-inserts, I got these:


[120982.699455] ------------[ cut here ]------------
[120982.699509] WARNING: CPU: 0 PID: 7953 at lib/list_debug.c:33 __list_add+0xac/0xc0()
[120982.699539] list_add corruption. prev->next should be next (ffff88019ffce4f8), but was 0000000d00000007. (prev=ffff880101dbfb48).
[120982.699566] Modules linked in: lgdt330x tuner_xc2028 tuner tvp5150 rc_hauppauge em28xx_rc rc_core xc5000 drxk em28xx_dvb dvb_core em28xx_alsa em28xx_v4l videobuf2_vmalloc videobuf2_memops videobuf2_core em28xx tveeprom v4l2_common videodev media netconsole usb_storage fuse ccm nf_conntrack_netbios_ns nf_conntrack_broadcast ipt_MASQUERADE ip6t_REJECT xt_conntrack ebtable_nat ebtable_broute bridge stp llc ebtable_filter ebtables ip6table_nat nf_conntrack_ipv6 nf_defrag_ipv6 nf_nat_ipv6 ip6table_mangle ip6table_security ip6table_raw ip6table_filter ip6_tables iptable_nat nf_conntrack_ipv4 nf_defrag_ipv4 nf_nat_ipv4 nf_nat nf_conntrack iptable_mangle iptable_security iptable_raw bnep arc4 vfat fat iwldvm mac80211 iwlwifi cfg80211 x86_pkg_temp_thermal coretemp kvm_intel kvm crc32_pclmul crc32c_intel ghash_clmulni_intel
[120982.701828]  snd_hda_codec_hdmi snd_hda_codec_realtek snd_hda_intel snd_hda_codec snd_hwdep snd_seq snd_seq_device snd_pcm iTCO_wdt iTCO_vendor_support btusb bluetooth joydev microcode serio_raw r8169 mii i2c_i801 lpc_ich mfd_core rfkill snd_page_alloc snd_timer snd mei_me soundcore mei shpchp nfsd auth_rpcgss nfs_acl lockd sunrpc nouveau i915 ttm i2c_algo_bit drm_kms_helper drm i2c_core mxm_wmi wmi video [last unloaded: videobuf2_memops]
[120982.703581] CPU: 0 PID: 7953 Comm: xawtv Tainted: G      D      3.13.0-rc1+ #24
[120982.703610] Hardware name: SAMSUNG ELECTRONICS CO., LTD. 550P5C/550P7C/SAMSUNG_NP1234567890, BIOS P04ABI.013.130220.dg 02/20/2013
[120982.703638]  0000000000000009 ffff88011f63bb70 ffffffff816a03c6 ffff88011f63bbb8
[120982.703794]  ffff88011f63bba8 ffffffff8106aaad ffff88018cfb3f48 ffff88019ffce4f8
[120982.703924]  ffff880101dbfb48 0000000000000282 0000000000000000 ffff88011f63bc08
[120982.704056] Call Trace:
[120982.704093]  [<ffffffff816a03c6>] dump_stack+0x45/0x56
[120982.704129]  [<ffffffff8106aaad>] warn_slowpath_common+0x7d/0xa0
[120982.704162]  [<ffffffff8106ab1c>] warn_slowpath_fmt+0x4c/0x50
[120982.704197]  [<ffffffff81343bac>] __list_add+0xac/0xc0
[120982.704233]  [<ffffffffa04fd70b>] buffer_queue+0x7b/0xb0 [em28xx_v4l]
[120982.704432]  [<ffffffffa04862d4>] __enqueue_in_driver+0x74/0x80 [videobuf2_core]
[120982.704469]  [<ffffffffa04878c0>] vb2_streamon+0xa0/0x140 [videobuf2_core]
[120982.704505]  [<ffffffffa04879a8>] vb2_ioctl_streamon+0x48/0x50 [videobuf2_core]
[120982.704543]  [<ffffffffa04b7a8a>] v4l_streamon+0x1a/0x20 [videodev]
[120982.704581]  [<ffffffffa04bb644>] __video_do_ioctl+0x2a4/0x330 [videodev]
[120982.704619]  [<ffffffffa04bb3a0>] ? v4l_dbg_s_register+0x150/0x150 [videodev]
[120982.704658]  [<ffffffffa04bb3a0>] ? v4l_dbg_s_register+0x150/0x150 [videodev]
[120982.704719]  [<ffffffffa04bcae0>] video_usercopy+0x240/0x5d0 [videodev]
[120982.704756]  [<ffffffff810b811d>] ? trace_hardirqs_on+0xd/0x10
[120982.704792]  [<ffffffffa04b663b>] ? v4l2_ioctl+0x5b/0x160 [videodev]
[120982.704829]  [<ffffffffa04b663b>] ? v4l2_ioctl+0x5b/0x160 [videodev]
[120982.704867]  [<ffffffffa04bce85>] video_ioctl2+0x15/0x20 [videodev]
[120982.704903]  [<ffffffffa04b6703>] v4l2_ioctl+0x123/0x160 [videodev]
[120982.704939]  [<ffffffff811db8b0>] do_vfs_ioctl+0x300/0x520
[120982.704974]  [<ffffffff812c7a96>] ? file_has_perm+0x86/0xa0
[120982.705006]  [<ffffffff811dbb51>] SyS_ioctl+0x81/0xa0
[120982.705039]  [<ffffffff816b1929>] system_call_fastpath+0x16/0x1b
[120982.705070] ---[ end trace 7e24c4fe20a76f18 ]---
[120985.899453] ------------[ cut here ]------------
[120985.899502] WARNING: CPU: 0 PID: 7953 at lib/list_debug.c:33 __list_add+0xac/0xc0()
[120985.899531] list_add corruption. prev->next should be next (ffff88019ffce4f8), but was           (null). (prev=ffff88018cfb0348).
[120985.899559] Modules linked in: lgdt330x tuner_xc2028 tuner tvp5150 rc_hauppauge em28xx_rc rc_core xc5000 drxk em28xx_dvb dvb_core em28xx_alsa em28xx_v4l videobuf2_vmalloc videobuf2_memops videobuf2_core em28xx tveeprom v4l2_common videodev media netconsole usb_storage fuse ccm nf_conntrack_netbios_ns nf_conntrack_broadcast ipt_MASQUERADE ip6t_REJECT xt_conntrack ebtable_nat ebtable_broute bridge stp llc ebtable_filter ebtables ip6table_nat nf_conntrack_ipv6 nf_defrag_ipv6 nf_nat_ipv6 ip6table_mangle ip6table_security ip6table_raw ip6table_filter ip6_tables iptable_nat nf_conntrack_ipv4 nf_defrag_ipv4 nf_nat_ipv4 nf_nat nf_conntrack iptable_mangle iptable_security iptable_raw bnep arc4 vfat fat iwldvm mac80211 iwlwifi cfg80211 x86_pkg_temp_thermal coretemp kvm_intel kvm crc32_pclmul crc32c_intel ghash_clmulni_intel
[120985.901761]  snd_hda_codec_hdmi snd_hda_codec_realtek snd_hda_intel snd_hda_codec snd_hwdep snd_seq snd_seq_device snd_pcm iTCO_wdt iTCO_vendor_support btusb bluetooth joydev microcode serio_raw r8169 mii i2c_i801 lpc_ich mfd_core rfkill snd_page_alloc snd_timer snd mei_me soundcore mei shpchp nfsd auth_rpcgss nfs_acl lockd sunrpc nouveau i915 ttm i2c_algo_bit drm_kms_helper drm i2c_core mxm_wmi wmi video [last unloaded: videobuf2_memops]
[120985.903502] CPU: 0 PID: 7953 Comm: xawtv Tainted: G      D W    3.13.0-rc1+ #24
[120985.903530] Hardware name: SAMSUNG ELECTRONICS CO., LTD. 550P5C/550P7C/SAMSUNG_NP1234567890, BIOS P04ABI.013.130220.dg 02/20/2013
[120985.903557]  0000000000000009 ffff88011f63bb70 ffffffff816a03c6 ffff88011f63bbb8
[120985.903686]  ffff88011f63bba8 ffffffff8106aaad ffff88018cfb0348 ffff88019ffce4f8
[120985.903826]  ffff88018cfb0348 0000000000000282 0000000000000000 ffff88011f63bc08
[120985.903955] Call Trace:
[120985.903988]  [<ffffffff816a03c6>] dump_stack+0x45/0x56
[120985.904021]  [<ffffffff8106aaad>] warn_slowpath_common+0x7d/0xa0
[120985.904052]  [<ffffffff8106ab1c>] warn_slowpath_fmt+0x4c/0x50
[120985.904083]  [<ffffffff81343bac>] __list_add+0xac/0xc0
[120985.904116]  [<ffffffffa04fd70b>] buffer_queue+0x7b/0xb0 [em28xx_v4l]
[120985.904295]  [<ffffffffa04862d4>] __enqueue_in_driver+0x74/0x80 [videobuf2_core]
[120985.904330]  [<ffffffffa04878c0>] vb2_streamon+0xa0/0x140 [videobuf2_core]
[120985.904363]  [<ffffffffa04879a8>] vb2_ioctl_streamon+0x48/0x50 [videobuf2_core]
[120985.904398]  [<ffffffffa04b7a8a>] v4l_streamon+0x1a/0x20 [videodev]
[120985.904433]  [<ffffffffa04bb644>] __video_do_ioctl+0x2a4/0x330 [videodev]
[120985.904470]  [<ffffffffa04bb3a0>] ? v4l_dbg_s_register+0x150/0x150 [videodev]
[120985.904504]  [<ffffffffa04bb3a0>] ? v4l_dbg_s_register+0x150/0x150 [videodev]
[120985.904540]  [<ffffffffa04bcae0>] video_usercopy+0x240/0x5d0 [videodev]
[120985.904575]  [<ffffffff810b811d>] ? trace_hardirqs_on+0xd/0x10
[120985.904608]  [<ffffffffa04b663b>] ? v4l2_ioctl+0x5b/0x160 [videodev]
[120985.904641]  [<ffffffffa04b663b>] ? v4l2_ioctl+0x5b/0x160 [videodev]
[120985.904676]  [<ffffffffa04bce85>] video_ioctl2+0x15/0x20 [videodev]
[120985.904710]  [<ffffffffa04b6703>] v4l2_ioctl+0x123/0x160 [videodev]
[120985.904743]  [<ffffffff811db8b0>] do_vfs_ioctl+0x300/0x520
[120985.904780]  [<ffffffff812c7a96>] ? file_has_perm+0x86/0xa0
[120985.904810]  [<ffffffff811dbb51>] SyS_ioctl+0x81/0xa0
[120985.904843]  [<ffffffff816b1929>] system_call_fastpath+0x16/0x1b
[120985.904871] ---[ end trace 7e24c4fe20a76f19 ]---
[120985.904896] ------------[ cut here ]------------
[120985.904922] WARNING: CPU: 0 PID: 7953 at lib/list_debug.c:36 __list_add+0x8a/0xc0()
[120985.904953] list_add double add: new=ffff88018cfb0348, prev=ffff88018cfb0348, next=ffff88019ffce4f8.
[120985.904978] Modules linked in: lgdt330x tuner_xc2028 tuner tvp5150 rc_hauppauge em28xx_rc rc_core xc5000 drxk em28xx_dvb dvb_core em28xx_alsa em28xx_v4l videobuf2_vmalloc videobuf2_memops videobuf2_core em28xx tveeprom v4l2_common videodev media netconsole usb_storage fuse ccm nf_conntrack_netbios_ns nf_conntrack_broadcast ipt_MASQUERADE ip6t_REJECT xt_conntrack ebtable_nat ebtable_broute bridge stp llc ebtable_filter ebtables ip6table_nat nf_conntrack_ipv6 nf_defrag_ipv6 nf_nat_ipv6 ip6table_mangle ip6table_security ip6table_raw ip6table_filter ip6_tables iptable_nat nf_conntrack_ipv4 nf_defrag_ipv4 nf_nat_ipv4 nf_nat nf_conntrack iptable_mangle iptable_security iptable_raw bnep arc4 vfat fat iwldvm mac80211 iwlwifi cfg80211 x86_pkg_temp_thermal coretemp kvm_intel kvm crc32_pclmul crc32c_intel ghash_clmulni_intel
[120985.907016]  snd_hda_codec_hdmi snd_hda_codec_realtek snd_hda_intel snd_hda_codec snd_hwdep snd_seq snd_seq_device snd_pcm iTCO_wdt iTCO_vendor_support btusb bluetooth joydev microcode serio_raw r8169 mii i2c_i801 lpc_ich mfd_core rfkill snd_page_alloc snd_timer snd mei_me soundcore mei shpchp nfsd auth_rpcgss nfs_acl lockd sunrpc nouveau i915 ttm i2c_algo_bit drm_kms_helper drm i2c_core mxm_wmi wmi video [last unloaded: videobuf2_memops]
[120985.908654] CPU: 0 PID: 7953 Comm: xawtv Tainted: G      D W    3.13.0-rc1+ #24
[120985.908680] Hardware name: SAMSUNG ELECTRONICS CO., LTD. 550P5C/550P7C/SAMSUNG_NP1234567890, BIOS P04ABI.013.130220.dg 02/20/2013
[120985.908707]  0000000000000009 ffff88011f63bb70 ffffffff816a03c6 ffff88011f63bbb8
[120985.908988]  ffff88011f63bba8 ffffffff8106aaad ffff88018cfb0348 ffff88019ffce4f8
[120985.909110]  ffff88018cfb0348 0000000000000282 0000000000000000 ffff88011f63bc08
[120985.909230] Call Trace:
[120985.909268]  [<ffffffff816a03c6>] dump_stack+0x45/0x56
[120985.909305]  [<ffffffff8106aaad>] warn_slowpath_common+0x7d/0xa0
[120985.909336]  [<ffffffff8106ab1c>] warn_slowpath_fmt+0x4c/0x50
[120985.909380]  [<ffffffff81343b8a>] __list_add+0x8a/0xc0
[120985.909410]  [<ffffffffa04fd70b>] buffer_queue+0x7b/0xb0 [em28xx_v4l]
[120985.909442]  [<ffffffffa04862d4>] __enqueue_in_driver+0x74/0x80 [videobuf2_core]
[120985.909474]  [<ffffffffa04878c0>] vb2_streamon+0xa0/0x140 [videobuf2_core]
[120985.909505]  [<ffffffffa04879a8>] vb2_ioctl_streamon+0x48/0x50 [videobuf2_core]
[120985.909537]  [<ffffffffa04b7a8a>] v4l_streamon+0x1a/0x20 [videodev]
[120985.909570]  [<ffffffffa04bb644>] __video_do_ioctl+0x2a4/0x330 [videodev]
[120985.909604]  [<ffffffffa04bb3a0>] ? v4l_dbg_s_register+0x150/0x150 [videodev]
[120985.909636]  [<ffffffffa04bb3a0>] ? v4l_dbg_s_register+0x150/0x150 [videodev]
[120985.909670]  [<ffffffffa04bcae0>] video_usercopy+0x240/0x5d0 [videodev]
[120985.909702]  [<ffffffff810b811d>] ? trace_hardirqs_on+0xd/0x10
[120985.909732]  [<ffffffffa04b663b>] ? v4l2_ioctl+0x5b/0x160 [videodev]
[120985.909764]  [<ffffffffa04b663b>] ? v4l2_ioctl+0x5b/0x160 [videodev]
[120985.909799]  [<ffffffffa04bce85>] video_ioctl2+0x15/0x20 [videodev]
[120985.909830]  [<ffffffffa04b6703>] v4l2_ioctl+0x123/0x160 [videodev]
[120985.909860]  [<ffffffff811db8b0>] do_vfs_ioctl+0x300/0x520
[120985.909890]  [<ffffffff812c7a96>] ? file_has_perm+0x86/0xa0
[120985.909918]  [<ffffffff811dbb51>] SyS_ioctl+0x81/0xa0
[120985.909948]  [<ffffffff816b1929>] system_call_fastpath+0x16/0x1b
[120985.909974] ---[ end trace 7e24c4fe20a76f1a ]---
[120985.910186] ------------[ cut here ]------------
[120985.910213] WARNING: CPU: 0 PID: 7953 at lib/list_debug.c:33 __list_add+0xac/0xc0()
[120985.910236] list_add corruption. prev->next should be next (ffff88019ffce4f8), but was ffff88018cfb0348. (prev=ffff88018cfb0348).
[120985.910257] Modules linked in: lgdt330x tuner_xc2028 tuner tvp5150 rc_hauppauge em28xx_rc rc_core xc5000 drxk em28xx_dvb dvb_core em28xx_alsa em28xx_v4l videobuf2_vmalloc videobuf2_memops videobuf2_core em28xx tveeprom v4l2_common videodev media netconsole usb_storage fuse ccm nf_conntrack_netbios_ns nf_conntrack_broadcast ipt_MASQUERADE ip6t_REJECT xt_conntrack ebtable_nat ebtable_broute bridge stp llc ebtable_filter ebtables ip6table_nat nf_conntrack_ipv6 nf_defrag_ipv6 nf_nat_ipv6 ip6table_mangle ip6table_security ip6table_raw ip6table_filter ip6_tables iptable_nat nf_conntrack_ipv4 nf_defrag_ipv4 nf_nat_ipv4 nf_nat nf_conntrack iptable_mangle iptable_security iptable_raw bnep arc4 vfat fat iwldvm mac80211 iwlwifi cfg80211 x86_pkg_temp_thermal coretemp kvm_intel kvm crc32_pclmul crc32c_intel ghash_clmulni_intel
[120985.912159]  snd_hda_codec_hdmi snd_hda_codec_realtek snd_hda_intel snd_hda_codec snd_hwdep snd_seq snd_seq_device snd_pcm iTCO_wdt iTCO_vendor_support btusb bluetooth joydev microcode serio_raw r8169 mii i2c_i801 lpc_ich mfd_core rfkill snd_page_alloc snd_timer snd mei_me soundcore mei shpchp nfsd auth_rpcgss nfs_acl lockd sunrpc nouveau i915 ttm i2c_algo_bit drm_kms_helper drm i2c_core mxm_wmi wmi video [last unloaded: videobuf2_memops]
[120985.913642] CPU: 0 PID: 7953 Comm: xawtv Tainted: G      D W    3.13.0-rc1+ #24
[120985.913667] Hardware name: SAMSUNG ELECTRONICS CO., LTD. 550P5C/550P7C/SAMSUNG_NP1234567890, BIOS P04ABI.013.130220.dg 02/20/2013
[120985.913691]  0000000000000009 ffff88011f63bb70 ffffffff816a03c6 ffff88011f63bbb8
[120985.913805]  ffff88011f63bba8 ffffffff8106aaad ffff88018cfb3f48 ffff88019ffce4f8
[120985.913920]  ffff88018cfb0348 0000000000000282 0000000000000000 ffff88011f63bc08
[120985.914035] Call Trace:
[120985.914063]  [<ffffffff816a03c6>] dump_stack+0x45/0x56
[120985.914093]  [<ffffffff8106aaad>] warn_slowpath_common+0x7d/0xa0
[120985.914121]  [<ffffffff8106ab1c>] warn_slowpath_fmt+0x4c/0x50
[120985.914150]  [<ffffffff81343bac>] __list_add+0xac/0xc0
[120985.914180]  [<ffffffffa04fd70b>] buffer_queue+0x7b/0xb0 [em28xx_v4l]
[120985.914353]  [<ffffffffa04862d4>] __enqueue_in_driver+0x74/0x80 [videobuf2_core]
[120985.914385]  [<ffffffffa04878c0>] vb2_streamon+0xa0/0x140 [videobuf2_core]
[120985.914416]  [<ffffffffa04879a8>] vb2_ioctl_streamon+0x48/0x50 [videobuf2_core]
[120985.914449]  [<ffffffffa04b7a8a>] v4l_streamon+0x1a/0x20 [videodev]
[120985.914482]  [<ffffffffa04bb644>] __video_do_ioctl+0x2a4/0x330 [videodev]
[120985.914515]  [<ffffffffa04bb3a0>] ? v4l_dbg_s_register+0x150/0x150 [videodev]
[120985.914548]  [<ffffffffa04bb3a0>] ? v4l_dbg_s_register+0x150/0x150 [videodev]
[120985.914580]  [<ffffffffa04bcae0>] video_usercopy+0x240/0x5d0 [videodev]
[120985.914612]  [<ffffffff810b811d>] ? trace_hardirqs_on+0xd/0x10
[120985.914643]  [<ffffffffa04b663b>] ? v4l2_ioctl+0x5b/0x160 [videodev]
[120985.914675]  [<ffffffffa04b663b>] ? v4l2_ioctl+0x5b/0x160 [videodev]
[120985.914708]  [<ffffffffa04bce85>] video_ioctl2+0x15/0x20 [videodev]
[120985.914740]  [<ffffffffa04b6703>] v4l2_ioctl+0x123/0x160 [videodev]
[120985.914770]  [<ffffffff811db8b0>] do_vfs_ioctl+0x300/0x520
[120985.914799]  [<ffffffff812c7a96>] ? file_has_perm+0x86/0xa0
[120985.914828]  [<ffffffff811dbb51>] SyS_ioctl+0x81/0xa0
[120985.914857]  [<ffffffff816b1929>] system_call_fastpath+0x16/0x1b
[120985.914884] ---[ end trace 7e24c4fe20a76f1b ]---
[120991.576999] em2882/3 #0: submit of audio urb failed
[120991.781651] ------------[ cut here ]------------
[120991.781700] WARNING: CPU: 0 PID: 7979 at lib/list_debug.c:33 __list_add+0xac/0xc0()
[120991.781730] list_add corruption. prev->next should be next (ffff88019ffce4f8), but was           (null). (prev=ffff88018cfb1b48).
[120991.781756] Modules linked in: lgdt330x tuner_xc2028 tuner tvp5150 rc_hauppauge em28xx_rc rc_core xc5000 drxk em28xx_dvb dvb_core em28xx_alsa em28xx_v4l videobuf2_vmalloc videobuf2_memops videobuf2_core em28xx tveeprom v4l2_common videodev media netconsole usb_storage fuse ccm nf_conntrack_netbios_ns nf_conntrack_broadcast ipt_MASQUERADE ip6t_REJECT xt_conntrack ebtable_nat ebtable_broute bridge stp llc ebtable_filter ebtables ip6table_nat nf_conntrack_ipv6 nf_defrag_ipv6 nf_nat_ipv6 ip6table_mangle ip6table_security ip6table_raw ip6table_filter ip6_tables iptable_nat nf_conntrack_ipv4 nf_defrag_ipv4 nf_nat_ipv4 nf_nat nf_conntrack iptable_mangle iptable_security iptable_raw bnep arc4 vfat fat iwldvm mac80211 iwlwifi cfg80211 x86_pkg_temp_thermal coretemp kvm_intel kvm crc32_pclmul crc32c_intel ghash_clmulni_intel
[120991.783977]  snd_hda_codec_hdmi snd_hda_codec_realtek snd_hda_intel snd_hda_codec snd_hwdep snd_seq snd_seq_device snd_pcm iTCO_wdt iTCO_vendor_support btusb bluetooth joydev microcode serio_raw r8169 mii i2c_i801 lpc_ich mfd_core rfkill snd_page_alloc snd_timer snd mei_me soundcore mei shpchp nfsd auth_rpcgss nfs_acl lockd sunrpc nouveau i915 ttm i2c_algo_bit drm_kms_helper drm i2c_core mxm_wmi wmi video [last unloaded: videobuf2_memops]
[120991.785750] CPU: 0 PID: 7979 Comm: tvtime Tainted: G      D W    3.13.0-rc1+ #24
[120991.785779] Hardware name: SAMSUNG ELECTRONICS CO., LTD. 550P5C/550P7C/SAMSUNG_NP1234567890, BIOS P04ABI.013.130220.dg 02/20/2013
[120991.785806]  0000000000000009 ffff88001254fb70 ffffffff816a03c6 ffff88001254fbb8
[120991.785938]  ffff88001254fba8 ffffffff8106aaad ffff88018cfb3f48 ffff88019ffce4f8
[120991.786102]  ffff88018cfb1b48 0000000000000282 0000000000000000 ffff88001254fc08
[120991.786233] Call Trace:
[120991.786268]  [<ffffffff816a03c6>] dump_stack+0x45/0x56
[120991.786319]  [<ffffffff8106aaad>] warn_slowpath_common+0x7d/0xa0
[120991.786359]  [<ffffffff8106ab1c>] warn_slowpath_fmt+0x4c/0x50
[120991.786393]  [<ffffffff81343bac>] __list_add+0xac/0xc0
[120991.786429]  [<ffffffffa04fd70b>] buffer_queue+0x7b/0xb0 [em28xx_v4l]
[120991.786619]  [<ffffffffa04862d4>] __enqueue_in_driver+0x74/0x80 [videobuf2_core]
[120991.786656]  [<ffffffffa04878c0>] vb2_streamon+0xa0/0x140 [videobuf2_core]
[120991.786690]  [<ffffffffa04879a8>] vb2_ioctl_streamon+0x48/0x50 [videobuf2_core]
[120991.786728]  [<ffffffffa04b7a8a>] v4l_streamon+0x1a/0x20 [videodev]
[120991.786767]  [<ffffffffa04bb644>] __video_do_ioctl+0x2a4/0x330 [videodev]
[120991.786804]  [<ffffffffa04bb3a0>] ? v4l_dbg_s_register+0x150/0x150 [videodev]
[120991.786841]  [<ffffffffa04bb3a0>] ? v4l_dbg_s_register+0x150/0x150 [videodev]
[120991.786880]  [<ffffffffa04bcae0>] video_usercopy+0x240/0x5d0 [videodev]
[120991.786917]  [<ffffffff810b811d>] ? trace_hardirqs_on+0xd/0x10
[120991.786952]  [<ffffffffa04b663b>] ? v4l2_ioctl+0x5b/0x160 [videodev]
[120991.786988]  [<ffffffffa04b663b>] ? v4l2_ioctl+0x5b/0x160 [videodev]
[120991.787027]  [<ffffffffa04bce85>] video_ioctl2+0x15/0x20 [videodev]
[120991.787063]  [<ffffffffa04b6703>] v4l2_ioctl+0x123/0x160 [videodev]
[120991.787098]  [<ffffffff811db8b0>] do_vfs_ioctl+0x300/0x520
[120991.787133]  [<ffffffff812c7a96>] ? file_has_perm+0x86/0xa0
[120991.787165]  [<ffffffff811dbb51>] SyS_ioctl+0x81/0xa0
[120991.787199]  [<ffffffff816b1929>] system_call_fastpath+0x16/0x1b
[120991.787230] ---[ end trace 7e24c4fe20a76f1c ]---

-- 

Cheers,
Mauro

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 5/7] em28xx-audio: remove a deplock circular dependency
  2014-01-14 18:43       ` Frank Schäfer
@ 2014-01-14 19:59         ` Mauro Carvalho Chehab
  2014-01-14 20:51           ` Frank Schäfer
  0 siblings, 1 reply; 40+ messages in thread
From: Mauro Carvalho Chehab @ 2014-01-14 19:59 UTC (permalink / raw)
  To: Frank Schäfer; +Cc: Linux Media Mailing List, Mauro Carvalho Chehab

Em Tue, 14 Jan 2014 19:43:53 +0100
Frank Schäfer <fschaefer.oss@googlemail.com> escreveu:

> On 14.01.2014 16:45, Mauro Carvalho Chehab wrote:
> > Em Mon, 13 Jan 2014 22:51:00 +0100
> > Frank Schäfer <fschaefer.oss@googlemail.com> escreveu:
> >
> >> Am 13.01.2014 00:00, schrieb Mauro Carvalho Chehab:
> >>> We can't lock at pcm close, as it causes circular dependency
> >>> lock issues with .init and .fini callbacks. So, move the code
> >>> that puts the device on mute to the kthread.
> >>>
> >>>      [  322.026316] ======================================================
> >>>      [  322.026356] [ INFO: possible circular locking dependency detected ]
> >>>      [  322.026397] 3.13.0-rc1+ #24 Not tainted
> >>>      [  322.026437] -------------------------------------------------------
> >>>      [  322.026476] khubd/54 is trying to acquire lock:
> >>>      [  322.026516]  (&pcm->open_mutex){+.+.+.}, at: [<ffffffffa04819e6>] snd_pcm_dev_disconnect+0x46/0x1e0 [snd_pcm]
> >>>      [  322.026727]
> >>>      but task is already holding lock:
> >>>      [  322.026767]  (register_mutex#3){+.+.+.}, at: [<ffffffffa04819c4>] snd_pcm_dev_disconnect+0x24/0x1e0 [snd_pcm]
> >>>      [  322.027005]
> >>>      which lock already depends on the new lock.
> >>>
> >>>      [  322.027045]
> >>>      the existing dependency chain (in reverse order) is:
> >>>      [  322.027084]
> >>>      -> #2 (register_mutex#3){+.+.+.}:
> >>>      [  322.027318]        [<ffffffff810b8fa3>] __lock_acquire+0xb43/0x1330
> >>>      [  322.027401]        [<ffffffff810b9f82>] lock_acquire+0xa2/0x120
> >>>      [  322.027479]        [<ffffffff816a5b6c>] mutex_lock_nested+0x5c/0x3c0
> >>>      [  322.027559]        [<ffffffffa04819c4>] snd_pcm_dev_disconnect+0x24/0x1e0 [snd_pcm]
> >>>      [  322.027642]        [<ffffffffa02e855a>] snd_device_disconnect+0x6a/0xf0 [snd]
> >>>      [  322.027727]        [<ffffffffa02e86ac>] snd_device_disconnect_all+0x4c/0x90 [snd]
> >>>      [  322.027814]        [<ffffffffa02e1876>] snd_card_disconnect+0x126/0x1d0 [snd]
> >>>      [  322.027898]        [<ffffffffa02e1ea8>] snd_card_free+0x18/0x90 [snd]
> >>>      [  322.027982]        [<ffffffffa087235f>] em28xx_audio_fini+0x8f/0xa0 [em28xx_alsa]
> >>>      [  322.028063]        [<ffffffffa085cba6>] em28xx_close_extension+0x56/0x90 [em28xx]
> >>>      [  322.028143]        [<ffffffffa085e639>] em28xx_usb_disconnect+0x79/0x90 [em28xx]
> >>>      [  322.028222]        [<ffffffff814a06e7>] usb_unbind_interface+0x67/0x1d0
> >>>      [  322.028302]        [<ffffffff8142920f>] __device_release_driver+0x7f/0xf0
> >>>      [  322.028381]        [<ffffffff814292a5>] device_release_driver+0x25/0x40
> >>>      [  322.028462]        [<ffffffff81428b0c>] bus_remove_device+0x11c/0x1a0
> >>>      [  322.028540]        [<ffffffff81425536>] device_del+0x136/0x1d0
> >>>      [  322.028619]        [<ffffffff8149e0c0>] usb_disable_device+0xb0/0x290
> >>>      [  322.028698]        [<ffffffff814930c5>] usb_disconnect+0xb5/0x1d0
> >>>      [  322.028779]        [<ffffffff81495ab6>] hub_port_connect_change+0xd6/0xad0
> >>>      [  322.028859]        [<ffffffff814967c3>] hub_events+0x313/0x9b0
> >>>      [  322.028940]        [<ffffffff81496e95>] hub_thread+0x35/0x170
> >>>      [  322.029019]        [<ffffffff8108ea2f>] kthread+0xff/0x120
> >>>      [  322.029099]        [<ffffffff816b187c>] ret_from_fork+0x7c/0xb0
> >>>      [  322.029179]
> >>>      -> #1 (&dev->lock#2){+.+.+.}:
> >>>      [  322.029414]        [<ffffffff810b8fa3>] __lock_acquire+0xb43/0x1330
> >>>      [  322.029494]        [<ffffffff810b9f82>] lock_acquire+0xa2/0x120
> >>>      [  322.029572]        [<ffffffff816a5b6c>] mutex_lock_nested+0x5c/0x3c0
> >>>      [  322.029651]        [<ffffffffa087122e>] snd_em28xx_pcm_close+0x3e/0x100 [em28xx_alsa]
> >>>      [  322.029732]        [<ffffffffa048620f>] snd_pcm_release_substream.part.29+0x3f/0x90 [snd_pcm]
> >>>      [  322.029816]        [<ffffffffa0486340>] snd_pcm_release+0xb0/0xd0 [snd_pcm]
> >>>      [  322.029900]        [<ffffffff811c9752>] __fput+0xe2/0x230
> >>>      [  322.029979]        [<ffffffff811c98ee>] ____fput+0xe/0x10
> >>>      [  322.030057]        [<ffffffff8108b64f>] task_work_run+0x9f/0xe0
> >>>      [  322.030135]        [<ffffffff81013a81>] do_notify_resume+0x61/0xa0
> >>>      [  322.030223]        [<ffffffff816b1c62>] int_signal+0x12/0x17
> >>>      [  322.030294]
> >>>      -> #0 (&pcm->open_mutex){+.+.+.}:
> >>>      [  322.030473]        [<ffffffff810b7a47>] check_prevs_add+0x947/0x950
> >>>      [  322.030546]        [<ffffffff810b8fa3>] __lock_acquire+0xb43/0x1330
> >>>      [  322.030618]        [<ffffffff810b9f82>] lock_acquire+0xa2/0x120
> >>>      [  322.030689]        [<ffffffff816a5b6c>] mutex_lock_nested+0x5c/0x3c0
> >>>      [  322.030760]        [<ffffffffa04819e6>] snd_pcm_dev_disconnect+0x46/0x1e0 [snd_pcm]
> >>>      [  322.030835]        [<ffffffffa02e855a>] snd_device_disconnect+0x6a/0xf0 [snd]
> >>>      [  322.030913]        [<ffffffffa02e86ac>] snd_device_disconnect_all+0x4c/0x90 [snd]
> >>>      [  322.030988]        [<ffffffffa02e1876>] snd_card_disconnect+0x126/0x1d0 [snd]
> >>>      [  322.031067]        [<ffffffffa02e1ea8>] snd_card_free+0x18/0x90 [snd]
> >>>      [  322.031146]        [<ffffffffa087235f>] em28xx_audio_fini+0x8f/0xa0 [em28xx_alsa]
> >>>      [  322.031220]        [<ffffffffa085cba6>] em28xx_close_extension+0x56/0x90 [em28xx]
> >>>      [  322.031292]        [<ffffffffa085e639>] em28xx_usb_disconnect+0x79/0x90 [em28xx]
> >>>      [  322.031363]        [<ffffffff814a06e7>] usb_unbind_interface+0x67/0x1d0
> >>>      [  322.031433]        [<ffffffff8142920f>] __device_release_driver+0x7f/0xf0
> >>>      [  322.031503]        [<ffffffff814292a5>] device_release_driver+0x25/0x40
> >>>      [  322.031573]        [<ffffffff81428b0c>] bus_remove_device+0x11c/0x1a0
> >>>      [  322.031643]        [<ffffffff81425536>] device_del+0x136/0x1d0
> >>>      [  322.031714]        [<ffffffff8149e0c0>] usb_disable_device+0xb0/0x290
> >>>      [  322.031784]        [<ffffffff814930c5>] usb_disconnect+0xb5/0x1d0
> >>>      [  322.031853]        [<ffffffff81495ab6>] hub_port_connect_change+0xd6/0xad0
> >>>      [  322.031922]        [<ffffffff814967c3>] hub_events+0x313/0x9b0
> >>>      [  322.031992]        [<ffffffff81496e95>] hub_thread+0x35/0x170
> >>>      [  322.032062]        [<ffffffff8108ea2f>] kthread+0xff/0x120
> >>>      [  322.032135]        [<ffffffff816b187c>] ret_from_fork+0x7c/0xb0
> >>>      [  322.032205]
> >>>      other info that might help us debug this:
> >>>
> >>>      [  322.032240] Chain exists of:
> >>>        &pcm->open_mutex --> &dev->lock#2 --> register_mutex#3
> >>>
> >>>      [  322.032547]  Possible unsafe locking scenario:
> >>>
> >>>      [  322.032582]        CPU0                    CPU1
> >>>      [  322.032616]        ----                    ----
> >>>      [  322.032654]   lock(register_mutex#3);
> >>>      [  322.032793]                                lock(&dev->lock#2);
> >>>      [  322.032929]                                lock(register_mutex#3);
> >>>      [  322.033064]   lock(&pcm->open_mutex);
> >>>      [  322.033168]
> >>>       *** DEADLOCK ***
> I don't get it. Where is the deadlock here ???
> Mauro, be honest: did you understand what's going on here ?
> 
> >>>
> >>>      [  322.033204] 6 locks held by khubd/54:
> >>>      [  322.033239]  #0:  (&__lockdep_no_validate__){......}, at: [<ffffffff81496564>] hub_events+0xb4/0x9b0
> >>>      [  322.033446]  #1:  (&__lockdep_no_validate__){......}, at: [<ffffffff81493076>] usb_disconnect+0x66/0x1d0
> >>>      [  322.033655]  #2:  (&__lockdep_no_validate__){......}, at: [<ffffffff8142929d>] device_release_driver+0x1d/0x40
> >>>      [  322.033859]  #3:  (em28xx_devlist_mutex){+.+.+.}, at: [<ffffffffa085cb77>] em28xx_close_extension+0x27/0x90 [em28xx]
> >>>      [  322.034067]  #4:  (&dev->lock#2){+.+.+.}, at: [<ffffffffa085cb81>] em28xx_close_extension+0x31/0x90 [em28xx]
> >>>      [  322.034307]  #5:  (register_mutex#3){+.+.+.}, at: [<ffffffffa04819c4>] snd_pcm_dev_disconnect+0x24/0x1e0 [snd_pcm]
> >>>      [  322.034552]
> >>>      stack backtrace:
> >>>      [  322.034588] CPU: 3 PID: 54 Comm: khubd Not tainted 3.13.0-rc1+ #24
> >>>      [  322.034624] Hardware name: SAMSUNG ELECTRONICS CO., LTD. 550P5C/550P7C/SAMSUNG_NP1234567890, BIOS P04ABI.013.130220.dg 02/20/2013
> >>>      [  322.034659]  ffffffff82513770 ffff880221bcd7c8 ffffffff816a03c6 ffffffff8250a810
> >>>      [  322.034832]  ffff880221bcd808 ffffffff8169a203 ffff880221bcd830 0000000000000005
> >>>      [  322.035004]  ffff8802222b2880 ffff8802222b3020 ffff8802222b3020 0000000000000006
> >>>      [  322.035187] Call Trace:
> >>>      [  322.035230]  [<ffffffff816a03c6>] dump_stack+0x45/0x56
> >>>      [  322.035276]  [<ffffffff8169a203>] print_circular_bug+0x200/0x20e
> >>>      [  322.035320]  [<ffffffff810b7a47>] check_prevs_add+0x947/0x950
> >>>      [  322.035365]  [<ffffffff8101b303>] ? native_sched_clock+0x13/0x80
> >>>      [  322.035409]  [<ffffffff810b8fa3>] __lock_acquire+0xb43/0x1330
> >>>      [  322.035454]  [<ffffffff810b9f82>] lock_acquire+0xa2/0x120
> >>>      [  322.035500]  [<ffffffffa04819e6>] ? snd_pcm_dev_disconnect+0x46/0x1e0 [snd_pcm]
> >>>      [  322.035550]  [<ffffffff816a5b6c>] mutex_lock_nested+0x5c/0x3c0
> >>>      [  322.035596]  [<ffffffffa04819e6>] ? snd_pcm_dev_disconnect+0x46/0x1e0 [snd_pcm]
> >>>      [  322.035648]  [<ffffffffa04819e6>] ? snd_pcm_dev_disconnect+0x46/0x1e0 [snd_pcm]
> >>>      [  322.035697]  [<ffffffff810b8045>] ? trace_hardirqs_on_caller+0x105/0x1d0
> >>>      [  322.035744]  [<ffffffffa04819e6>] snd_pcm_dev_disconnect+0x46/0x1e0 [snd_pcm]
> >>>      [  322.035797]  [<ffffffffa02e855a>] snd_device_disconnect+0x6a/0xf0 [snd]
> >>>      [  322.035852]  [<ffffffffa02e86ac>] snd_device_disconnect_all+0x4c/0x90 [snd]
> >>>      [  322.035904]  [<ffffffffa02e1876>] snd_card_disconnect+0x126/0x1d0 [snd]
> >>>      [  322.035957]  [<ffffffffa02e1ea8>] snd_card_free+0x18/0x90 [snd]
> >>>      [  322.036008]  [<ffffffffa087235f>] em28xx_audio_fini+0x8f/0xa0 [em28xx_alsa]
> >>>      [  322.036054]  [<ffffffffa085cba6>] em28xx_close_extension+0x56/0x90 [em28xx]
> >>>      [  322.036100]  [<ffffffffa085e639>] em28xx_usb_disconnect+0x79/0x90 [em28xx]
> >>>      [  322.036144]  [<ffffffff814a06e7>] usb_unbind_interface+0x67/0x1d0
> >>>      [  322.036188]  [<ffffffff8142920f>] __device_release_driver+0x7f/0xf0
> >>>      [  322.036231]  [<ffffffff814292a5>] device_release_driver+0x25/0x40
> >>>      [  322.036274]  [<ffffffff81428b0c>] bus_remove_device+0x11c/0x1a0
> >>>      [  322.036318]  [<ffffffff81425536>] device_del+0x136/0x1d0
> >>>      [  322.036361]  [<ffffffff8149e0c0>] usb_disable_device+0xb0/0x290
> >>>      [  322.036404]  [<ffffffff814930c5>] usb_disconnect+0xb5/0x1d0
> >>>      [  322.036447]  [<ffffffff81495ab6>] hub_port_connect_change+0xd6/0xad0
> >>>      [  322.036492]  [<ffffffff8149cb04>] ? usb_control_msg+0xd4/0x110
> >>>      [  322.036535]  [<ffffffff814967c3>] hub_events+0x313/0x9b0
> >>>      [  322.036579]  [<ffffffff810b8045>] ? trace_hardirqs_on_caller+0x105/0x1d0
> >>>      [  322.036623]  [<ffffffff81496e95>] hub_thread+0x35/0x170
> >>>      [  322.036667]  [<ffffffff810af310>] ? abort_exclusive_wait+0xb0/0xb0
> >>>      [  322.036711]  [<ffffffff81496e60>] ? hub_events+0x9b0/0x9b0
> >>>      [  322.036756]  [<ffffffff8108ea2f>] kthread+0xff/0x120
> >>>      [  322.036802]  [<ffffffff8108e930>] ? kthread_create_on_node+0x250/0x250
> >>>      [  322.036846]  [<ffffffff816b187c>] ret_from_fork+0x7c/0xb0
> >>>      [  322.036890]  [<ffffffff8108e930>] ? kthread_create_on_node+0x250/0x250
> >>>
> >>> Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
> >>> ---
> >>>   drivers/media/usb/em28xx/em28xx-audio.c | 10 +++++++---
> >>>   1 file changed, 7 insertions(+), 3 deletions(-)
> >>>
> >>> diff --git a/drivers/media/usb/em28xx/em28xx-audio.c b/drivers/media/usb/em28xx/em28xx-audio.c
> >>> index cdc2fcf3e05e..5e16fcf18cac 100644
> >>> --- a/drivers/media/usb/em28xx/em28xx-audio.c
> >>> +++ b/drivers/media/usb/em28xx/em28xx-audio.c
> >>> @@ -311,20 +311,17 @@ static int snd_em28xx_pcm_close(struct snd_pcm_substream *substream)
> >>>   	dprintk("closing device\n");
> >>>   
> >>>   	dev->mute = 1;
> >>> -	mutex_lock(&dev->lock);
> >>>   	dev->adev.users--;
> >>>   	if (atomic_read(&dev->stream_started) > 0) {
> >>>   		atomic_set(&dev->stream_started, 0);
> >>>   		schedule_work(&dev->wq_trigger);
> >>>   	}
> >>>   
> >>> -	em28xx_audio_analog_set(dev);
> >>>   	if (substream->runtime->dma_area) {
> >>>   		dprintk("freeing\n");
> >>>   		vfree(substream->runtime->dma_area);
> >>>   		substream->runtime->dma_area = NULL;
> >>>   	}
> >>> -	mutex_unlock(&dev->lock);
> >>>   
> >>>   	return 0;
> >>>   }
> >>> @@ -395,6 +392,13 @@ static void audio_trigger(struct work_struct *work)
> >>>   	} else {
> >>>   		dprintk("stopping capture");
> >>>   		em28xx_deinit_isoc_audio(dev);
> >>> +
> >>> +		/* Mute device if needed */
> >>> +		if (dev->mute) {
> >>> +			mutex_lock(&dev->lock);
> >>> +			em28xx_audio_analog_set(dev);
> >>> +			mutex_unlock(&dev->lock);
> >>> +		}
> >>>   	}
> >>>   }
> After thinking about this for a while:
> Does your patch
> 
> [PATCH] em28xx: push mutex down to extensions on .fini callback
> 
> which you've sent afterwards fix this warning, too ?

Yes, the above patch fixed the circular lock issues.

I dropped this patch.

The only patch pending to be applied on this series is patch 4.

-- 

Cheers,
Mauro

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 3/7] em28xx: Only deallocate struct em28xx after finishing all extensions
  2014-01-14 18:55             ` Mauro Carvalho Chehab
  2014-01-14 19:31               ` Mauro Carvalho Chehab
@ 2014-01-14 20:48               ` Frank Schäfer
  2014-01-14 21:20                 ` Mauro Carvalho Chehab
  1 sibling, 1 reply; 40+ messages in thread
From: Frank Schäfer @ 2014-01-14 20:48 UTC (permalink / raw)
  To: Mauro Carvalho Chehab; +Cc: Linux Media Mailing List, Mauro Carvalho Chehab

Am 14.01.2014 19:55, schrieb Mauro Carvalho Chehab:
> Em Tue, 14 Jan 2014 19:13:00 +0100
> Frank Schäfer <fschaefer.oss@googlemail.com> escreveu:
>
>> On 14.01.2014 14:10, Mauro Carvalho Chehab wrote:
>>> Em Mon, 13 Jan 2014 22:55:36 +0100
>>> Frank Schäfer <fschaefer.oss@googlemail.com> escreveu:
>>>
>>>> Am 13.01.2014 20:23, schrieb Mauro Carvalho Chehab:
>>>>> Em Mon, 13 Jan 2014 20:02:19 +0100
>>>>> Frank Schäfer <fschaefer.oss@googlemail.com> escreveu:
>>>>>
>>>>>> On 13.01.2014 00:00, Mauro Carvalho Chehab wrote:
>>>>>>> We can't free struct em28xx while one of the extensions is still
>>>>>>> using it.
>>>>>>>
>>>>>>> So, add a kref() to control it, freeing it only after the
>>>>>>> extensions fini calls.
>>>>>>>
>>>>>>> Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
>>>>>>> ---
>>>>>>>    drivers/media/usb/em28xx/em28xx-audio.c |  5 ++++-
>>>>>>>    drivers/media/usb/em28xx/em28xx-cards.c | 34 ++++++++++++++++-----------------
>>>>>>>    drivers/media/usb/em28xx/em28xx-dvb.c   |  5 ++++-
>>>>>>>    drivers/media/usb/em28xx/em28xx-input.c |  8 +++++++-
>>>>>>>    drivers/media/usb/em28xx/em28xx-video.c | 11 +++++------
>>>>>>>    drivers/media/usb/em28xx/em28xx.h       |  9 +++++++--
>>>>>>>    6 files changed, 44 insertions(+), 28 deletions(-)
>>>>>>>
>>>>>>> diff --git a/drivers/media/usb/em28xx/em28xx-audio.c b/drivers/media/usb/em28xx/em28xx-audio.c
>>>>>>> index 97d9105e6830..8e959dae8358 100644
>>>>>>> --- a/drivers/media/usb/em28xx/em28xx-audio.c
>>>>>>> +++ b/drivers/media/usb/em28xx/em28xx-audio.c
>>>>>>> @@ -878,6 +878,8 @@ static int em28xx_audio_init(struct em28xx *dev)
>>>>>>>    
>>>>>>>    	em28xx_info("Binding audio extension\n");
>>>>>>>    
>>>>>>> +	kref_get(&dev->ref);
>>>>>>> +
>>>>>>>    	printk(KERN_INFO "em28xx-audio.c: Copyright (C) 2006 Markus "
>>>>>>>    			 "Rechberger\n");
>>>>>>>    	printk(KERN_INFO
>>>>>>> @@ -949,7 +951,7 @@ static int em28xx_audio_fini(struct em28xx *dev)
>>>>>>>    	if (dev == NULL)
>>>>>>>    		return 0;
>>>>>>>    
>>>>>>> -	if (dev->has_alsa_audio != 1) {
>>>>>>> +	if (!dev->has_alsa_audio) {
>>>>>>>    		/* This device does not support the extension (in this case
>>>>>>>    		   the device is expecting the snd-usb-audio module or
>>>>>>>    		   doesn't have analog audio support at all) */
>>>>>>> @@ -963,6 +965,7 @@ static int em28xx_audio_fini(struct em28xx *dev)
>>>>>>>    		dev->adev.sndcard = NULL;
>>>>>>>    	}
>>>>>>>    
>>>>>>> +	kref_put(&dev->ref, em28xx_free_device);
>>>>>>>    	return 0;
>>>>>>>    }
>>>>>>>    
>>>>>>> diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c
>>>>>>> index 3b332d527ccb..df92f417634a 100644
>>>>>>> --- a/drivers/media/usb/em28xx/em28xx-cards.c
>>>>>>> +++ b/drivers/media/usb/em28xx/em28xx-cards.c
>>>>>>> @@ -2867,16 +2867,18 @@ static void flush_request_modules(struct em28xx *dev)
>>>>>>>    	flush_work(&dev->request_module_wk);
>>>>>>>    }
>>>>>>>    
>>>>>>> -/*
>>>>>>> - * em28xx_release_resources()
>>>>>>> - * unregisters the v4l2,i2c and usb devices
>>>>>>> - * called when the device gets disconnected or at module unload
>>>>>>> -*/
>>>>>>> -void em28xx_release_resources(struct em28xx *dev)
>>>>>>> +/**
>>>>>>> + * em28xx_release_resources() -  unregisters the v4l2,i2c and usb devices
>>>>>>> + *
>>>>>>> + * @ref: struct kref for em28xx device
>>>>>>> + *
>>>>>>> + * This is called when all extensions and em28xx core unregisters a device
>>>>>>> + */
>>>>>>> +void em28xx_free_device(struct kref *ref)
>>>>>>>    {
>>>>>>> -	/*FIXME: I2C IR should be disconnected */
>>>>>>> +	struct em28xx *dev = kref_to_dev(ref);
>>>>>>>    
>>>>>>> -	mutex_lock(&dev->lock);
>>>>>>> +	em28xx_info("Freeing device\n");
>>>>>>>    
>>>>>>>    	if (dev->def_i2c_bus)
>>>>>>>    		em28xx_i2c_unregister(dev, 1);
>>>>>>> @@ -2887,9 +2889,10 @@ void em28xx_release_resources(struct em28xx *dev)
>>>>>>>    	/* Mark device as unused */
>>>>>>>    	clear_bit(dev->devno, &em28xx_devused);
>>>>>>>    
>>>>>>> -	mutex_unlock(&dev->lock);
>>>>>>> -};
>>>>>>> -EXPORT_SYMBOL_GPL(em28xx_release_resources);
>>>>>>> +	kfree(dev->alt_max_pkt_size_isoc);
>>>>>>> +	kfree(dev);
>>>>>>> +}
>>>>>>> +EXPORT_SYMBOL_GPL(em28xx_free_device);
>>>>>>>    
>>>>>>>    /*
>>>>>>>     * em28xx_init_dev()
>>>>>>> @@ -3342,6 +3345,8 @@ static int em28xx_usb_probe(struct usb_interface *interface,
>>>>>>>    			    dev->dvb_xfer_bulk ? "bulk" : "isoc");
>>>>>>>    	}
>>>>>>>    
>>>>>>> +	kref_init(&dev->ref);
>>>>>>> +
>>>>>>>    	request_modules(dev);
>>>>>>>    
>>>>>>>    	/* Should be the last thing to do, to avoid newer udev's to
>>>>>>> @@ -3390,12 +3395,7 @@ static void em28xx_usb_disconnect(struct usb_interface *interface)
>>>>>>>    
>>>>>>>    	em28xx_close_extension(dev);
>>>>>>>    
>>>>>>> -	em28xx_release_resources(dev);
>>>>>>> -
>>>>>>> -	if (!dev->users) {
>>>>>>> -		kfree(dev->alt_max_pkt_size_isoc);
>>>>>>> -		kfree(dev);
>>>>>>> -	}
>>>>>>> +	kref_put(&dev->ref, em28xx_free_device);
>>>>>>>    }
>>>>>>>    
>>>>>>>    static struct usb_driver em28xx_usb_driver = {
>>>>>>> diff --git a/drivers/media/usb/em28xx/em28xx-dvb.c b/drivers/media/usb/em28xx/em28xx-dvb.c
>>>>>>> index 5ea563e3f0e4..8674ae5fce06 100644
>>>>>>> --- a/drivers/media/usb/em28xx/em28xx-dvb.c
>>>>>>> +++ b/drivers/media/usb/em28xx/em28xx-dvb.c
>>>>>>> @@ -1010,11 +1010,11 @@ static int em28xx_dvb_init(struct em28xx *dev)
>>>>>>>    	em28xx_info("Binding DVB extension\n");
>>>>>>>    
>>>>>>>    	dvb = kzalloc(sizeof(struct em28xx_dvb), GFP_KERNEL);
>>>>>>> -
>>>>>>>    	if (dvb == NULL) {
>>>>>>>    		em28xx_info("em28xx_dvb: memory allocation failed\n");
>>>>>>>    		return -ENOMEM;
>>>>>>>    	}
>>>>>>> +	kref_get(&dev->ref);
>>>>>>>    	dev->dvb = dvb;
>>>>>>>    	dvb->fe[0] = dvb->fe[1] = NULL;
>>>>>>>    
>>>>>>> @@ -1442,6 +1442,7 @@ static int em28xx_dvb_init(struct em28xx *dev)
>>>>>>>    	dvb->adapter.mfe_shared = mfe_shared;
>>>>>>>    
>>>>>>>    	em28xx_info("DVB extension successfully initialized\n");
>>>>>>> +
>>>>>>>    ret:
>>>>>>>    	em28xx_set_mode(dev, EM28XX_SUSPEND);
>>>>>>>    	mutex_unlock(&dev->lock);
>>>>>>> @@ -1492,6 +1493,8 @@ static int em28xx_dvb_fini(struct em28xx *dev)
>>>>>>>    		dev->dvb = NULL;
>>>>>>>    	}
>>>>>>>    
>>>>>>> +	kref_put(&dev->ref, em28xx_free_device);
>>>>>>> +
>>>>>>>    	return 0;
>>>>>>>    }
>>>>>>>    
>>>>>>> diff --git a/drivers/media/usb/em28xx/em28xx-input.c b/drivers/media/usb/em28xx/em28xx-input.c
>>>>>>> index 61c061f3a476..33388b5922a0 100644
>>>>>>> --- a/drivers/media/usb/em28xx/em28xx-input.c
>>>>>>> +++ b/drivers/media/usb/em28xx/em28xx-input.c
>>>>>>> @@ -676,6 +676,8 @@ static int em28xx_ir_init(struct em28xx *dev)
>>>>>>>    		return 0;
>>>>>>>    	}
>>>>>>>    
>>>>>>> +	kref_get(&dev->ref);
>>>>>>> +
>>>>>>>    	if (dev->board.buttons)
>>>>>>>    		em28xx_init_buttons(dev);
>>>>>>>    
>>>>>>> @@ -814,7 +816,7 @@ static int em28xx_ir_fini(struct em28xx *dev)
>>>>>>>    
>>>>>>>    	/* skip detach on non attached boards */
>>>>>>>    	if (!ir)
>>>>>>> -		return 0;
>>>>>>> +		goto ref_put;
>>>>>>>    
>>>>>>>    	if (ir->rc)
>>>>>>>    		rc_unregister_device(ir->rc);
>>>>>>> @@ -822,6 +824,10 @@ static int em28xx_ir_fini(struct em28xx *dev)
>>>>>>>    	/* done */
>>>>>>>    	kfree(ir);
>>>>>>>    	dev->ir = NULL;
>>>>>>> +
>>>>>>> +ref_put:
>>>>>>> +	kref_put(&dev->ref, em28xx_free_device);
>>>>>>> +
>>>>>>>    	return 0;
>>>>>>>    }
>>>>>>>    
>>>>>>> diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c
>>>>>>> index 587ff3fe9402..dc10cec772ba 100644
>>>>>>> --- a/drivers/media/usb/em28xx/em28xx-video.c
>>>>>>> +++ b/drivers/media/usb/em28xx/em28xx-video.c
>>>>>>> @@ -1922,8 +1922,7 @@ static int em28xx_v4l2_fini(struct em28xx *dev)
>>>>>>>    	v4l2_ctrl_handler_free(&dev->ctrl_handler);
>>>>>>>    	v4l2_device_unregister(&dev->v4l2_dev);
>>>>>>>    
>>>>>>> -	if (dev->users)
>>>>>>> -		em28xx_warn("Device is open ! Memory deallocation is deferred on last close.\n");
>>>>>>> +	kref_put(&dev->ref, em28xx_free_device);
>>>>>>>    
>>>>>>>    	return 0;
>>>>>>>    }
>>>>>>> @@ -1945,11 +1944,9 @@ static int em28xx_v4l2_close(struct file *filp)
>>>>>>>    	mutex_lock(&dev->lock);
>>>>>>>    
>>>>>>>    	if (dev->users == 1) {
>>>>>>> -		/* free the remaining resources if device is disconnected */
>>>>>>> -		if (dev->disconnected) {
>>>>>>> -			kfree(dev->alt_max_pkt_size_isoc);
>>>>>>> +		/* No sense to try to write to the device */
>>>>>>> +		if (dev->disconnected)
>>>>>>>    			goto exit;
>>>>>>> -		}
>>>>>>>    
>>>>>>>    		/* Save some power by putting tuner to sleep */
>>>>>>>    		v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_power, 0);
>>>>>>> @@ -2201,6 +2198,8 @@ static int em28xx_v4l2_init(struct em28xx *dev)
>>>>>>>    
>>>>>>>    	em28xx_info("Registering V4L2 extension\n");
>>>>>>>    
>>>>>>> +	kref_get(&dev->ref);
>>>>>>> +
>>>>>>>    	mutex_lock(&dev->lock);
>>>>>>>    
>>>>>>>    	ret = v4l2_device_register(&dev->udev->dev, &dev->v4l2_dev);
>>>>>>> diff --git a/drivers/media/usb/em28xx/em28xx.h b/drivers/media/usb/em28xx/em28xx.h
>>>>>>> index 5d5d1b6f0294..d38c08e4da60 100644
>>>>>>> --- a/drivers/media/usb/em28xx/em28xx.h
>>>>>>> +++ b/drivers/media/usb/em28xx/em28xx.h
>>>>>>> @@ -32,6 +32,7 @@
>>>>>>>    #include <linux/workqueue.h>
>>>>>>>    #include <linux/i2c.h>
>>>>>>>    #include <linux/mutex.h>
>>>>>>> +#include <linux/kref.h>
>>>>>>>    #include <linux/videodev2.h>
>>>>>>>    
>>>>>>>    #include <media/videobuf2-vmalloc.h>
>>>>>>> @@ -531,9 +532,11 @@ struct em28xx_i2c_bus {
>>>>>>>    	enum em28xx_i2c_algo_type algo_type;
>>>>>>>    };
>>>>>>>    
>>>>>>> -
>>>>>>>    /* main device struct */
>>>>>>>    struct em28xx {
>>>>>>> +	struct kref ref;
>>>>>>> +
>>>>>>> +
>>>>>>>    	/* generic device properties */
>>>>>>>    	char name[30];		/* name (including minor) of the device */
>>>>>>>    	int model;		/* index in the device_data struct */
>>>>>>> @@ -706,6 +709,8 @@ struct em28xx {
>>>>>>>    	struct em28xx_dvb *dvb;
>>>>>>>    };
>>>>>>>    
>>>>>>> +#define kref_to_dev(d) container_of(d, struct em28xx, ref)
>>>>>>> +
>>>>>>>    struct em28xx_ops {
>>>>>>>    	struct list_head next;
>>>>>>>    	char *name;
>>>>>>> @@ -763,7 +768,7 @@ extern struct em28xx_board em28xx_boards[];
>>>>>>>    extern struct usb_device_id em28xx_id_table[];
>>>>>>>    int em28xx_tuner_callback(void *ptr, int component, int command, int arg);
>>>>>>>    void em28xx_setup_xc3028(struct em28xx *dev, struct xc2028_ctrl *ctl);
>>>>>>> -void em28xx_release_resources(struct em28xx *dev);
>>>>>>> +void em28xx_free_device(struct kref *ref);
>>>>>>>    
>>>>>>>    /* Provided by em28xx-camera.c */
>>>>>>>    int em28xx_detect_sensor(struct em28xx *dev);
>>>>>> I welcome this patch and the general approach looks good.
>>>>>> I had started working on the same issue, but it's not that trivial.
>>>>>>
>>>>>> At first glance there seem to be several issues, but I will need to
>>>>>> review this patch in more detail and also make some tests.
>>>>>> Unfortunately, I don't have much time this evening, So could you please
>>>>>> hold it back another day ?
>>>>>> I hope I can review the other remaining patch of this series (patch 5/7)
>>>>>> later this evening.
>>>>> We're running out of time for 3.14. I think we should merge this patch
>>>>> series, and your patch series for 3.14, to be together with the em28xx-v4l
>>>>> split.
>>>>>
>>>>> My plan is to merge the remaining patches for 3.14 today or, in the worse
>>>>> case, tomorrow.
>>>>>
>>>>> If we slip on some bug, we'll still have the 3.14-rc cycle to fix, if the
>>>>> series gets merged, but, if we miss the bus, I'm afraid that we'll end
>>>>> by having more problems that will be hard to fix with trivial patches, due
>>>>> to em28xx-v4l split changes that also affected the driver removal and device
>>>>> close code.
>>>>>
>>>>> FYI, I tested this code and also Antti with our devices, randomly removing
>>>>> the devices while streaming, and this is now finally working.
>>>>>
>>>>> I won't doubt that there are some cases that require fixes (and
>>>>> it seems that em28xx-rc has one of such corner cases), but they'll likely
>>>>> can be solved with somewhat short and trivial patches.
>>>>>
>>>>> Cheers,
>>>>> Mauro
>>>> This is a very critical patch and exactly the kind of change that should
>>>> _never_ be hurried !
>>>> FAICS it has some severe issues and it's not clear how easy it will be
>>>> to fix it within the the 3.14-rc cycle.
>>>> As long as it's not ready, don't merge it for 3.14.
>>> What issues? So far, you didn't point any.
>> I already stated that I didn't have the time yet to review and test it 
>> in detail, but I'm going to do that as soon as possible.
>> If you can't wait, there's nothing I can do, sorry.
>>
>> At first glance it seems there are at least 2 issues:
>> 1.) use after freeing in v4l-extension (happens when the device is 
>> closed after the usb disconnect)
> That's basically what this patch fixes. Both V4L2 and ALSA handles it
> well, if you warn the subsystem that a device will be removed.
>
> If are there still any issues, we may add a kref_get() at device open,
> an a kref_put() at device close on the affected sub-driver.
Ok, I've tested it and I was right here.
This is what happens when closing a disconnected device:

[  144.045691] usb 1-8: USB disconnect, device number 7
[  144.047387] em2765 #0: disconnecting em2765 #0 video
[  144.047403] em2765 #0: V4L2 device video1 deregistered
[  144.050197] em2765 #0: Deregistering snapshot button
[  144.058336] em2765 #0: Freeing device
[  147.525267] : em28xx_v4l2_close() called
[  147.525287] : em28xx_videodevice_release() called


I will make some tests tomorrow, but here is a first suggestion how to
fix this:

Remove the kref_put() call from em28xx_v4l2_fini().
Instead, add the following lines to em28xx_videodevice_release():

if (dev->users == 0) {
        dev->users--; /* avoid multiple kref_put() calls when the
devices are unregistered and no device is open */
        kref_put(&dev->ref, em28xx_free_device);
}

That should fix it.

Interestingly no oops happens. I will have to take a closer look at this
tomorrow, but I suspect that the dev we obtain from struct file filp is
an outdated copy of the original device struct.
If that would be true and no bad things can happen in the close()
function we actually wouldn't need kref for the v4l extension at all.

Of course, the ideal solution would be, if we could just clear the
device struct at the end of the usb disconnect handler, because we can
be sure that the fini() functions have already made sure that dev isn't
used anymore.

Btw, what happens in em28xx-audio ?
Does the ALSA core also allow to call the close() function when the
device is already gone ?


>
>> 2.) error paths in the init() functions ?
> It should be ok. Basically, kref_get() is called even if an error
> occurs, and kref_put() is called even if init fails. Ok, this is an
> overkill, but makes the patch simpler to review. We may fine tune it
> on a latter patch.
>
> I opted to call kref_get() as soon as possible, to avoid the risk of
> the device to be removed while the extension is still being
> initialized (yes, if you remove a device too quick, even before pulseaudio
> starts opening the device), it used to crash.
I didn't have neough time to look at this part today.

>
>>> On both my tests and Antti's one,
>>> with this series, there were significant improvements on removing existing
>>> bugs with device removal.
>> I'm talking about this specific patch here, not the whole series.
>> I have no objections against the rest of the series (well, with the 
>> exception of patch 5 at the moment).
> I see. Well, let me do some tests with all patches except 3 and 5 applied,
> to see how it behaves.
>
>>>> em28xx resources releasing is broken since ... well... at least 2 years.
>>>> 3.14 will already be much better and nobody will care if this remaining
>>>> issue is addressed a kernel release later.
>>> Although I think that we're properly releasing resources, I'm a way less
>>> concerned about keeping some leaked memory while releasing them than I am
>>> concerned that a device removal that would cause an OOPS, or a deadly
>>> crash at the USB or ALSA stack that prevents other devices to be probed.
>>>
>>> Due to em28xx-v4l calling em28xx_release_resources(), now both the
>>> USB and ALSA stacks crashes if you remove a device while ALSA is streaming.
>>>
>>> That happens because em28xx, I2C, etc will be freed by em28xx-v4l, but
>>> those resources are still needed by em28xx-alsa. That makes that the
>>> .fini code there to cause crash at ALSA stack, and, sometimes, at the
>>> USB stack.
>> That's not true anymore, em28xx_release_resources() is now only called 
>> by the usb disconnect handler in the core _after_ all fini() functions 
>> have been called.
>> Maybe you tested that without my patch series ? See patch 7/8.
> No, we tested it with your full series applied:
> 	http://git.linuxtv.org/mchehab/experimental.git/shortlog/refs/heads/em28xx
Ok, but the above is nevertheless not true anymore.
The only place where em28xx_release_resources is called() is
em28xx_usb_disconnect().

>
>>> As nowadays lots of components depend on pulseaudio, the ALSA crash
>>> causes pulse to stop work, likely keeping it into some dead lock status.
>>> This makes the entire machine to become really slow, when it doesn't
>>> crash.
>>>
>>> This is a serious regression that should be fixed.
>>>
>>> This patch series for sure fixes it. As I said, there are two independent
>>> series of tests verifying that (both using several different em28xx
>>> devices).
>>>
>>>> Be warned !
>>>>
>>>>
>


^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 5/7] em28xx-audio: remove a deplock circular dependency
  2014-01-14 19:59         ` Mauro Carvalho Chehab
@ 2014-01-14 20:51           ` Frank Schäfer
  0 siblings, 0 replies; 40+ messages in thread
From: Frank Schäfer @ 2014-01-14 20:51 UTC (permalink / raw)
  To: Mauro Carvalho Chehab; +Cc: Linux Media Mailing List, Mauro Carvalho Chehab

Am 14.01.2014 20:59, schrieb Mauro Carvalho Chehab:
>> After thinking about this for a while:
>> > Does your patch
>> > 
>> > [PATCH] em28xx: push mutex down to extensions on .fini callback
>> > 
>> > which you've sent afterwards fix this warning, too ?
> Yes, the above patch fixed the circular lock issues.
Ok, great, one problem less. :-)

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 3/7] em28xx: Only deallocate struct em28xx after finishing all extensions
  2014-01-14 19:31               ` Mauro Carvalho Chehab
@ 2014-01-14 20:57                 ` Frank Schäfer
  0 siblings, 0 replies; 40+ messages in thread
From: Frank Schäfer @ 2014-01-14 20:57 UTC (permalink / raw)
  To: Mauro Carvalho Chehab; +Cc: Linux Media Mailing List

Am 14.01.2014 20:31, schrieb Mauro Carvalho Chehab:
>
> Ok, patch 5 is not needed anymore.
>
> However, after a series of removals and re-inserts, I got these:
>
>
> [120982.699455] ------------[ cut here ]------------
> [120982.699509] WARNING: CPU: 0 PID: 7953 at lib/list_debug.c:33 __list_add+0xac/0xc0()
> [120982.699539] list_add corruption. prev->next should be next (ffff88019ffce4f8), but was 0000000d00000007. (prev=ffff880101dbfb48).
> [120982.699566] Modules linked in: lgdt330x tuner_xc2028 tuner tvp5150 rc_hauppauge em28xx_rc rc_core xc5000 drxk em28xx_dvb dvb_core em28xx_alsa em28xx_v4l videobuf2_vmalloc videobuf2_memops videobuf2_core em28xx tveeprom v4l2_common videodev media netconsole usb_storage fuse ccm nf_conntrack_netbios_ns nf_conntrack_broadcast ipt_MASQUERADE ip6t_REJECT xt_conntrack ebtable_nat ebtable_broute bridge stp llc ebtable_filter ebtables ip6table_nat nf_conntrack_ipv6 nf_defrag_ipv6 nf_nat_ipv6 ip6table_mangle ip6table_security ip6table_raw ip6table_filter ip6_tables iptable_nat nf_conntrack_ipv4 nf_defrag_ipv4 nf_nat_ipv4 nf_nat nf_conntrack iptable_mangle iptable_security iptable_raw bnep arc4 vfat fat iwldvm mac80211 iwlwifi cfg80211 x86_pkg_temp_thermal coretemp kvm_intel kvm crc32_pclmul crc32c_intel ghash_clmulni_intel
> [120982.701828]  snd_hda_codec_hdmi snd_hda_codec_realtek snd_hda_intel snd_hda_codec snd_hwdep snd_seq snd_seq_device snd_pcm iTCO_wdt iTCO_vendor_support btusb bluetooth joydev microcode serio_raw r8169 mii i2c_i801 lpc_ich mfd_core rfkill snd_page_alloc snd_timer snd mei_me soundcore mei shpchp nfsd auth_rpcgss nfs_acl lockd sunrpc nouveau i915 ttm i2c_algo_bit drm_kms_helper drm i2c_core mxm_wmi wmi video [last unloaded: videobuf2_memops]
> [120982.703581] CPU: 0 PID: 7953 Comm: xawtv Tainted: G      D      3.13.0-rc1+ #24
> [120982.703610] Hardware name: SAMSUNG ELECTRONICS CO., LTD. 550P5C/550P7C/SAMSUNG_NP1234567890, BIOS P04ABI.013.130220.dg 02/20/2013
> [120982.703638]  0000000000000009 ffff88011f63bb70 ffffffff816a03c6 ffff88011f63bbb8
> [120982.703794]  ffff88011f63bba8 ffffffff8106aaad ffff88018cfb3f48 ffff88019ffce4f8
> [120982.703924]  ffff880101dbfb48 0000000000000282 0000000000000000 ffff88011f63bc08
> [120982.704056] Call Trace:
> [120982.704093]  [<ffffffff816a03c6>] dump_stack+0x45/0x56
> [120982.704129]  [<ffffffff8106aaad>] warn_slowpath_common+0x7d/0xa0
> [120982.704162]  [<ffffffff8106ab1c>] warn_slowpath_fmt+0x4c/0x50
> [120982.704197]  [<ffffffff81343bac>] __list_add+0xac/0xc0
> [120982.704233]  [<ffffffffa04fd70b>] buffer_queue+0x7b/0xb0 [em28xx_v4l]
> [120982.704432]  [<ffffffffa04862d4>] __enqueue_in_driver+0x74/0x80 [videobuf2_core]
> [120982.704469]  [<ffffffffa04878c0>] vb2_streamon+0xa0/0x140 [videobuf2_core]
> [120982.704505]  [<ffffffffa04879a8>] vb2_ioctl_streamon+0x48/0x50 [videobuf2_core]
> [120982.704543]  [<ffffffffa04b7a8a>] v4l_streamon+0x1a/0x20 [videodev]
> [120982.704581]  [<ffffffffa04bb644>] __video_do_ioctl+0x2a4/0x330 [videodev]
> [120982.704619]  [<ffffffffa04bb3a0>] ? v4l_dbg_s_register+0x150/0x150 [videodev]
> [120982.704658]  [<ffffffffa04bb3a0>] ? v4l_dbg_s_register+0x150/0x150 [videodev]
> [120982.704719]  [<ffffffffa04bcae0>] video_usercopy+0x240/0x5d0 [videodev]
> [120982.704756]  [<ffffffff810b811d>] ? trace_hardirqs_on+0xd/0x10
> [120982.704792]  [<ffffffffa04b663b>] ? v4l2_ioctl+0x5b/0x160 [videodev]
> [120982.704829]  [<ffffffffa04b663b>] ? v4l2_ioctl+0x5b/0x160 [videodev]
> [120982.704867]  [<ffffffffa04bce85>] video_ioctl2+0x15/0x20 [videodev]
> [120982.704903]  [<ffffffffa04b6703>] v4l2_ioctl+0x123/0x160 [videodev]
> [120982.704939]  [<ffffffff811db8b0>] do_vfs_ioctl+0x300/0x520
> [120982.704974]  [<ffffffff812c7a96>] ? file_has_perm+0x86/0xa0
> [120982.705006]  [<ffffffff811dbb51>] SyS_ioctl+0x81/0xa0
> [120982.705039]  [<ffffffff816b1929>] system_call_fastpath+0x16/0x1b
> [120982.705070] ---[ end trace 7e24c4fe20a76f18 ]---
> [120985.899453] ------------[ cut here ]------------
> [120985.899502] WARNING: CPU: 0 PID: 7953 at lib/list_debug.c:33 __list_add+0xac/0xc0()
> [120985.899531] list_add corruption. prev->next should be next (ffff88019ffce4f8), but was           (null). (prev=ffff88018cfb0348).
> [120985.899559] Modules linked in: lgdt330x tuner_xc2028 tuner tvp5150 rc_hauppauge em28xx_rc rc_core xc5000 drxk em28xx_dvb dvb_core em28xx_alsa em28xx_v4l videobuf2_vmalloc videobuf2_memops videobuf2_core em28xx tveeprom v4l2_common videodev media netconsole usb_storage fuse ccm nf_conntrack_netbios_ns nf_conntrack_broadcast ipt_MASQUERADE ip6t_REJECT xt_conntrack ebtable_nat ebtable_broute bridge stp llc ebtable_filter ebtables ip6table_nat nf_conntrack_ipv6 nf_defrag_ipv6 nf_nat_ipv6 ip6table_mangle ip6table_security ip6table_raw ip6table_filter ip6_tables iptable_nat nf_conntrack_ipv4 nf_defrag_ipv4 nf_nat_ipv4 nf_nat nf_conntrack iptable_mangle iptable_security iptable_raw bnep arc4 vfat fat iwldvm mac80211 iwlwifi cfg80211 x86_pkg_temp_thermal coretemp kvm_intel kvm crc32_pclmul crc32c_intel ghash_clmulni_intel
> [120985.901761]  snd_hda_codec_hdmi snd_hda_codec_realtek snd_hda_intel snd_hda_codec snd_hwdep snd_seq snd_seq_device snd_pcm iTCO_wdt iTCO_vendor_support btusb bluetooth joydev microcode serio_raw r8169 mii i2c_i801 lpc_ich mfd_core rfkill snd_page_alloc snd_timer snd mei_me soundcore mei shpchp nfsd auth_rpcgss nfs_acl lockd sunrpc nouveau i915 ttm i2c_algo_bit drm_kms_helper drm i2c_core mxm_wmi wmi video [last unloaded: videobuf2_memops]
> [120985.903502] CPU: 0 PID: 7953 Comm: xawtv Tainted: G      D W    3.13.0-rc1+ #24
> [120985.903530] Hardware name: SAMSUNG ELECTRONICS CO., LTD. 550P5C/550P7C/SAMSUNG_NP1234567890, BIOS P04ABI.013.130220.dg 02/20/2013
> [120985.903557]  0000000000000009 ffff88011f63bb70 ffffffff816a03c6 ffff88011f63bbb8
> [120985.903686]  ffff88011f63bba8 ffffffff8106aaad ffff88018cfb0348 ffff88019ffce4f8
> [120985.903826]  ffff88018cfb0348 0000000000000282 0000000000000000 ffff88011f63bc08
> [120985.903955] Call Trace:
> [120985.903988]  [<ffffffff816a03c6>] dump_stack+0x45/0x56
> [120985.904021]  [<ffffffff8106aaad>] warn_slowpath_common+0x7d/0xa0
> [120985.904052]  [<ffffffff8106ab1c>] warn_slowpath_fmt+0x4c/0x50
> [120985.904083]  [<ffffffff81343bac>] __list_add+0xac/0xc0
> [120985.904116]  [<ffffffffa04fd70b>] buffer_queue+0x7b/0xb0 [em28xx_v4l]
> [120985.904295]  [<ffffffffa04862d4>] __enqueue_in_driver+0x74/0x80 [videobuf2_core]
> [120985.904330]  [<ffffffffa04878c0>] vb2_streamon+0xa0/0x140 [videobuf2_core]
> [120985.904363]  [<ffffffffa04879a8>] vb2_ioctl_streamon+0x48/0x50 [videobuf2_core]
> [120985.904398]  [<ffffffffa04b7a8a>] v4l_streamon+0x1a/0x20 [videodev]
> [120985.904433]  [<ffffffffa04bb644>] __video_do_ioctl+0x2a4/0x330 [videodev]
> [120985.904470]  [<ffffffffa04bb3a0>] ? v4l_dbg_s_register+0x150/0x150 [videodev]
> [120985.904504]  [<ffffffffa04bb3a0>] ? v4l_dbg_s_register+0x150/0x150 [videodev]
> [120985.904540]  [<ffffffffa04bcae0>] video_usercopy+0x240/0x5d0 [videodev]
> [120985.904575]  [<ffffffff810b811d>] ? trace_hardirqs_on+0xd/0x10
> [120985.904608]  [<ffffffffa04b663b>] ? v4l2_ioctl+0x5b/0x160 [videodev]
> [120985.904641]  [<ffffffffa04b663b>] ? v4l2_ioctl+0x5b/0x160 [videodev]
> [120985.904676]  [<ffffffffa04bce85>] video_ioctl2+0x15/0x20 [videodev]
> [120985.904710]  [<ffffffffa04b6703>] v4l2_ioctl+0x123/0x160 [videodev]
> [120985.904743]  [<ffffffff811db8b0>] do_vfs_ioctl+0x300/0x520
> [120985.904780]  [<ffffffff812c7a96>] ? file_has_perm+0x86/0xa0
> [120985.904810]  [<ffffffff811dbb51>] SyS_ioctl+0x81/0xa0
> [120985.904843]  [<ffffffff816b1929>] system_call_fastpath+0x16/0x1b
> [120985.904871] ---[ end trace 7e24c4fe20a76f19 ]---
> [120985.904896] ------------[ cut here ]------------
> [120985.904922] WARNING: CPU: 0 PID: 7953 at lib/list_debug.c:36 __list_add+0x8a/0xc0()
> [120985.904953] list_add double add: new=ffff88018cfb0348, prev=ffff88018cfb0348, next=ffff88019ffce4f8.
> [120985.904978] Modules linked in: lgdt330x tuner_xc2028 tuner tvp5150 rc_hauppauge em28xx_rc rc_core xc5000 drxk em28xx_dvb dvb_core em28xx_alsa em28xx_v4l videobuf2_vmalloc videobuf2_memops videobuf2_core em28xx tveeprom v4l2_common videodev media netconsole usb_storage fuse ccm nf_conntrack_netbios_ns nf_conntrack_broadcast ipt_MASQUERADE ip6t_REJECT xt_conntrack ebtable_nat ebtable_broute bridge stp llc ebtable_filter ebtables ip6table_nat nf_conntrack_ipv6 nf_defrag_ipv6 nf_nat_ipv6 ip6table_mangle ip6table_security ip6table_raw ip6table_filter ip6_tables iptable_nat nf_conntrack_ipv4 nf_defrag_ipv4 nf_nat_ipv4 nf_nat nf_conntrack iptable_mangle iptable_security iptable_raw bnep arc4 vfat fat iwldvm mac80211 iwlwifi cfg80211 x86_pkg_temp_thermal coretemp kvm_intel kvm crc32_pclmul crc32c_intel ghash_clmulni_intel
> [120985.907016]  snd_hda_codec_hdmi snd_hda_codec_realtek snd_hda_intel snd_hda_codec snd_hwdep snd_seq snd_seq_device snd_pcm iTCO_wdt iTCO_vendor_support btusb bluetooth joydev microcode serio_raw r8169 mii i2c_i801 lpc_ich mfd_core rfkill snd_page_alloc snd_timer snd mei_me soundcore mei shpchp nfsd auth_rpcgss nfs_acl lockd sunrpc nouveau i915 ttm i2c_algo_bit drm_kms_helper drm i2c_core mxm_wmi wmi video [last unloaded: videobuf2_memops]
> [120985.908654] CPU: 0 PID: 7953 Comm: xawtv Tainted: G      D W    3.13.0-rc1+ #24
> [120985.908680] Hardware name: SAMSUNG ELECTRONICS CO., LTD. 550P5C/550P7C/SAMSUNG_NP1234567890, BIOS P04ABI.013.130220.dg 02/20/2013
> [120985.908707]  0000000000000009 ffff88011f63bb70 ffffffff816a03c6 ffff88011f63bbb8
> [120985.908988]  ffff88011f63bba8 ffffffff8106aaad ffff88018cfb0348 ffff88019ffce4f8
> [120985.909110]  ffff88018cfb0348 0000000000000282 0000000000000000 ffff88011f63bc08
> [120985.909230] Call Trace:
> [120985.909268]  [<ffffffff816a03c6>] dump_stack+0x45/0x56
> [120985.909305]  [<ffffffff8106aaad>] warn_slowpath_common+0x7d/0xa0
> [120985.909336]  [<ffffffff8106ab1c>] warn_slowpath_fmt+0x4c/0x50
> [120985.909380]  [<ffffffff81343b8a>] __list_add+0x8a/0xc0
> [120985.909410]  [<ffffffffa04fd70b>] buffer_queue+0x7b/0xb0 [em28xx_v4l]
> [120985.909442]  [<ffffffffa04862d4>] __enqueue_in_driver+0x74/0x80 [videobuf2_core]
> [120985.909474]  [<ffffffffa04878c0>] vb2_streamon+0xa0/0x140 [videobuf2_core]
> [120985.909505]  [<ffffffffa04879a8>] vb2_ioctl_streamon+0x48/0x50 [videobuf2_core]
> [120985.909537]  [<ffffffffa04b7a8a>] v4l_streamon+0x1a/0x20 [videodev]
> [120985.909570]  [<ffffffffa04bb644>] __video_do_ioctl+0x2a4/0x330 [videodev]
> [120985.909604]  [<ffffffffa04bb3a0>] ? v4l_dbg_s_register+0x150/0x150 [videodev]
> [120985.909636]  [<ffffffffa04bb3a0>] ? v4l_dbg_s_register+0x150/0x150 [videodev]
> [120985.909670]  [<ffffffffa04bcae0>] video_usercopy+0x240/0x5d0 [videodev]
> [120985.909702]  [<ffffffff810b811d>] ? trace_hardirqs_on+0xd/0x10
> [120985.909732]  [<ffffffffa04b663b>] ? v4l2_ioctl+0x5b/0x160 [videodev]
> [120985.909764]  [<ffffffffa04b663b>] ? v4l2_ioctl+0x5b/0x160 [videodev]
> [120985.909799]  [<ffffffffa04bce85>] video_ioctl2+0x15/0x20 [videodev]
> [120985.909830]  [<ffffffffa04b6703>] v4l2_ioctl+0x123/0x160 [videodev]
> [120985.909860]  [<ffffffff811db8b0>] do_vfs_ioctl+0x300/0x520
> [120985.909890]  [<ffffffff812c7a96>] ? file_has_perm+0x86/0xa0
> [120985.909918]  [<ffffffff811dbb51>] SyS_ioctl+0x81/0xa0
> [120985.909948]  [<ffffffff816b1929>] system_call_fastpath+0x16/0x1b
> [120985.909974] ---[ end trace 7e24c4fe20a76f1a ]---
> [120985.910186] ------------[ cut here ]------------
> [120985.910213] WARNING: CPU: 0 PID: 7953 at lib/list_debug.c:33 __list_add+0xac/0xc0()
> [120985.910236] list_add corruption. prev->next should be next (ffff88019ffce4f8), but was ffff88018cfb0348. (prev=ffff88018cfb0348).
> [120985.910257] Modules linked in: lgdt330x tuner_xc2028 tuner tvp5150 rc_hauppauge em28xx_rc rc_core xc5000 drxk em28xx_dvb dvb_core em28xx_alsa em28xx_v4l videobuf2_vmalloc videobuf2_memops videobuf2_core em28xx tveeprom v4l2_common videodev media netconsole usb_storage fuse ccm nf_conntrack_netbios_ns nf_conntrack_broadcast ipt_MASQUERADE ip6t_REJECT xt_conntrack ebtable_nat ebtable_broute bridge stp llc ebtable_filter ebtables ip6table_nat nf_conntrack_ipv6 nf_defrag_ipv6 nf_nat_ipv6 ip6table_mangle ip6table_security ip6table_raw ip6table_filter ip6_tables iptable_nat nf_conntrack_ipv4 nf_defrag_ipv4 nf_nat_ipv4 nf_nat nf_conntrack iptable_mangle iptable_security iptable_raw bnep arc4 vfat fat iwldvm mac80211 iwlwifi cfg80211 x86_pkg_temp_thermal coretemp kvm_intel kvm crc32_pclmul crc32c_intel ghash_clmulni_intel
> [120985.912159]  snd_hda_codec_hdmi snd_hda_codec_realtek snd_hda_intel snd_hda_codec snd_hwdep snd_seq snd_seq_device snd_pcm iTCO_wdt iTCO_vendor_support btusb bluetooth joydev microcode serio_raw r8169 mii i2c_i801 lpc_ich mfd_core rfkill snd_page_alloc snd_timer snd mei_me soundcore mei shpchp nfsd auth_rpcgss nfs_acl lockd sunrpc nouveau i915 ttm i2c_algo_bit drm_kms_helper drm i2c_core mxm_wmi wmi video [last unloaded: videobuf2_memops]
> [120985.913642] CPU: 0 PID: 7953 Comm: xawtv Tainted: G      D W    3.13.0-rc1+ #24
> [120985.913667] Hardware name: SAMSUNG ELECTRONICS CO., LTD. 550P5C/550P7C/SAMSUNG_NP1234567890, BIOS P04ABI.013.130220.dg 02/20/2013
> [120985.913691]  0000000000000009 ffff88011f63bb70 ffffffff816a03c6 ffff88011f63bbb8
> [120985.913805]  ffff88011f63bba8 ffffffff8106aaad ffff88018cfb3f48 ffff88019ffce4f8
> [120985.913920]  ffff88018cfb0348 0000000000000282 0000000000000000 ffff88011f63bc08
> [120985.914035] Call Trace:
> [120985.914063]  [<ffffffff816a03c6>] dump_stack+0x45/0x56
> [120985.914093]  [<ffffffff8106aaad>] warn_slowpath_common+0x7d/0xa0
> [120985.914121]  [<ffffffff8106ab1c>] warn_slowpath_fmt+0x4c/0x50
> [120985.914150]  [<ffffffff81343bac>] __list_add+0xac/0xc0
> [120985.914180]  [<ffffffffa04fd70b>] buffer_queue+0x7b/0xb0 [em28xx_v4l]
> [120985.914353]  [<ffffffffa04862d4>] __enqueue_in_driver+0x74/0x80 [videobuf2_core]
> [120985.914385]  [<ffffffffa04878c0>] vb2_streamon+0xa0/0x140 [videobuf2_core]
> [120985.914416]  [<ffffffffa04879a8>] vb2_ioctl_streamon+0x48/0x50 [videobuf2_core]
> [120985.914449]  [<ffffffffa04b7a8a>] v4l_streamon+0x1a/0x20 [videodev]
> [120985.914482]  [<ffffffffa04bb644>] __video_do_ioctl+0x2a4/0x330 [videodev]
> [120985.914515]  [<ffffffffa04bb3a0>] ? v4l_dbg_s_register+0x150/0x150 [videodev]
> [120985.914548]  [<ffffffffa04bb3a0>] ? v4l_dbg_s_register+0x150/0x150 [videodev]
> [120985.914580]  [<ffffffffa04bcae0>] video_usercopy+0x240/0x5d0 [videodev]
> [120985.914612]  [<ffffffff810b811d>] ? trace_hardirqs_on+0xd/0x10
> [120985.914643]  [<ffffffffa04b663b>] ? v4l2_ioctl+0x5b/0x160 [videodev]
> [120985.914675]  [<ffffffffa04b663b>] ? v4l2_ioctl+0x5b/0x160 [videodev]
> [120985.914708]  [<ffffffffa04bce85>] video_ioctl2+0x15/0x20 [videodev]
> [120985.914740]  [<ffffffffa04b6703>] v4l2_ioctl+0x123/0x160 [videodev]
> [120985.914770]  [<ffffffff811db8b0>] do_vfs_ioctl+0x300/0x520
> [120985.914799]  [<ffffffff812c7a96>] ? file_has_perm+0x86/0xa0
> [120985.914828]  [<ffffffff811dbb51>] SyS_ioctl+0x81/0xa0
> [120985.914857]  [<ffffffff816b1929>] system_call_fastpath+0x16/0x1b
> [120985.914884] ---[ end trace 7e24c4fe20a76f1b ]---
> [120991.576999] em2882/3 #0: submit of audio urb failed
> [120991.781651] ------------[ cut here ]------------
> [120991.781700] WARNING: CPU: 0 PID: 7979 at lib/list_debug.c:33 __list_add+0xac/0xc0()
> [120991.781730] list_add corruption. prev->next should be next (ffff88019ffce4f8), but was           (null). (prev=ffff88018cfb1b48).
> [120991.781756] Modules linked in: lgdt330x tuner_xc2028 tuner tvp5150 rc_hauppauge em28xx_rc rc_core xc5000 drxk em28xx_dvb dvb_core em28xx_alsa em28xx_v4l videobuf2_vmalloc videobuf2_memops videobuf2_core em28xx tveeprom v4l2_common videodev media netconsole usb_storage fuse ccm nf_conntrack_netbios_ns nf_conntrack_broadcast ipt_MASQUERADE ip6t_REJECT xt_conntrack ebtable_nat ebtable_broute bridge stp llc ebtable_filter ebtables ip6table_nat nf_conntrack_ipv6 nf_defrag_ipv6 nf_nat_ipv6 ip6table_mangle ip6table_security ip6table_raw ip6table_filter ip6_tables iptable_nat nf_conntrack_ipv4 nf_defrag_ipv4 nf_nat_ipv4 nf_nat nf_conntrack iptable_mangle iptable_security iptable_raw bnep arc4 vfat fat iwldvm mac80211 iwlwifi cfg80211 x86_pkg_temp_thermal coretemp kvm_intel kvm crc32_pclmul crc32c_intel ghash_clmulni_intel
> [120991.783977]  snd_hda_codec_hdmi snd_hda_codec_realtek snd_hda_intel snd_hda_codec snd_hwdep snd_seq snd_seq_device snd_pcm iTCO_wdt iTCO_vendor_support btusb bluetooth joydev microcode serio_raw r8169 mii i2c_i801 lpc_ich mfd_core rfkill snd_page_alloc snd_timer snd mei_me soundcore mei shpchp nfsd auth_rpcgss nfs_acl lockd sunrpc nouveau i915 ttm i2c_algo_bit drm_kms_helper drm i2c_core mxm_wmi wmi video [last unloaded: videobuf2_memops]
> [120991.785750] CPU: 0 PID: 7979 Comm: tvtime Tainted: G      D W    3.13.0-rc1+ #24
> [120991.785779] Hardware name: SAMSUNG ELECTRONICS CO., LTD. 550P5C/550P7C/SAMSUNG_NP1234567890, BIOS P04ABI.013.130220.dg 02/20/2013
> [120991.785806]  0000000000000009 ffff88001254fb70 ffffffff816a03c6 ffff88001254fbb8
> [120991.785938]  ffff88001254fba8 ffffffff8106aaad ffff88018cfb3f48 ffff88019ffce4f8
> [120991.786102]  ffff88018cfb1b48 0000000000000282 0000000000000000 ffff88001254fc08
> [120991.786233] Call Trace:
> [120991.786268]  [<ffffffff816a03c6>] dump_stack+0x45/0x56
> [120991.786319]  [<ffffffff8106aaad>] warn_slowpath_common+0x7d/0xa0
> [120991.786359]  [<ffffffff8106ab1c>] warn_slowpath_fmt+0x4c/0x50
> [120991.786393]  [<ffffffff81343bac>] __list_add+0xac/0xc0
> [120991.786429]  [<ffffffffa04fd70b>] buffer_queue+0x7b/0xb0 [em28xx_v4l]
> [120991.786619]  [<ffffffffa04862d4>] __enqueue_in_driver+0x74/0x80 [videobuf2_core]
> [120991.786656]  [<ffffffffa04878c0>] vb2_streamon+0xa0/0x140 [videobuf2_core]
> [120991.786690]  [<ffffffffa04879a8>] vb2_ioctl_streamon+0x48/0x50 [videobuf2_core]
> [120991.786728]  [<ffffffffa04b7a8a>] v4l_streamon+0x1a/0x20 [videodev]
> [120991.786767]  [<ffffffffa04bb644>] __video_do_ioctl+0x2a4/0x330 [videodev]
> [120991.786804]  [<ffffffffa04bb3a0>] ? v4l_dbg_s_register+0x150/0x150 [videodev]
> [120991.786841]  [<ffffffffa04bb3a0>] ? v4l_dbg_s_register+0x150/0x150 [videodev]
> [120991.786880]  [<ffffffffa04bcae0>] video_usercopy+0x240/0x5d0 [videodev]
> [120991.786917]  [<ffffffff810b811d>] ? trace_hardirqs_on+0xd/0x10
> [120991.786952]  [<ffffffffa04b663b>] ? v4l2_ioctl+0x5b/0x160 [videodev]
> [120991.786988]  [<ffffffffa04b663b>] ? v4l2_ioctl+0x5b/0x160 [videodev]
> [120991.787027]  [<ffffffffa04bce85>] video_ioctl2+0x15/0x20 [videodev]
> [120991.787063]  [<ffffffffa04b6703>] v4l2_ioctl+0x123/0x160 [videodev]
> [120991.787098]  [<ffffffff811db8b0>] do_vfs_ioctl+0x300/0x520
> [120991.787133]  [<ffffffff812c7a96>] ? file_has_perm+0x86/0xa0
> [120991.787165]  [<ffffffff811dbb51>] SyS_ioctl+0x81/0xa0
> [120991.787199]  [<ffffffff816b1929>] system_call_fastpath+0x16/0x1b
> [120991.787230] ---[ end trace 7e24c4fe20a76f1c ]---
Nice. :/
Maybe it's time to check the videobuf2 handling.



^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 3/7] em28xx: Only deallocate struct em28xx after finishing all extensions
  2014-01-14 20:48               ` Frank Schäfer
@ 2014-01-14 21:20                 ` Mauro Carvalho Chehab
  2014-01-15 18:48                   ` Frank Schäfer
  0 siblings, 1 reply; 40+ messages in thread
From: Mauro Carvalho Chehab @ 2014-01-14 21:20 UTC (permalink / raw)
  To: Frank Schäfer; +Cc: Linux Media Mailing List, Mauro Carvalho Chehab

Em Tue, 14 Jan 2014 21:48:16 +0100
Frank Schäfer <fschaefer.oss@googlemail.com> escreveu:

> Am 14.01.2014 19:55, schrieb Mauro Carvalho Chehab:
> > Em Tue, 14 Jan 2014 19:13:00 +0100
> > Frank Schäfer <fschaefer.oss@googlemail.com> escreveu:
> >
...
> >> At first glance it seems there are at least 2 issues:
> >> 1.) use after freeing in v4l-extension (happens when the device is 
> >> closed after the usb disconnect)
> > That's basically what this patch fixes. Both V4L2 and ALSA handles it
> > well, if you warn the subsystem that a device will be removed.
> >
> > If are there still any issues, we may add a kref_get() at device open,
> > an a kref_put() at device close on the affected sub-driver.
> Ok, I've tested it and I was right here.
> This is what happens when closing a disconnected device:
> 
> [  144.045691] usb 1-8: USB disconnect, device number 7
> [  144.047387] em2765 #0: disconnecting em2765 #0 video
> [  144.047403] em2765 #0: V4L2 device video1 deregistered
> [  144.050197] em2765 #0: Deregistering snapshot button
> [  144.058336] em2765 #0: Freeing device
> [  147.525267] : em28xx_v4l2_close() called
> [  147.525287] : em28xx_videodevice_release() called
> 
> 
> I will make some tests tomorrow, but here is a first suggestion how to
> fix this:
> 
> Remove the kref_put() call from em28xx_v4l2_fini().
> Instead, add the following lines to em28xx_videodevice_release():
> 
> if (dev->users == 0) {
>         dev->users--; /* avoid multiple kref_put() calls when the
> devices are unregistered and no device is open */
>         kref_put(&dev->ref, em28xx_free_device);
> }
> 
> That should fix it.

What I actually did on version 2 (already submitted) is that it is calling 
kref_get() at open, and kref_put() at close.

> Interestingly no oops happens. I will have to take a closer look at this
> tomorrow, but I suspect that the dev we obtain from struct file filp is
> an outdated copy of the original device struct.

Likely.

> If that would be true and no bad things can happen in the close()
> function we actually wouldn't need kref for the v4l extension at all.

Still, it will be writing on a deallocated buffer, and this can be
making some memory used by some other part of the Kernel dirty.

> Of course, the ideal solution would be, if we could just clear the
> device struct at the end of the usb disconnect handler, because we can
> be sure that the fini() functions have already made sure that dev isn't
> used anymore.
>
> Btw, what happens in em28xx-audio ?
> Does the ALSA core also allow to call the close() function when the
> device is already gone ?

I suspect so. This is what happens when I remove HVR-950 while both
audio and video are still streaming:

[ 4313.540907] usb 3-4: USB disconnect, device number 7
[ 4313.541280] em2882/3 #0: Disconnecting em2882/3 #0
[ 4313.541313] em2882/3 #0: Closing video extension
[ 4313.541352] em2882/3 #0: V4L2 device vbi0 deregistered
[ 4313.541635] em2882/3 #0: V4L2 device video0 deregistered
[ 4313.542188] em2882/3 #0: Closing audio extension

(I waited for ~5 secs before removing the driver)

[ 4317.470747] em2882/3 #0: couldn't setup AC97 register 2
[ 4317.470772] em2882/3 #0: couldn't setup AC97 register 4
[ 4317.470785] em2882/3 #0: couldn't setup AC97 register 6
[ 4317.470797] em2882/3 #0: couldn't setup AC97 register 54
[ 4317.470810] em2882/3 #0: couldn't setup AC97 register 56
[ 4317.470950] em2882/3 #0: Closing DVB extension
[ 4317.471890] xc2028 19-0061: destroying instance
[ 4317.471913] em2882/3 #0: Closing input extension
[ 4317.489374] em2882/3 #0: Freeing device

As the code now have a kref for open/close on both audio and video
extensions, that means that em28xx close was called after device
removal, as otherwise, we won't see the "Freeing device" print.


-- 

Cheers,
Mauro

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 3/7] em28xx: Only deallocate struct em28xx after finishing all extensions
  2014-01-14 21:20                 ` Mauro Carvalho Chehab
@ 2014-01-15 18:48                   ` Frank Schäfer
  0 siblings, 0 replies; 40+ messages in thread
From: Frank Schäfer @ 2014-01-15 18:48 UTC (permalink / raw)
  To: Mauro Carvalho Chehab; +Cc: Linux Media Mailing List, Mauro Carvalho Chehab

Am 14.01.2014 22:20, schrieb Mauro Carvalho Chehab:
> Em Tue, 14 Jan 2014 21:48:16 +0100
> Frank Schäfer <fschaefer.oss@googlemail.com> escreveu:
>
>> Am 14.01.2014 19:55, schrieb Mauro Carvalho Chehab:
>>> Em Tue, 14 Jan 2014 19:13:00 +0100
>>> Frank Schäfer <fschaefer.oss@googlemail.com> escreveu:
>>>
> ...
>>>> At first glance it seems there are at least 2 issues:
>>>> 1.) use after freeing in v4l-extension (happens when the device is 
>>>> closed after the usb disconnect)
>>> That's basically what this patch fixes. Both V4L2 and ALSA handles it
>>> well, if you warn the subsystem that a device will be removed.
>>>
>>> If are there still any issues, we may add a kref_get() at device open,
>>> an a kref_put() at device close on the affected sub-driver.
>> Ok, I've tested it and I was right here.
>> This is what happens when closing a disconnected device:
>>
>> [  144.045691] usb 1-8: USB disconnect, device number 7
>> [  144.047387] em2765 #0: disconnecting em2765 #0 video
>> [  144.047403] em2765 #0: V4L2 device video1 deregistered
>> [  144.050197] em2765 #0: Deregistering snapshot button
>> [  144.058336] em2765 #0: Freeing device
>> [  147.525267] : em28xx_v4l2_close() called
>> [  147.525287] : em28xx_videodevice_release() called
>>
>>
>> I will make some tests tomorrow, but here is a first suggestion how to
>> fix this:
>>
>> Remove the kref_put() call from em28xx_v4l2_fini().
>> Instead, add the following lines to em28xx_videodevice_release():
>>
>> if (dev->users == 0) {
>>         dev->users--; /* avoid multiple kref_put() calls when the
>> devices are unregistered and no device is open */
>>         kref_put(&dev->ref, em28xx_free_device);
>> }
>>
>> That should fix it.
> What I actually did on version 2 (already submitted) is that it is calling 
> kref_get() at open, and kref_put() at close.
Yes, that's even better.

>
>> Interestingly no oops happens. I will have to take a closer look at this
>> tomorrow, but I suspect that the dev we obtain from struct file filp is
>> an outdated copy of the original device struct.
> Likely.
>
>> If that would be true and no bad things can happen in the close()
>> function we actually wouldn't need kref for the v4l extension at all.
> Still, it will be writing on a deallocated buffer, and this can be
> making some memory used by some other part of the Kernel dirty.
>
>> Of course, the ideal solution would be, if we could just clear the
>> device struct at the end of the usb disconnect handler, because we can
>> be sure that the fini() functions have already made sure that dev isn't
>> used anymore.
>>
>> Btw, what happens in em28xx-audio ?
>> Does the ALSA core also allow to call the close() function when the
>> device is already gone ?
> I suspect so. This is what happens when I remove HVR-950 while both
> audio and video are still streaming:
>
> [ 4313.540907] usb 3-4: USB disconnect, device number 7
> [ 4313.541280] em2882/3 #0: Disconnecting em2882/3 #0
> [ 4313.541313] em2882/3 #0: Closing video extension
> [ 4313.541352] em2882/3 #0: V4L2 device vbi0 deregistered
> [ 4313.541635] em2882/3 #0: V4L2 device video0 deregistered
> [ 4313.542188] em2882/3 #0: Closing audio extension
>
> (I waited for ~5 secs before removing the driver)
>
> [ 4317.470747] em2882/3 #0: couldn't setup AC97 register 2
> [ 4317.470772] em2882/3 #0: couldn't setup AC97 register 4
> [ 4317.470785] em2882/3 #0: couldn't setup AC97 register 6
> [ 4317.470797] em2882/3 #0: couldn't setup AC97 register 54
> [ 4317.470810] em2882/3 #0: couldn't setup AC97 register 56
> [ 4317.470950] em2882/3 #0: Closing DVB extension
> [ 4317.471890] xc2028 19-0061: destroying instance
> [ 4317.471913] em2882/3 #0: Closing input extension
> [ 4317.489374] em2882/3 #0: Freeing device
>
> As the code now have a kref for open/close on both audio and video
> extensions, that means that em28xx close was called after device
> removal, as otherwise, we won't see the "Freeing device" print.
Ok, thanks.
I will make further tests now.

Regards,
Frank

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH v2] em28xx: Only deallocate struct em28xx after finishing all extensions
  2014-01-14 17:36   ` [PATCH v2] " Mauro Carvalho Chehab
@ 2014-01-15 21:13     ` Frank Schäfer
  2014-02-09 18:41       ` Frank Schäfer
  0 siblings, 1 reply; 40+ messages in thread
From: Frank Schäfer @ 2014-01-15 21:13 UTC (permalink / raw)
  To: Mauro Carvalho Chehab; +Cc: Linux Media Mailing List, Mauro Carvalho Chehab

Am 14.01.2014 18:36, schrieb Mauro Carvalho Chehab:
> We can't free struct em28xx while one of the extensions is still
> using it.
>
> So, add a kref() to control it, freeing it only after the
> extensions fini calls.
>
> Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
> ---
>
> v2:
> 	- patch was rebased;
> 	- as em28xx-audio close uses struct em28xx dev, add a kref in order
> 	  to track audio open/close.
>
>  drivers/media/usb/em28xx/em28xx-audio.c |  8 +++++++-
>  drivers/media/usb/em28xx/em28xx-cards.c | 34 ++++++++++++++++-----------------
>  drivers/media/usb/em28xx/em28xx-dvb.c   |  5 ++++-
>  drivers/media/usb/em28xx/em28xx-input.c |  8 +++++++-
>  drivers/media/usb/em28xx/em28xx-video.c | 14 ++++++++------
>  drivers/media/usb/em28xx/em28xx.h       |  9 +++++++--
>  6 files changed, 50 insertions(+), 28 deletions(-)
>
> diff --git a/drivers/media/usb/em28xx/em28xx-audio.c b/drivers/media/usb/em28xx/em28xx-audio.c
> index 45bea1adc11c..73eeeaf6551f 100644
> --- a/drivers/media/usb/em28xx/em28xx-audio.c
> +++ b/drivers/media/usb/em28xx/em28xx-audio.c
> @@ -265,6 +265,8 @@ static int snd_em28xx_capture_open(struct snd_pcm_substream *substream)
>  
>  	dprintk("opening device and trying to acquire exclusive lock\n");
>  
> +	kref_get(&dev->ref);
> +
When snd_em28xx_capture_open() fails, there will never be a close()
call, right ?
So kref_get() needs to be called when we are sure that the function
succeeds.

>  	runtime->hw = snd_em28xx_hw_capture;
>  	if ((dev->alt == 0 || dev->audio_ifnum) && dev->adev.users == 0) {
>  		int nonblock = !!(substream->f_flags & O_NONBLOCK);
> @@ -330,6 +332,7 @@ static int snd_em28xx_pcm_close(struct snd_pcm_substream *substream)
>  		substream->runtime->dma_area = NULL;
>  	}
>  	mutex_unlock(&dev->lock);
> +	kref_put(&dev->ref, em28xx_free_device);
>  
>  	return 0;
>  }
> @@ -886,6 +889,8 @@ static int em28xx_audio_init(struct em28xx *dev)
>  
>  	em28xx_info("Binding audio extension\n");
>  
> +	kref_get(&dev->ref);
> +
>  	printk(KERN_INFO "em28xx-audio.c: Copyright (C) 2006 Markus "
>  			 "Rechberger\n");
>  	printk(KERN_INFO
> @@ -958,7 +963,7 @@ static int em28xx_audio_fini(struct em28xx *dev)
>  	if (dev == NULL)
>  		return 0;
>  
> -	if (dev->has_alsa_audio != 1) {
> +	if (!dev->has_alsa_audio) {
>  		/* This device does not support the extension (in this case
>  		   the device is expecting the snd-usb-audio module or
>  		   doesn't have analog audio support at all) */
> @@ -977,6 +982,7 @@ static int em28xx_audio_fini(struct em28xx *dev)
>  		dev->adev.sndcard = NULL;
>  	}
>  
> +	kref_put(&dev->ref, em28xx_free_device);
>  	return 0;
>  }
>  
> diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c
> index e08d65b2e352..8fc0a437054e 100644
> --- a/drivers/media/usb/em28xx/em28xx-cards.c
> +++ b/drivers/media/usb/em28xx/em28xx-cards.c
> @@ -2867,16 +2867,18 @@ static void flush_request_modules(struct em28xx *dev)
>  	flush_work(&dev->request_module_wk);
>  }
>  
> -/*
> - * em28xx_release_resources()
> - * unregisters the v4l2,i2c and usb devices
> - * called when the device gets disconnected or at module unload
> -*/
> -void em28xx_release_resources(struct em28xx *dev)
> +/**
> + * em28xx_release_resources() -  unregisters the v4l2,i2c and usb devices
> + *
> + * @ref: struct kref for em28xx device
> + *
> + * This is called when all extensions and em28xx core unregisters a device
> + */
> +void em28xx_free_device(struct kref *ref)
>  {
> -	/*FIXME: I2C IR should be disconnected */
> +	struct em28xx *dev = kref_to_dev(ref);
>  
> -	mutex_lock(&dev->lock);
> +	em28xx_info("Freeing device\n");
>  
>  	if (dev->def_i2c_bus)
>  		em28xx_i2c_unregister(dev, 1);
> @@ -2887,9 +2889,10 @@ void em28xx_release_resources(struct em28xx *dev)
>  	/* Mark device as unused */
>  	clear_bit(dev->devno, &em28xx_devused);
>  
> -	mutex_unlock(&dev->lock);
> -};
> -EXPORT_SYMBOL_GPL(em28xx_release_resources);
> +	kfree(dev->alt_max_pkt_size_isoc);
> +	kfree(dev);
> +}
> +EXPORT_SYMBOL_GPL(em28xx_free_device);
This reintroduces the sysfs group removal warnings.
Just keep em28xx_release_resources() as is and add let
em28xx_free_device() call the the two kfrees() only.

>  /*
>   * em28xx_init_dev()
> @@ -3342,6 +3345,8 @@ static int em28xx_usb_probe(struct usb_interface *interface,
>  			    dev->dvb_xfer_bulk ? "bulk" : "isoc");
>  	}
>  
> +	kref_init(&dev->ref);
> +
>  	request_modules(dev);
>  
>  	/* Should be the last thing to do, to avoid newer udev's to
> @@ -3385,12 +3390,7 @@ static void em28xx_usb_disconnect(struct usb_interface *interface)
>  
>  	em28xx_close_extension(dev);
>  
> -	em28xx_release_resources(dev);
Keep this call (see above).

> -
> -	if (!dev->users) {
> -		kfree(dev->alt_max_pkt_size_isoc);
> -		kfree(dev);
> -	}
> +	kref_put(&dev->ref, em28xx_free_device);
>  }
>  
>  static struct usb_driver em28xx_usb_driver = {
> diff --git a/drivers/media/usb/em28xx/em28xx-dvb.c b/drivers/media/usb/em28xx/em28xx-dvb.c
> index 881a813836eb..7df21e33a923 100644
> --- a/drivers/media/usb/em28xx/em28xx-dvb.c
> +++ b/drivers/media/usb/em28xx/em28xx-dvb.c
> @@ -1005,11 +1005,11 @@ static int em28xx_dvb_init(struct em28xx *dev)
>  	em28xx_info("Binding DVB extension\n");
>  
>  	dvb = kzalloc(sizeof(struct em28xx_dvb), GFP_KERNEL);
> -
>  	if (dvb == NULL) {
>  		em28xx_info("em28xx_dvb: memory allocation failed\n");
>  		return -ENOMEM;
>  	}
> +	kref_get(&dev->ref);
This one needs to be moved between the em28xx_infp() and the kzalloc()
call above.

>  	dev->dvb = dvb;
>  	dvb->fe[0] = dvb->fe[1] = NULL;
>  
> @@ -1437,6 +1437,7 @@ static int em28xx_dvb_init(struct em28xx *dev)
>  	dvb->adapter.mfe_shared = mfe_shared;
>  
>  	em28xx_info("DVB extension successfully initialized\n");
> +
>  ret:
>  	em28xx_set_mode(dev, EM28XX_SUSPEND);
>  	mutex_unlock(&dev->lock);
> @@ -1489,6 +1490,8 @@ static int em28xx_dvb_fini(struct em28xx *dev)
>  		dev->dvb = NULL;
>  	}
>  
> +	kref_put(&dev->ref, em28xx_free_device);
> +
>  	return 0;
>  }
>  
> diff --git a/drivers/media/usb/em28xx/em28xx-input.c b/drivers/media/usb/em28xx/em28xx-input.c
> index 3d54c04e5230..c98d784a2772 100644
> --- a/drivers/media/usb/em28xx/em28xx-input.c
> +++ b/drivers/media/usb/em28xx/em28xx-input.c
> @@ -675,6 +675,8 @@ static int em28xx_ir_init(struct em28xx *dev)
>  		return 0;
>  	}
>  
> +	kref_get(&dev->ref);
> +
>  	if (dev->board.buttons)
>  		em28xx_init_buttons(dev);
>  
> @@ -817,7 +819,7 @@ static int em28xx_ir_fini(struct em28xx *dev)
>  
>  	/* skip detach on non attached boards */
>  	if (!ir)
> -		return 0;
> +		goto ref_put;
>  
>  	if (ir->rc)
>  		rc_unregister_device(ir->rc);
> @@ -825,6 +827,10 @@ static int em28xx_ir_fini(struct em28xx *dev)
>  	/* done */
>  	kfree(ir);
>  	dev->ir = NULL;
> +
> +ref_put:
> +	kref_put(&dev->ref, em28xx_free_device);
> +
>  	return 0;
>  }
>  
> diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c
> index aabcafbdab46..f801af8d3f61 100644
> --- a/drivers/media/usb/em28xx/em28xx-video.c
> +++ b/drivers/media/usb/em28xx/em28xx-video.c
> @@ -1837,6 +1837,7 @@ static int em28xx_v4l2_open(struct file *filp)
>  			video_device_node_name(vdev), v4l2_type_names[fh_type],
>  			dev->users);
>  
> +	kref_get(&dev->ref);
The same as with open() in em28xx-alsa:
kref_get() needs to be called when we are sure that the function succeeds.

>  	if (mutex_lock_interruptible(&dev->lock))
>  		return -ERESTARTSYS;
> @@ -1926,9 +1927,8 @@ static int em28xx_v4l2_fini(struct em28xx *dev)
>  	v4l2_ctrl_handler_free(&dev->ctrl_handler);
>  	v4l2_device_unregister(&dev->v4l2_dev);
>  
> -	if (dev->users)
> -		em28xx_warn("Device is open ! Memory deallocation is deferred on last close.\n");
>  	mutex_unlock(&dev->lock);
> +	kref_put(&dev->ref, em28xx_free_device);
>  
>  	return 0;
>  }
> @@ -1950,11 +1950,9 @@ static int em28xx_v4l2_close(struct file *filp)
>  	mutex_lock(&dev->lock);
>  
>  	if (dev->users == 1) {
> -		/* free the remaining resources if device is disconnected */
> -		if (dev->disconnected) {
> -			kfree(dev->alt_max_pkt_size_isoc);
> +		/* No sense to try to write to the device */
> +		if (dev->disconnected)
>  			goto exit;
> -		}
>  
>  		/* Save some power by putting tuner to sleep */
>  		v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_power, 0);
> @@ -1975,6 +1973,8 @@ static int em28xx_v4l2_close(struct file *filp)
>  exit:
>  	dev->users--;
>  	mutex_unlock(&dev->lock);
> +	kref_put(&dev->ref, em28xx_free_device);
> +
>  	return 0;
>  }
>  
> @@ -2206,6 +2206,8 @@ static int em28xx_v4l2_init(struct em28xx *dev)
>  
>  	em28xx_info("Registering V4L2 extension\n");
>  
> +	kref_get(&dev->ref);
> +
>  	mutex_lock(&dev->lock);
>  
>  	ret = v4l2_device_register(&dev->udev->dev, &dev->v4l2_dev);
> diff --git a/drivers/media/usb/em28xx/em28xx.h b/drivers/media/usb/em28xx/em28xx.h
> index 10b817245f7e..8b3438891bb3 100644
> --- a/drivers/media/usb/em28xx/em28xx.h
> +++ b/drivers/media/usb/em28xx/em28xx.h
> @@ -32,6 +32,7 @@
>  #include <linux/workqueue.h>
>  #include <linux/i2c.h>
>  #include <linux/mutex.h>
> +#include <linux/kref.h>
>  #include <linux/videodev2.h>
>  
>  #include <media/videobuf2-vmalloc.h>
> @@ -533,9 +534,11 @@ struct em28xx_i2c_bus {
>  	enum em28xx_i2c_algo_type algo_type;
>  };
>  
> -
>  /* main device struct */
>  struct em28xx {
> +	struct kref ref;
> +
> +
One empty line is enough.

>  	/* generic device properties */
>  	char name[30];		/* name (including minor) of the device */
>  	int model;		/* index in the device_data struct */
> @@ -708,6 +711,8 @@ struct em28xx {
>  	struct em28xx_dvb *dvb;
>  };
>  
> +#define kref_to_dev(d) container_of(d, struct em28xx, ref)
> +
I wonder why this macro isn't provided by kref.h.

>  struct em28xx_ops {
>  	struct list_head next;
>  	char *name;
> @@ -765,7 +770,7 @@ extern struct em28xx_board em28xx_boards[];
>  extern struct usb_device_id em28xx_id_table[];
>  int em28xx_tuner_callback(void *ptr, int component, int command, int arg);
>  void em28xx_setup_xc3028(struct em28xx *dev, struct xc2028_ctrl *ctl);
> -void em28xx_release_resources(struct em28xx *dev);
> +void em28xx_free_device(struct kref *ref);
>  
>  /* Provided by em28xx-camera.c */
>  int em28xx_detect_sensor(struct em28xx *dev);
I've made several tests with my devices and I'm facing some issues with
the current media-tree (e.g. a kernel panic with a hard lockup when
reconnecting the laplace webcam).
But none of them seems to be related to this change.
Anyway, when we're finished with it, we need to stabilize things...



^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH v2] em28xx: Only deallocate struct em28xx after finishing all extensions
  2014-01-15 21:13     ` Frank Schäfer
@ 2014-02-09 18:41       ` Frank Schäfer
  2014-02-09 20:09         ` Mauro Carvalho Chehab
  0 siblings, 1 reply; 40+ messages in thread
From: Frank Schäfer @ 2014-02-09 18:41 UTC (permalink / raw)
  To: Mauro Carvalho Chehab; +Cc: Linux Media Mailing List, Mauro Carvalho Chehab


Am 15.01.2014 22:13, schrieb Frank Schäfer:
> Am 14.01.2014 18:36, schrieb Mauro Carvalho Chehab:
>> We can't free struct em28xx while one of the extensions is still
>> using it.
>>
>> So, add a kref() to control it, freeing it only after the
>> extensions fini calls.
>>
>> Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
>> ---
>>
>> v2:
>> 	- patch was rebased;
>> 	- as em28xx-audio close uses struct em28xx dev, add a kref in order
>> 	  to track audio open/close.
>>
>>  drivers/media/usb/em28xx/em28xx-audio.c |  8 +++++++-
>>  drivers/media/usb/em28xx/em28xx-cards.c | 34 ++++++++++++++++-----------------
>>  drivers/media/usb/em28xx/em28xx-dvb.c   |  5 ++++-
>>  drivers/media/usb/em28xx/em28xx-input.c |  8 +++++++-
>>  drivers/media/usb/em28xx/em28xx-video.c | 14 ++++++++------
>>  drivers/media/usb/em28xx/em28xx.h       |  9 +++++++--
>>  6 files changed, 50 insertions(+), 28 deletions(-)
>>
>> diff --git a/drivers/media/usb/em28xx/em28xx-audio.c b/drivers/media/usb/em28xx/em28xx-audio.c
>> index 45bea1adc11c..73eeeaf6551f 100644
>> --- a/drivers/media/usb/em28xx/em28xx-audio.c
>> +++ b/drivers/media/usb/em28xx/em28xx-audio.c
>> @@ -265,6 +265,8 @@ static int snd_em28xx_capture_open(struct snd_pcm_substream *substream)
>>  
>>  	dprintk("opening device and trying to acquire exclusive lock\n");
>>  
>> +	kref_get(&dev->ref);
>> +
> When snd_em28xx_capture_open() fails, there will never be a close()
> call, right ?
> So kref_get() needs to be called when we are sure that the function
> succeeds.
>
>>  	runtime->hw = snd_em28xx_hw_capture;
>>  	if ((dev->alt == 0 || dev->audio_ifnum) && dev->adev.users == 0) {
>>  		int nonblock = !!(substream->f_flags & O_NONBLOCK);
>> @@ -330,6 +332,7 @@ static int snd_em28xx_pcm_close(struct snd_pcm_substream *substream)
>>  		substream->runtime->dma_area = NULL;
>>  	}
>>  	mutex_unlock(&dev->lock);
>> +	kref_put(&dev->ref, em28xx_free_device);
>>  
>>  	return 0;
>>  }
>> @@ -886,6 +889,8 @@ static int em28xx_audio_init(struct em28xx *dev)
>>  
>>  	em28xx_info("Binding audio extension\n");
>>  
>> +	kref_get(&dev->ref);
>> +
>>  	printk(KERN_INFO "em28xx-audio.c: Copyright (C) 2006 Markus "
>>  			 "Rechberger\n");
>>  	printk(KERN_INFO
>> @@ -958,7 +963,7 @@ static int em28xx_audio_fini(struct em28xx *dev)
>>  	if (dev == NULL)
>>  		return 0;
>>  
>> -	if (dev->has_alsa_audio != 1) {
>> +	if (!dev->has_alsa_audio) {
>>  		/* This device does not support the extension (in this case
>>  		   the device is expecting the snd-usb-audio module or
>>  		   doesn't have analog audio support at all) */
>> @@ -977,6 +982,7 @@ static int em28xx_audio_fini(struct em28xx *dev)
>>  		dev->adev.sndcard = NULL;
>>  	}
>>  
>> +	kref_put(&dev->ref, em28xx_free_device);
>>  	return 0;
>>  }
>>  
>> diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c
>> index e08d65b2e352..8fc0a437054e 100644
>> --- a/drivers/media/usb/em28xx/em28xx-cards.c
>> +++ b/drivers/media/usb/em28xx/em28xx-cards.c
>> @@ -2867,16 +2867,18 @@ static void flush_request_modules(struct em28xx *dev)
>>  	flush_work(&dev->request_module_wk);
>>  }
>>  
>> -/*
>> - * em28xx_release_resources()
>> - * unregisters the v4l2,i2c and usb devices
>> - * called when the device gets disconnected or at module unload
>> -*/
>> -void em28xx_release_resources(struct em28xx *dev)
>> +/**
>> + * em28xx_release_resources() -  unregisters the v4l2,i2c and usb devices
>> + *
>> + * @ref: struct kref for em28xx device
>> + *
>> + * This is called when all extensions and em28xx core unregisters a device
>> + */
>> +void em28xx_free_device(struct kref *ref)
>>  {
>> -	/*FIXME: I2C IR should be disconnected */
>> +	struct em28xx *dev = kref_to_dev(ref);
>>  
>> -	mutex_lock(&dev->lock);
>> +	em28xx_info("Freeing device\n");
>>  
>>  	if (dev->def_i2c_bus)
>>  		em28xx_i2c_unregister(dev, 1);
>> @@ -2887,9 +2889,10 @@ void em28xx_release_resources(struct em28xx *dev)
>>  	/* Mark device as unused */
>>  	clear_bit(dev->devno, &em28xx_devused);
>>  
>> -	mutex_unlock(&dev->lock);
>> -};
>> -EXPORT_SYMBOL_GPL(em28xx_release_resources);
>> +	kfree(dev->alt_max_pkt_size_isoc);
>> +	kfree(dev);
>> +}
>> +EXPORT_SYMBOL_GPL(em28xx_free_device);
> This reintroduces the sysfs group removal warnings.
> Just keep em28xx_release_resources() as is and add let
> em28xx_free_device() call the the two kfrees() only.
>
>>  /*
>>   * em28xx_init_dev()
>> @@ -3342,6 +3345,8 @@ static int em28xx_usb_probe(struct usb_interface *interface,
>>  			    dev->dvb_xfer_bulk ? "bulk" : "isoc");
>>  	}
>>  
>> +	kref_init(&dev->ref);
>> +
>>  	request_modules(dev);
>>  
>>  	/* Should be the last thing to do, to avoid newer udev's to
>> @@ -3385,12 +3390,7 @@ static void em28xx_usb_disconnect(struct usb_interface *interface)
>>  
>>  	em28xx_close_extension(dev);
>>  
>> -	em28xx_release_resources(dev);
> Keep this call (see above).
>
>> -
>> -	if (!dev->users) {
>> -		kfree(dev->alt_max_pkt_size_isoc);
>> -		kfree(dev);
>> -	}
>> +	kref_put(&dev->ref, em28xx_free_device);
>>  }
>>  
>>  static struct usb_driver em28xx_usb_driver = {
>> diff --git a/drivers/media/usb/em28xx/em28xx-dvb.c b/drivers/media/usb/em28xx/em28xx-dvb.c
>> index 881a813836eb..7df21e33a923 100644
>> --- a/drivers/media/usb/em28xx/em28xx-dvb.c
>> +++ b/drivers/media/usb/em28xx/em28xx-dvb.c
>> @@ -1005,11 +1005,11 @@ static int em28xx_dvb_init(struct em28xx *dev)
>>  	em28xx_info("Binding DVB extension\n");
>>  
>>  	dvb = kzalloc(sizeof(struct em28xx_dvb), GFP_KERNEL);
>> -
>>  	if (dvb == NULL) {
>>  		em28xx_info("em28xx_dvb: memory allocation failed\n");
>>  		return -ENOMEM;
>>  	}
>> +	kref_get(&dev->ref);
> This one needs to be moved between the em28xx_infp() and the kzalloc()
> call above.
>
>>  	dev->dvb = dvb;
>>  	dvb->fe[0] = dvb->fe[1] = NULL;
>>  
>> @@ -1437,6 +1437,7 @@ static int em28xx_dvb_init(struct em28xx *dev)
>>  	dvb->adapter.mfe_shared = mfe_shared;
>>  
>>  	em28xx_info("DVB extension successfully initialized\n");
>> +
>>  ret:
>>  	em28xx_set_mode(dev, EM28XX_SUSPEND);
>>  	mutex_unlock(&dev->lock);
>> @@ -1489,6 +1490,8 @@ static int em28xx_dvb_fini(struct em28xx *dev)
>>  		dev->dvb = NULL;
>>  	}
>>  
>> +	kref_put(&dev->ref, em28xx_free_device);
>> +
>>  	return 0;
>>  }
>>  
>> diff --git a/drivers/media/usb/em28xx/em28xx-input.c b/drivers/media/usb/em28xx/em28xx-input.c
>> index 3d54c04e5230..c98d784a2772 100644
>> --- a/drivers/media/usb/em28xx/em28xx-input.c
>> +++ b/drivers/media/usb/em28xx/em28xx-input.c
>> @@ -675,6 +675,8 @@ static int em28xx_ir_init(struct em28xx *dev)
>>  		return 0;
>>  	}
>>  
>> +	kref_get(&dev->ref);
>> +
>>  	if (dev->board.buttons)
>>  		em28xx_init_buttons(dev);
>>  
>> @@ -817,7 +819,7 @@ static int em28xx_ir_fini(struct em28xx *dev)
>>  
>>  	/* skip detach on non attached boards */
>>  	if (!ir)
>> -		return 0;
>> +		goto ref_put;
>>  
>>  	if (ir->rc)
>>  		rc_unregister_device(ir->rc);
>> @@ -825,6 +827,10 @@ static int em28xx_ir_fini(struct em28xx *dev)
>>  	/* done */
>>  	kfree(ir);
>>  	dev->ir = NULL;
>> +
>> +ref_put:
>> +	kref_put(&dev->ref, em28xx_free_device);
>> +
>>  	return 0;
>>  }
>>  
>> diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c
>> index aabcafbdab46..f801af8d3f61 100644
>> --- a/drivers/media/usb/em28xx/em28xx-video.c
>> +++ b/drivers/media/usb/em28xx/em28xx-video.c
>> @@ -1837,6 +1837,7 @@ static int em28xx_v4l2_open(struct file *filp)
>>  			video_device_node_name(vdev), v4l2_type_names[fh_type],
>>  			dev->users);
>>  
>> +	kref_get(&dev->ref);
> The same as with open() in em28xx-alsa:
> kref_get() needs to be called when we are sure that the function succeeds.
>
>>  	if (mutex_lock_interruptible(&dev->lock))
>>  		return -ERESTARTSYS;
>> @@ -1926,9 +1927,8 @@ static int em28xx_v4l2_fini(struct em28xx *dev)
>>  	v4l2_ctrl_handler_free(&dev->ctrl_handler);
>>  	v4l2_device_unregister(&dev->v4l2_dev);
>>  
>> -	if (dev->users)
>> -		em28xx_warn("Device is open ! Memory deallocation is deferred on last close.\n");
>>  	mutex_unlock(&dev->lock);
>> +	kref_put(&dev->ref, em28xx_free_device);
>>  
>>  	return 0;
>>  }
>> @@ -1950,11 +1950,9 @@ static int em28xx_v4l2_close(struct file *filp)
>>  	mutex_lock(&dev->lock);
>>  
>>  	if (dev->users == 1) {
>> -		/* free the remaining resources if device is disconnected */
>> -		if (dev->disconnected) {
>> -			kfree(dev->alt_max_pkt_size_isoc);
>> +		/* No sense to try to write to the device */
>> +		if (dev->disconnected)
>>  			goto exit;
>> -		}
>>  
>>  		/* Save some power by putting tuner to sleep */
>>  		v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_power, 0);
>> @@ -1975,6 +1973,8 @@ static int em28xx_v4l2_close(struct file *filp)
>>  exit:
>>  	dev->users--;
>>  	mutex_unlock(&dev->lock);
>> +	kref_put(&dev->ref, em28xx_free_device);
>> +
>>  	return 0;
>>  }
>>  
>> @@ -2206,6 +2206,8 @@ static int em28xx_v4l2_init(struct em28xx *dev)
>>  
>>  	em28xx_info("Registering V4L2 extension\n");
>>  
>> +	kref_get(&dev->ref);
>> +
>>  	mutex_lock(&dev->lock);
>>  
>>  	ret = v4l2_device_register(&dev->udev->dev, &dev->v4l2_dev);
>> diff --git a/drivers/media/usb/em28xx/em28xx.h b/drivers/media/usb/em28xx/em28xx.h
>> index 10b817245f7e..8b3438891bb3 100644
>> --- a/drivers/media/usb/em28xx/em28xx.h
>> +++ b/drivers/media/usb/em28xx/em28xx.h
>> @@ -32,6 +32,7 @@
>>  #include <linux/workqueue.h>
>>  #include <linux/i2c.h>
>>  #include <linux/mutex.h>
>> +#include <linux/kref.h>
>>  #include <linux/videodev2.h>
>>  
>>  #include <media/videobuf2-vmalloc.h>
>> @@ -533,9 +534,11 @@ struct em28xx_i2c_bus {
>>  	enum em28xx_i2c_algo_type algo_type;
>>  };
>>  
>> -
>>  /* main device struct */
>>  struct em28xx {
>> +	struct kref ref;
>> +
>> +
> One empty line is enough.
>
>>  	/* generic device properties */
>>  	char name[30];		/* name (including minor) of the device */
>>  	int model;		/* index in the device_data struct */
>> @@ -708,6 +711,8 @@ struct em28xx {
>>  	struct em28xx_dvb *dvb;
>>  };
>>  
>> +#define kref_to_dev(d) container_of(d, struct em28xx, ref)
>> +
> I wonder why this macro isn't provided by kref.h.
>
>>  struct em28xx_ops {
>>  	struct list_head next;
>>  	char *name;
>> @@ -765,7 +770,7 @@ extern struct em28xx_board em28xx_boards[];
>>  extern struct usb_device_id em28xx_id_table[];
>>  int em28xx_tuner_callback(void *ptr, int component, int command, int arg);
>>  void em28xx_setup_xc3028(struct em28xx *dev, struct xc2028_ctrl *ctl);
>> -void em28xx_release_resources(struct em28xx *dev);
>> +void em28xx_free_device(struct kref *ref);
>>  
>>  /* Provided by em28xx-camera.c */
>>  int em28xx_detect_sensor(struct em28xx *dev);
> I've made several tests with my devices and I'm facing some issues with
> the current media-tree (e.g. a kernel panic with a hard lockup when
> reconnecting the laplace webcam).
> But none of them seems to be related to this change.
> Anyway, when we're finished with it, we need to stabilize things...
Ping !
Are you going to continue working on this patch ?
I've planned to come up with some follow-up changes... ;-)

Regards,
Frank

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH v2] em28xx: Only deallocate struct em28xx after finishing all extensions
  2014-02-09 18:41       ` Frank Schäfer
@ 2014-02-09 20:09         ` Mauro Carvalho Chehab
  2014-02-12 18:00           ` Frank Schäfer
  0 siblings, 1 reply; 40+ messages in thread
From: Mauro Carvalho Chehab @ 2014-02-09 20:09 UTC (permalink / raw)
  To: Frank Schäfer; +Cc: Linux Media Mailing List, Mauro Carvalho Chehab

Em Sun, 09 Feb 2014 19:41:09 +0100
Frank Schäfer <fschaefer.oss@googlemail.com> escreveu:

> 
> Am 15.01.2014 22:13, schrieb Frank Schäfer:
> > Am 14.01.2014 18:36, schrieb Mauro Carvalho Chehab:
> >> We can't free struct em28xx while one of the extensions is still
> >> using it.
> >>
> >> So, add a kref() to control it, freeing it only after the
> >> extensions fini calls.
> >>
> >> Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
> >> ---
> >>
> >> v2:
> >> 	- patch was rebased;
> >> 	- as em28xx-audio close uses struct em28xx dev, add a kref in order
> >> 	  to track audio open/close.
> >>
> >>  drivers/media/usb/em28xx/em28xx-audio.c |  8 +++++++-
> >>  drivers/media/usb/em28xx/em28xx-cards.c | 34 ++++++++++++++++-----------------
> >>  drivers/media/usb/em28xx/em28xx-dvb.c   |  5 ++++-
> >>  drivers/media/usb/em28xx/em28xx-input.c |  8 +++++++-
> >>  drivers/media/usb/em28xx/em28xx-video.c | 14 ++++++++------
> >>  drivers/media/usb/em28xx/em28xx.h       |  9 +++++++--
> >>  6 files changed, 50 insertions(+), 28 deletions(-)
> >>
> >> diff --git a/drivers/media/usb/em28xx/em28xx-audio.c b/drivers/media/usb/em28xx/em28xx-audio.c
> >> index 45bea1adc11c..73eeeaf6551f 100644
> >> --- a/drivers/media/usb/em28xx/em28xx-audio.c
> >> +++ b/drivers/media/usb/em28xx/em28xx-audio.c
> >> @@ -265,6 +265,8 @@ static int snd_em28xx_capture_open(struct snd_pcm_substream *substream)
> >>  
> >>  	dprintk("opening device and trying to acquire exclusive lock\n");
> >>  
> >> +	kref_get(&dev->ref);
> >> +
> > When snd_em28xx_capture_open() fails, there will never be a close()
> > call, right ?
> > So kref_get() needs to be called when we are sure that the function
> > succeeds.

Makes sense.

> >
> >>  	runtime->hw = snd_em28xx_hw_capture;
> >>  	if ((dev->alt == 0 || dev->audio_ifnum) && dev->adev.users == 0) {
> >>  		int nonblock = !!(substream->f_flags & O_NONBLOCK);
> >> @@ -330,6 +332,7 @@ static int snd_em28xx_pcm_close(struct snd_pcm_substream *substream)
> >>  		substream->runtime->dma_area = NULL;
> >>  	}
> >>  	mutex_unlock(&dev->lock);
> >> +	kref_put(&dev->ref, em28xx_free_device);
> >>  
> >>  	return 0;
> >>  }
> >> @@ -886,6 +889,8 @@ static int em28xx_audio_init(struct em28xx *dev)
> >>  
> >>  	em28xx_info("Binding audio extension\n");
> >>  
> >> +	kref_get(&dev->ref);
> >> +
> >>  	printk(KERN_INFO "em28xx-audio.c: Copyright (C) 2006 Markus "
> >>  			 "Rechberger\n");
> >>  	printk(KERN_INFO
> >> @@ -958,7 +963,7 @@ static int em28xx_audio_fini(struct em28xx *dev)
> >>  	if (dev == NULL)
> >>  		return 0;
> >>  
> >> -	if (dev->has_alsa_audio != 1) {
> >> +	if (!dev->has_alsa_audio) {
> >>  		/* This device does not support the extension (in this case
> >>  		   the device is expecting the snd-usb-audio module or
> >>  		   doesn't have analog audio support at all) */
> >> @@ -977,6 +982,7 @@ static int em28xx_audio_fini(struct em28xx *dev)
> >>  		dev->adev.sndcard = NULL;
> >>  	}
> >>  
> >> +	kref_put(&dev->ref, em28xx_free_device);
> >>  	return 0;
> >>  }
> >>  
> >> diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c
> >> index e08d65b2e352..8fc0a437054e 100644
> >> --- a/drivers/media/usb/em28xx/em28xx-cards.c
> >> +++ b/drivers/media/usb/em28xx/em28xx-cards.c
> >> @@ -2867,16 +2867,18 @@ static void flush_request_modules(struct em28xx *dev)
> >>  	flush_work(&dev->request_module_wk);
> >>  }
> >>  
> >> -/*
> >> - * em28xx_release_resources()
> >> - * unregisters the v4l2,i2c and usb devices
> >> - * called when the device gets disconnected or at module unload
> >> -*/
> >> -void em28xx_release_resources(struct em28xx *dev)
> >> +/**
> >> + * em28xx_release_resources() -  unregisters the v4l2,i2c and usb devices
> >> + *
> >> + * @ref: struct kref for em28xx device
> >> + *
> >> + * This is called when all extensions and em28xx core unregisters a device
> >> + */
> >> +void em28xx_free_device(struct kref *ref)
> >>  {
> >> -	/*FIXME: I2C IR should be disconnected */
> >> +	struct em28xx *dev = kref_to_dev(ref);
> >>  
> >> -	mutex_lock(&dev->lock);
> >> +	em28xx_info("Freeing device\n");
> >>  
> >>  	if (dev->def_i2c_bus)
> >>  		em28xx_i2c_unregister(dev, 1);
> >> @@ -2887,9 +2889,10 @@ void em28xx_release_resources(struct em28xx *dev)
> >>  	/* Mark device as unused */
> >>  	clear_bit(dev->devno, &em28xx_devused);
> >>  
> >> -	mutex_unlock(&dev->lock);
> >> -};
> >> -EXPORT_SYMBOL_GPL(em28xx_release_resources);
> >> +	kfree(dev->alt_max_pkt_size_isoc);
> >> +	kfree(dev);
> >> +}
> >> +EXPORT_SYMBOL_GPL(em28xx_free_device);
> > This reintroduces the sysfs group removal warnings.
> > Just keep em28xx_release_resources() as is and add let
> > em28xx_free_device() call the the two kfrees() only.

Calling em28xx_free_device from any subdriver seems wrong, as all subdevs
need it. We should drop it only at the last kref_put().

You should remind that subdrivers can be removed and reinserted any time,
without causing OOPS or other issues.

So, if this is still needed to avoid sysfs warnings, then there's
something else wrong.

> >
> >>  /*
> >>   * em28xx_init_dev()
> >> @@ -3342,6 +3345,8 @@ static int em28xx_usb_probe(struct usb_interface *interface,
> >>  			    dev->dvb_xfer_bulk ? "bulk" : "isoc");
> >>  	}
> >>  
> >> +	kref_init(&dev->ref);
> >> +
> >>  	request_modules(dev);
> >>  
> >>  	/* Should be the last thing to do, to avoid newer udev's to
> >> @@ -3385,12 +3390,7 @@ static void em28xx_usb_disconnect(struct usb_interface *interface)
> >>  
> >>  	em28xx_close_extension(dev);
> >>  
> >> -	em28xx_release_resources(dev);
> > Keep this call (see above).
> >
> >> -
> >> -	if (!dev->users) {
> >> -		kfree(dev->alt_max_pkt_size_isoc);
> >> -		kfree(dev);
> >> -	}
> >> +	kref_put(&dev->ref, em28xx_free_device);
> >>  }
> >>  
> >>  static struct usb_driver em28xx_usb_driver = {
> >> diff --git a/drivers/media/usb/em28xx/em28xx-dvb.c b/drivers/media/usb/em28xx/em28xx-dvb.c
> >> index 881a813836eb..7df21e33a923 100644
> >> --- a/drivers/media/usb/em28xx/em28xx-dvb.c
> >> +++ b/drivers/media/usb/em28xx/em28xx-dvb.c
> >> @@ -1005,11 +1005,11 @@ static int em28xx_dvb_init(struct em28xx *dev)
> >>  	em28xx_info("Binding DVB extension\n");
> >>  
> >>  	dvb = kzalloc(sizeof(struct em28xx_dvb), GFP_KERNEL);
> >> -
> >>  	if (dvb == NULL) {
> >>  		em28xx_info("em28xx_dvb: memory allocation failed\n");
> >>  		return -ENOMEM;
> >>  	}
> >> +	kref_get(&dev->ref);
> > This one needs to be moved between the em28xx_infp() and the kzalloc()
> > call above.
> >
> >>  	dev->dvb = dvb;
> >>  	dvb->fe[0] = dvb->fe[1] = NULL;
> >>  
> >> @@ -1437,6 +1437,7 @@ static int em28xx_dvb_init(struct em28xx *dev)
> >>  	dvb->adapter.mfe_shared = mfe_shared;
> >>  
> >>  	em28xx_info("DVB extension successfully initialized\n");
> >> +
> >>  ret:
> >>  	em28xx_set_mode(dev, EM28XX_SUSPEND);
> >>  	mutex_unlock(&dev->lock);
> >> @@ -1489,6 +1490,8 @@ static int em28xx_dvb_fini(struct em28xx *dev)
> >>  		dev->dvb = NULL;
> >>  	}
> >>  
> >> +	kref_put(&dev->ref, em28xx_free_device);
> >> +
> >>  	return 0;
> >>  }
> >>  
> >> diff --git a/drivers/media/usb/em28xx/em28xx-input.c b/drivers/media/usb/em28xx/em28xx-input.c
> >> index 3d54c04e5230..c98d784a2772 100644
> >> --- a/drivers/media/usb/em28xx/em28xx-input.c
> >> +++ b/drivers/media/usb/em28xx/em28xx-input.c
> >> @@ -675,6 +675,8 @@ static int em28xx_ir_init(struct em28xx *dev)
> >>  		return 0;
> >>  	}
> >>  
> >> +	kref_get(&dev->ref);
> >> +
> >>  	if (dev->board.buttons)
> >>  		em28xx_init_buttons(dev);
> >>  
> >> @@ -817,7 +819,7 @@ static int em28xx_ir_fini(struct em28xx *dev)
> >>  
> >>  	/* skip detach on non attached boards */
> >>  	if (!ir)
> >> -		return 0;
> >> +		goto ref_put;
> >>  
> >>  	if (ir->rc)
> >>  		rc_unregister_device(ir->rc);
> >> @@ -825,6 +827,10 @@ static int em28xx_ir_fini(struct em28xx *dev)
> >>  	/* done */
> >>  	kfree(ir);
> >>  	dev->ir = NULL;
> >> +
> >> +ref_put:
> >> +	kref_put(&dev->ref, em28xx_free_device);
> >> +
> >>  	return 0;
> >>  }
> >>  
> >> diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c
> >> index aabcafbdab46..f801af8d3f61 100644
> >> --- a/drivers/media/usb/em28xx/em28xx-video.c
> >> +++ b/drivers/media/usb/em28xx/em28xx-video.c
> >> @@ -1837,6 +1837,7 @@ static int em28xx_v4l2_open(struct file *filp)
> >>  			video_device_node_name(vdev), v4l2_type_names[fh_type],
> >>  			dev->users);
> >>  
> >> +	kref_get(&dev->ref);
> > The same as with open() in em28xx-alsa:
> > kref_get() needs to be called when we are sure that the function succeeds.
> >
> >>  	if (mutex_lock_interruptible(&dev->lock))
> >>  		return -ERESTARTSYS;
> >> @@ -1926,9 +1927,8 @@ static int em28xx_v4l2_fini(struct em28xx *dev)
> >>  	v4l2_ctrl_handler_free(&dev->ctrl_handler);
> >>  	v4l2_device_unregister(&dev->v4l2_dev);
> >>  
> >> -	if (dev->users)
> >> -		em28xx_warn("Device is open ! Memory deallocation is deferred on last close.\n");
> >>  	mutex_unlock(&dev->lock);
> >> +	kref_put(&dev->ref, em28xx_free_device);
> >>  
> >>  	return 0;
> >>  }
> >> @@ -1950,11 +1950,9 @@ static int em28xx_v4l2_close(struct file *filp)
> >>  	mutex_lock(&dev->lock);
> >>  
> >>  	if (dev->users == 1) {
> >> -		/* free the remaining resources if device is disconnected */
> >> -		if (dev->disconnected) {
> >> -			kfree(dev->alt_max_pkt_size_isoc);
> >> +		/* No sense to try to write to the device */
> >> +		if (dev->disconnected)
> >>  			goto exit;
> >> -		}
> >>  
> >>  		/* Save some power by putting tuner to sleep */
> >>  		v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_power, 0);
> >> @@ -1975,6 +1973,8 @@ static int em28xx_v4l2_close(struct file *filp)
> >>  exit:
> >>  	dev->users--;
> >>  	mutex_unlock(&dev->lock);
> >> +	kref_put(&dev->ref, em28xx_free_device);
> >> +
> >>  	return 0;
> >>  }
> >>  
> >> @@ -2206,6 +2206,8 @@ static int em28xx_v4l2_init(struct em28xx *dev)
> >>  
> >>  	em28xx_info("Registering V4L2 extension\n");
> >>  
> >> +	kref_get(&dev->ref);
> >> +
> >>  	mutex_lock(&dev->lock);
> >>  
> >>  	ret = v4l2_device_register(&dev->udev->dev, &dev->v4l2_dev);
> >> diff --git a/drivers/media/usb/em28xx/em28xx.h b/drivers/media/usb/em28xx/em28xx.h
> >> index 10b817245f7e..8b3438891bb3 100644
> >> --- a/drivers/media/usb/em28xx/em28xx.h
> >> +++ b/drivers/media/usb/em28xx/em28xx.h
> >> @@ -32,6 +32,7 @@
> >>  #include <linux/workqueue.h>
> >>  #include <linux/i2c.h>
> >>  #include <linux/mutex.h>
> >> +#include <linux/kref.h>
> >>  #include <linux/videodev2.h>
> >>  
> >>  #include <media/videobuf2-vmalloc.h>
> >> @@ -533,9 +534,11 @@ struct em28xx_i2c_bus {
> >>  	enum em28xx_i2c_algo_type algo_type;
> >>  };
> >>  
> >> -
> >>  /* main device struct */
> >>  struct em28xx {
> >> +	struct kref ref;
> >> +
> >> +
> > One empty line is enough.
> >
> >>  	/* generic device properties */
> >>  	char name[30];		/* name (including minor) of the device */
> >>  	int model;		/* index in the device_data struct */
> >> @@ -708,6 +711,8 @@ struct em28xx {
> >>  	struct em28xx_dvb *dvb;
> >>  };
> >>  
> >> +#define kref_to_dev(d) container_of(d, struct em28xx, ref)
> >> +
> > I wonder why this macro isn't provided by kref.h.
> >

Because kref doesn't know struct em28xx. 

> >>  struct em28xx_ops {
> >>  	struct list_head next;
> >>  	char *name;
> >> @@ -765,7 +770,7 @@ extern struct em28xx_board em28xx_boards[];
> >>  extern struct usb_device_id em28xx_id_table[];
> >>  int em28xx_tuner_callback(void *ptr, int component, int command, int arg);
> >>  void em28xx_setup_xc3028(struct em28xx *dev, struct xc2028_ctrl *ctl);
> >> -void em28xx_release_resources(struct em28xx *dev);
> >> +void em28xx_free_device(struct kref *ref);
> >>  
> >>  /* Provided by em28xx-camera.c */
> >>  int em28xx_detect_sensor(struct em28xx *dev);
> > I've made several tests with my devices and I'm facing some issues with
> > the current media-tree (e.g. a kernel panic with a hard lockup when
> > reconnecting the laplace webcam).
> > But none of them seems to be related to this change.
> > Anyway, when we're finished with it, we need to stabilize things...
> Ping !
> Are you going to continue working on this patch ?
> I've planned to come up with some follow-up changes... ;-)

Yes, but I'm currently without time to do your proposal changes and
test, as I'm in a 2-week business trip. I didn't bring any test machine.

If you want, I can commit this one as-is, and you can do your
proposed changes on a separate patch.

> 
> Regards,
> Frank


-- 

Cheers,
Mauro

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH v2] em28xx: Only deallocate struct em28xx after finishing all extensions
  2014-02-09 20:09         ` Mauro Carvalho Chehab
@ 2014-02-12 18:00           ` Frank Schäfer
  2014-03-05 14:22             ` [PATCH v3] " Mauro Carvalho Chehab
  0 siblings, 1 reply; 40+ messages in thread
From: Frank Schäfer @ 2014-02-12 18:00 UTC (permalink / raw)
  To: Mauro Carvalho Chehab; +Cc: Linux Media Mailing List, Mauro Carvalho Chehab


Am 09.02.2014 21:09, schrieb Mauro Carvalho Chehab:
>> Ping !
>> > Are you going to continue working on this patch ?
>> > I've planned to come up with some follow-up changes... ;-)
> Yes, but I'm currently without time to do your proposal changes and
> test, as I'm in a 2-week business trip. I didn't bring any test machine.
Ok, good to know.

> If you want, I can commit this one as-is, and you can do your
> proposed changes on a separate patch.
No problem, I can wait.
The current version of the patch would reintroduce the sysfs group
warnings, so I think its safer to do the changes all at once.

Regards,
Frank

^ permalink raw reply	[flat|nested] 40+ messages in thread

* [PATCH v3] em28xx: Only deallocate struct em28xx after finishing all extensions
  2014-02-12 18:00           ` Frank Schäfer
@ 2014-03-05 14:22             ` Mauro Carvalho Chehab
  2014-03-07 17:04               ` Frank Schäfer
  0 siblings, 1 reply; 40+ messages in thread
From: Mauro Carvalho Chehab @ 2014-03-05 14:22 UTC (permalink / raw)
  To: Frank Schäfer
  Cc: Mauro Carvalho Chehab, Linux Media Mailing List,
	Mauro Carvalho Chehab

We can't free struct em28xx while one of the extensions is still
using it.

So, add a kref() to control it, freeing it only after the
extensions fini calls.

Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
---
 drivers/media/usb/em28xx/em28xx-audio.c |  7 ++++++-
 drivers/media/usb/em28xx/em28xx-cards.c | 31 ++++++++++++++++++++++++-------
 drivers/media/usb/em28xx/em28xx-dvb.c   |  6 +++++-
 drivers/media/usb/em28xx/em28xx-input.c |  8 +++++++-
 drivers/media/usb/em28xx/em28xx-video.c | 15 ++++++++-------
 drivers/media/usb/em28xx/em28xx.h       |  8 ++++++--
 6 files changed, 56 insertions(+), 19 deletions(-)

diff --git a/drivers/media/usb/em28xx/em28xx-audio.c b/drivers/media/usb/em28xx/em28xx-audio.c
index 0f5b6f3e7a3f..f75c0a5494d6 100644
--- a/drivers/media/usb/em28xx/em28xx-audio.c
+++ b/drivers/media/usb/em28xx/em28xx-audio.c
@@ -301,6 +301,7 @@ static int snd_em28xx_capture_open(struct snd_pcm_substream *substream)
 			goto err;
 	}
 
+	kref_get(&dev->ref);
 	dev->adev.users++;
 	mutex_unlock(&dev->lock);
 
@@ -341,6 +342,7 @@ static int snd_em28xx_pcm_close(struct snd_pcm_substream *substream)
 		substream->runtime->dma_area = NULL;
 	}
 	mutex_unlock(&dev->lock);
+	kref_put(&dev->ref, em28xx_free_device);
 
 	return 0;
 }
@@ -895,6 +897,8 @@ static int em28xx_audio_init(struct em28xx *dev)
 
 	em28xx_info("Binding audio extension\n");
 
+	kref_get(&dev->ref);
+
 	printk(KERN_INFO "em28xx-audio.c: Copyright (C) 2006 Markus "
 			 "Rechberger\n");
 	printk(KERN_INFO
@@ -967,7 +971,7 @@ static int em28xx_audio_fini(struct em28xx *dev)
 	if (dev == NULL)
 		return 0;
 
-	if (dev->has_alsa_audio != 1) {
+	if (!dev->has_alsa_audio) {
 		/* This device does not support the extension (in this case
 		   the device is expecting the snd-usb-audio module or
 		   doesn't have analog audio support at all) */
@@ -986,6 +990,7 @@ static int em28xx_audio_fini(struct em28xx *dev)
 		dev->adev.sndcard = NULL;
 	}
 
+	kref_put(&dev->ref, em28xx_free_device);
 	return 0;
 }
 
diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c
index 2fb300e882f0..512448b757c9 100644
--- a/drivers/media/usb/em28xx/em28xx-cards.c
+++ b/drivers/media/usb/em28xx/em28xx-cards.c
@@ -2939,7 +2939,7 @@ static void flush_request_modules(struct em28xx *dev)
  * unregisters the v4l2,i2c and usb devices
  * called when the device gets disconnected or at module unload
 */
-void em28xx_release_resources(struct em28xx *dev)
+static void em28xx_release_resources(struct em28xx *dev)
 {
 	/*FIXME: I2C IR should be disconnected */
 
@@ -2956,7 +2956,26 @@ void em28xx_release_resources(struct em28xx *dev)
 
 	mutex_unlock(&dev->lock);
 };
-EXPORT_SYMBOL_GPL(em28xx_release_resources);
+
+/**
+ * em28xx_free_defice() - Free em28xx device
+ *
+ * @ref: struct kref for em28xx device
+ *
+ * This is called when all extensions and em28xx core unregisters a device
+ */
+void em28xx_free_device(struct kref *ref)
+{
+	struct em28xx *dev = kref_to_dev(ref);
+
+	em28xx_info("Freeing device\n");
+
+	if (!dev->disconnected)
+		em28xx_release_resources(dev);
+
+	kfree(dev->alt_max_pkt_size_isoc);
+	kfree(dev);
+}
 
 /*
  * em28xx_init_dev()
@@ -3409,6 +3428,8 @@ static int em28xx_usb_probe(struct usb_interface *interface,
 			    dev->dvb_xfer_bulk ? "bulk" : "isoc");
 	}
 
+	kref_init(&dev->ref);
+
 	request_modules(dev);
 
 	/* Should be the last thing to do, to avoid newer udev's to
@@ -3453,11 +3474,7 @@ static void em28xx_usb_disconnect(struct usb_interface *interface)
 	em28xx_close_extension(dev);
 
 	em28xx_release_resources(dev);
-
-	if (!dev->users) {
-		kfree(dev->alt_max_pkt_size_isoc);
-		kfree(dev);
-	}
+	kref_put(&dev->ref, em28xx_free_device);
 }
 
 static int em28xx_usb_suspend(struct usb_interface *interface,
diff --git a/drivers/media/usb/em28xx/em28xx-dvb.c b/drivers/media/usb/em28xx/em28xx-dvb.c
index d4986bdfbdc3..6dbc71ba2820 100644
--- a/drivers/media/usb/em28xx/em28xx-dvb.c
+++ b/drivers/media/usb/em28xx/em28xx-dvb.c
@@ -1043,7 +1043,6 @@ static int em28xx_dvb_init(struct em28xx *dev)
 	em28xx_info("Binding DVB extension\n");
 
 	dvb = kzalloc(sizeof(struct em28xx_dvb), GFP_KERNEL);
-
 	if (dvb == NULL) {
 		em28xx_info("em28xx_dvb: memory allocation failed\n");
 		return -ENOMEM;
@@ -1521,6 +1520,9 @@ static int em28xx_dvb_init(struct em28xx *dev)
 	dvb->adapter.mfe_shared = mfe_shared;
 
 	em28xx_info("DVB extension successfully initialized\n");
+
+	kref_get(&dev->ref);
+
 ret:
 	em28xx_set_mode(dev, EM28XX_SUSPEND);
 	mutex_unlock(&dev->lock);
@@ -1579,6 +1581,8 @@ static int em28xx_dvb_fini(struct em28xx *dev)
 		dev->dvb = NULL;
 	}
 
+	kref_put(&dev->ref, em28xx_free_device);
+
 	return 0;
 }
 
diff --git a/drivers/media/usb/em28xx/em28xx-input.c b/drivers/media/usb/em28xx/em28xx-input.c
index 47a2c1dcccbf..2a9bf667f208 100644
--- a/drivers/media/usb/em28xx/em28xx-input.c
+++ b/drivers/media/usb/em28xx/em28xx-input.c
@@ -676,6 +676,8 @@ static int em28xx_ir_init(struct em28xx *dev)
 		return 0;
 	}
 
+	kref_get(&dev->ref);
+
 	if (dev->board.buttons)
 		em28xx_init_buttons(dev);
 
@@ -816,7 +818,7 @@ static int em28xx_ir_fini(struct em28xx *dev)
 
 	/* skip detach on non attached boards */
 	if (!ir)
-		return 0;
+		goto ref_put;
 
 	if (ir->rc)
 		rc_unregister_device(ir->rc);
@@ -824,6 +826,10 @@ static int em28xx_ir_fini(struct em28xx *dev)
 	/* done */
 	kfree(ir);
 	dev->ir = NULL;
+
+ref_put:
+	kref_put(&dev->ref, em28xx_free_device);
+
 	return 0;
 }
 
diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c
index 19af6b3e9e2b..32aa55f033fc 100644
--- a/drivers/media/usb/em28xx/em28xx-video.c
+++ b/drivers/media/usb/em28xx/em28xx-video.c
@@ -1837,7 +1837,6 @@ static int em28xx_v4l2_open(struct file *filp)
 			video_device_node_name(vdev), v4l2_type_names[fh_type],
 			dev->users);
 
-
 	if (mutex_lock_interruptible(&dev->lock))
 		return -ERESTARTSYS;
 	fh = kzalloc(sizeof(struct em28xx_fh), GFP_KERNEL);
@@ -1869,6 +1868,7 @@ static int em28xx_v4l2_open(struct file *filp)
 		v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_radio);
 	}
 
+	kref_get(&dev->ref);
 	dev->users++;
 
 	mutex_unlock(&dev->lock);
@@ -1926,9 +1926,8 @@ static int em28xx_v4l2_fini(struct em28xx *dev)
 		dev->clk = NULL;
 	}
 
-	if (dev->users)
-		em28xx_warn("Device is open ! Memory deallocation is deferred on last close.\n");
 	mutex_unlock(&dev->lock);
+	kref_put(&dev->ref, em28xx_free_device);
 
 	return 0;
 }
@@ -1976,11 +1975,9 @@ static int em28xx_v4l2_close(struct file *filp)
 	mutex_lock(&dev->lock);
 
 	if (dev->users == 1) {
-		/* free the remaining resources if device is disconnected */
-		if (dev->disconnected) {
-			kfree(dev->alt_max_pkt_size_isoc);
+		/* No sense to try to write to the device */
+		if (dev->disconnected)
 			goto exit;
-		}
 
 		/* Save some power by putting tuner to sleep */
 		v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_power, 0);
@@ -2001,6 +1998,8 @@ static int em28xx_v4l2_close(struct file *filp)
 exit:
 	dev->users--;
 	mutex_unlock(&dev->lock);
+	kref_put(&dev->ref, em28xx_free_device);
+
 	return 0;
 }
 
@@ -2515,6 +2514,8 @@ static int em28xx_v4l2_init(struct em28xx *dev)
 
 	em28xx_info("V4L2 extension successfully initialized\n");
 
+	kref_get(&dev->ref);
+
 	mutex_unlock(&dev->lock);
 	return 0;
 
diff --git a/drivers/media/usb/em28xx/em28xx.h b/drivers/media/usb/em28xx/em28xx.h
index 9e44f5bfc48b..2051fc9fb932 100644
--- a/drivers/media/usb/em28xx/em28xx.h
+++ b/drivers/media/usb/em28xx/em28xx.h
@@ -32,6 +32,7 @@
 #include <linux/workqueue.h>
 #include <linux/i2c.h>
 #include <linux/mutex.h>
+#include <linux/kref.h>
 #include <linux/videodev2.h>
 
 #include <media/videobuf2-vmalloc.h>
@@ -536,9 +537,10 @@ struct em28xx_i2c_bus {
 	enum em28xx_i2c_algo_type algo_type;
 };
 
-
 /* main device struct */
 struct em28xx {
+	struct kref ref;
+
 	/* generic device properties */
 	char name[30];		/* name (including minor) of the device */
 	int model;		/* index in the device_data struct */
@@ -710,6 +712,8 @@ struct em28xx {
 	struct em28xx_dvb *dvb;
 };
 
+#define kref_to_dev(d) container_of(d, struct em28xx, ref)
+
 struct em28xx_ops {
 	struct list_head next;
 	char *name;
@@ -771,7 +775,7 @@ extern struct em28xx_board em28xx_boards[];
 extern struct usb_device_id em28xx_id_table[];
 int em28xx_tuner_callback(void *ptr, int component, int command, int arg);
 void em28xx_setup_xc3028(struct em28xx *dev, struct xc2028_ctrl *ctl);
-void em28xx_release_resources(struct em28xx *dev);
+void em28xx_free_device(struct kref *ref);
 
 /* Provided by em28xx-camera.c */
 int em28xx_detect_sensor(struct em28xx *dev);
-- 
1.8.5.3


^ permalink raw reply related	[flat|nested] 40+ messages in thread

* Re: [PATCH v3] em28xx: Only deallocate struct em28xx after finishing all extensions
  2014-03-05 14:22             ` [PATCH v3] " Mauro Carvalho Chehab
@ 2014-03-07 17:04               ` Frank Schäfer
  2014-03-07 17:38                 ` Mauro Carvalho Chehab
  0 siblings, 1 reply; 40+ messages in thread
From: Frank Schäfer @ 2014-03-07 17:04 UTC (permalink / raw)
  To: Mauro Carvalho Chehab; +Cc: Linux Media Mailing List, Mauro Carvalho Chehab


Am 05.03.2014 15:22, schrieb Mauro Carvalho Chehab:
> We can't free struct em28xx while one of the extensions is still
> using it.
>
> So, add a kref() to control it, freeing it only after the
> extensions fini calls.
>
> Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
> ---
>  drivers/media/usb/em28xx/em28xx-audio.c |  7 ++++++-
>  drivers/media/usb/em28xx/em28xx-cards.c | 31 ++++++++++++++++++++++++-------
>  drivers/media/usb/em28xx/em28xx-dvb.c   |  6 +++++-
>  drivers/media/usb/em28xx/em28xx-input.c |  8 +++++++-
>  drivers/media/usb/em28xx/em28xx-video.c | 15 ++++++++-------
>  drivers/media/usb/em28xx/em28xx.h       |  8 ++++++--
>  6 files changed, 56 insertions(+), 19 deletions(-)
>
> diff --git a/drivers/media/usb/em28xx/em28xx-audio.c b/drivers/media/usb/em28xx/em28xx-audio.c
> index 0f5b6f3e7a3f..f75c0a5494d6 100644
> --- a/drivers/media/usb/em28xx/em28xx-audio.c
> +++ b/drivers/media/usb/em28xx/em28xx-audio.c
> @@ -301,6 +301,7 @@ static int snd_em28xx_capture_open(struct snd_pcm_substream *substream)
>  			goto err;
>  	}
>  
> +	kref_get(&dev->ref);
>  	dev->adev.users++;
>  	mutex_unlock(&dev->lock);
>  
> @@ -341,6 +342,7 @@ static int snd_em28xx_pcm_close(struct snd_pcm_substream *substream)
>  		substream->runtime->dma_area = NULL;
>  	}
>  	mutex_unlock(&dev->lock);
> +	kref_put(&dev->ref, em28xx_free_device);
>  
>  	return 0;
>  }
> @@ -895,6 +897,8 @@ static int em28xx_audio_init(struct em28xx *dev)
>  
>  	em28xx_info("Binding audio extension\n");
>  
> +	kref_get(&dev->ref);
> +
>  	printk(KERN_INFO "em28xx-audio.c: Copyright (C) 2006 Markus "
>  			 "Rechberger\n");
>  	printk(KERN_INFO
> @@ -967,7 +971,7 @@ static int em28xx_audio_fini(struct em28xx *dev)
>  	if (dev == NULL)
>  		return 0;
>  
> -	if (dev->has_alsa_audio != 1) {
> +	if (!dev->has_alsa_audio) {
>  		/* This device does not support the extension (in this case
>  		   the device is expecting the snd-usb-audio module or
>  		   doesn't have analog audio support at all) */
> @@ -986,6 +990,7 @@ static int em28xx_audio_fini(struct em28xx *dev)
>  		dev->adev.sndcard = NULL;
>  	}
>  
> +	kref_put(&dev->ref, em28xx_free_device);
>  	return 0;
>  }
>  
> diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c
> index 2fb300e882f0..512448b757c9 100644
> --- a/drivers/media/usb/em28xx/em28xx-cards.c
> +++ b/drivers/media/usb/em28xx/em28xx-cards.c
> @@ -2939,7 +2939,7 @@ static void flush_request_modules(struct em28xx *dev)
>   * unregisters the v4l2,i2c and usb devices
>   * called when the device gets disconnected or at module unload
>  */
> -void em28xx_release_resources(struct em28xx *dev)
> +static void em28xx_release_resources(struct em28xx *dev)
>  {
>  	/*FIXME: I2C IR should be disconnected */
>  
> @@ -2956,7 +2956,26 @@ void em28xx_release_resources(struct em28xx *dev)
>  
>  	mutex_unlock(&dev->lock);
>  };
> -EXPORT_SYMBOL_GPL(em28xx_release_resources);
> +
> +/**
> + * em28xx_free_defice() - Free em28xx device
> + *
> + * @ref: struct kref for em28xx device
> + *
> + * This is called when all extensions and em28xx core unregisters a device
> + */
> +void em28xx_free_device(struct kref *ref)
> +{
> +	struct em28xx *dev = kref_to_dev(ref);
> +
> +	em28xx_info("Freeing device\n");
> +
> +	if (!dev->disconnected)
> +		em28xx_release_resources(dev);
Hmm... good catch !

> +
> +	kfree(dev->alt_max_pkt_size_isoc);
> +	kfree(dev);
> +}
>  
>  /*
>   * em28xx_init_dev()
> @@ -3409,6 +3428,8 @@ static int em28xx_usb_probe(struct usb_interface *interface,
>  			    dev->dvb_xfer_bulk ? "bulk" : "isoc");
>  	}
>  
> +	kref_init(&dev->ref);
> +
>  	request_modules(dev);
>  
>  	/* Should be the last thing to do, to avoid newer udev's to
> @@ -3453,11 +3474,7 @@ static void em28xx_usb_disconnect(struct usb_interface *interface)
>  	em28xx_close_extension(dev);
>  
>  	em28xx_release_resources(dev);
> -
> -	if (!dev->users) {
> -		kfree(dev->alt_max_pkt_size_isoc);
> -		kfree(dev);
> -	}
> +	kref_put(&dev->ref, em28xx_free_device);
>  }
>  
>  static int em28xx_usb_suspend(struct usb_interface *interface,
> diff --git a/drivers/media/usb/em28xx/em28xx-dvb.c b/drivers/media/usb/em28xx/em28xx-dvb.c
> index d4986bdfbdc3..6dbc71ba2820 100644
> --- a/drivers/media/usb/em28xx/em28xx-dvb.c
> +++ b/drivers/media/usb/em28xx/em28xx-dvb.c
> @@ -1043,7 +1043,6 @@ static int em28xx_dvb_init(struct em28xx *dev)
>  	em28xx_info("Binding DVB extension\n");
>  
>  	dvb = kzalloc(sizeof(struct em28xx_dvb), GFP_KERNEL);
> -
>  	if (dvb == NULL) {
>  		em28xx_info("em28xx_dvb: memory allocation failed\n");
>  		return -ENOMEM;
> @@ -1521,6 +1520,9 @@ static int em28xx_dvb_init(struct em28xx *dev)
>  	dvb->adapter.mfe_shared = mfe_shared;
>  
>  	em28xx_info("DVB extension successfully initialized\n");
> +
> +	kref_get(&dev->ref);
> +

The fini() functions are always called, even if an error occured in init().
So (in opposition to the open()/close() functions) kref_get() needs to
be called at the beginning of the init() methods.

"dev->is_audio_only" and "!dev->board.has_dvb" is checked in both
functions (init+fini), so the right place here is one line before or after

    em28xx_info("Binding DVB extension\n");


Everything else looks good.

Regards,
Frank

>  ret:
>  	em28xx_set_mode(dev, EM28XX_SUSPEND);
>  	mutex_unlock(&dev->lock);
> @@ -1579,6 +1581,8 @@ static int em28xx_dvb_fini(struct em28xx *dev)
>  		dev->dvb = NULL;
>  	}
>  
> +	kref_put(&dev->ref, em28xx_free_device);
> +
>  	return 0;
>  }
>  
> diff --git a/drivers/media/usb/em28xx/em28xx-input.c b/drivers/media/usb/em28xx/em28xx-input.c
> index 47a2c1dcccbf..2a9bf667f208 100644
> --- a/drivers/media/usb/em28xx/em28xx-input.c
> +++ b/drivers/media/usb/em28xx/em28xx-input.c
> @@ -676,6 +676,8 @@ static int em28xx_ir_init(struct em28xx *dev)
>  		return 0;
>  	}
>  
> +	kref_get(&dev->ref);
> +
>  	if (dev->board.buttons)
>  		em28xx_init_buttons(dev);
>  
> @@ -816,7 +818,7 @@ static int em28xx_ir_fini(struct em28xx *dev)
>  
>  	/* skip detach on non attached boards */
>  	if (!ir)
> -		return 0;
> +		goto ref_put;
>  
>  	if (ir->rc)
>  		rc_unregister_device(ir->rc);
> @@ -824,6 +826,10 @@ static int em28xx_ir_fini(struct em28xx *dev)
>  	/* done */
>  	kfree(ir);
>  	dev->ir = NULL;
> +
> +ref_put:
> +	kref_put(&dev->ref, em28xx_free_device);
> +
>  	return 0;
>  }
>  
> diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c
> index 19af6b3e9e2b..32aa55f033fc 100644
> --- a/drivers/media/usb/em28xx/em28xx-video.c
> +++ b/drivers/media/usb/em28xx/em28xx-video.c
> @@ -1837,7 +1837,6 @@ static int em28xx_v4l2_open(struct file *filp)
>  			video_device_node_name(vdev), v4l2_type_names[fh_type],
>  			dev->users);
>  
> -
>  	if (mutex_lock_interruptible(&dev->lock))
>  		return -ERESTARTSYS;
>  	fh = kzalloc(sizeof(struct em28xx_fh), GFP_KERNEL);
> @@ -1869,6 +1868,7 @@ static int em28xx_v4l2_open(struct file *filp)
>  		v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_radio);
>  	}
>  
> +	kref_get(&dev->ref);
>  	dev->users++;
>  
>  	mutex_unlock(&dev->lock);
> @@ -1926,9 +1926,8 @@ static int em28xx_v4l2_fini(struct em28xx *dev)
>  		dev->clk = NULL;
>  	}
>  
> -	if (dev->users)
> -		em28xx_warn("Device is open ! Memory deallocation is deferred on last close.\n");
>  	mutex_unlock(&dev->lock);
> +	kref_put(&dev->ref, em28xx_free_device);
>  
>  	return 0;
>  }
> @@ -1976,11 +1975,9 @@ static int em28xx_v4l2_close(struct file *filp)
>  	mutex_lock(&dev->lock);
>  
>  	if (dev->users == 1) {
> -		/* free the remaining resources if device is disconnected */
> -		if (dev->disconnected) {
> -			kfree(dev->alt_max_pkt_size_isoc);
> +		/* No sense to try to write to the device */
> +		if (dev->disconnected)
>  			goto exit;
> -		}
>  
>  		/* Save some power by putting tuner to sleep */
>  		v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_power, 0);
> @@ -2001,6 +1998,8 @@ static int em28xx_v4l2_close(struct file *filp)
>  exit:
>  	dev->users--;
>  	mutex_unlock(&dev->lock);
> +	kref_put(&dev->ref, em28xx_free_device);
> +
>  	return 0;
>  }
>  
> @@ -2515,6 +2514,8 @@ static int em28xx_v4l2_init(struct em28xx *dev)
>  
>  	em28xx_info("V4L2 extension successfully initialized\n");
>  
> +	kref_get(&dev->ref);
> +
>  	mutex_unlock(&dev->lock);
>  	return 0;
>  
> diff --git a/drivers/media/usb/em28xx/em28xx.h b/drivers/media/usb/em28xx/em28xx.h
> index 9e44f5bfc48b..2051fc9fb932 100644
> --- a/drivers/media/usb/em28xx/em28xx.h
> +++ b/drivers/media/usb/em28xx/em28xx.h
> @@ -32,6 +32,7 @@
>  #include <linux/workqueue.h>
>  #include <linux/i2c.h>
>  #include <linux/mutex.h>
> +#include <linux/kref.h>
>  #include <linux/videodev2.h>
>  
>  #include <media/videobuf2-vmalloc.h>
> @@ -536,9 +537,10 @@ struct em28xx_i2c_bus {
>  	enum em28xx_i2c_algo_type algo_type;
>  };
>  
> -
>  /* main device struct */
>  struct em28xx {
> +	struct kref ref;
> +
>  	/* generic device properties */
>  	char name[30];		/* name (including minor) of the device */
>  	int model;		/* index in the device_data struct */
> @@ -710,6 +712,8 @@ struct em28xx {
>  	struct em28xx_dvb *dvb;
>  };
>  
> +#define kref_to_dev(d) container_of(d, struct em28xx, ref)
> +
>  struct em28xx_ops {
>  	struct list_head next;
>  	char *name;
> @@ -771,7 +775,7 @@ extern struct em28xx_board em28xx_boards[];
>  extern struct usb_device_id em28xx_id_table[];
>  int em28xx_tuner_callback(void *ptr, int component, int command, int arg);
>  void em28xx_setup_xc3028(struct em28xx *dev, struct xc2028_ctrl *ctl);
> -void em28xx_release_resources(struct em28xx *dev);
> +void em28xx_free_device(struct kref *ref);
>  
>  /* Provided by em28xx-camera.c */
>  int em28xx_detect_sensor(struct em28xx *dev);


^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH v3] em28xx: Only deallocate struct em28xx after finishing all extensions
  2014-03-07 17:04               ` Frank Schäfer
@ 2014-03-07 17:38                 ` Mauro Carvalho Chehab
  2014-03-08 10:51                   ` Frank Schäfer
  0 siblings, 1 reply; 40+ messages in thread
From: Mauro Carvalho Chehab @ 2014-03-07 17:38 UTC (permalink / raw)
  To: Frank Schäfer; +Cc: Linux Media Mailing List, Mauro Carvalho Chehab

Em Fri, 07 Mar 2014 18:04:52 +0100
Frank Schäfer <fschaefer.oss@googlemail.com> escreveu:

> 
> Am 05.03.2014 15:22, schrieb Mauro Carvalho Chehab:
> > We can't free struct em28xx while one of the extensions is still
> > using it.
> >
> > So, add a kref() to control it, freeing it only after the
> > extensions fini calls.
> >
> > Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
> > ---
> >  drivers/media/usb/em28xx/em28xx-audio.c |  7 ++++++-
> >  drivers/media/usb/em28xx/em28xx-cards.c | 31 ++++++++++++++++++++++++-------
> >  drivers/media/usb/em28xx/em28xx-dvb.c   |  6 +++++-
> >  drivers/media/usb/em28xx/em28xx-input.c |  8 +++++++-
> >  drivers/media/usb/em28xx/em28xx-video.c | 15 ++++++++-------
> >  drivers/media/usb/em28xx/em28xx.h       |  8 ++++++--
> >  6 files changed, 56 insertions(+), 19 deletions(-)
> >
> > diff --git a/drivers/media/usb/em28xx/em28xx-audio.c b/drivers/media/usb/em28xx/em28xx-audio.c
> > index 0f5b6f3e7a3f..f75c0a5494d6 100644
> > --- a/drivers/media/usb/em28xx/em28xx-audio.c
> > +++ b/drivers/media/usb/em28xx/em28xx-audio.c
> > @@ -301,6 +301,7 @@ static int snd_em28xx_capture_open(struct snd_pcm_substream *substream)
> >  			goto err;
> >  	}
> >  
> > +	kref_get(&dev->ref);
> >  	dev->adev.users++;
> >  	mutex_unlock(&dev->lock);
> >  
> > @@ -341,6 +342,7 @@ static int snd_em28xx_pcm_close(struct snd_pcm_substream *substream)
> >  		substream->runtime->dma_area = NULL;
> >  	}
> >  	mutex_unlock(&dev->lock);
> > +	kref_put(&dev->ref, em28xx_free_device);
> >  
> >  	return 0;
> >  }
> > @@ -895,6 +897,8 @@ static int em28xx_audio_init(struct em28xx *dev)
> >  
> >  	em28xx_info("Binding audio extension\n");
> >  
> > +	kref_get(&dev->ref);
> > +
> >  	printk(KERN_INFO "em28xx-audio.c: Copyright (C) 2006 Markus "
> >  			 "Rechberger\n");
> >  	printk(KERN_INFO
> > @@ -967,7 +971,7 @@ static int em28xx_audio_fini(struct em28xx *dev)
> >  	if (dev == NULL)
> >  		return 0;
> >  
> > -	if (dev->has_alsa_audio != 1) {
> > +	if (!dev->has_alsa_audio) {
> >  		/* This device does not support the extension (in this case
> >  		   the device is expecting the snd-usb-audio module or
> >  		   doesn't have analog audio support at all) */
> > @@ -986,6 +990,7 @@ static int em28xx_audio_fini(struct em28xx *dev)
> >  		dev->adev.sndcard = NULL;
> >  	}
> >  
> > +	kref_put(&dev->ref, em28xx_free_device);
> >  	return 0;
> >  }
> >  
> > diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c
> > index 2fb300e882f0..512448b757c9 100644
> > --- a/drivers/media/usb/em28xx/em28xx-cards.c
> > +++ b/drivers/media/usb/em28xx/em28xx-cards.c
> > @@ -2939,7 +2939,7 @@ static void flush_request_modules(struct em28xx *dev)
> >   * unregisters the v4l2,i2c and usb devices
> >   * called when the device gets disconnected or at module unload
> >  */
> > -void em28xx_release_resources(struct em28xx *dev)
> > +static void em28xx_release_resources(struct em28xx *dev)
> >  {
> >  	/*FIXME: I2C IR should be disconnected */
> >  
> > @@ -2956,7 +2956,26 @@ void em28xx_release_resources(struct em28xx *dev)
> >  
> >  	mutex_unlock(&dev->lock);
> >  };
> > -EXPORT_SYMBOL_GPL(em28xx_release_resources);
> > +
> > +/**
> > + * em28xx_free_defice() - Free em28xx device
> > + *
> > + * @ref: struct kref for em28xx device
> > + *
> > + * This is called when all extensions and em28xx core unregisters a device
> > + */
> > +void em28xx_free_device(struct kref *ref)
> > +{
> > +	struct em28xx *dev = kref_to_dev(ref);
> > +
> > +	em28xx_info("Freeing device\n");
> > +
> > +	if (!dev->disconnected)
> > +		em28xx_release_resources(dev);
> Hmm... good catch !
> 
> > +
> > +	kfree(dev->alt_max_pkt_size_isoc);
> > +	kfree(dev);
> > +}
> >  
> >  /*
> >   * em28xx_init_dev()
> > @@ -3409,6 +3428,8 @@ static int em28xx_usb_probe(struct usb_interface *interface,
> >  			    dev->dvb_xfer_bulk ? "bulk" : "isoc");
> >  	}
> >  
> > +	kref_init(&dev->ref);
> > +
> >  	request_modules(dev);
> >  
> >  	/* Should be the last thing to do, to avoid newer udev's to
> > @@ -3453,11 +3474,7 @@ static void em28xx_usb_disconnect(struct usb_interface *interface)
> >  	em28xx_close_extension(dev);
> >  
> >  	em28xx_release_resources(dev);
> > -
> > -	if (!dev->users) {
> > -		kfree(dev->alt_max_pkt_size_isoc);
> > -		kfree(dev);
> > -	}
> > +	kref_put(&dev->ref, em28xx_free_device);
> >  }
> >  
> >  static int em28xx_usb_suspend(struct usb_interface *interface,
> > diff --git a/drivers/media/usb/em28xx/em28xx-dvb.c b/drivers/media/usb/em28xx/em28xx-dvb.c
> > index d4986bdfbdc3..6dbc71ba2820 100644
> > --- a/drivers/media/usb/em28xx/em28xx-dvb.c
> > +++ b/drivers/media/usb/em28xx/em28xx-dvb.c
> > @@ -1043,7 +1043,6 @@ static int em28xx_dvb_init(struct em28xx *dev)
> >  	em28xx_info("Binding DVB extension\n");
> >  
> >  	dvb = kzalloc(sizeof(struct em28xx_dvb), GFP_KERNEL);
> > -
> >  	if (dvb == NULL) {
> >  		em28xx_info("em28xx_dvb: memory allocation failed\n");
> >  		return -ENOMEM;
> > @@ -1521,6 +1520,9 @@ static int em28xx_dvb_init(struct em28xx *dev)
> >  	dvb->adapter.mfe_shared = mfe_shared;
> >  
> >  	em28xx_info("DVB extension successfully initialized\n");
> > +
> > +	kref_get(&dev->ref);
> > +
> 
> The fini() functions are always called, even if an error occured in init().
> So (in opposition to the open()/close() functions) kref_get() needs to
> be called at the beginning of the init() methods.
> 
> "dev->is_audio_only" and "!dev->board.has_dvb" is checked in both
> functions (init+fini), so the right place here is one line before or after
> 
>     em28xx_info("Binding DVB extension\n");
> 
> 
> Everything else looks good.

I actually prefer to fix it the other way, at the code for kref_put()...
see below

> 
> Regards,
> Frank
> 
> >  ret:
> >  	em28xx_set_mode(dev, EM28XX_SUSPEND);
> >  	mutex_unlock(&dev->lock);
> > @@ -1579,6 +1581,8 @@ static int em28xx_dvb_fini(struct em28xx *dev)
> >  		dev->dvb = NULL;

Putting the kref_put() here. This part of the code is only called if
dev->dvb it not NULL, and this is only possible to happen if the
DVB is properly initialized.

> >  	}
> >  
> > +	kref_put(&dev->ref, em28xx_free_device);
> > +
> >  	return 0;
> >  }
> >  
> > diff --git a/drivers/media/usb/em28xx/em28xx-input.c b/drivers/media/usb/em28xx/em28xx-input.c
> > index 47a2c1dcccbf..2a9bf667f208 100644
> > --- a/drivers/media/usb/em28xx/em28xx-input.c
> > +++ b/drivers/media/usb/em28xx/em28xx-input.c
> > @@ -676,6 +676,8 @@ static int em28xx_ir_init(struct em28xx *dev)
> >  		return 0;
> >  	}
> >  
> > +	kref_get(&dev->ref);
> > +
> >  	if (dev->board.buttons)
> >  		em28xx_init_buttons(dev);
> >  
> > @@ -816,7 +818,7 @@ static int em28xx_ir_fini(struct em28xx *dev)
> >  
> >  	/* skip detach on non attached boards */
> >  	if (!ir)
> > -		return 0;
> > +		goto ref_put;
> >  
> >  	if (ir->rc)
> >  		rc_unregister_device(ir->rc);
> > @@ -824,6 +826,10 @@ static int em28xx_ir_fini(struct em28xx *dev)
> >  	/* done */
> >  	kfree(ir);
> >  	dev->ir = NULL;
> > +
> > +ref_put:
> > +	kref_put(&dev->ref, em28xx_free_device);
> > +
> >  	return 0;
> >  }
> >  
> > diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c
> > index 19af6b3e9e2b..32aa55f033fc 100644
> > --- a/drivers/media/usb/em28xx/em28xx-video.c
> > +++ b/drivers/media/usb/em28xx/em28xx-video.c
> > @@ -1837,7 +1837,6 @@ static int em28xx_v4l2_open(struct file *filp)
> >  			video_device_node_name(vdev), v4l2_type_names[fh_type],
> >  			dev->users);
> >  
> > -
> >  	if (mutex_lock_interruptible(&dev->lock))
> >  		return -ERESTARTSYS;
> >  	fh = kzalloc(sizeof(struct em28xx_fh), GFP_KERNEL);
> > @@ -1869,6 +1868,7 @@ static int em28xx_v4l2_open(struct file *filp)
> >  		v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_radio);
> >  	}
> >  
> > +	kref_get(&dev->ref);
> >  	dev->users++;
> >  
> >  	mutex_unlock(&dev->lock);
> > @@ -1926,9 +1926,8 @@ static int em28xx_v4l2_fini(struct em28xx *dev)
> >  		dev->clk = NULL;
> >  	}
> >  
> > -	if (dev->users)
> > -		em28xx_warn("Device is open ! Memory deallocation is deferred on last close.\n");
> >  	mutex_unlock(&dev->lock);
> > +	kref_put(&dev->ref, em28xx_free_device);
> >  
> >  	return 0;
> >  }
> > @@ -1976,11 +1975,9 @@ static int em28xx_v4l2_close(struct file *filp)
> >  	mutex_lock(&dev->lock);
> >  
> >  	if (dev->users == 1) {
> > -		/* free the remaining resources if device is disconnected */
> > -		if (dev->disconnected) {
> > -			kfree(dev->alt_max_pkt_size_isoc);
> > +		/* No sense to try to write to the device */
> > +		if (dev->disconnected)
> >  			goto exit;
> > -		}
> >  
> >  		/* Save some power by putting tuner to sleep */
> >  		v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_power, 0);
> > @@ -2001,6 +1998,8 @@ static int em28xx_v4l2_close(struct file *filp)
> >  exit:
> >  	dev->users--;
> >  	mutex_unlock(&dev->lock);
> > +	kref_put(&dev->ref, em28xx_free_device);
> > +
> >  	return 0;
> >  }
> >  
> > @@ -2515,6 +2514,8 @@ static int em28xx_v4l2_init(struct em28xx *dev)
> >  
> >  	em28xx_info("V4L2 extension successfully initialized\n");
> >  
> > +	kref_get(&dev->ref);
> > +
> >  	mutex_unlock(&dev->lock);
> >  	return 0;
> >  
> > diff --git a/drivers/media/usb/em28xx/em28xx.h b/drivers/media/usb/em28xx/em28xx.h
> > index 9e44f5bfc48b..2051fc9fb932 100644
> > --- a/drivers/media/usb/em28xx/em28xx.h
> > +++ b/drivers/media/usb/em28xx/em28xx.h
> > @@ -32,6 +32,7 @@
> >  #include <linux/workqueue.h>
> >  #include <linux/i2c.h>
> >  #include <linux/mutex.h>
> > +#include <linux/kref.h>
> >  #include <linux/videodev2.h>
> >  
> >  #include <media/videobuf2-vmalloc.h>
> > @@ -536,9 +537,10 @@ struct em28xx_i2c_bus {
> >  	enum em28xx_i2c_algo_type algo_type;
> >  };
> >  
> > -
> >  /* main device struct */
> >  struct em28xx {
> > +	struct kref ref;
> > +
> >  	/* generic device properties */
> >  	char name[30];		/* name (including minor) of the device */
> >  	int model;		/* index in the device_data struct */
> > @@ -710,6 +712,8 @@ struct em28xx {
> >  	struct em28xx_dvb *dvb;
> >  };
> >  
> > +#define kref_to_dev(d) container_of(d, struct em28xx, ref)
> > +
> >  struct em28xx_ops {
> >  	struct list_head next;
> >  	char *name;
> > @@ -771,7 +775,7 @@ extern struct em28xx_board em28xx_boards[];
> >  extern struct usb_device_id em28xx_id_table[];
> >  int em28xx_tuner_callback(void *ptr, int component, int command, int arg);
> >  void em28xx_setup_xc3028(struct em28xx *dev, struct xc2028_ctrl *ctl);
> > -void em28xx_release_resources(struct em28xx *dev);
> > +void em28xx_free_device(struct kref *ref);
> >  
> >  /* Provided by em28xx-camera.c */
> >  int em28xx_detect_sensor(struct em28xx *dev);
> 


-- 

Cheers,
Mauro

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH v3] em28xx: Only deallocate struct em28xx after finishing all extensions
  2014-03-07 17:38                 ` Mauro Carvalho Chehab
@ 2014-03-08 10:51                   ` Frank Schäfer
  0 siblings, 0 replies; 40+ messages in thread
From: Frank Schäfer @ 2014-03-08 10:51 UTC (permalink / raw)
  To: Mauro Carvalho Chehab; +Cc: Linux Media Mailing List, Mauro Carvalho Chehab


Am 07.03.2014 18:38, schrieb Mauro Carvalho Chehab:
>>> static int em28xx_usb_suspend(struct usb_interface *interface,
>>> > > diff --git a/drivers/media/usb/em28xx/em28xx-dvb.c b/drivers/media/usb/em28xx/em28xx-dvb.c
>>> > > index d4986bdfbdc3..6dbc71ba2820 100644
>>> > > --- a/drivers/media/usb/em28xx/em28xx-dvb.c
>>> > > +++ b/drivers/media/usb/em28xx/em28xx-dvb.c
>>> > > @@ -1043,7 +1043,6 @@ static int em28xx_dvb_init(struct em28xx *dev)
>>> > >  	em28xx_info("Binding DVB extension\n");
>>> > >  
>>> > >  	dvb = kzalloc(sizeof(struct em28xx_dvb), GFP_KERNEL);
>>> > > -
>>> > >  	if (dvb == NULL) {
>>> > >  		em28xx_info("em28xx_dvb: memory allocation failed\n");
>>> > >  		return -ENOMEM;
>>> > > @@ -1521,6 +1520,9 @@ static int em28xx_dvb_init(struct em28xx *dev)
>>> > >  	dvb->adapter.mfe_shared = mfe_shared;
>>> > >  
>>> > >  	em28xx_info("DVB extension successfully initialized\n");
>>> > > +
>>> > > +	kref_get(&dev->ref);
>>> > > +
>> > 
>> > The fini() functions are always called, even if an error occured in init().
>> > So (in opposition to the open()/close() functions) kref_get() needs to
>> > be called at the beginning of the init() methods.
>> > 
>> > "dev->is_audio_only" and "!dev->board.has_dvb" is checked in both
>> > functions (init+fini), so the right place here is one line before or after
>> > 
>> >     em28xx_info("Binding DVB extension\n");
>> > 
>> > 
>> > Everything else looks good.
> I actually prefer to fix it the other way, at the code for kref_put()...
> see below
...
>> > 
>> > Regards,
>> > Frank
>> > 
>>> > >  ret:
>>> > >  	em28xx_set_mode(dev, EM28XX_SUSPEND);
>>> > >  	mutex_unlock(&dev->lock);
>>> > > @@ -1579,6 +1581,8 @@ static int em28xx_dvb_fini(struct em28xx *dev)
>>> > >  		dev->dvb = NULL;
> Putting the kref_put() here. This part of the code is only called if
> dev->dvb it not NULL, and this is only possible to happen if the
> DVB is properly initialized.
Yes, that works, too.

Regards,
Frank

>
>>> > >  	}
>>> > >  
>>> > > +	kref_put(&dev->ref, em28xx_free_device);
>>> > > +
>>> > >  	return 0;
>>> > >  }


^ permalink raw reply	[flat|nested] 40+ messages in thread

end of thread, other threads:[~2014-03-08 10:50 UTC | newest]

Thread overview: 40+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2014-01-12 23:00 [PATCH 0/7] Fix remaining issues with em28xx device removal Mauro Carvalho Chehab
2014-01-12 23:00 ` [PATCH 1/7] em28xx-audio: fix return code on device disconnect Mauro Carvalho Chehab
2014-01-13 18:38   ` Frank Schäfer
2014-01-12 23:00 ` [PATCH 2/7] em28xx-audio: simplify error handling Mauro Carvalho Chehab
2014-01-13 18:41   ` Frank Schäfer
2014-01-12 23:00 ` [PATCH 3/7] em28xx: Only deallocate struct em28xx after finishing all extensions Mauro Carvalho Chehab
2014-01-13 19:02   ` Frank Schäfer
2014-01-13 19:23     ` Mauro Carvalho Chehab
2014-01-13 21:55       ` Frank Schäfer
2014-01-14 13:10         ` Mauro Carvalho Chehab
2014-01-14 18:13           ` Frank Schäfer
2014-01-14 18:55             ` Mauro Carvalho Chehab
2014-01-14 19:31               ` Mauro Carvalho Chehab
2014-01-14 20:57                 ` Frank Schäfer
2014-01-14 20:48               ` Frank Schäfer
2014-01-14 21:20                 ` Mauro Carvalho Chehab
2014-01-15 18:48                   ` Frank Schäfer
2014-01-14 17:36   ` [PATCH v2] " Mauro Carvalho Chehab
2014-01-15 21:13     ` Frank Schäfer
2014-02-09 18:41       ` Frank Schäfer
2014-02-09 20:09         ` Mauro Carvalho Chehab
2014-02-12 18:00           ` Frank Schäfer
2014-03-05 14:22             ` [PATCH v3] " Mauro Carvalho Chehab
2014-03-07 17:04               ` Frank Schäfer
2014-03-07 17:38                 ` Mauro Carvalho Chehab
2014-03-08 10:51                   ` Frank Schäfer
2014-01-12 23:00 ` [PATCH 4/7] em28xx-audio: disconnect before freeing URBs Mauro Carvalho Chehab
2014-01-13 18:47   ` Frank Schäfer
2014-01-12 23:00 ` [PATCH 5/7] em28xx-audio: remove a deplock circular dependency Mauro Carvalho Chehab
2014-01-13 21:51   ` Frank Schäfer
2014-01-14 15:45     ` Mauro Carvalho Chehab
2014-01-14 18:43       ` Frank Schäfer
2014-01-14 19:59         ` Mauro Carvalho Chehab
2014-01-14 20:51           ` Frank Schäfer
2014-01-12 23:00 ` [PATCH 6/7] em28xx: print a message at disconnect Mauro Carvalho Chehab
2014-01-13 18:51   ` Frank Schäfer
2014-01-12 23:00 ` [PATCH 7/7] em28xx: Fix usb diconnect logic Mauro Carvalho Chehab
2014-01-13 18:53   ` Frank Schäfer
2014-01-13 17:30 ` [PATCH 0/7] Fix remaining issues with em28xx device removal Antti Palosaari
2014-01-13 17:50   ` Mauro Carvalho Chehab

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).