linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* blk-softirq vs smp_call_function_single_async()
@ 2020-06-08 11:58 Peter Zijlstra
  2020-06-08 15:45 ` Christoph Hellwig
  0 siblings, 1 reply; 8+ messages in thread
From: Peter Zijlstra @ 2020-06-08 11:58 UTC (permalink / raw)
  To: Jens Axboe; +Cc: frederic, linux-kernel, linux-block

Hi Jens,

I've been going through smp_call_function_single_async() users and
stumbled upon blk-softirq.c, which has:

static int raise_blk_irq(int cpu, struct request *rq)
{
	if (cpu_online(cpu)) {
		call_single_data_t *data = &rq->csd;

		data->func = trigger_softirq;
		data->info = rq;
		data->flags = 0;

		smp_call_function_single_async(cpu, data);
		return 0;
	}

	return 1;
}

What, if anything, guarantees rq->csd is not already in use at that
time?

The purpose of that CSD is to make the BLOCK_SOFTIRQ go, but there's
plenty of other ways to tickle that, afaict. So if that races vs someone
else, and that completes whatever was needed, then can't we get to
raise_blk_irq() again, even though the csd is still enqueued?

Worse; it has: data->flags = 0; so our early exit will not happen, even
when it should.

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

* Re: blk-softirq vs smp_call_function_single_async()
  2020-06-08 11:58 blk-softirq vs smp_call_function_single_async() Peter Zijlstra
@ 2020-06-08 15:45 ` Christoph Hellwig
  2020-06-08 15:58   ` Peter Zijlstra
  0 siblings, 1 reply; 8+ messages in thread
From: Christoph Hellwig @ 2020-06-08 15:45 UTC (permalink / raw)
  To: Peter Zijlstra; +Cc: Jens Axboe, frederic, linux-kernel, linux-block

On Mon, Jun 08, 2020 at 01:58:00PM +0200, Peter Zijlstra wrote:
> Hi Jens,
> 
> I've been going through smp_call_function_single_async() users and
> stumbled upon blk-softirq.c, which has:
> 
> static int raise_blk_irq(int cpu, struct request *rq)
> {
> 	if (cpu_online(cpu)) {
> 		call_single_data_t *data = &rq->csd;
> 
> 		data->func = trigger_softirq;
> 		data->info = rq;
> 		data->flags = 0;
> 
> 		smp_call_function_single_async(cpu, data);
> 		return 0;
> 	}
> 
> 	return 1;
> }
> 
> What, if anything, guarantees rq->csd is not already in use at that
> time?

A request can only be completed once.

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

* Re: blk-softirq vs smp_call_function_single_async()
  2020-06-08 15:45 ` Christoph Hellwig
@ 2020-06-08 15:58   ` Peter Zijlstra
  2020-06-08 16:33     ` Christoph Hellwig
  0 siblings, 1 reply; 8+ messages in thread
From: Peter Zijlstra @ 2020-06-08 15:58 UTC (permalink / raw)
  To: Christoph Hellwig; +Cc: Jens Axboe, frederic, linux-kernel, linux-block

On Mon, Jun 08, 2020 at 08:45:57AM -0700, Christoph Hellwig wrote:
> On Mon, Jun 08, 2020 at 01:58:00PM +0200, Peter Zijlstra wrote:
> > Hi Jens,
> > 
> > I've been going through smp_call_function_single_async() users and
> > stumbled upon blk-softirq.c, which has:
> > 
> > static int raise_blk_irq(int cpu, struct request *rq)
> > {
> > 	if (cpu_online(cpu)) {
> > 		call_single_data_t *data = &rq->csd;
> > 
> > 		data->func = trigger_softirq;
> > 		data->info = rq;
> > 		data->flags = 0;
> > 
> > 		smp_call_function_single_async(cpu, data);
> > 		return 0;
> > 	}
> > 
> > 	return 1;
> > }
> > 
> > What, if anything, guarantees rq->csd is not already in use at that
> > time?
> 
> A request can only be completed once.

Sure, but that doesn't help.

CPU0				CPU1

 raise_blk_irq()		BLOCK_SOFTIRQ
   IPI -> CPU1

				// picks up thing from CPU0
				req->complete(req);


	<big hole where CSD is active and request completed>

				<IPI>
				  trigger_softirq()


