Skip to contentSkip to conversation

dvb: siano: free spinlock before schedule()

PATCH In review Kulikov Vasiliy 4 participants 5 messages Jul 27, 2010 – Aug 24, 2010

Subsystems (2)
lore
Share & tools
lore
#0 lore raw

PATCH 1/1 dvb: siano: free spinlock before schedule()

Calling schedule() holding spinlock with disables irqs is improper. As spinlock protects list coredev->buffers, it can be unlocked untill wakeup. This bug was introduced in a9349315f65cd6a16e8fab1f6cf0fd40f379c4db.

---
 drivers/media/dvb/siano/smscoreapi.c |    6 ++++--
 1 files changed, 4 insertions(+), 2 deletions(-)
drivers/media/dvb/siano/smscoreapi.c +4 -2
index 7f2c94a..d93468c 100644
@@ -1113,9 +1113,11 @@ struct smscore_buffer_t *smscore_getbuffer(struct smscore_device_t *coredev)
 	 */
 
 	prepare_to_wait(&coredev->buffer_mng_waitq, &wait, TASK_INTERRUPTIBLE);
-
-	if (list_empty(&coredev->buffers))
+	if (list_empty(&coredev->buffers)) {
+		spin_unlock_irqrestore(&coredev->bufferslock, flags);
 		schedule();
+		spin_lock_irqsave(&coredev->bufferslock, flags);
+	}
 
 	finish_wait(&coredev->buffer_mng_waitq, &wait);
 
Signature · 1 line
1.7.0.4
#1 lore raw
Quoted 16 lines · Kulikov Vasiliy

Calling schedule() holding spinlock with disables irqs is improper. As spinlock protects list coredev->buffers, it can be unlocked untill wakeup. This bug was introduced in a9349315f65cd6a16e8fab1f6cf0fd40f379c4db.

---
 drivers/media/dvb/siano/smscoreapi.c |    6 ++++--
 1 files changed, 4 insertions(+), 2 deletions(-)
drivers/media/dvb/siano/smscoreapi.c +0 -0
index 7f2c94a..d93468c 100644
@@ -1113,9 +1113,11 @@ struct smscore_buffer_t *smscore_getbuffer(struct smscore_device_t *coredev)
 	 */
 

drivers/media/dvb/siano/smscoreapi.c struct smscore_buffer_t *smscore_getbuffer(struct smscore_device_t *coredev) · line 1122

Quoted 10 lines
drivers/media/dvb/siano/smscoreapi.c +4 -2
 	prepare_to_wait(&coredev->buffer_mng_waitq, &wait, TASK_INTERRUPTIBLE);
-
-	if (list_empty(&coredev->buffers))
+	if (list_empty(&coredev->buffers)) {
+		spin_unlock_irqrestore(&coredev->bufferslock, flags);
 		schedule();
+		spin_lock_irqsave(&coredev->bufferslock, flags);
+	}
 
 	finish_wait(&coredev->buffer_mng_waitq, &wait);

There is a better fix (which fixes the potential NULL dereference):
http://lkml.org/lkml/2010/6/7/175

Richard, could you address the comments there and resend?

regards,

Signature · 1 line
js
#2 lore raw

On Wed, Jul 28, 2010 at 12:24:39AM +0200, Jiri Slaby wrote:

sorry for seeing this so late, was flooded with email lately.

Quoted 4 lines

There is a better fix (which fixes the potential NULL dereference):
http://lkml.org/lkml/2010/6/7/175

Richard, could you address the comments there and resend?

I am running this patch since many weeks (after fixing the compile error obviously). Did not implement your beautification suggestion yet, was doing all kinds of experiments with IR and had plenty of unrelated issues.

Richard

drivers/media/dvb/siano/smscoreapi.c renamed from drivers/media/dvb/siano/smscoreapi.c.rz +12 -17
@@ -1100,31 +1100,26 @@
  *
  * @return pointer to descriptor on success, NULL on error.
  */
-struct smscore_buffer_t *smscore_getbuffer(struct smscore_device_t *coredev)
+
+struct smscore_buffer_t *get_entry(struct smscore_device_t *coredev)
 {
 	struct smscore_buffer_t *cb = NULL;
 	unsigned long flags;
 
-	DEFINE_WAIT(wait);
-
 	spin_lock_irqsave(&coredev->bufferslock, flags);
-
-	/* This function must return a valid buffer, since the buffer list is
-	 * finite, we check that there is an available buffer, if not, we wait
-	 * until such buffer become available.
-	 */
-
-	prepare_to_wait(&coredev->buffer_mng_waitq, &wait, TASK_INTERRUPTIBLE);
-
-	if (list_empty(&coredev->buffers))
-		schedule();
-
-	finish_wait(&coredev->buffer_mng_waitq, &wait);
-
+	if (!list_empty(&coredev->buffers)) {
 	cb = (struct smscore_buffer_t *) coredev->buffers.next;
 	list_del(&cb->entry);
-
+	}
 	spin_unlock_irqrestore(&coredev->bufferslock, flags);
+	return cb;
+}
+
+struct smscore_buffer_t *smscore_getbuffer(struct smscore_device_t *coredev)
+{
+	struct smscore_buffer_t *cb = NULL;
+
+	wait_event(coredev->buffer_mng_waitq, (cb = get_entry(coredev)));
 
 	return cb;
 }
#3 lore raw

Em 08-08-2010 13:10, Richard Zidlicky escreveu:

Quoted 12 lines · Jiri Slaby

sorry for seeing this so late, was flooded with email lately.

