Re: [PATCH] mm/hugetlb: fix deadlock in hugetlb_cow error path

From: Mike Kravetz
Date: Tue Dec 15 2020 - 17:41:16 EST


On 12/14/20 5:06 PM, Mike Kravetz wrote:
> diff --git a/mm/hugetlb.c b/mm/hugetlb.c
> index d029d938d26d..8713f8ef0f4c 100644
> --- a/mm/hugetlb.c
> +++ b/mm/hugetlb.c
> @@ -4106,10 +4106,30 @@ static vm_fault_t hugetlb_cow(struct mm_struct *mm, struct vm_area_struct *vma,
> * may get SIGKILLed if it later faults.
> */
> if (outside_reserve) {
> + struct address_space *mapping = vma->vm_file->f_mapping;
> + pgoff_t idx;
> + u32 hash;
> +
> put_page(old_page);
> BUG_ON(huge_pte_none(pte));
> + /*
> + * Drop hugetlb_fault_mutex and i_mmap_rwsem before
> + * unmapping. unmapping needs to hold i_mmap_rwsem
> + * in write mode. Dropping i_mmap_rwsem in read mode
> + * here is OK as COW mappings do not interact with
> + * PMD sharing.
> + *
> + * Reacquire both after unmap operation.
> + */
> + idx = vma_hugecache_offset(h, vma, haddr);
> + hash = hugetlb_fault_mutex_hash(mapping, idx);
> + mutex_unlock(&hugetlb_fault_mutex_table[hash]);
> + i_mmap_unlock_read(vma->vm_file->f_mapping);

The assignment 'mapping = vma->vm_file->f_mapping' is done at the beginning
of this block. Silly that it is not used here.

> +
> unmap_ref_private(mm, vma, old_page, haddr);
> - BUG_ON(huge_pte_none(pte));
> +
> + i_mmap_lock_read(vma->vm_file->f_mapping);

and here.

> + mutex_lock(&hugetlb_fault_mutex_table[hash]);
> spin_lock(ptl);
> ptep = huge_pte_offset(mm, haddr, huge_page_size(h));
> if (likely(ptep &&
>

Updated patch to use block local variable mapping.