All of lore.kernel.org
 help / color / mirror / Atom feed
* [Xenomai-core] [PATCH] xnpipe: fix state tracking of Linux side
@ 2008-10-13 20:40 Jan Kiszka
  2008-10-17 11:17 ` Jan Kiszka
  0 siblings, 1 reply; 4+ messages in thread
From: Jan Kiszka @ 2008-10-13 20:40 UTC (permalink / raw)
  To: xenomai-core

[-- Attachment #1: Type: text/plain, Size: 4591 bytes --]

The state tracking of Linux tasks queue on xnpipe events was fairly
broken. An easy way to corrupt some xnpipe_state_t object was to kill a
Linux task blocked on opening a /dev/rtpX device (this left the state
object queued in xnpipe_sleep, and hell broke loose on next queuing).

Another problem that popped up after reworking xnpipe queuing was a
stalled XNPIPE_USER_CONN after receiving a signal in xnpipe_open.

The following patch addresses both issues, appears to run fine so far
(at least the test case no longer triggers), and also cleans up some
redundant nklock acquisitions/releases. Nevertheless, I may miss some
corner case that might have triggered the original design. So please
check carefully.

Jan

---
 ksrc/nucleus/pipe.c |   64 +++++++++++++++++++---------------------------------
 1 file changed, 24 insertions(+), 40 deletions(-)

Index: b/ksrc/nucleus/pipe.c
===================================================================
--- a/ksrc/nucleus/pipe.c
+++ b/ksrc/nucleus/pipe.c
@@ -88,38 +88,39 @@ static inline void xnpipe_minor_free(int
 
 static inline void xnpipe_enqueue_wait(xnpipe_state_t *state, int mask)
 {
-	spl_t s;
-
-	xnlock_get_irqsave(&nklock, s);
-
 	if (state->wcount++ == 0)
 		appendq(&xnpipe_sleepq, &state->slink);
 
 	__setbits(state->status, mask);
+}
 
-	xnlock_put_irqrestore(&nklock, s);
+static inline void xnpipe_dequeue_wait(xnpipe_state_t *state, int mask)
+{
+	if (testbits(state->status, mask)) {
+		if (--state->wcount == 0)
+			removeq(&xnpipe_sleepq, &state->slink);
+		__clrbits(state->status, mask);
+	}
 }
 
 /* Must be entered with nklock held. */
-#define xnpipe_wait(__state, __mask, __s, __cond)	\
-({							\
-	wait_queue_head_t *__waitq;			\
-	DEFINE_WAIT(__wait);				\
-	int __sigpending;				\
-							\
-	if ((__mask) & XNPIPE_USER_WREAD)		\
-		__waitq = &(__state)->readq;		\
-	else						\
-		__waitq = &(__state)->syncq;		\
-							\
-	xnpipe_enqueue_wait(__state, __mask);		\
-	xnlock_put_irqrestore(&nklock, __s);		\
+#define xnpipe_wait(__state, __mask, __s, __cond)			\
+({									\
+	wait_queue_head_t *__waitq;					\
+	DEFINE_WAIT(__wait);						\
+	int __sigpending;						\
+									\
+	if ((__mask) & XNPIPE_USER_WREAD)				\
+		__waitq = &(__state)->readq;				\
+	else								\
+		__waitq = &(__state)->syncq;				\
+									\
+	xnpipe_enqueue_wait(__state, __mask);				\
+	xnlock_put_irqrestore(&nklock, __s);				\
 									\
 	prepare_to_wait_exclusive(__waitq, &__wait, TASK_INTERRUPTIBLE);\
 									\
-	if (__cond)							\
-		xnpipe_dequeue_wait(__state, __mask);			\
-	else								\
+	if (!__cond)							\
 		schedule();						\
 									\
 	finish_wait(__waitq, &__wait);					\
@@ -127,25 +128,11 @@ static inline void xnpipe_enqueue_wait(x
 									\
 	/* Restore the interrupt state initially set by the caller. */	\
 	xnlock_get_irqsave(&nklock, __s);				\
+	xnpipe_dequeue_wait(__state, __mask);				\
 									\
 	__sigpending;							\
 })
 
-static inline void xnpipe_dequeue_wait(xnpipe_state_t *state, int mask)
-{
-	spl_t s;
-
-	xnlock_get_irqsave(&nklock, s);
-
-	if (testbits(state->status, mask)) {
-		if (--state->wcount == 0)
-			removeq(&xnpipe_sleepq, &state->slink);
-		__clrbits(state->status, mask);
-	}
-
-	xnlock_put_irqrestore(&nklock, s);
-}
-
 static void xnpipe_wakeup_proc(void *cookie)
 {
 	xnholder_t *holder, *nholder;
@@ -168,7 +155,6 @@ static void xnpipe_wakeup_proc(void *coo
 			   before calling wake_up_interruptible(). */
 			if ((rbits & XNPIPE_USER_WREAD_READY) != 0) {
 				if (waitqueue_active(&state->readq)) {
-					xnpipe_dequeue_wait(state, XNPIPE_USER_WREAD);
 					xnlock_put_irqrestore(&nklock, s);
 					wake_up_interruptible(&state->readq);
 					rbits &= ~XNPIPE_USER_WREAD_READY;
@@ -177,7 +163,6 @@ static void xnpipe_wakeup_proc(void *coo
 			}
 			if ((rbits & XNPIPE_USER_WSYNC_READY) != 0) {
 				if (waitqueue_active(&state->syncq)) {
-					xnpipe_dequeue_wait(state, XNPIPE_USER_WSYNC);
 					xnlock_put_irqrestore(&nklock, s);
 					wake_up_interruptible(&state->syncq);
 					rbits &= ~XNPIPE_USER_WSYNC_READY;
@@ -666,8 +651,7 @@ static int xnpipe_open(struct inode *ino
 		sigpending = xnpipe_wait(state, XNPIPE_USER_WREAD, s,
 					 testbits(state->status, XNPIPE_KERN_CONN));
 		if (sigpending) {
-			if (!testbits(state->status, XNPIPE_KERN_CONN))
-				xnpipe_cleanup_user_conn(state);
+			xnpipe_cleanup_user_conn(state);
 			xnlock_put_irqrestore(&nklock, s);
 			return -ERESTARTSYS;
 		}


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 257 bytes --]

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

* Re: [Xenomai-core] [PATCH] xnpipe: fix state tracking of Linux side
  2008-10-13 20:40 [Xenomai-core] [PATCH] xnpipe: fix state tracking of Linux side Jan Kiszka
@ 2008-10-17 11:17 ` Jan Kiszka
  2008-10-17 13:45   ` Philippe Gerum
  0 siblings, 1 reply; 4+ messages in thread
From: Jan Kiszka @ 2008-10-17 11:17 UTC (permalink / raw)
  To: Philippe Gerum; +Cc: xenomai-core

Jan Kiszka wrote:
> The state tracking of Linux tasks queue on xnpipe events was fairly
> broken. An easy way to corrupt some xnpipe_state_t object was to kill a
> Linux task blocked on opening a /dev/rtpX device (this left the state
> object queued in xnpipe_sleep, and hell broke loose on next queuing).
> 
> Another problem that popped up after reworking xnpipe queuing was a
> stalled XNPIPE_USER_CONN after receiving a signal in xnpipe_open.
> 
> The following patch addresses both issues, appears to run fine so far
> (at least the test case no longer triggers), and also cleans up some
> redundant nklock acquisitions/releases. Nevertheless, I may miss some
> corner case that might have triggered the original design. So please
> check carefully.

While fighting over a single bit elsewhere, let's not forget this open
issue: Customer asks for a solution of the hard lock-up he faced, and
/me would like to know if this fix comes with no obvious regressions.

TIA,
Jan

> ---
>  ksrc/nucleus/pipe.c |   64 +++++++++++++++++++---------------------------------
>  1 file changed, 24 insertions(+), 40 deletions(-)
> 
> Index: b/ksrc/nucleus/pipe.c
> ===================================================================
> --- a/ksrc/nucleus/pipe.c
> +++ b/ksrc/nucleus/pipe.c
> @@ -88,38 +88,39 @@ static inline void xnpipe_minor_free(int
>  
>  static inline void xnpipe_enqueue_wait(xnpipe_state_t *state, int mask)
>  {
> -	spl_t s;
> -
> -	xnlock_get_irqsave(&nklock, s);
> -
>  	if (state->wcount++ == 0)
>  		appendq(&xnpipe_sleepq, &state->slink);
>  
>  	__setbits(state->status, mask);
> +}
>  
> -	xnlock_put_irqrestore(&nklock, s);
> +static inline void xnpipe_dequeue_wait(xnpipe_state_t *state, int mask)
> +{
> +	if (testbits(state->status, mask)) {
> +		if (--state->wcount == 0)
> +			removeq(&xnpipe_sleepq, &state->slink);
> +		__clrbits(state->status, mask);
> +	}
>  }
>  
>  /* Must be entered with nklock held. */
> -#define xnpipe_wait(__state, __mask, __s, __cond)	\
> -({							\
> -	wait_queue_head_t *__waitq;			\
> -	DEFINE_WAIT(__wait);				\
> -	int __sigpending;				\
> -							\
> -	if ((__mask) & XNPIPE_USER_WREAD)		\
> -		__waitq = &(__state)->readq;		\
> -	else						\
> -		__waitq = &(__state)->syncq;		\
> -							\
> -	xnpipe_enqueue_wait(__state, __mask);		\
> -	xnlock_put_irqrestore(&nklock, __s);		\
> +#define xnpipe_wait(__state, __mask, __s, __cond)			\
> +({									\
> +	wait_queue_head_t *__waitq;					\
> +	DEFINE_WAIT(__wait);						\
> +	int __sigpending;						\
> +									\
> +	if ((__mask) & XNPIPE_USER_WREAD)				\
> +		__waitq = &(__state)->readq;				\
> +	else								\
> +		__waitq = &(__state)->syncq;				\
> +									\
> +	xnpipe_enqueue_wait(__state, __mask);				\
> +	xnlock_put_irqrestore(&nklock, __s);				\
>  									\
>  	prepare_to_wait_exclusive(__waitq, &__wait, TASK_INTERRUPTIBLE);\
>  									\
> -	if (__cond)							\
> -		xnpipe_dequeue_wait(__state, __mask);			\
> -	else								\
> +	if (!__cond)							\
>  		schedule();						\
>  									\
>  	finish_wait(__waitq, &__wait);					\
> @@ -127,25 +128,11 @@ static inline void xnpipe_enqueue_wait(x
>  									\
>  	/* Restore the interrupt state initially set by the caller. */	\
>  	xnlock_get_irqsave(&nklock, __s);				\
> +	xnpipe_dequeue_wait(__state, __mask);				\
>  									\
>  	__sigpending;							\
>  })
>  
> -static inline void xnpipe_dequeue_wait(xnpipe_state_t *state, int mask)
> -{
> -	spl_t s;
> -
> -	xnlock_get_irqsave(&nklock, s);
> -
> -	if (testbits(state->status, mask)) {
> -		if (--state->wcount == 0)
> -			removeq(&xnpipe_sleepq, &state->slink);
> -		__clrbits(state->status, mask);
> -	}
> -
> -	xnlock_put_irqrestore(&nklock, s);
> -}
> -
>  static void xnpipe_wakeup_proc(void *cookie)
>  {
>  	xnholder_t *holder, *nholder;
> @@ -168,7 +155,6 @@ static void xnpipe_wakeup_proc(void *coo
>  			   before calling wake_up_interruptible(). */
>  			if ((rbits & XNPIPE_USER_WREAD_READY) != 0) {
>  				if (waitqueue_active(&state->readq)) {
> -					xnpipe_dequeue_wait(state, XNPIPE_USER_WREAD);
>  					xnlock_put_irqrestore(&nklock, s);
>  					wake_up_interruptible(&state->readq);
>  					rbits &= ~XNPIPE_USER_WREAD_READY;
> @@ -177,7 +163,6 @@ static void xnpipe_wakeup_proc(void *coo
>  			}
>  			if ((rbits & XNPIPE_USER_WSYNC_READY) != 0) {
>  				if (waitqueue_active(&state->syncq)) {
> -					xnpipe_dequeue_wait(state, XNPIPE_USER_WSYNC);
>  					xnlock_put_irqrestore(&nklock, s);
>  					wake_up_interruptible(&state->syncq);
>  					rbits &= ~XNPIPE_USER_WSYNC_READY;
> @@ -666,8 +651,7 @@ static int xnpipe_open(struct inode *ino
>  		sigpending = xnpipe_wait(state, XNPIPE_USER_WREAD, s,
>  					 testbits(state->status, XNPIPE_KERN_CONN));
>  		if (sigpending) {
> -			if (!testbits(state->status, XNPIPE_KERN_CONN))
> -				xnpipe_cleanup_user_conn(state);
> +			xnpipe_cleanup_user_conn(state);
>  			xnlock_put_irqrestore(&nklock, s);
>  			return -ERESTARTSYS;
>  		}

-- 
Siemens AG, Corporate Technology, CT SE 2
Corporate Competence Center Embedded Linux


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

* Re: [Xenomai-core] [PATCH] xnpipe: fix state tracking of Linux side
  2008-10-17 11:17 ` Jan Kiszka