What happens to a struct request after completion, is it free()d
or reused? If reused, how do we guarantee CSD completion before
free()ing?



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

* Re: blk-softirq vs smp_call_function_single_async()
  2020-06-08 15:58   ` Peter Zijlstra
@ 2020-06-08 16:33     ` Christoph Hellwig
  2020-06-08 16:40       ` Peter Zijlstra
  0 siblings, 1 reply; 8+ messages in thread
From: Christoph Hellwig @ 2020-06-08 16:33 UTC (permalink / raw)
  To: Peter Zijlstra
  Cc: Christoph Hellwig, Jens Axboe, frederic, linux-kernel, linux-block

On Mon, Jun 08, 2020 at 05:58:33PM +0200, Peter Zijlstra wrote:
> > A request can only be completed once.
> 
> Sure, but that doesn't help.
> 
> CPU0				CPU1
> 
>  raise_blk_irq()		BLOCK_SOFTIRQ
>    IPI -> CPU1
> 
> 				// picks up thing from CPU0
> 				req->complete(req);
> 
> 
> 	<big hole where CSD is active and request completed>
> 
> 				<IPI>
> 				  trigger_softirq()
> 
> 
> What happens to a struct request after completion, is it free()d
> or reused? If reused, how do we guarantee CSD completion before
> free()ing?

The request is freed in the block layer sense by __blk_mq_free_request
(which doesn't actually free the memory, so it eventually gets reused).

__blk_mq_free_request is called from blk_mq_end_request which
is called from the drivers ->complete_rq method, which is called
from the block softirq.

What is the method to guaranteed CSD completion?

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

* Re: blk-softirq vs smp_call_function_single_async()
  2020-06-08 16:33     ` Christoph Hellwig
@ 2020-06-08 16:40       ` Peter Zijlstra
  2020-06-08 16:42         ` Christoph Hellwig
  2020-06-08 21:34         ` Jens Axboe
  0 siblings, 2 replies; 8+ messages in thread
From: Peter Zijlstra @ 2020-06-08 16:40 UTC (permalink / raw)
  To: Christoph Hellwig; +Cc: Jens Axboe, frederic, linux-kernel, linux-block

On Mon, Jun 08, 2020 at 09:33:42AM -0700, Christoph Hellwig wrote:
> On Mon, Jun 08, 2020 at 05:58:33PM +0200, Peter Zijlstra wrote:
> > > A request can only be completed once.
> > 
> > Sure, but that doesn't help.
> > 
> > CPU0				CPU1
> > 
> >  raise_blk_irq()		BLOCK_SOFTIRQ
> >    IPI -> CPU1
> > 
> > 				// picks up thing from CPU0
> > 				req->complete(req);
> > 
> > 
> > 	<big hole where CSD is active and request completed>
> > 
> > 				<IPI>
> > 				  trigger_softirq()
> > 
> > 
> > What happens to a struct request after completion, is it free()d
> > or reused? If reused, how do we guarantee CSD completion before
> > free()ing?
> 
> The request is freed in the block layer sense by __blk_mq_free_request
> (which doesn't actually free the memory, so it eventually gets reused).
> 
> __blk_mq_free_request is called from blk_mq_end_request which
> is called from the drivers ->complete_rq method, which is called
> from the block softirq.
> 
> What is the method to guaranteed CSD completion?

There isn't one, it was meant to be used with static allocations.

Frederic proposed changing all these to irq_work, and I think I'll go do
that. First dinner though.

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

* Re: blk-softirq vs smp_call_function_single_async()
  2020-06-08 16:40       ` Peter Zijlstra
@ 2020-06-08 16:42         ` Christoph Hellwig
  2020-06-09 13:38           ` Peter Zijlstra
  2020-06-08 21:34         ` Jens Axboe
  1 sibling, 1 reply; 8+ messages in thread
From: Christoph Hellwig @ 2020-06-08 16:42 UTC (permalink / raw)
  To: Peter Zijlstra
  Cc: Christoph Hellwig, Jens Axboe, frederic, linux-kernel, linux-block

On Mon, Jun 08, 2020 at 06:40:09PM +0200, Peter Zijlstra wrote:
> There isn't one, it was meant to be used with static allocations.
> 
> Frederic proposed changing all these to irq_work, and I think I'll go do
> that. First dinner though.

The irq_work API looks reasonable.  What are the tradeoffs for
smp_call_single_async vs irq_work?

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

* Re: blk-softirq vs smp_call_function_single_async()
  2020-06-08 16:40       ` Peter Zijlstra
  2020-06-08 16:42         ` Christoph Hellwig
@ 2020-06-08 21:34         ` Jens Axboe
  1 sibling, 0 replies; 8+ messages in thread
