• Paolo Bonzini's avatar
    srcu: Allow use of Classic SRCU from both process and interrupt context · 2ae7cdab
    Paolo Bonzini authored
    commit 1123a604 upstream.
    
    Linu Cherian reported a WARN in cleanup_srcu_struct() when shutting
    down a guest running iperf on a VFIO assigned device.  This happens
    because irqfd_wakeup() calls srcu_read_lock(&kvm->irq_srcu) in interrupt
    context, while a worker thread does the same inside kvm_set_irq().  If the
    interrupt happens while the worker thread is executing __srcu_read_lock(),
    updates to the Classic SRCU ->lock_count[] field or the Tree SRCU
    ->srcu_lock_count[] field can be lost.
    
    The docs say you are not supposed to call srcu_read_lock() and
    srcu_read_unlock() from irq context, but KVM interrupt injection happens
    from (host) interrupt context and it would be nice if SRCU supported the
    use case.  KVM is using SRCU here not really for the "sleepable" part,
    but rather due to its IPI-free fast detection of grace periods.  It is
    therefore not desirable to switch back to RCU, which would effectively
    revert commit 719d93cd ("kvm/irqchip: Speed up KVM_SET_GSI_ROUTING",
    2014-01-16).
    
    However, the docs are overly conservative.  You can have an SRCU instance
    only has users in irq context, and you can mix process and irq context
    as long as process context users disable interrupts.  In addition,
    __srcu_read_unlock() actually uses this_cpu_dec() on both Tree SRCU and
    Classic SRCU.  For those two implementations, only srcu_read_lock()
    is unsafe.
    
    When Classic SRCU's __srcu_read_unlock() was changed to use this_cpu_dec(),
    in commit 5a41344a ("srcu: Simplify __srcu_read_unlock() via
    this_cpu_dec()", 2012-11-29), __srcu_read_lock() did two increments.
    Therefore it kept __this_cpu_inc(), with preempt_disable/enable in
    the caller.  Tree SRCU however only does one increment, so on most
    architectures it is more efficient for __srcu_read_lock() to use
    this_cpu_inc(), and any performance differences appear to be down in
    the noise.
    
    Fixes: 719d93cd ("kvm/irqchip: Speed up KVM_SET_GSI_ROUTING")
    Reported-by: default avatarLinu Cherian <linuc.decode@gmail.com>
    Suggested-by: default avatarLinu Cherian <linuc.decode@gmail.com>
    Cc: kvm@vger.kernel.org
    Signed-off-by: default avatarPaolo Bonzini <pbonzini@redhat.com>
    Cc: Linus Torvalds <torvalds@linux-foundation.org>
    Signed-off-by: default avatarPaul E. McKenney <paulmck@linux.vnet.ibm.com>
    [bwh: Backported to 3.16: __srcu_read_lock() still updates two different
     counters.  So follow what  _this_cpu_generic_to_op() does and use
     raw_local_irq_{save,restore}() and raw_cpu_ptr().]
    Signed-off-by: default avatarBen Hutchings <ben@decadent.org.uk>
    2ae7cdab
srcu.c 22 KB