@ 2008-10-17 13:45   ` Philippe Gerum
  2008-10-17 13:49     ` Jan Kiszka
  0 siblings, 1 reply; 4+ messages in thread
From: Philippe Gerum @ 2008-10-17 13:45 UTC (permalink / raw)
  To: Jan Kiszka; +Cc: xenomai-core

Jan Kiszka wrote:
> Jan Kiszka wrote:
>> The state tracking of Linux tasks queue on xnpipe events was fairly
>> broken. An easy way to corrupt some xnpipe_state_t object was to kill a
>> Linux task blocked on opening a /dev/rtpX device (this left the state
>> object queued in xnpipe_sleep, and hell broke loose on next queuing).
>>
>> Another problem that popped up after reworking xnpipe queuing was a
>> stalled XNPIPE_USER_CONN after receiving a signal in xnpipe_open.
>>
>> The following patch addresses both issues, appears to run fine so far
>> (at least the test case no longer triggers), and also cleans up some
>> redundant nklock acquisitions/releases. Nevertheless, I may miss some
>> corner case that might have triggered the original design. So please
>> check carefully.
> 
> While fighting over a single bit elsewhere, let's not forget this open
> issue:

I did not forget this issue. It is close to the top of stack now.

 Customer asks for a solution of the hard lock-up he faced, and
