Skip to contentSkip to conversation

schedule inside spin_lock_irqsave?

PATCH In review Richard Zidlicky 3 participants 8 messages May 30, 2010 – Jul 6, 2010 Media (V4L/DVB)

lore
Share & tools
lore
#0 lore raw

Hi,

came across following snippet of code (2.6.34:drivers/media/dvb/siano/smscoreapi.c) and since prepare_to_wait is new for me I am wondering if this is can work?

struct smscore_buffer_t *smscore_getbuffer(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);

	cb = (struct smscore_buffer_t *) coredev->buffers.next;
	list_del(&cb->entry);

	spin_unlock_irqrestore(&coredev->bufferslock, flags);

	return cb;
}

Regards
Richard

#1 lore raw
Quoted 22 lines · Richard Zidlicky

Hi,

came across following snippet of code (2.6.34:drivers/media/dvb/siano/smscoreapi.c) and since prepare_to_wait is new for me I am wondering if this is can work?

struct smscore_buffer_t *smscore_getbuffer(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))
Quoted 8 lines
		schedule();

	finish_wait(&coredev->buffer_mng_waitq, &wait);

	cb = (struct smscore_buffer_t *) coredev->buffers.next;
	list_del(&cb->entry);

	spin_unlock_irqrestore(&coredev->bufferslock, flags);

Yep, that's a double bug.
1) If the waiting is interrupted, it will die because the list is still empty.
2) If there is no entry in the list, it will deadlock at least on UP. This should be
wait_event(&coredev->buffer_mng_waitq, cb = get_entry()); with get_entry like:
struct smscore_buffer_t *get_entry(void)
{
struct smscore_buffer_t *cb = NULL; 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;
}

regards,

Signature · 1 line
js
#2 lore raw
Quoted 6 lines · Jiri Slaby

struct smscore_buffer_t *get_entry(void)
{
struct smscore_buffer_t *cb = NULL; spin_lock_irqsave(&coredev->bufferslock, flags);

  if (!list_empty(&coredev->buffers)) {
    cb = (struct smscore_buffer_t *) coredev->buffers.next;

Looking at the smscore_buffer_t definition, this is really ugly since it relies on entry being the first in the structure. It should be list_first_entry(&coredev->buffers, ...) instead, cast-less.

Quoted 5 lines
    list_del(&cb->entry);

} spin_unlock_irqrestore(&coredev->bufferslock, flags); return cb;
}

Signature · 1 line
js
#3 lore raw

On Sun, May 30, 2010 at 05:24:38PM +0200, Jiri Slaby wrote:

Hi,

Quoted 1 line
Quoted 1 line

came across following snippet of code (2.6.34:drivers/media/dvb/siano/smscoreapi.c) and

...
...
...

Quoted 14 lines

This should be wait_event(&coredev->buffer_mng_waitq, cb = get_entry()); with get_entry like:
struct smscore_buffer_t *get_entry(void)
{
struct smscore_buffer_t *cb = NULL; 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;
}

...
...
...

Quoted 10 lines

Looking at the smscore_buffer_t definition, this is really ugly since it relies on entry being the first in the structure. It should be list_first_entry(&coredev->buffers, ...) instead, cast-less.

Quoted 5 lines
    list_del(&cb->entry);

} spin_unlock_irqrestore(&coredev->bufferslock, flags); return cb;
}

thanks for the suggestions, is it on anyones TODO list or should I cook up my own patch? Would take a few more days till I can get at it.

BTW does anyone have knowledge how to enable IR receiver code for the smsxxx devices? Looks like its just the matter of setting sms_board_gpio_cfg.ir to the "right" value
- which value?

Richard

#4 lore raw

PATCH 1/1 schedule inside spin_lock_irqsave

In reply to Jiri Slaby

Hi,

I have done a minimaly invasive patch for the stable 2.6.34 kernel and stress-tested it for many hours, definitely seems to improve the behaviour.

I have left out your beautification suggestion for now, want to do more playing with other aspects of the driver. There still seem to be issues when the device is unplugged while in use and such.

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(void)
 {
 	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()));
 
 	return cb;
 }

Richard

#5 lore raw

Re: [PATCH 2.6.34] schedule inside spin_lock_irqsave

Quoted 15 lines · Richard Zidlicky

Hi,

I have done a minimaly invasive patch for the stable 2.6.34 kernel and stress-tested it for many hours, definitely seems to improve the behaviour.

I have left out your beautification suggestion for now, want to do more playing with other aspects of the driver. There still seem to be issues when the device is unplugged while in use and such.

