linux-fsdevel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH] block: Avoid missed wakeup in request waitqueue
@ 2012-05-28  4:19 Asias He
  2012-05-28 10:26 ` Tejun Heo
  0 siblings, 1 reply; 6+ messages in thread
From: Asias He @ 2012-05-28  4:19 UTC (permalink / raw)
  To: Jens Axboe, Tejun Heo; +Cc: linux-fsdevel, linux-kernel, Asias He

After hot-unplug a stressed disk, I found that rl->wait[] is not empty
while rl->count[] is empty and there are theads still sleeping on
get_request after the queue cleanup. With simple debug code, I found
there are exactly nr_sleep - nr_wakeup of theads in D state. So there
are missed wakeup.

  $ dmesg | grep nr_sleep
  [   52.917115] ---> nr_sleep=1046, nr_wakeup=873, delta=173
  $ vmstat 1
  1 173  0 712640  24292  96172 0 0  0  0  419  757  0  0  0 100  0

To quote Tejun:

  Ah, okay, freed_request() wakes up single waiter with the assumption
  that after the wakeup there will at least be one successful allocation
  which in turn will continue the wakeup chain until the wait list is
  empty - ie. waiter wakeup is dependent on successful request
  allocation happening after each wakeup.  With queue marked dead, any
  woken up waiter fails the allocation path, so the wakeup chaining is
  lost and we're left with hung waiters. What we need is wake_up_all()
  after drain completion.

This patch fixes the missed wakeup by waking up all the theads which
are sleeping on wait queue after queue drain.

Signed-off-by: Asias He <asias@redhat.com>
---
 block/blk-core.c |   11 ++++++++++-
 1 file changed, 10 insertions(+), 1 deletion(-)

diff --git a/block/blk-core.c b/block/blk-core.c
index 1f61b74..1a45877 100644
--- a/block/blk-core.c
+++ b/block/blk-core.c
@@ -359,9 +359,10 @@ EXPORT_SYMBOL(blk_put_queue);
  */
 void blk_drain_queue(struct request_queue *q, bool drain_all)
 {
+	int i;
+
 	while (true) {
 		bool drain = false;
-		int i;
 
 		spin_lock_irq(q->queue_lock);
 
@@ -400,6 +401,14 @@ void blk_drain_queue(struct request_queue *q, bool drain_all)
 			break;
 		msleep(10);
 	}
+
+	/* Wake up threads which are sleeping on get_request() */
+	spin_lock_irq(q->queue_lock);
+	for (i = 0; i < ARRAY_SIZE(q->rq.wait); i++) {
+		if (waitqueue_active(&q->rq.wait[i]))
+			wake_up_all(&q->rq.wait[i]);
+	}
+	spin_unlock_irq(q->queue_lock);
 }
 
 /**
-- 
1.7.10.2

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

* Re: [PATCH] block: Avoid missed wakeup in request waitqueue
  2012-05-28  4:19 [PATCH] block: Avoid missed wakeup in request waitqueue Asias He
@ 2012-05-28 10:26 ` Tejun Heo
  2012-05-29  1:15   ` [PATCH V2] " Asias He
  2012-05-29  1:16   ` [PATCH] " Asias He
  0 siblings, 2 replies; 6+ messages in thread
From: Tejun Heo @ 2012-05-28 10:26 UTC (permalink / raw)
  To: Asias He; +Cc: Jens Axboe, linux-fsdevel, linux-kernel