> /me would like to know if this fix comes with no obvious regressions.
> 

The patch looks sane, but I want to run a few tests that have been developed
over time to chase bugs in that code, before giving the patch a go. ETA: tomorrow.

> TIA,
> Jan
> 
>> ---
>>  ksrc/nucleus/pipe.c |   64 +++++++++++++++++++---------------------------------
>>  1 file changed, 24 insertions(+), 40 deletions(-)
>>
>> Index: b/ksrc/nucleus/pipe.c
>> ===================================================================
>> --- a/ksrc/nucleus/pipe.c
>> +++ b/ksrc/nucleus/pipe.c
>> @@ -88,38 +88,39 @@ static inline void xnpipe_minor_free(int
>>  
>>  static inline void xnpipe_enqueue_wait(xnpipe_state_t *state, int mask)
>>  {
>> -	spl_t s;
>> -
>> -	xnlock_get_irqsave(&nklock, s);
>> -
>>  	if (state->wcount++ == 0)
>>  		appendq(&xnpipe_sleepq, &state->slink);
>>  
>>  	__setbits(state->status, mask);
>> +}
>>  
>> -	xnlock_put_irqrestore(&nklock, s);
>> +static inline void xnpipe_dequeue_wait(xnpipe_state_t *state, int mask)
>> +{
>> +	if (testbits(state->status, mask)) {
>> +		if (--state->wcount == 0)
>> +			removeq(&xnpipe_sleepq, &state->slink);
>> +		__clrbits(state->status, mask);
>> +	}
>>  }
>>  
>>  /* Must be entered with nklock held. */
>> -#define xnpipe_wait(__state, __mask, __s, __cond)	\
>> -({							\
>> -	wait_queue_head_t *__waitq;			\
>> -	DEFINE_WAIT(__wait);				\
>> -	int __sigpending;				\
>> -							\
>> -	if ((__mask) & XNPIPE_USER_WREAD)		\
>> -		__waitq = &(__state)->readq;		\
>> -	else						\
>> -		__waitq = &(__state)->syncq;		\
>> -							\
>> -	xnpipe_enqueue_wait(__state, __mask);		\
>> -	xnlock_put_irqrestore(&nklock, __s);		\
>> +#define xnpipe_wait(__state, __mask, __s, __cond)			\
>> +({									\
>> +	wait_queue_head_t *__waitq;					\
>> +	DEFINE_WAIT(__wait);						\
>> +	int __sigpending;						\
>> +									\
>> +	if ((__mask) & XNPIPE_USER_WREAD)				\
>> +		__waitq = &(__state)->readq;				\
>> +	else								\
>> +		__waitq = &(__state)->syncq;				\
>> +									\
>> +	xnpipe_enqueue_wait(__state, __mask);				\
>> +	xnlock_put_irqrestore(&nklock, __s);				\
>>  									\
>>  	prepare_to_wait_exclusive(__waitq, &__wait, TASK_INTERRUPTIBLE);\
>>  									\
>> -	if (__cond)							\
>> -		xnpipe_dequeue_wait(__state, __mask);			\
>> -	else								\
>> +	if (!__cond)							\
>>  		schedule();						\
>>  									\
>>  	finish_wait(__waitq, &__wait);					\
>> @@ -127,25 +128,11 @@ static inline void xnpipe_enqueue_wait(x
>>  									\
>>  	/* Restore the interrupt state initially set by the caller. */	\
>>  	xnlock_get_irqsave(&nklock, __s);				\
>> +	xnpipe_dequeue_wait(__state, __mask);				\
>>  									\
>>  	__sigpending;							\
>>  })
>>  
>> -static inline void xnpipe_dequeue_wait(xnpipe_state_t *state, int mask)
>> -{
>> -	spl_t s;
>> -
>> -	xnlock_get_irqsave(&nklock, s);
>> -
>> -	if (testbits(state->status, mask)) {
>> -		if (--state->wcount == 0)
>> -			removeq(&xnpipe_sleepq, &state->slink);
>> -		__clrbits(state->status, mask);
>> -	}
>> -
>> -	xnlock_put_irqrestore(&nklock, s);
>> -}
>> -
>>  static void xnpipe_wakeup_proc(void *cookie)
>>  {
>>  	xnholder_t *holder, *nholder;
>> @@ -168,7 +155,6 @@ static void xnpipe_wakeup_proc(void *coo
>>  			   before calling wake_up_interruptible(). */
>>  			if ((rbits & XNPIPE_USER_WREAD_READY) != 0) {
>>  				if (waitqueue_active(&state->readq)) {
>> -					xnpipe_dequeue_wait(state, XNPIPE_USER_WREAD);
>>  					xnlock_put_irqrestore(&nklock, s);
>>  					wake_up_interruptible(&state->readq);
>>  					rbits &= ~XNPIPE_USER_WREAD_READY;
>> @@ -177,7 +163,6 @@ static void xnpipe_wakeup_proc(void *coo
>>  			}
>>  			if ((rbits & XNPIPE_USER_WSYNC_READY) != 0) {
>>  				if (waitqueue_active(&state->syncq)) {
>> -					xnpipe_dequeue_wait(state, XNPIPE_USER_WSYNC);
>>  					xnlock_put_irqrestore(&nklock, s);
>>  					wake_up_interruptible(&state->syncq);
>>  					rbits &= ~XNPIPE_USER_WSYNC_READY;
>> @@ -666,8 +651,7 @@ static int xnpipe_open(struct inode *ino
>>  		sigpending = xnpipe_wait(state, XNPIPE_USER_WREAD, s,
>>  					 testbits(state->status, XNPIPE_KERN_CONN));
>>  		if (sigpending) {
>> -			if (!testbits(state->status, XNPIPE_KERN_CONN))
>> -				xnpipe_cleanup_user_conn(state);
>> +			xnpipe_cleanup_user_conn(state);
>>  			xnlock_put_irqrestore(&nklock, s);
>>  			return -ERESTARTSYS;
>>  		}
> 


-- 
Philippe.


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

* Re: [Xenomai-core] [PATCH] xnpipe: fix state tracking of Linux side
  2008-10-17 13:45   ` Philippe Gerum
@ 2008-10-17 13:49     ` Jan Kiszka
  0 siblings, 0 replies; 4+ messages in thread
From: Jan Kiszka @ 2008-10-17 13:49 UTC (permalink / raw)
  To: rpm; +Cc: xenomai-core

Philippe Gerum wrote:
> Jan Kiszka wrote:
>> Jan Kiszka wrote:
>>> The state tracking of Linux tasks queue on xnpipe events was fairly
>>> broken. An easy way to corrupt some xnpipe_state_t object was to kill a
>>> Linux task blocked on opening a /dev/rtpX device (this left the state
>>> object queued in xnpipe_sleep, and hell broke loose on next queuing).
>>>
>>> Another problem that popped up after reworking xnpipe queuing was a
>>> stalled XNPIPE_USER_CONN after receiving a signal in xnpipe_open.
>>>
>>> The following patch addresses both issues, appears to run fine so far
>>> (at least the test case no longer triggers), and also cleans up some
>>> redundant nklock acquisitions/releases. Nevertheless, I may miss some
>>> corner case that might have triggered the original design. So please
>>> check carefully.
>> While fighting over a single bit elsewhere, let's not forget this open
>> issue:
> 
> I did not forget this issue. It is close to the top of stack now.
> 
>  Customer asks for a solution of the hard lock-up he faced, and
>> /me would like to know if this fix comes with no obvious regressions.
>>
> 
> The patch looks sane, but I want to run a few tests that have been developed
> over time to chase bugs in that code, before giving the patch a go. ETA: tomorrow.
> 

Great, thanks.

Jan

-- 
Siemens AG, Corporate Technology, CT SE 2
Corporate Competence Center Embedded Linux


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

end of thread, other threads:[~2008-10-17 13:49 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2008-10-13 20:40 [Xenomai-core] [PATCH] xnpipe: fix state tracking of Linux side Jan Kiszka
2008-10-17 11:17 ` Jan Kiszka
2008-10-17 13:45   ` Philippe Gerum
2008-10-17 13:49     ` Jan Kiszka

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.