On 2012-10-25 18:21, Avi Kivity wrote:
> On 10/25/2012 11:31 AM, Jan Kiszka wrote:
>> On 2012-10-25 11:01, Avi Kivity wrote:
>>> On 10/24/2012 09:17 AM, Jan Kiszka wrote:
>>>>>>
>>>>>> This is ugly for many reasons. First of all, it is racy as the register
>>>>>> content may change while dropping the device lock, no? Then you would
>>>>>> raise or clear an IRQ spuriously.
>>>>>>
>>>>> Device state's intact is protected by busy flag, and will not broken
>>>>
>>>> Except that the busy flag concept is broken in itself.
>>>
>>> How do we fix an mmio that ends up mmio'ing back to itself, perhaps
>>> indirectly? Note this is broken in mainline too, but in a different way.
>>>
>>> Do we introduce clever locks that can detect deadlocks?
>>
>> That problem is already addressed (to my understanding) by blocking
>> nested MMIO in general.
>
> That doesn't work cross-thread.
>
> vcpu A: write to device X, dma-ing to device Y
> vcpu B: write to device Y, dma-ing to device X
We will deny DMA-ing from device X on behalf of a VCPU, ie. in dispatch
context, to Y.
What we do not deny, though, is DMA-ing from an I/O thread that
processes an event for device X. If the invoked callback of device X
holds the device lock across some DMA request to Y, then we risk to run
into the same ABBA issue. Hmm...
>
> My suggestion was to drop the locks around DMA, then re-acquire the lock
> and re-validate data.
Maybe possible, but hairy depending on the device model.
>
>> The brokenness of the busy flag is that it
>> prevents concurrent MMIO by dropping requests.
>
> Right.
>
>>
>>>
>>>> I see that we have a all-or-nothing problem here: to address this
>>>> properly, we need to convert the IRQ path to lock-less (or at least
>>>> compatible with holding per-device locks) as well.
>>>
>>> There is a transitional path where writing to a register that can cause
>>> IRQ changes takes both the big lock and the local lock.
>>>
>>> Eventually, though, of course all inner subsystems must be threaded for
>>> this work to have value.
>>>
>>
>> But that transitional path must not introduce regressions. Opening a
>> race window between IRQ cause update and event injection is such a
>> thing, just like dropping concurrent requests on the floor.
>
> Can you explain the race?
Context A Context B
device.lock
...
device.set interrupt_cause = 0
lower_irq = true
...
device.unlock
device.lock
...
device.interrupt_cause = 42
raise_irq = true
...
device.unlock
if (raise_irq)
bql.lock
set_irq(device.irqno)
bql.unlock
if (lower_irq)
bql.lock
clear_irq(device.irqno)
bql.unlock
And there it goes, our interrupt event.
Jan
--
Siemens AG, Corporate Technology, CT RTC ITP SDP-DE
Corporate Competence Center Embedded Linux