@ -821,26 +821,23 @@ void prep_transhuge_page(struct page *page)
set_compound_page_dtor ( page , TRANSHUGE_PAGE_DTOR ) ;
}
static int __do_huge_pmd_anonymous_page ( struct mm_struct * mm ,
struct vm_area_struct * vma ,
unsigned long address , pmd_t * pmd ,
struct page * page , gfp_t gfp ,
unsigned int flags )
static int __do_huge_pmd_anonymous_page ( struct fault_env * fe , struct page * page ,
gfp_t gfp )
{
struct vm_area_struct * vma = fe - > vma ;
struct mem_cgroup * memcg ;
pgtable_t pgtable ;
spinlock_t * ptl ;
unsigned long haddr = address & HPAGE_PMD_MASK ;
unsigned long haddr = fe - > address & HPAGE_PMD_MASK ;
VM_BUG_ON_PAGE ( ! PageCompound ( page ) , page ) ;
if ( mem_cgroup_try_charge ( page , mm , gfp , & memcg , true ) ) {
if ( mem_cgroup_try_charge ( page , vma - > vm_ mm, gfp , & memcg , true ) ) {
put_page ( page ) ;
count_vm_event ( THP_FAULT_FALLBACK ) ;
return VM_FAULT_FALLBACK ;
}
pgtable = pte_alloc_one ( mm , haddr ) ;
pgtable = pte_alloc_one ( vma - > vm_ mm, haddr ) ;
if ( unlikely ( ! pgtable ) ) {
mem_cgroup_cancel_charge ( page , memcg , true ) ;
put_page ( page ) ;
@ -855,12 +852,12 @@ static int __do_huge_pmd_anonymous_page(struct mm_struct *mm,
*/
__SetPageUptodate ( page ) ;
ptl = pmd_lock ( mm , pmd ) ;
if ( unlikely ( ! pmd_none ( * pmd ) ) ) {
spin_unlock ( ptl ) ;
fe - > ptl = pmd_lock ( vma - > vm_ mm, fe - > pmd ) ;
if ( unlikely ( ! pmd_none ( * fe - > pmd ) ) ) {
spin_unlock ( fe - > ptl ) ;
mem_cgroup_cancel_charge ( page , memcg , true ) ;
put_page ( page ) ;
pte_free ( mm , pgtable ) ;
pte_free ( vma - > vm_ mm, pgtable ) ;
} else {
pmd_t entry ;
@ -868,12 +865,11 @@ static int __do_huge_pmd_anonymous_page(struct mm_struct *mm,
if ( userfaultfd_missing ( vma ) ) {
int ret ;
spin_unlock ( ptl ) ;
spin_unlock ( fe - > ptl ) ;
mem_cgroup_cancel_charge ( page , memcg , true ) ;
put_page ( page ) ;
pte_free ( mm , pgtable ) ;
ret = handle_userfault ( vma , address , flags ,
VM_UFFD_MISSING ) ;
pte_free ( vma - > vm_mm , pgtable ) ;
ret = handle_userfault ( fe , VM_UFFD_MISSING ) ;
VM_BUG_ON ( ret & VM_FAULT_FALLBACK ) ;
return ret ;
}
@ -883,11 +879,11 @@ static int __do_huge_pmd_anonymous_page(struct mm_struct *mm,
page_add_new_anon_rmap ( page , vma , haddr , true ) ;
mem_cgroup_commit_charge ( page , memcg , false , true ) ;
lru_cache_add_active_or_unevictable ( page , vma ) ;
pgtable_trans_huge_deposit ( mm , pmd , pgtable ) ;
set_pmd_at ( mm , haddr , pmd , entry ) ;
add_mm_counter ( mm , MM_ANONPAGES , HPAGE_PMD_NR ) ;
atomic_long_inc ( & mm - > nr_ptes ) ;
spin_unlock ( ptl ) ;
pgtable_trans_huge_deposit ( vma - > vm_ mm, fe - > pmd , pgtable ) ;
set_pmd_at ( vma - > vm_ mm, haddr , fe - > pmd , entry ) ;
add_mm_counter ( vma - > vm_ mm, MM_ANONPAGES , HPAGE_PMD_NR ) ;
atomic_long_inc ( & vma - > vm_ mm- > nr_ptes ) ;
spin_unlock ( fe - > ptl ) ;
count_vm_event ( THP_FAULT_ALLOC ) ;
}
@ -937,13 +933,12 @@ static bool set_huge_zero_page(pgtable_t pgtable, struct mm_struct *mm,
return true ;
}
int do_huge_pmd_anonymous_page ( struct mm_struct * mm , struct vm_area_struct * vma ,
unsigned long address , pmd_t * pmd ,
unsigned int flags )
int do_huge_pmd_anonymous_page ( struct fault_env * fe )
{
struct vm_area_struct * vma = fe - > vma ;
gfp_t gfp ;
struct page * page ;
unsigned long haddr = address & HPAGE_PMD_MASK ;
unsigned long haddr = fe - > address & HPAGE_PMD_MASK ;
if ( haddr < vma - > vm_start | | haddr + HPAGE_PMD_SIZE > vma - > vm_end )
return VM_FAULT_FALLBACK ;
@ -951,42 +946,40 @@ int do_huge_pmd_anonymous_page(struct mm_struct *mm, struct vm_area_struct *vma,
return VM_FAULT_OOM ;
if ( unlikely ( khugepaged_enter ( vma , vma - > vm_flags ) ) )
return VM_FAULT_OOM ;
if ( ! ( flags & FAULT_FLAG_WRITE ) & & ! mm_forbids_zeropage ( mm ) & &
if ( ! ( fe - > flags & FAULT_FLAG_WRITE ) & &
! mm_forbids_zeropage ( vma - > vm_mm ) & &
transparent_hugepage_use_zero_page ( ) ) {
spinlock_t * ptl ;
pgtable_t pgtable ;
struct page * zero_page ;
bool set ;
int ret ;
pgtable = pte_alloc_one ( mm , haddr ) ;
pgtable = pte_alloc_one ( vma - > vm_ mm, haddr ) ;
if ( unlikely ( ! pgtable ) )
return VM_FAULT_OOM ;
zero_page = get_huge_zero_page ( ) ;
if ( unlikely ( ! zero_page ) ) {
pte_free ( mm , pgtable ) ;
pte_free ( vma - > vm_ mm, pgtable ) ;
count_vm_event ( THP_FAULT_FALLBACK ) ;
return VM_FAULT_FALLBACK ;
}
ptl = pmd_lock ( mm , pmd ) ;
fe - > ptl = pmd_lock ( vma - > vm_ mm, fe - > pmd ) ;
ret = 0 ;
set = false ;
if ( pmd_none ( * pmd ) ) {
if ( pmd_none ( * fe - > pmd ) ) {
if ( userfaultfd_missing ( vma ) ) {
spin_unlock ( ptl ) ;
ret = handle_userfault ( vma , address , flags ,
VM_UFFD_MISSING ) ;
spin_unlock ( fe - > ptl ) ;
ret = handle_userfault ( fe , VM_UFFD_MISSING ) ;
VM_BUG_ON ( ret & VM_FAULT_FALLBACK ) ;
} else {
set_huge_zero_page ( pgtable , mm , vma ,
haddr , pmd ,
zero_page ) ;
spin_unlock ( ptl ) ;
set_huge_zero_page ( pgtable , vma - > vm_mm , vma ,
haddr , fe - > pmd , zero_page ) ;
spin_unlock ( fe - > ptl ) ;
set = true ;
}
} else
spin_unlock ( ptl ) ;
spin_unlock ( fe - > ptl ) ;
if ( ! set ) {
pte_free ( mm , pgtable ) ;
pte_free ( vma - > vm_ mm, pgtable ) ;
put_huge_zero_page ( ) ;
}
return ret ;
@ -998,8 +991,7 @@ int do_huge_pmd_anonymous_page(struct mm_struct *mm, struct vm_area_struct *vma,
return VM_FAULT_FALLBACK ;
}
prep_transhuge_page ( page ) ;
return __do_huge_pmd_anonymous_page ( mm , vma , address , pmd , page , gfp ,
flags ) ;
return __do_huge_pmd_anonymous_page ( fe , page , gfp ) ;
}
static void insert_pfn_pmd ( struct vm_area_struct * vma , unsigned long addr ,
@ -1172,38 +1164,31 @@ out:
return ret ;
}
void huge_pmd_set_accessed ( struct mm_struct * mm ,
struct vm_area_struct * vma ,
unsigned long address ,
pmd_t * pmd , pmd_t orig_pmd ,
int dirty )
void huge_pmd_set_accessed ( struct fault_env * fe , pmd_t orig_pmd )
{
spinlock_t * ptl ;
pmd_t entry ;
unsigned long haddr ;
ptl = pmd_lock ( mm , pmd ) ;
if ( unlikely ( ! pmd_same ( * pmd , orig_pmd ) ) )
fe - > ptl = pmd_lock ( fe - > vma - > vm_ mm, fe - > pmd ) ;
if ( unlikely ( ! pmd_same ( * fe - > pmd , orig_pmd ) ) )
goto unlock ;
entry = pmd_mkyoung ( orig_pmd ) ;
haddr = address & HPAGE_PMD_MASK ;
if ( pmdp_set_access_flags ( vma , haddr , pmd , entry , dirty ) )
update_mmu_cache_pmd ( vma , address , pmd ) ;
haddr = fe - > address & HPAGE_PMD_MASK ;
if ( pmdp_set_access_flags ( fe - > vma , haddr , fe - > pmd , entry ,
fe - > flags & FAULT_FLAG_WRITE ) )
update_mmu_cache_pmd ( fe - > vma , fe - > address , fe - > pmd ) ;
unlock :
spin_unlock ( ptl ) ;
spin_unlock ( fe - > ptl ) ;
}
static int do_huge_pmd_wp_page_fallback ( struct mm_struct * mm ,
struct vm_area_struct * vma ,
unsigned long address ,
pmd_t * pmd , pmd_t orig_pmd ,
struct page * page ,
unsigned long haddr )
static int do_huge_pmd_wp_page_fallback ( struct fault_env * fe , pmd_t orig_pmd ,
struct page * page )
{
struct vm_area_struct * vma = fe - > vma ;
unsigned long haddr = fe - > address & HPAGE_PMD_MASK ;
struct mem_cgroup * memcg ;
spinlock_t * ptl ;
pgtable_t pgtable ;
pmd_t _pmd ;
int ret = 0 , i ;
@ -1220,11 +1205,11 @@ static int do_huge_pmd_wp_page_fallback(struct mm_struct *mm,
for ( i = 0 ; i < HPAGE_PMD_NR ; i + + ) {
pages [ i ] = alloc_page_vma_node ( GFP_HIGHUSER_MOVABLE |
__GFP_OTHER_NODE ,
vma , address , page_to_nid ( page ) ) ;
__GFP_OTHER_NODE , vma ,
fe - > address , page_to_nid ( page ) ) ;
if ( unlikely ( ! pages [ i ] | |
mem_cgroup_try_charge ( pages [ i ] , mm , GFP_KERNEL ,
& memcg , false ) ) ) {
mem_cgroup_try_charge ( pages [ i ] , vma - > vm_mm ,
GFP_KERNEL , & memcg , false ) ) ) {
if ( pages [ i ] )
put_page ( pages [ i ] ) ;
while ( - - i > = 0 ) {
@ -1250,41 +1235,41 @@ static int do_huge_pmd_wp_page_fallback(struct mm_struct *mm,
mmun_start = haddr ;
mmun_end = haddr + HPAGE_PMD_SIZE ;
mmu_notifier_invalidate_range_start ( mm , mmun_start , mmun_end ) ;
mmu_notifier_invalidate_range_start ( vma - > vm_ mm, mmun_start , mmun_end ) ;
ptl = pmd_lock ( mm , pmd ) ;
if ( unlikely ( ! pmd_same ( * pmd , orig_pmd ) ) )
fe - > ptl = pmd_lock ( vma - > vm_ mm, fe - > pmd ) ;
if ( unlikely ( ! pmd_same ( * fe - > pmd , orig_pmd ) ) )
goto out_free_pages ;
VM_BUG_ON_PAGE ( ! PageHead ( page ) , page ) ;
pmdp_huge_clear_flush_notify ( vma , haddr , pmd ) ;
pmdp_huge_clear_flush_notify ( vma , haddr , fe - > pmd ) ;
/* leave pmd empty until pte is filled */
pgtable = pgtable_trans_huge_withdraw ( mm , pmd ) ;
pmd_populate ( mm , & _pmd , pgtable ) ;
pgtable = pgtable_trans_huge_withdraw ( vma - > vm_ mm, fe - > pmd ) ;
pmd_populate ( vma - > vm_ mm, & _pmd , pgtable ) ;
for ( i = 0 ; i < HPAGE_PMD_NR ; i + + , haddr + = PAGE_SIZE ) {
pte_t * pte , entry ;
pte_t entry ;
entry = mk_pte ( pages [ i ] , vma - > vm_page_prot ) ;
entry = maybe_mkwrite ( pte_mkdirty ( entry ) , vma ) ;
memcg = ( void * ) page_private ( pages [ i ] ) ;
set_page_private ( pages [ i ] , 0 ) ;
page_add_new_anon_rmap ( pages [ i ] , vma , haddr , false ) ;
page_add_new_anon_rmap ( pages [ i ] , fe - > vma , haddr , false ) ;
mem_cgroup_commit_charge ( pages [ i ] , memcg , false , false ) ;
lru_cache_add_active_or_unevictable ( pages [ i ] , vma ) ;
pte = pte_offset_map ( & _pmd , haddr ) ;
VM_BUG_ON ( ! pte_none ( * pte ) ) ;
set_pte_at ( mm , haddr , pte , entry ) ;
pte_unmap ( pte ) ;
fe - > pte = pte_offset_map ( & _pmd , haddr ) ;
VM_BUG_ON ( ! pte_none ( * fe - > pte ) ) ;
set_pte_at ( vma - > vm_ mm, haddr , fe - > pte , entry ) ;
pte_unmap ( fe - > pte ) ;
}
kfree ( pages ) ;
smp_wmb ( ) ; /* make pte visible before pmd */
pmd_populate ( mm , pmd , pgtable ) ;
pmd_populate ( vma - > vm_ mm, fe - > pmd , pgtable ) ;
page_remove_rmap ( page , true ) ;
spin_unlock ( ptl ) ;
spin_unlock ( fe - > ptl ) ;
mmu_notifier_invalidate_range_end ( mm , mmun_start , mmun_end ) ;
mmu_notifier_invalidate_range_end ( vma - > vm_ mm, mmun_start , mmun_end ) ;
ret | = VM_FAULT_WRITE ;
put_page ( page ) ;
@ -1293,8 +1278,8 @@ out:
return ret ;
out_free_pages :
spin_unlock ( ptl ) ;
mmu_notifier_invalidate_range_end ( mm , mmun_start , mmun_end ) ;
spin_unlock ( fe - > ptl ) ;
mmu_notifier_invalidate_range_end ( vma - > vm_ mm, mmun_start , mmun_end ) ;
for ( i = 0 ; i < HPAGE_PMD_NR ; i + + ) {
memcg = ( void * ) page_private ( pages [ i ] ) ;
set_page_private ( pages [ i ] , 0 ) ;
@ -1305,25 +1290,23 @@ out_free_pages:
goto out ;
}
int do_huge_pmd_wp_page ( struct mm_struct * mm , struct vm_area_struct * vma ,
unsigned long address , pmd_t * pmd , pmd_t orig_pmd )
int do_huge_pmd_wp_page ( struct fault_env * fe , pmd_t orig_pmd )
{
spinlock_t * ptl ;
int ret = 0 ;
struct vm_area_struct * vma = fe - > vma ;
struct page * page = NULL , * new_page ;
struct mem_cgroup * memcg ;
unsigned long haddr ;
unsigned long haddr = fe - > address & HPAGE_PMD_MASK ;
unsigned long mmun_start ; /* For mmu_notifiers */
unsigned long mmun_end ; /* For mmu_notifiers */
gfp_t huge_gfp ; /* for allocation and charge */
int ret = 0 ;
ptl = pmd_lockptr ( mm , pmd ) ;
fe - > ptl = pmd_lockptr ( vma - > vm_ mm, fe - > pmd ) ;
VM_BUG_ON_VMA ( ! vma - > anon_vma , vma ) ;
haddr = address & HPAGE_PMD_MASK ;
if ( is_huge_zero_pmd ( orig_pmd ) )
goto alloc ;
spin_lock ( ptl ) ;
if ( unlikely ( ! pmd_same ( * pmd , orig_pmd ) ) )
spin_lock ( fe - > ptl ) ;
if ( unlikely ( ! pmd_same ( * fe - > pmd , orig_pmd ) ) )
goto out_unlock ;
page = pmd_page ( orig_pmd ) ;
@ -1336,13 +1319,13 @@ int do_huge_pmd_wp_page(struct mm_struct *mm, struct vm_area_struct *vma,
pmd_t entry ;
entry = pmd_mkyoung ( orig_pmd ) ;
entry = maybe_pmd_mkwrite ( pmd_mkdirty ( entry ) , vma ) ;
if ( pmdp_set_access_flags ( vma , haddr , pmd , entry , 1 ) )
update_mmu_cache_pmd ( vma , address , pmd ) ;
if ( pmdp_set_access_flags ( vma , haddr , fe - > pmd , entry , 1 ) )
update_mmu_cache_pmd ( vma , fe - > address , fe - > pmd ) ;
ret | = VM_FAULT_WRITE ;
goto out_unlock ;
}
get_page ( page ) ;
spin_unlock ( ptl ) ;
spin_unlock ( fe - > ptl ) ;
alloc :
if ( transparent_hugepage_enabled ( vma ) & &
! transparent_hugepage_debug_cow ( ) ) {
@ -1355,13 +1338,12 @@ alloc:
prep_transhuge_page ( new_page ) ;
} else {
if ( ! page ) {
split_huge_pmd ( vma , pmd , address ) ;
split_huge_pmd ( vma , fe - > pmd , fe - > address ) ;
ret | = VM_FAULT_FALLBACK ;
} else {
ret = do_huge_pmd_wp_page_fallback ( mm , vma , address ,
pmd , orig_pmd , page , haddr ) ;
ret = do_huge_pmd_wp_page_fallback ( fe , orig_pmd , page ) ;
if ( ret & VM_FAULT_OOM ) {
split_huge_pmd ( vma , pmd , address ) ;
split_huge_pmd ( vma , fe - > pmd , fe - > address ) ;
ret | = VM_FAULT_FALLBACK ;
}
put_page ( page ) ;
@ -1370,14 +1352,12 @@ alloc:
goto out ;
}
if ( unlikely ( mem_cgroup_try_charge ( new_page , mm , huge_gfp , & memcg ,
true ) ) ) {
if ( unlikely ( mem_cgroup_try_charge ( new_page , vma - > vm_mm ,
huge_gfp , & memcg , true ) ) ) {
put_page ( new_page ) ;
if ( page ) {
split_huge_pmd ( vma , pmd , address ) ;
split_huge_pmd ( vma , fe - > pmd , fe - > address ) ;
if ( page )
put_page ( page ) ;
} else
split_huge_pmd ( vma , pmd , address ) ;
ret | = VM_FAULT_FALLBACK ;
count_vm_event ( THP_FAULT_FALLBACK ) ;
goto out ;
@ -1393,13 +1373,13 @@ alloc:
mmun_start = haddr ;
mmun_end = haddr + HPAGE_PMD_SIZE ;
mmu_notifier_invalidate_range_start ( mm , mmun_start , mmun_end ) ;
mmu_notifier_invalidate_range_start ( vma - > vm_ mm, mmun_start , mmun_end ) ;
spin_lock ( ptl ) ;
spin_lock ( fe - > ptl ) ;
if ( page )
put_page ( page ) ;
if ( unlikely ( ! pmd_same ( * pmd , orig_pmd ) ) ) {
spin_unlock ( ptl ) ;
if ( unlikely ( ! pmd_same ( * fe - > pmd , orig_pmd ) ) ) {
spin_unlock ( fe - > ptl ) ;
mem_cgroup_cancel_charge ( new_page , memcg , true ) ;
put_page ( new_page ) ;
goto out_mn ;
@ -1407,14 +1387,14 @@ alloc:
pmd_t entry ;
entry = mk_huge_pmd ( new_page , vma - > vm_page_prot ) ;
entry = maybe_pmd_mkwrite ( pmd_mkdirty ( entry ) , vma ) ;
pmdp_huge_clear_flush_notify ( vma , haddr , pmd ) ;
pmdp_huge_clear_flush_notify ( vma , haddr , fe - > pmd ) ;
page_add_new_anon_rmap ( new_page , vma , haddr , true ) ;
mem_cgroup_commit_charge ( new_page , memcg , false , true ) ;
lru_cache_add_active_or_unevictable ( new_page , vma ) ;
set_pmd_at ( mm , haddr , pmd , entry ) ;
update_mmu_cache_pmd ( vma , address , pmd ) ;
set_pmd_at ( vma - > vm_ mm, haddr , fe - > pmd , entry ) ;
update_mmu_cache_pmd ( vma , fe - > address , fe - > pmd ) ;
if ( ! page ) {
add_mm_counter ( mm , MM_ANONPAGES , HPAGE_PMD_NR ) ;
add_mm_counter ( vma - > vm_ mm, MM_ANONPAGES , HPAGE_PMD_NR ) ;
put_huge_zero_page ( ) ;
} else {
VM_BUG_ON_PAGE ( ! PageHead ( page ) , page ) ;
@ -1423,13 +1403,13 @@ alloc:
}
ret | = VM_FAULT_WRITE ;
}
spin_unlock ( ptl ) ;
spin_unlock ( fe - > ptl ) ;
out_mn :
mmu_notifier_invalidate_range_end ( mm , mmun_start , mmun_end ) ;
mmu_notifier_invalidate_range_end ( vma - > vm_ mm, mmun_start , mmun_end ) ;
out :
return ret ;
out_unlock :
spin_unlock ( ptl ) ;
spin_unlock ( fe - > ptl ) ;
return ret ;
}
@ -1489,13 +1469,12 @@ out:
}
/* NUMA hinting page fault entry point for trans huge pmds */
int do_huge_pmd_numa_page ( struct mm_struct * mm , struct vm_area_struct * vma ,
unsigned long addr , pmd_t pmd , pmd_t * pmdp )
int do_huge_pmd_numa_page ( struct fault_env * fe , pmd_t pmd )
{
spinlock_t * ptl ;
struct vm_area_struct * vma = fe - > vma ;
struct anon_vma * anon_vma = NULL ;
struct page * page ;
unsigned long haddr = addr & HPAGE_PMD_MASK ;
unsigned long haddr = fe - > address & HPAGE_PMD_MASK ;
int page_nid = - 1 , this_nid = numa_node_id ( ) ;
int target_nid , last_cpupid = - 1 ;
bool page_locked ;
@ -1506,8 +1485,8 @@ int do_huge_pmd_numa_page(struct mm_struct *mm, struct vm_area_struct *vma,
/* A PROT_NONE fault should not end up here */
BUG_ON ( ! ( vma - > vm_flags & ( VM_READ | VM_EXEC | VM_WRITE ) ) ) ;
ptl = pmd_lock ( mm , pmdp ) ;
if ( unlikely ( ! pmd_same ( pmd , * pmdp ) ) )
fe - > ptl = pmd_lock ( vma - > vm_ mm, fe - > pmd ) ;
if ( unlikely ( ! pmd_same ( pmd , * fe - > pmd ) ) )
goto out_unlock ;
/*
@ -1515,9 +1494,9 @@ int do_huge_pmd_numa_page(struct mm_struct *mm, struct vm_area_struct *vma,
* without disrupting NUMA hinting information . Do not relock and
* check_same as the page may no longer be mapped .
*/
if ( unlikely ( pmd_trans_migrating ( * pmdp ) ) ) {
page = pmd_page ( * pmdp ) ;
spin_unlock ( ptl ) ;
if ( unlikely ( pmd_trans_migrating ( * fe - > pmd ) ) ) {
page = pmd_page ( * fe - > pmd ) ;
spin_unlock ( fe - > ptl ) ;
wait_on_page_locked ( page ) ;
goto out ;
}
@ -1550,7 +1529,7 @@ int do_huge_pmd_numa_page(struct mm_struct *mm, struct vm_area_struct *vma,
/* Migration could have started since the pmd_trans_migrating check */
if ( ! page_locked ) {
spin_unlock ( ptl ) ;
spin_unlock ( fe - > ptl ) ;
wait_on_page_locked ( page ) ;
page_nid = - 1 ;
goto out ;
@ -1561,12 +1540,12 @@ int do_huge_pmd_numa_page(struct mm_struct *mm, struct vm_area_struct *vma,
* to serialises splits
*/
get_page ( page ) ;
spin_unlock ( ptl ) ;
spin_unlock ( fe - > ptl ) ;
anon_vma = page_lock_anon_vma_read ( page ) ;
/* Confirm the PMD did not change while page_table_lock was released */
spin_lock ( ptl ) ;
if ( unlikely ( ! pmd_same ( pmd , * pmdp ) ) ) {
spin_lock ( fe - > ptl ) ;
if ( unlikely ( ! pmd_same ( pmd , * fe - > pmd ) ) ) {
unlock_page ( page ) ;
put_page ( page ) ;
page_nid = - 1 ;
@ -1584,9 +1563,9 @@ int do_huge_pmd_numa_page(struct mm_struct *mm, struct vm_area_struct *vma,
* Migrate the THP to the requested node , returns with page unlocked
* and access rights restored .
*/
spin_unlock ( ptl ) ;
migrated = migrate_misplaced_transhuge_page ( mm , vma ,
pmdp , pmd , addr , page , target_nid ) ;
spin_unlock ( fe - > ptl ) ;
migrated = migrate_misplaced_transhuge_page ( vma - > vm_ mm, vma ,
fe - > pmd , pmd , fe - > address , page , target_nid ) ;
if ( migrated ) {
flags | = TNF_MIGRATED ;
page_nid = target_nid ;
@ -1601,18 +1580,18 @@ clear_pmdnuma:
pmd = pmd_mkyoung ( pmd ) ;
if ( was_writable )
pmd = pmd_mkwrite ( pmd ) ;
set_pmd_at ( mm , haddr , pmdp , pmd ) ;
update_mmu_cache_pmd ( vma , addr , pmdp ) ;
set_pmd_at ( vma - > vm_ mm, haddr , fe - > pmd , pmd ) ;
update_mmu_cache_pmd ( vma , fe - > address , fe - > pmd ) ;
unlock_page ( page ) ;
out_unlock :
spin_unlock ( ptl ) ;
spin_unlock ( fe - > ptl ) ;
out :
if ( anon_vma )
page_unlock_anon_vma_read ( anon_vma ) ;
if ( page_nid ! = - 1 )
task_numa_fault ( last_cpupid , page_nid , HPAGE_PMD_NR , flags ) ;
task_numa_fault ( last_cpupid , page_nid , HPAGE_PMD_NR , fe - > f lags ) ;
return 0 ;
}
@ -2413,20 +2392,23 @@ static bool __collapse_huge_page_swapin(struct mm_struct *mm,
struct vm_area_struct * vma ,
unsigned long address , pmd_t * pmd )
{
unsigned long _address ;
pte_t * pte , pteval ;
pte_t pteval ;
int swapped_in = 0 , ret = 0 ;
pte = pte_offset_map ( pmd , address ) ;
for ( _address = address ; _address < address + HPAGE_PMD_NR * PAGE_SIZE ;
pte + + , _address + = PAGE_SIZE ) {
pteval = * pte ;
struct fault_env fe = {
. vma = vma ,
. address = address ,
. flags = FAULT_FLAG_ALLOW_RETRY ,
. pmd = pmd ,
} ;
fe . pte = pte_offset_map ( pmd , address ) ;
for ( ; fe . address < address + HPAGE_PMD_NR * PAGE_SIZE ;
fe . pte + + , fe . address + = PAGE_SIZE ) {
pteval = * fe . pte ;
if ( ! is_swap_pte ( pteval ) )
continue ;
swapped_in + + ;
ret = do_swap_page ( mm , vma , _address , pte , pmd ,
FAULT_FLAG_ALLOW_RETRY ,
pteval ) ;
ret = do_swap_page ( & fe , pteval ) ;
/* do_swap_page returns VM_FAULT_RETRY with released mmap_sem */
if ( ret & VM_FAULT_RETRY ) {
down_read ( & mm - > mmap_sem ) ;
@ -2442,10 +2424,10 @@ static bool __collapse_huge_page_swapin(struct mm_struct *mm,
return false ;
}
/* pte is unmapped now, we need to map it */
pte = pte_offset_map ( pmd , _ address) ;
fe . pte = pte_offset_map ( pmd , fe . address ) ;
}
pte - - ;
pte_unmap ( pte ) ;
fe . pte - - ;
pte_unmap ( fe . pte ) ;
trace_mm_collapse_huge_page_swapin ( mm , swapped_in , 1 ) ;
return true ;
}