Quoted 4 lines

There is a better fix (which fixes the potential NULL dereference):
http://lkml.org/lkml/2010/6/7/175

Richard, could you address the comments there and resend?

I am running this patch since many weeks (after fixing the compile error obviously). Did not implement your beautification suggestion yet, was doing all kinds of experiments with IR and had plenty of unrelated issues.

This patch seems a way better than the previous patch. I've rebased it against the current tree (and fixed the identation).

The only missing issue on it is the lack of your Signed-off-by. Richard, could you please send it to us?

---
 drivers/media/dvb/siano/smscoreapi.c |   31 +++++++++++++------------------
 1 file changed, 13 insertions(+), 18 deletions(-)
drivers/media/dvb/siano/smscoreapi.c +13 -18
@@ -1098,31 +1098,26 @@ EXPORT_SYMBOL_GPL(smscore_onresponse);
  *
  * @return pointer to descriptor on success, NULL on error.
  */
-struct smscore_buffer_t *smscore_getbuffer(struct smscore_device_t *coredev)
+
+struct smscore_buffer_t *get_entry(struct smscore_device_t *coredev)
 {
 	struct smscore_buffer_t *cb = NULL;
 	unsigned long flags;
 
-	DEFINE_WAIT(wait);
-
 	spin_lock_irqsave(&coredev->bufferslock, flags);
+	if (!list_empty(&coredev->buffers)) {
+		cb = (struct smscore_buffer_t *) coredev->buffers.next;
+		list_del(&cb->entry);
+	}
+	spin_unlock_irqrestore(&coredev->bufferslock, flags);
+	return cb;
+}
 
-	/* This function must return a valid buffer, since the buffer list is
-	 * finite, we check that there is an available buffer, if not, we wait
-	 * until such buffer become available.
-	 */
-
-	prepare_to_wait(&coredev->buffer_mng_waitq, &wait, TASK_INTERRUPTIBLE);
-
-	if (list_empty(&coredev->buffers))
-		schedule();
-
-	finish_wait(&coredev->buffer_mng_waitq, &wait);
-
-	cb = (struct smscore_buffer_t *) coredev->buffers.next;
-	list_del(&cb->entry);
+struct smscore_buffer_t *smscore_getbuffer(struct smscore_device_t *coredev)
+{
+	struct smscore_buffer_t *cb = NULL;
 
-	spin_unlock_irqrestore(&coredev->bufferslock, flags);
+	wait_event(coredev->buffer_mng_waitq, (cb = get_entry(coredev)));
 
 	return cb;
 }
#4 lore raw
Quoted 8 lines · Mauro Carvalho Chehab

Em 08-08-2010 13:10, Richard Zidlicky escreveu:

Quoted 7 lines · Jiri Slaby

sorry for seeing this so late, was flooded with email lately.

Quoted 2 lines

There is a better fix (which fixes the potential NULL dereference):
http://lkml.org/lkml/2010/6/7/175

Quoted 8 lines
Quoted 5 lines
Quoted 1 line

Richard, could you address the comments there and resend?

I am running this patch since many weeks (after fixing the compile error obviously). Did not implement your beautification suggestion yet, was doing all kinds of experiments with IR and had plenty of unrelated issues.

This patch seems a way better than the previous patch. I've rebased it against the current tree (and fixed the identation).

thanks for looking at it.

Quoted 2 lines

The only missing issue on it is the lack of your Signed-off-by. Richard, could you please send it to us?

PS: I will be away for a while.

Quoted 52 lines
---
 drivers/media/dvb/siano/smscoreapi.c |   31 +++++++++++++------------------
 1 file changed, 13 insertions(+), 18 deletions(-)
drivers/media/dvb/siano/smscoreapi.c +13 -18
@@ -1098,31 +1098,26 @@ EXPORT_SYMBOL_GPL(smscore_onresponse);
  *
  * @return pointer to descriptor on success, NULL on error.
  */
-struct smscore_buffer_t *smscore_getbuffer(struct smscore_device_t *coredev)
+
+struct smscore_buffer_t *get_entry(struct smscore_device_t *coredev)
 {
 	struct smscore_buffer_t *cb = NULL;
 	unsigned long flags;
 
-	DEFINE_WAIT(wait);
-
 	spin_lock_irqsave(&coredev->bufferslock, flags);
+	if (!list_empty(&coredev->buffers)) {
+		cb = (struct smscore_buffer_t *) coredev->buffers.next;
+		list_del(&cb->entry);
+	}
+	spin_unlock_irqrestore(&coredev->bufferslock, flags);
+	return cb;
+}
 
-	/* This function must return a valid buffer, since the buffer list is
-	 * finite, we check that there is an available buffer, if not, we wait
-	 * until such buffer become available.
-	 */
-
-	prepare_to_wait(&coredev->buffer_mng_waitq, &wait, TASK_INTERRUPTIBLE);
-
-	if (list_empty(&coredev->buffers))
-		schedule();
-
-	finish_wait(&coredev->buffer_mng_waitq, &wait);
-
-	cb = (struct smscore_buffer_t *) coredev->buffers.next;
-	list_del(&cb->entry);
+struct smscore_buffer_t *smscore_getbuffer(struct smscore_device_t *coredev)
+{
+	struct smscore_buffer_t *cb = NULL;
 
-	spin_unlock_irqrestore(&coredev->bufferslock, flags);
+	wait_event(coredev->buffer_mng_waitq, (cb = get_entry(coredev)));
 
 	return cb;
 }