From: Jens Axboe @ 2020-06-08 21:34 UTC (permalink / raw)
  To: Peter Zijlstra, Christoph Hellwig; +Cc: frederic, linux-kernel, linux-block

On 6/8/20 10:40 AM, Peter Zijlstra wrote:
> On Mon, Jun 08, 2020 at 09:33:42AM -0700, Christoph Hellwig wrote:
>> On Mon, Jun 08, 2020 at 05:58:33PM +0200, Peter Zijlstra wrote:
>>>> A request can only be completed once.
>>>
>>> Sure, but that doesn't help.
>>>
>>> CPU0				CPU1
>>>
>>>  raise_blk_irq()		BLOCK_SOFTIRQ
>>>    IPI -> CPU1
>>>
>>> 				// picks up thing from CPU0
>>> 				req->complete(req);
>>>
>>>
>>> 	<big hole where CSD is active and request completed>
>>>
>>> 				<IPI>
>>> 				  trigger_softirq()
>>>
>>>
>>> What happens to a struct request after completion, is it free()d
>>> or reused? If reused, how do we guarantee CSD completion before
>>> free()ing?
>>
>> The request is freed in the block layer sense by __blk_mq_free_request
>> (which doesn't actually free the memory, so it eventually gets reused).
>>
>> __blk_mq_free_request is called from blk_mq_end_request which
>> is called from the drivers ->complete_rq method, which is called
>> from the block softirq.
>>
>> What is the method to guaranteed CSD completion?
> 
> There isn't one, it was meant to be used with static allocations.
> 
> Frederic proposed changing all these to irq_work, and I think I'll go do
> that. First dinner though.

That sounds good to me, and will also shrink struct request a bit,
which is always nice.

-- 
Jens Axboe


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

* Re: blk-softirq vs smp_call_function_single_async()
  2020-06-08 16:42         ` Christoph Hellwig
@ 2020-06-09 13:38           ` Peter Zijlstra
  0 siblings, 0 replies; 8+ messages in thread
From: Peter Zijlstra @ 2020-06-09 13:38 UTC (permalink / raw)
  To: Christoph Hellwig; +Cc: Jens Axboe, frederic, linux-kernel, linux-block

On Mon, Jun 08, 2020 at 09:42:54AM -0700, Christoph Hellwig wrote:
> On Mon, Jun 08, 2020 at 06:40:09PM +0200, Peter Zijlstra wrote:
> > There isn't one, it was meant to be used with static allocations.
> > 
> > Frederic proposed changing all these to irq_work, and I think I'll go do
> > that. First dinner though.

OK, after having looked at this more, I think my initial analysis is
actually wrong and this code should work as-is.

The thing that I missed yesterday is that we only add the request to the
blk_cpu_done list in the IPI, this means that the race I described
earlier is not in fact possible.

The IPI must happen for progress to be made.

And the same is true for blk_mq_force_complete_rq(), which also uses
this csd.

> The irq_work API looks reasonable.  What are the tradeoffs for
> smp_call_single_async vs irq_work?

To still answer your question; irq_work_queue*() has an atomic op extra
that allows for more convenient semantics -- but is in your case
strictly superfluous.

Still, Jens' point about irq_work being smaller stands, and I think more
users could benefit from something intermediate. Let me continue with
the cleanups / audit and see what comes out at the end.

Thanks!

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

end of thread, other threads:[~2020-06-09 13:39 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-06-08 11:58 blk-softirq vs smp_call_function_single_async() Peter Zijlstra
2020-06-08 15:45 ` Christoph Hellwig
2020-06-08 15:58   ` Peter Zijlstra
2020-06-08 16:33     ` Christoph Hellwig
2020-06-08 16:40       ` Peter Zijlstra
2020-06-08 16:42         ` Christoph Hellwig
2020-06-09 13:38           ` Peter Zijlstra
2020-06-08 21:34         ` Jens Axboe

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