• Ira Weiny's avatar
    mm/shmem: ensure proper fallback if page faults · 5dc21f0c
    Ira Weiny authored
    The kernel test robot flagged a recursive lock as a result of a conversion
    from kmap_atomic() to kmap_local_folio()[Link]
    
    The cause was due to the code depending on the kmap_atomic() side effect
    of disabling page faults.  In that case the code expects the fault to fail
    and take the fallback case.
    
    git archaeology implied that the recursion may not be an actual bug.[1]
    However, depending on the implementation of the mmap_lock and the
    condition of the call there may still be a deadlock.[2] So this is not
    purely a lockdep issue.  Considering a single threaded call stack there
    are 3 options.
    
    	1) Different mm's are in play (no issue)
    	2) Readlock implementation is recursive and same mm is in play
    	   (no issue)
    	3) Readlock implementation is _not_ recursive (issue)
    
    The mmap_lock is recursive so with a single thread there is no issue.
    
    However, Matthew pointed out a deadlock scenario when you consider
    additional process' and threads thusly.
    
    "The readlock implementation is only recursive if nobody else has taken a
    write lock.  If you have a multithreaded process, one of the other threads
    can call mmap() and that will prevent recursion (due to fairness).  Even
    if it's a different process that you're trying to acquire the mmap read
    lock on, you can still get into a deadly embrace.  eg:
    
    process A thread 1 takes read lock on own mmap_lock
    process A thread 2 calls mmap, blocks taking write lock
    process B thread 1 takes page fault, read lock on own mmap lock
    process B thread 2 calls mmap, blocks taking write lock
    process A thread 1 blocks taking read lock on process B
    process B thread 1 blocks taking read lock on process A
    
    Now all four threads are blocked waiting for each other."
    
    Regardless using pagefault_disable() ensures that no matter what locking
    implementation is used a deadlock will not occur.  Add an explicit
    pagefault_disable() and a big comment to explain this for future souls
    looking at this code.
    
    [1] https://lore.kernel.org/all/Y1MymJ%2FINb45AdaY@iweiny-desk3/
    [2] https://lore.kernel.org/lkml/Y1bXBtGTCym77%2FoD@casper.infradead.org/
    
    Link: https://lkml.kernel.org/r/20221025220108.2366043-1-ira.weiny@intel.com
    Link: https://lore.kernel.org/r/202210211215.9dc6efb5-yujie.liu@intel.com
    Fixes: 7a7256d5 ("shmem: convert shmem_mfill_atomic_pte() to use a folio")
    Signed-off-by: default avatarIra Weiny <ira.weiny@intel.com>
    Reported-by: default avatarMatthew Wilcox (Oracle) <willy@infradead.org>
    Reported-by: default avatarkernel test robot <yujie.liu@intel.com>
    Cc: Randy Dunlap <rdunlap@infradead.org>
    Cc: Peter Xu <peterx@redhat.com>
    Cc: Andrea Arcangeli <aarcange@redhat.com>
    Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
    5dc21f0c
shmem.c 112 KB