History

mm/hugetlb: fix deadlock in hugetlb_cow error path

syzbot reported the deadlock here [1]. The issue is in hugetlb cow error handling when there are not enough huge pages for the faulting task which took the original reservation. It is possible that other (child) tasks could have consumed pages associated with the reservation. In this case, we want the task which took the original reservation to succeed. So, we unmap any associated pages in children so that they can be used by the faulting task that owns the reservation. The unmapping code needs to hold i_mmap_rwsem in write mode. However, due to commit c0d0381ade79 ("hugetlbfs: use i_mmap_rwsem for more pmd sharing synchronization") we are already holding i_mmap_rwsem in read mode when hugetlb_cow is called. Technically, i_mmap_rwsem does not need to be held in read mode for COW mappings as they can not share pmd's. Modifying the fault code to not take i_mmap_rwsem in read mode for COW (and other non-sharable) mappings is too involved for a stable fix. Instead, we simply drop the hugetlb_fault_mutex and i_mmap_rwsem before unmapping. This is OK as it is technically not needed. They are reacquired after unmapping as expected by calling code. Since this is done in an uncommon error path, the overhead of dropping and reacquiring mutexes is acceptable. While making changes, remove redundant BUG_ON after unmap_ref_private. [1] https://lkml.kernel.org/r/000000000000b73ccc05b5cf8558@google.com

Mike Kravetz committed 5 years ago

Commit e7dd91c1 parent 7cf22a11 file · +21 −1Browse files

Unified · Split

mm/hugetlb.c+21−1
@@ -4105,10 +4105,30 @@ retry_avoidcopy: · 4104 unmodified lines
4105 * may get SIGKILLed if it later faults.4105 * may get SIGKILLed if it later faults.
4106 */4106 */
4107 if (outside_reserve) {4107 if (outside_reserve) {
4108 struct address_space *mapping = vma->vm_file->f_mapping;
4109 pgoff_t idx;
4110 u32 hash;
4111
4108 put_page(old_page);4112 put_page(old_page);
4109 BUG_ON(huge_pte_none(pte));4113 BUG_ON(huge_pte_none(pte));
4114 /*
4115 * Drop hugetlb_fault_mutex and i_mmap_rwsem before
4116 * unmapping. unmapping needs to hold i_mmap_rwsem
4117 * in write mode. Dropping i_mmap_rwsem in read mode
4118 * here is OK as COW mappings do not interact with
4119 * PMD sharing.
4120 *
4121 * Reacquire both after unmap operation.
4122 */
4123 idx = vma_hugecache_offset(h, vma, haddr);
4124 hash = hugetlb_fault_mutex_hash(mapping, idx);
4125 mutex_unlock(&hugetlb_fault_mutex_table[hash]);
4126 i_mmap_unlock_read(mapping);
4127
4110 unmap_ref_private(mm, vma, old_page, haddr);4128 unmap_ref_private(mm, vma, old_page, haddr);
4111 BUG_ON(huge_pte_none(pte));4129
4130 i_mmap_lock_read(mapping);
4131 mutex_lock(&hugetlb_fault_mutex_table[hash]);
4112 spin_lock(ptl);4132 spin_lock(ptl);
4113 ptep = huge_pte_offset(mm, haddr, huge_page_size(h));4133 ptep = huge_pte_offset(mm, haddr, huge_page_size(h));
4114 if (likely(ptep &&4134 if (likely(ptep &&