Skip to content

Commit ecfbd73

Browse files
mjkravetzakpm00
authored andcommitted
hugetlb: take hugetlb vma_lock when clearing vma_lock->vma pointer
hugetlb file truncation/hole punch code may need to back out and take locks in order in the routine hugetlb_unmap_file_folio(). This code could race with vma freeing as pointed out in [1] and result in accessing a stale vma pointer. To address this, take the vma_lock when clearing the vma_lock->vma pointer. [1] https://lore.kernel.org/linux-mm/[email protected]/ [[email protected]: address build issues] Link: https://lkml.kernel.org/r/Yz5L1uxQYR1VqFtJ@monkey Link: https://lkml.kernel.org/r/[email protected] Fixes: "hugetlb: use new vma_lock for pmd sharing synchronization" Signed-off-by: Mike Kravetz <[email protected]> Cc: Andrea Arcangeli <[email protected]> Cc: "Aneesh Kumar K.V" <[email protected]> Cc: Axel Rasmussen <[email protected]> Cc: David Hildenbrand <[email protected]> Cc: Davidlohr Bueso <[email protected]> Cc: James Houghton <[email protected]> Cc: "Kirill A. Shutemov" <[email protected]> Cc: Miaohe Lin <[email protected]> Cc: Michal Hocko <[email protected]> Cc: Mina Almasry <[email protected]> Cc: Muchun Song <[email protected]> Cc: Naoya Horiguchi <[email protected]> Cc: Pasha Tatashin <[email protected]> Cc: Peter Xu <[email protected]> Cc: Prakash Sangappa <[email protected]> Cc: Sven Schnelle <[email protected]> Signed-off-by: Andrew Morton <[email protected]>
1 parent 131a79b commit ecfbd73

File tree

1 file changed

+32
-10
lines changed

1 file changed

+32
-10
lines changed

mm/hugetlb.c

Lines changed: 32 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ struct mutex *hugetlb_fault_mutex_table ____cacheline_aligned_in_smp;
9393
static int hugetlb_acct_memory(struct hstate *h, long delta);
9494
static void hugetlb_vma_lock_free(struct vm_area_struct *vma);
9595
static void hugetlb_vma_lock_alloc(struct vm_area_struct *vma);
96+
static void __hugetlb_vma_unlock_write_free(struct vm_area_struct *vma);
9697

9798
static inline bool subpool_is_free(struct hugepage_subpool *spool)
9899
{
@@ -5188,8 +5189,7 @@ void __unmap_hugepage_range_final(struct mmu_gather *tlb,
51885189
* be asynchrously deleted. If the page tables are shared, there
51895190
* will be issues when accessed by someone else.
51905191
*/
5191-
hugetlb_vma_unlock_write(vma);
5192-
hugetlb_vma_lock_free(vma);
5192+
__hugetlb_vma_unlock_write_free(vma);
51935193

51945194
i_mmap_unlock_write(vma->vm_file->f_mapping);
51955195
}
@@ -6828,6 +6828,30 @@ void hugetlb_vma_lock_release(struct kref *kref)
68286828
kfree(vma_lock);
68296829
}
68306830

6831+
void __hugetlb_vma_unlock_write_put(struct hugetlb_vma_lock *vma_lock)
6832+
{
6833+
struct vm_area_struct *vma = vma_lock->vma;
6834+
6835+
/*
6836+
* vma_lock structure may or not be released as a result of put,
6837+
* it certainly will no longer be attached to vma so clear pointer.
6838+
* Semaphore synchronizes access to vma_lock->vma field.
6839+
*/
6840+
vma_lock->vma = NULL;
6841+
vma->vm_private_data = NULL;
6842+
up_write(&vma_lock->rw_sema);
6843+
kref_put(&vma_lock->refs, hugetlb_vma_lock_release);
6844+
}
6845+
6846+
static void __hugetlb_vma_unlock_write_free(struct vm_area_struct *vma)
6847+
{
6848+
if (__vma_shareable_flags_pmd(vma)) {
6849+
struct hugetlb_vma_lock *vma_lock = vma->vm_private_data;
6850+
6851+
__hugetlb_vma_unlock_write_put(vma_lock);
6852+
}
6853+
}
6854+
68316855
static void hugetlb_vma_lock_free(struct vm_area_struct *vma)
68326856
{
68336857
/*
@@ -6839,14 +6863,8 @@ static void hugetlb_vma_lock_free(struct vm_area_struct *vma)
68396863
if (vma->vm_private_data) {
68406864
struct hugetlb_vma_lock *vma_lock = vma->vm_private_data;
68416865

6842-
/*
6843-
* vma_lock structure may or not be released, but it
6844-
* certainly will no longer be attached to vma so clear
6845-
* pointer.
6846-
*/
6847-
vma_lock->vma = NULL;
6848-
kref_put(&vma_lock->refs, hugetlb_vma_lock_release);
6849-
vma->vm_private_data = NULL;
6866+
down_write(&vma_lock->rw_sema);
6867+
__hugetlb_vma_unlock_write_put(vma_lock);
68506868
}
68516869
}
68526870

@@ -6997,6 +7015,10 @@ void hugetlb_vma_lock_release(struct kref *kref)
69977015
{
69987016
}
69997017

7018+
static void __hugetlb_vma_unlock_write_free(struct vm_area_struct *vma)
7019+
{
7020+
}
7021+
70007022
static void hugetlb_vma_lock_free(struct vm_area_struct *vma)
70017023
{
70027024
}

0 commit comments

Comments
 (0)