On Mon, May 28, 2012 at 12:19:03PM +0800, Asias He wrote:
> diff --git a/block/blk-core.c b/block/blk-core.c
> index 1f61b74..1a45877 100644
> --- a/block/blk-core.c
> +++ b/block/blk-core.c
> @@ -359,9 +359,10 @@ EXPORT_SYMBOL(blk_put_queue);
>   */
>  void blk_drain_queue(struct request_queue *q, bool drain_all)
>  {
> +	int i;
> +
>  	while (true) {
>  		bool drain = false;
> -		int i;
>  
>  		spin_lock_irq(q->queue_lock);
>  
> @@ -400,6 +401,14 @@ void blk_drain_queue(struct request_queue *q, bool drain_all)
>  			break;
>  		msleep(10);
>  	}
> +
> +	/* Wake up threads which are sleeping on get_request() */
> +	spin_lock_irq(q->queue_lock);
> +	for (i = 0; i < ARRAY_SIZE(q->rq.wait); i++) {
> +		if (waitqueue_active(&q->rq.wait[i]))
> +			wake_up_all(&q->rq.wait[i]);
> +	}
> +	spin_unlock_irq(q->queue_lock);

I don't think we need waitqueue_active() optimization here.  Let's
just do,

	/* please explain why this is necessary */
	for (i = 0; i < ARRAY_SIZE(q->rq.wait); i++)
		wake_up_all(&q->rq.wait[i]);

Thanks.

-- 
tejun

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

* [PATCH V2] block: Avoid missed wakeup in request waitqueue
  2012-05-28 10:26 ` Tejun Heo
@ 2012-05-29  1:15   ` Asias He
  2012-05-29  1:21     ` Tejun Heo
  2012-05-29  1:16   ` [PATCH] " Asias He
  1 sibling, 1 reply; 6+ messages in thread
From: Asias He @ 2012-05-29  1:15 UTC (permalink / raw)
  To: Jens Axboe, Tejun Heo; +Cc: linux-fsdevel, linux-kernel, Asias He

After hot-unplug a stressed disk, I found that rl->wait[] is not empty
while rl->count[] is empty and there are theads still sleeping on
get_request after the queue cleanup. With simple debug code, I found
there are exactly nr_sleep - nr_wakeup of theads in D state. So there
are missed wakeup.

  $ dmesg | grep nr_sleep
  [   52.917115] ---> nr_sleep=1046, nr_wakeup=873, delta=173
  $ vmstat 1
  1 173  0 712640  24292  96172 0 0  0  0  419  757  0  0  0 100  0

To quote Tejun:

  Ah, okay, freed_request() wakes up single waiter with the assumption
  that after the wakeup there will at least be one successful allocation
  which in turn will continue the wakeup chain until the wait list is
  empty - ie. waiter wakeup is dependent on successful request
  allocation happening after each wakeup.  With queue marked dead, any
  woken up waiter fails the allocation path, so the wakeup chaining is
  lost and we're left with hung waiters. What we need is wake_up_all()
  after drain completion.

This patch fixes the missed wakeup by waking up all the theads which
are sleeping on wait queue after queue drain.

Changes in v2: Drop waitqueue_active() optimization

Signed-off-by: Asias He <asias@redhat.com>
---
 block/blk-core.c |   13 ++++++++++++-
 1 file changed, 12 insertions(+), 1 deletion(-)

diff --git a/block/blk-core.c b/block/blk-core.c
index 1f61b74..232fe89 100644
--- a/block/blk-core.c
+++ b/block/blk-core.c
@@ -359,9 +359,10 @@ EXPORT_SYMBOL(blk_put_queue);
  */
 void blk_drain_queue(struct request_queue *q, bool drain_all)
 {
+	int i;
+
 	while (true) {
 		bool drain = false;
-		int i;
 
 		spin_lock_irq(q->queue_lock);
 
@@ -400,6 +401,16 @@ void blk_drain_queue(struct request_queue *q, bool drain_all)
 			break;
 		msleep(10);
 	}
+
+	/*
+	 * With queue marked dead, any woken up waiter will fail the
+	 * allocation path, so the wakeup chaining is lost and we're
+	 * left with hung waiters. We need to wake up those waiters.
+	 */
+	spin_lock_irq(q->queue_lock);
+	for (i = 0; i < ARRAY_SIZE(q->rq.wait); i++)
+		wake_up_all(&q->rq.wait[i]);
+	spin_unlock_irq(q->queue_lock);
 }
 
 /**
-- 
1.7.10.2


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

* Re: [PATCH] block: Avoid missed wakeup in request waitqueue
  2012-05-28 10:26 ` Tejun Heo
  2012-05-29  1:15   ` [PATCH V2] " Asias He
@ 2012-05-29  1:16   ` Asias He
  1 sibling, 0 replies; 6+ messages in thread
From: Asias He @ 2012-05-29  1:16 UTC (permalink / raw)
  To: Tejun Heo; +Cc: Jens Axboe, linux-fsdevel, linux-kernel

On 05/28/2012 06:26 PM, Tejun Heo wrote:
> On Mon, May 28, 2012 at 12:19:03PM +0800, Asias He wrote:
>> diff --git a/block/blk-core.c b/block/blk-core.c
>> index 1f61b74..1a45877 100644
>> --- a/block/blk-core.c
>> +++ b/block/blk-core.c
>> @@ -359,9 +359,10 @@ EXPORT_SYMBOL(blk_put_queue);
>>    */
>>   void blk_drain_queue(struct request_queue *q, bool drain_all)
>>   {
>> +	int i;
>> +
>>   	while (true) {
>>   		bool drain = false;
>> -		int i;
>>
>>   		spin_lock_irq(q->queue_lock);
>>
>> @@ -400,6 +401,14 @@ void blk_drain_queue(struct request_queue *q, bool drain_all)
>>   			break;
>>   		msleep(10);
>>   	}
>> +
>> +	/* Wake up threads which are sleeping on get_request() */
>> +	spin_lock_irq(q->queue_lock);
>> +	for (i = 0; i<  ARRAY_SIZE(q->rq.wait); i++) {
>> +		if (waitqueue_active(&q->rq.wait[i]))
>> +			wake_up_all(&q->rq.wait[i]);
>> +	}
>> +	spin_unlock_irq(q->queue_lock);
>
> I don't think we need waitqueue_active() optimization here.  Let's
> just do,
>
> 	/* please explain why this is necessary */
> 	for (i = 0; i<  ARRAY_SIZE(q->rq.wait); i++)
> 		wake_up_all(&q->rq.wait[i]);

OK. V2 is on its way.


-- 
Asias

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

* Re: [PATCH V2] block: Avoid missed wakeup in request waitqueue
  2012-05-29  1:15   ` [PATCH V2] " Asias He
@ 2012-05-29  1:21     ` Tejun Heo
  2012-06-06  2:14       ` Asias He
  0 siblings, 1 reply; 6+ messages in thread
From: Tejun Heo @ 2012-05-29  1:21 UTC (permalink / raw)
  To: Asias He; +Cc: Jens Axboe, linux-fsdevel, linux-kernel

On Tue, May 29, 2012 at 09:15:00AM +0800, Asias He wrote:
> After hot-unplug a stressed disk, I found that rl->wait[] is not empty
> while rl->count[] is empty and there are theads still sleeping on
> get_request after the queue cleanup. With simple debug code, I found
> there are exactly nr_sleep - nr_wakeup of theads in D state. So there
> are missed wakeup.
> 
>   $ dmesg | grep nr_sleep
>   [   52.917115] ---> nr_sleep=1046, nr_wakeup=873, delta=173
>   $ vmstat 1
>   1 173  0 712640  24292  96172 0 0  0  0  419  757  0  0  0 100  0
> 
> To quote Tejun:
> 
>   Ah, okay, freed_request() wakes up single waiter with the assumption
>   that after the wakeup there will at least be one successful allocation
>   which in turn will continue the wakeup chain until the wait list is
>   empty - ie. waiter wakeup is dependent on successful request
>   allocation happening after each wakeup.  With queue marked dead, any
>   woken up waiter fails the allocation path, so the wakeup chaining is
>   lost and we're left with hung waiters. What we need is wake_up_all()
>   after drain completion.
> 
> This patch fixes the missed wakeup by waking up all the theads which
> are sleeping on wait queue after queue drain.
> 
> Changes in v2: Drop waitqueue_active() optimization
> 
> Signed-off-by: Asias He <asias@redhat.com>

Acked-by: Tejun Heo <tj@kernel.org>

Jens, this one wants Cc: stable.

Thanks.

-- 
tejun

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

* Re: [PATCH V2] block: Avoid missed wakeup in request waitqueue
  2012-05-29  1:21     ` Tejun Heo
@ 2012-06-06  2:14       ` Asias He
  0 siblings, 0 replies; 6+ messages in thread
From: Asias He @ 2012-06-06  2:14 UTC (permalink / raw)
  To: Jens Axboe; +Cc: Tejun Heo, linux-fsdevel, linux-kernel

Hello, Jens

On 05/29/2012 09:21 AM, Tejun Heo wrote:
> On Tue, May 29, 2012 at 09:15:00AM +0800, Asias He wrote:
>> After hot-unplug a stressed disk, I found that rl->wait[] is not empty
>> while rl->count[] is empty and there are theads still sleeping on
>> get_request after the queue cleanup. With simple debug code, I found
>> there are exactly nr_sleep - nr_wakeup of theads in D state. So there
>> are missed wakeup.
>>
>>    $ dmesg | grep nr_sleep
>>    [   52.917115] --->  nr_sleep=1046, nr_wakeup=873, delta=173
>>    $ vmstat 1
>>    1 173  0 712640  24292  96172 0 0  0  0  419  757  0  0  0 100  0
>>
>> To quote Tejun:
>>
>>    Ah, okay, freed_request() wakes up single waiter with the assumption
>>    that after the wakeup there will at least be one successful allocation
>>    which in turn will continue the wakeup chain until the wait list is
>>    empty - ie. waiter wakeup is dependent on successful request
>>    allocation happening after each wakeup.  With queue marked dead, any
>>    woken up waiter fails the allocation path, so the wakeup chaining is
>>    lost and we're left with hung waiters. What we need is wake_up_all()
>>    after drain completion.
>>
>> This patch fixes the missed wakeup by waking up all the theads which
>> are sleeping on wait queue after queue drain.
>>
>> Changes in v2: Drop waitqueue_active() optimization
>>
>> Signed-off-by: Asias He<asias@redhat.com>
>
> Acked-by: Tejun Heo<tj@kernel.org>
>
> Jens, this one wants Cc: stable.

Ping.

-- 
Asias

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

end of thread, other threads:[~2012-06-06  2:13 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2012-05-28  4:19 [PATCH] block: Avoid missed wakeup in request waitqueue Asias He
2012-05-28 10:26 ` Tejun Heo
2012-05-29  1:15   ` [PATCH V2] " Asias He
2012-05-29  1:21     ` Tejun Heo
2012-06-06  2:14       ` Asias He
2012-05-29  1:16   ` [PATCH] " Asias He

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).