hugetlbfs: use i_mmap_rwsem for more pmd sharing synchronization
[linux-2.6-microblaze.git] / mm / userfaultfd.c
index 1b0d7ab..bd96855 100644 (file)
@@ -276,10 +276,14 @@ retry:
                BUG_ON(dst_addr >= dst_start + len);
 
                /*
-                * 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(mapping, idx);
                mutex_lock(&hugetlb_fault_mutex_table[hash]);
 
@@ -287,6 +291,7 @@ retry:
                dst_pte = huge_pte_alloc(dst_mm, dst_addr, vma_hpagesize);
                if (!dst_pte) {
                        mutex_unlock(&hugetlb_fault_mutex_table[hash]);
+                       i_mmap_unlock_read(mapping);
                        goto out_unlock;
                }
 
@@ -294,6 +299,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;
                }
 
@@ -301,6 +307,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();