[Devel] [PATCH RHEL7 COMMIT] mutex: Disable irqs in spin_[un]lock_mutex()

Konstantin Khorenko khorenko at virtuozzo.com
Fri May 13 15:47:46 MSK 2022


The commit is pushed to "branch-rh7-3.10.0-1160.62.1.vz7.187.x-ovz" and will appear at https://src.openvz.org/scm/ovz/vzkernel.git
after rh7-3.10.0-1160.62.1.vz7.187.2
------>
commit 5af4306ad845768b5a52e7734071e4fba62984c3
Author: Konstantin Khorenko <khorenko at virtuozzo.com>
Date:   Thu May 12 16:31:06 2022 +0300

    mutex: Disable irqs in spin_[un]lock_mutex()
    
    We've got an NMI and it turned out that in kaio fastpath code
    we do an unforgivable thing: we call mutex_trylock() in an IRQ context,
    consequently we get a punishment, deadlock:
    
    CPU 0 (kworker)                                 CPU 1 (ploop_fsync)
    ===============                                 ===================
    ext4_io_submit [ext4]                           aio_run_iocb
     submit_bio                                      ext4_file_write_iter [ext4]
      generic_make_request                          ! mutex_unlock(&inode->i_mutex);
       ploop_make_request [ploop]                      __mutex_unlock_slowpath
    !   spin_lock_irq(&plo->lock);                  // grabbed i_mutex->wait_lock, but no ret
        kaio_fastmap [pio_kaio]                        IRQ -> SOFTIRQ
         ext4_fastmap [ext4]                           ...
          mutex_unlock(&inode->i_mutex);               scsi_end_request
           __mutex_unlock_slowpath                      blk_update_request
    !       spin_lock_mutex(&i_mutex->wait_lock)         bio_endio
                                                          ploop_fast_end_io [ploop]
                                                     !     spin_lock_irqsave(&plo->lock);
    
    ====================================================================
    static __always_inline void queued_spin_lock(struct qspinlock *lock)
    {
            u32 val;
    
            val = atomic_cmpxchg(&lock->val, 0, _Q_LOCKED_VAL);
    // IRQ happened right here on CPU 1, val == 0
            if (likely(val == 0))
                    return;
            queued_spin_lock_slowpath(lock, val);
    }
    ====================================================================
    
    Unfortunately this cannot be easily avoided (and following the rules):
    fastpath is a hack and as we work with inode, we must hold its mutex,
    and ploop_make_request() itself may be called in an IRQ context.
    
    A workaround for this hack may be locking IRQ in
    spin_[un]lock_mutex(mutex->wait_lock).
    It's safe because in case CONFIG_DEBUG_MUTEXES spin_[un]lock_mutex()
    do disable/enable irqs.
    
    https://jira.sw.ru/browse/PSBM-139963
    Signed-off-by: Konstantin Khorenko <khorenko at virtuozzo.com>
---
 kernel/mutex.h | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/kernel/mutex.h b/kernel/mutex.h
index 4115fbf83b12..779af03f0ccf 100644
--- a/kernel/mutex.h
+++ b/kernel/mutex.h
@@ -10,9 +10,9 @@
  */
 
 #define spin_lock_mutex(lock, flags) \
-		do { spin_lock(lock); (void)(flags); } while (0)
+		do { spin_lock_irqsave(lock, flags); } while (0)
 #define spin_unlock_mutex(lock, flags) \
-		do { spin_unlock(lock); (void)(flags); } while (0)
+		do { spin_unlock_irqrestore(lock, flags); } while (0)
 #define mutex_remove_waiter(lock, waiter, ti) \
 		__list_del((waiter)->list.prev, (waiter)->list.next)
 


More information about the Devel mailing list