hugetlbfs: use i_mmap_rwsem for more pmd sharing synchronization
[linux-2.6-microblaze.git] / mm / userfaultfd.c
index 458acda..4836858 100644 (file)
@@ -267,10 +267,14 @@ retry:
                VM_BUG_ON(dst_addr & ~huge_page_mask(h));
 
                /*
-                * Serialize via hugetlb_fault_mutex
+                * Serialize via i_mmap_rwsem and hugetlb_fault_mutex.
+                * i_mmap_rwsem ensures the dst_pte remains valid even
+                * in the case of shared pmds.  fault mutex prevents
+                * races with other faulting threads.
                 */
-               idx = linear_page_index(dst_vma, dst_addr);
                mapping = dst_vma->vm_file->f_mapping;
+               i_mmap_lock_read(mapping);
+               idx = linear_page_index(dst_vma, dst_addr);
                hash = hugetlb_fault_mutex_hash(h, dst_mm, dst_vma, mapping,
                                                                idx, dst_addr);
                mutex_lock(&hugetlb_fault_mutex_table[hash]);
@@ -279,6 +283,7 @@ retry:
                dst_pte = huge_pte_alloc(dst_mm, dst_addr, huge_page_size(h));
                if (!dst_pte) {
                        mutex_unlock(&hugetlb_fault_mutex_table[hash]);
+                       i_mmap_unlock_read(mapping);
                        goto out_unlock;
                }
 
@@ -286,6 +291,7 @@ retry:
                dst_pteval = huge_ptep_get(dst_pte);
                if (!huge_pte_none(dst_pteval)) {
                        mutex_unlock(&hugetlb_fault_mutex_table[hash]);
+                       i_mmap_unlock_read(mapping);
                        goto out_unlock;
                }
 
@@ -293,6 +299,7 @@ retry:
                                                dst_addr, src_addr, &page);
 
                mutex_unlock(&hugetlb_fault_mutex_table[hash]);
+               i_mmap_unlock_read(mapping);
                vm_alloc_shared = vm_shared;
 
                cond_resched();