• Vivek Goyal's avatar
    dax: Wake up all waiters after invalidating dax entry · 23738832
    Vivek Goyal authored
    I am seeing missed wakeups which ultimately lead to a deadlock when I am
    using virtiofs with DAX enabled and running "make -j". I had to mount
    virtiofs as rootfs and also reduce to dax window size to 256M to reproduce
    the problem consistently.
    
    So here is the problem. put_unlocked_entry() wakes up waiters only
    if entry is not null as well as !dax_is_conflict(entry). But if I
    call multiple instances of invalidate_inode_pages2() in parallel,
    then I can run into a situation where there are waiters on
    this index but nobody will wake these waiters.
    
    invalidate_inode_pages2()
      invalidate_inode_pages2_range()
        invalidate_exceptional_entry2()
          dax_invalidate_mapping_entry_sync()
            __dax_invalidate_entry() {
                    xas_lock_irq(&xas);
                    entry = get_unlocked_entry(&xas, 0);
                    ...
                    ...
                    dax_disassociate_entry(entry, mapping, trunc);
                    xas_store(&xas, NULL);
                    ...
                    ...
                    put_unlocked_entry(&xas, entry);
                    xas_unlock_irq(&xas);
            }
    
    Say a fault in in progress and it has locked entry at offset say "0x1c".
    Now say three instances of invalidate_inode_pages2() are in progress
    (A, B, C) and they all try to invalidate entry at offset "0x1c". Given
    dax entry is locked, all tree instances A, B, C will wait in wait queue.
    
    When dax fault finishes, say A is woken up. It will store NULL entry
    at index "0x1c" and wake up B. When B comes along it will find "entry=0"
    at page offset 0x1c and it will call put_unlocked_entry(&xas, 0). And
    this means put_unlocked_entry() will not wake up next waiter, given
    the current code. And that means C continues to wait and is not woken
    up.
    
    This patch fixes the issue by waking up all waiters when a dax entry
    has been invalidated. This seems to fix the deadlock I am facing
    and I can make forward progress.
    Reported-by: default avatarSergio Lopez <slp@redhat.com>
    Fixes: ac401cc7 ("dax: New fault locking")
    Reviewed-by: default avatarJan Kara <jack@suse.cz>
    Suggested-by: default avatarDan Williams <dan.j.williams@intel.com>
    Signed-off-by: default avatarVivek Goyal <vgoyal@redhat.com>
    Link: https://lore.kernel.org/r/20210428190314.1865312-4-vgoyal@redhat.comSigned-off-by: default avatarDan Williams <dan.j.williams@intel.com>
    23738832
dax.c 46.7 KB