drivers/media/dvb/siano/smscoreapi.c renamed from drivers/media/dvb/siano/smscoreapi.c.rz +0 -0
@@ -1100,31 +1100,26 @@
  *
  * @return pointer to descriptor on success, NULL on error.
  */

drivers/media/dvb/siano/smscoreapi.c line 1109

Quoted 10 lines
drivers/media/dvb/siano/smscoreapi.c renamed from drivers/media/dvb/siano/smscoreapi.c.rz +2 -3
-struct smscore_buffer_t *smscore_getbuffer(struct smscore_device_t *coredev)
+
+struct smscore_buffer_t *get_entry(void)
 {
 	struct smscore_buffer_t *cb = NULL;
 	unsigned long flags;
 
-	DEFINE_WAIT(wait);
-
 	spin_lock_irqsave(&coredev->bufferslock, flags);

Sorry, maybe I'm just blind, but where is 'coredev' defined in this scope? You probably forgot to pass it to get_entry?

How could this be compiled? Is there coredev defined globally?

Quoted 30 lines
drivers/media/dvb/siano/smscoreapi.c renamed from drivers/media/dvb/siano/smscoreapi.c.rz +10 -14
-
-	/* 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()));
 
 	return cb;
 }
Signature · 1 line
js
#6 lore raw

Re: [PATCH 2.6.34] schedule inside spin_lock_irqsave

Quoted 23 lines · Jiri Slaby
Quoted 22 lines · Richard Zidlicky

Hi,

I have done a minimaly invasive patch for the stable 2.6.34 kernel and stress-tested it for many hours, definitely seems to improve the behaviour.

I have left out your beautification suggestion for now, want to do more playing with other aspects of the driver. There still seem to be issues when the device is unplugged while in use and such.

drivers/media/dvb/siano/smscoreapi.c renamed from drivers/media/dvb/siano/smscoreapi.c.rz +2 -1
@@ -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(void)
 {
 	struct smscore_buffer_t *cb = NULL;
 	unsigned long flags;
 
Quoted 8 lines

drivers/media/dvb/siano/smscoreapi.c line 1109

Quoted 3 lines
drivers/media/dvb/siano/smscoreapi.c renamed from drivers/media/dvb/siano/smscoreapi.c.rz +0 -2
-	DEFINE_WAIT(wait);
-
 	spin_lock_irqsave(&coredev->bufferslock, flags);

Sorry, maybe I'm just blind, but where is 'coredev' defined in this scope? You probably forgot to pass it to get_entry?

How could this be compiled? Is there coredev defined globally?

good catch. I think it failed and despite a different kernel id the old module was loaded.

Here is the new version, this time lightly tested

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;
 }

Richard

#7 lore raw

Re: [PATCH 2.6.34] schedule inside spin_lock_irqsave

Em 07-06-2010 10:00, Richard Zidlicky escreveu:

Quoted 31 lines · Jiri Slaby
Quoted 30 lines · Richard Zidlicky
Quoted 15 lines

Hi,

I have done a minimaly invasive patch for the stable 2.6.34 kernel and stress-tested it for many hours, definitely seems to improve the behaviour.

I have left out your beautification suggestion for now, want to do more playing with other aspects of the driver. There still seem to be issues when the device is unplugged while in use and such.

drivers/media/dvb/siano/smscoreapi.c renamed from drivers/media/dvb/siano/smscoreapi.c.rz +0 -0
@@ -1100,31 +1100,26 @@
  *
  * @return pointer to descriptor on success, NULL on error.
  */

drivers/media/dvb/siano/smscoreapi.c line 1109

Quoted 10 lines
drivers/media/dvb/siano/smscoreapi.c renamed from drivers/media/dvb/siano/smscoreapi.c.rz +2 -3
-struct smscore_buffer_t *smscore_getbuffer(struct smscore_device_t *coredev)
+
+struct smscore_buffer_t *get_entry(void)
 {
 	struct smscore_buffer_t *cb = NULL;
 	unsigned long flags;
 
-	DEFINE_WAIT(wait);
-
 	spin_lock_irqsave(&coredev->bufferslock, flags);

Sorry, maybe I'm just blind, but where is 'coredev' defined in this scope? You probably forgot to pass it to get_entry?

Quoted 6 lines
Quoted 1 line

How could this be compiled? Is there coredev defined globally?

good catch. I think it failed and despite a different kernel id the old module was loaded.

Here is the new version, this time lightly tested

Could you please fix the indentation and send your SOB for this patch?

Cheers,
Mauro.

Quoted 54 lines
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;
 }

Richard
--
To unsubscribe from this list: send the line "unsubscribe linux-media" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html