FAILED: patch "[PATCH] hugetlb: use same fault hash key for shared and private" failed to apply to 4.4-stable tree
Subsystems (4)
[email protected]
maintainerThe patch below does not apply to the 4.4-stable tree.
If someone wants it applied there, or to any other stable or longterm tree, then please email the backport, including the original git commit id to <[email protected]>.
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
From 1b426bac66e6cc83c9f2d92b96e4e72acf43419a Mon Sep 17 00:00:00 2001
From: Mike Kravetz <[email protected]>
Date: Mon, 13 May 2019 17:19:41 -0700
Subject: [PATCH] hugetlb: use same fault hash key for shared and private
mappings
hugetlb uses a fault mutex hash table to prevent page faults of the same pages concurrently. The key for shared and private mappings is different. Shared keys off address_space and file index. Private keys off mm and virtual address. Consider a private mappings of a populated hugetlbfs file. A fault will map the page from the file and if needed do a COW to map a writable page.
Hugetlbfs hole punch uses the fault mutex to prevent mappings of file pages. It uses the address_space file index key. However, private mappings will use a different key and could race with this code to map the file page. This causes problems (BUG) for the page cache remove code as it expects the page to be unmapped. A sample stack is:
page dumped because: VM_BUG_ON_PAGE(page_mapped(page)) kernel BUG at mm/filemap.c:169! ... RIP: 0010:unaccount_page_cache_page+0x1b8/0x200 ... Call Trace: __delete_from_page_cache+0x39/0x220 delete_from_page_cache+0x45/0x70 remove_inode_hugepages+0x13c/0x380 ? __add_to_page_cache_locked+0x162/0x380 hugetlbfs_fallocate+0x403/0x540 ? _cond_resched+0x15/0x30 ? __inode_security_revalidate+0x5d/0x70 ? selinux_file_permission+0x100/0x130 vfs_fallocate+0x13f/0x270 ksys_fallocate+0x3c/0x80 __x64_sys_fallocate+0x1a/0x20 do_syscall_64+0x5b/0x180 entry_SYSCALL_64_after_hwframe+0x44/0xa9
There seems to be another potential COW issue/race with this approach of different private and shared keys as noted in commit 8382d914ebf7 ("mm, hugetlb: improve page-fault scalability").
Since every hugetlb mapping (even anon and private) is actually a file mapping, just use the address_space index key for all mappings. This results in potentially more hash collisions. However, this should not be the common case.
fs/hugetlbfs/inode.c +2 -5
@@ -440,9 +440,7 @@ static void remove_inode_hugepages(struct inode *inode, loff_t lstart,u32 hash; index = page->index; - hash =hugetlb_fault_mutex_hash (h, current->mm, - &pseudo_vma, - mapping, index,0 ); + hash =hugetlb_fault_mutex_hash (h, mapping, index,0 );mutex_lock (&hugetlb_fault_mutex_table[hash]);/*
@@ -639,8 +637,7 @@ static long hugetlbfs_fallocate(struct file *file, int mode, loff_t offset, addr = index * hpage_size;/* mutex taken here, fault path and hole punch */ - hash =hugetlb_fault_mutex_hash (h, mm, &pseudo_vma, mapping, - index, addr); + hash =hugetlb_fault_mutex_hash (h, mapping, index, addr);mutex_lock (&hugetlb_fault_mutex_table[hash]);/* See if already present in mapping to avoid alloc/free */
include/linux/hugetlb.h +1 -3
@@ -123,9 +123,7 @@ void move_hugetlb_state(struct page *oldpage, struct page *newpage, int reason);void free_huge_page (struct page *page);void hugetlb_fix_reserve_counts (struct inode *inode);extern struct mutex *hugetlb_fault_mutex_table; -u32 hugetlb_fault_mutex_hash (struct hstate *h,struct mm_struct *mm, -struct vm_area_struct *vma, -struct address_space *mapping, +u32 hugetlb_fault_mutex_hash (struct hstate *h,struct address_space *mapping,pgoff_t idx,unsigned long address);pte_t *huge_pmd_share (struct mm_struct *mm,unsigned long addr,pud_t *pud);
mm/hugetlb.c +6 -16
@@ -3824,8 +3824,7 @@ static vm_fault_t hugetlb_no_page(struct mm_struct *mm,* handling userfault. Reacquire after handling * fault to make calling code simpler. */ - hash =hugetlb_fault_mutex_hash (h, mm, vma, mapping, - idx, haddr); + hash =hugetlb_fault_mutex_hash (h, mapping, idx, haddr);mutex_unlock (&hugetlb_fault_mutex_table[hash]); ret =handle_userfault (&vmf,VM_UFFD_MISSING );mutex_lock (&hugetlb_fault_mutex_table[hash]);
@@ -3933,21 +3932,14 @@ static vm_fault_t hugetlb_no_page(struct mm_struct *mm, }#ifdef CONFIG_SMP -u32 hugetlb_fault_mutex_hash (struct hstate *h,struct mm_struct *mm, -struct vm_area_struct *vma, -struct address_space *mapping, +u32 hugetlb_fault_mutex_hash (struct hstate *h,struct address_space *mapping,pgoff_t idx,unsigned long address) {unsigned long key[2 ];u32 hash; -if (vma->vm_flags &VM_SHARED ) { - key[0 ] = (unsigned long ) mapping; - key[1 ] = idx; - }else { - key[0 ] = (unsigned long ) mm; - key[1 ] = address >>huge_page_shift (h); - } + key[0 ] = (unsigned long ) mapping; + key[1 ] = idx; hash =jhash2 ((u32 *)&key,sizeof (key)/sizeof (u32),0 );
@@ -3958,9 +3950,7 @@ u32 hugetlb_fault_mutex_hash(struct hstate *h, struct mm_struct *mm,* For uniprocesor systems we always use a single mutex, so just * return 0 and avoid the hashing overhead. */ -u32 hugetlb_fault_mutex_hash (struct hstate *h,struct mm_struct *mm, -struct vm_area_struct *vma, -struct address_space *mapping, +u32 hugetlb_fault_mutex_hash (struct hstate *h,struct address_space *mapping,pgoff_t idx,unsigned long address) {return 0 ;
@@ -4005,7 +3995,7 @@ vm_fault_t hugetlb_fault(struct mm_struct *mm, struct vm_area_struct *vma,* get spurious allocation failures if two CPUs race to instantiate * the same page in the page cache. */ - hash =hugetlb_fault_mutex_hash (h, mm, vma, mapping, idx, haddr); + hash =hugetlb_fault_mutex_hash (h, mapping, idx, haddr);mutex_lock (&hugetlb_fault_mutex_table[hash]); entry =huge_ptep_get (ptep);
mm/userfaultfd.c +1 -2
@@ -271,8 +271,7 @@ static __always_inline ssize_t __mcopy_atomic_hugetlb(struct mm_struct *dst_mm,*/ idx =linear_page_index (dst_vma, dst_addr); mapping = dst_vma->vm_file->f_mapping; - hash =hugetlb_fault_mutex_hash (h, dst_mm, dst_vma, mapping, - idx, dst_addr); + hash =hugetlb_fault_mutex_hash (h, mapping, idx, dst_addr);mutex_lock (&hugetlb_fault_mutex_table[hash]); err = -ENOMEM ;
Quoted 5 lines · On 5/17/19 8:00 AM, [email protected] wrote:
The patch below does not apply to the 4.4-stable tree.
If someone wants it applied there, or to any other stable or longterm tree, then please email the backport, including the original git commit id to <[email protected]>.
From: Mike Kravetz <[email protected]>
Date: Thu, 23 May 2019 13:52:15 -0700
Subject: [PATCH] hugetlb: use same fault hash key for shared and private
mappings
commit 1b426bac66e6cc83c9f2d92b96e4e72acf43419a upstream.
hugetlb uses a fault mutex hash table to prevent page faults of the same pages concurrently. The key for shared and private mappings is different. Shared keys off address_space and file index. Private keys off mm and virtual address. Consider a private mappings of a populated hugetlbfs file. A fault will map the page from the file and if needed do a COW to map a writable page.
Hugetlbfs hole punch uses the fault mutex to prevent mappings of file pages. It uses the address_space file index key. However, private mappings will use a different key and could race with this code to map the file page. This causes problems (BUG) for the page cache remove code as it expects the page to be unmapped. A sample stack is:
page dumped because: VM_BUG_ON_PAGE(page_mapped(page)) kernel BUG at mm/filemap.c:169! ... RIP: 0010:unaccount_page_cache_page+0x1b8/0x200 ... Call Trace: __delete_from_page_cache+0x39/0x220 delete_from_page_cache+0x45/0x70 remove_inode_hugepages+0x13c/0x380 ? __add_to_page_cache_locked+0x162/0x380 hugetlbfs_fallocate+0x403/0x540 ? _cond_resched+0x15/0x30 ? __inode_security_revalidate+0x5d/0x70 ? selinux_file_permission+0x100/0x130 vfs_fallocate+0x13f/0x270 ksys_fallocate+0x3c/0x80 __x64_sys_fallocate+0x1a/0x20 do_syscall_64+0x5b/0x180 entry_SYSCALL_64_after_hwframe+0x44/0xa9
There seems to be another potential COW issue/race with this approach of different private and shared keys as noted in commit 8382d914ebf7 ("mm, hugetlb: improve page-fault scalability").
Since every hugetlb mapping (even anon and private) is actually a file mapping, just use the address_space index key for all mappings. This results in potentially more hash collisions. However, this should not be the common case.
--- fs/hugetlbfs/inode.c | 7 ++----- include/linux/hugetlb.h | 4 +--- mm/hugetlb.c | 19 +++++-------------- 3 files changed, 8 insertions(+), 22 deletions(-)
fs/hugetlbfs/inode.c +2 -5
@@ -414,9 +414,7 @@ static void remove_inode_hugepages(struct inode *inode, loff_t lstart,if (next >= end)break ; - hash =hugetlb_fault_mutex_hash (h, current->mm, - &pseudo_vma, - mapping, next,0 ); + hash =hugetlb_fault_mutex_hash (h, mapping, next,0 );mutex_lock (&hugetlb_fault_mutex_table[hash]);lock_page (page);
@@ -633,8 +631,7 @@ static long hugetlbfs_fallocate(struct file *file, int mode, loff_t offset, addr = index * hpage_size;/* mutex taken here, fault path and hole punch */ - hash =hugetlb_fault_mutex_hash (h, mm, &pseudo_vma, mapping, - index, addr); + hash =hugetlb_fault_mutex_hash (h, mapping, index, addr);mutex_lock (&hugetlb_fault_mutex_table[hash]);/* See if already present in mapping to avoid alloc/free */
include/linux/hugetlb.h +1 -3
@@ -91,9 +91,7 @@ void putback_active_hugepage(struct page *page);void free_huge_page (struct page *page);void hugetlb_fix_reserve_counts (struct inode *inode,bool restore_reserve);extern struct mutex *hugetlb_fault_mutex_table; -u32 hugetlb_fault_mutex_hash (struct hstate *h,struct mm_struct *mm, -struct vm_area_struct *vma, -struct address_space *mapping, +u32 hugetlb_fault_mutex_hash (struct hstate *h,struct address_space *mapping,pgoff_t idx,unsigned long address);#ifdef CONFIG_ARCH_WANT_HUGE_PMD_SHARE
mm/hugetlb.c +5 -14
@@ -3703,21 +3703,14 @@ backout_unlocked: }#ifdef CONFIG_SMP -u32 hugetlb_fault_mutex_hash (struct hstate *h,struct mm_struct *mm, -struct vm_area_struct *vma, -struct address_space *mapping, +u32 hugetlb_fault_mutex_hash (struct hstate *h,struct address_space *mapping,pgoff_t idx,unsigned long address) {unsigned long key[2 ];u32 hash; -if (vma->vm_flags &VM_SHARED ) { - key[0 ] = (unsigned long ) mapping; - key[1 ] = idx; - }else { - key[0 ] = (unsigned long ) mm; - key[1 ] = address >>huge_page_shift (h); - } + key[0 ] = (unsigned long ) mapping; + key[1 ] = idx; hash =jhash2 ((u32 *)&key,sizeof (key)/sizeof (u32),0 );
@@ -3728,9 +3721,7 @@ u32 hugetlb_fault_mutex_hash(struct hstate *h, struct mm_struct *mm,* For uniprocesor systems we always use a single mutex, so just * return 0 and avoid the hashing overhead. */ -u32 hugetlb_fault_mutex_hash (struct hstate *h,struct mm_struct *mm, -struct vm_area_struct *vma, -struct address_space *mapping, +u32 hugetlb_fault_mutex_hash (struct hstate *h,struct address_space *mapping,pgoff_t idx,unsigned long address) {return 0 ;
@@ -3776,7 +3767,7 @@ int hugetlb_fault(struct mm_struct *mm, struct vm_area_struct *vma,* get spurious allocation failures if two CPUs race to instantiate * the same page in the page cache. */ - hash =hugetlb_fault_mutex_hash (h, mm, vma, mapping, idx, address); + hash =hugetlb_fault_mutex_hash (h, mapping, idx, address);mutex_lock (&hugetlb_fault_mutex_table[hash]); entry =huge_ptep_get (ptep);
Signature · 1 line
2.20.1
Greg KH
maintainerQuoted 7 lines · Mike Kravetz
Quoted 5 lines · On 5/17/19 8:00 AM, [email protected] wrote:
The patch below does not apply to the 4.4-stable tree.
If someone wants it applied there, or to any other stable or longterm tree, then please email the backport, including the original git commit id to <[email protected]>.
Quoted 6 lines
From: Mike Kravetz <[email protected]>
Date: Thu, 23 May 2019 13:52:15 -0700
Subject: [PATCH] hugetlb: use same fault hash key for shared and private
mappingscommit
1b426bac66e6cc83c9f2d92b96e4e72acf43419aupstream.
Thanks for all of these, now queued up,
greg k-h
Greg KH
maintainerQuoted 82 lines · Mike Kravetz
Quoted 5 lines · On 5/17/19 8:00 AM, [email protected] wrote:
The patch below does not apply to the 4.4-stable tree.
If someone wants it applied there, or to any other stable or longterm tree, then please email the backport, including the original git commit id to <[email protected]>.From: Mike Kravetz <[email protected]>
Date: Thu, 23 May 2019 13:52:15 -0700
Subject: [PATCH] hugetlb: use same fault hash key for shared and private
mappingscommit
1b426bac66e6cc83c9f2d92b96e4e72acf43419aupstream.hugetlb uses a fault mutex hash table to prevent page faults of the same pages concurrently. The key for shared and private mappings is different. Shared keys off
address_spaceand file index. Private keys off mm and virtual address. Consider a private mappings of a populated hugetlbfs file. A fault will map the page from the file and if needed do a COW to map a writable page.Hugetlbfs hole punch uses the fault mutex to prevent mappings of file pages. It uses the
address_spacefile index key. However, private mappings will use a different key and could race with this code to map the file page. This causes problems (BUG) for the page cache remove code as it expects the page to be unmapped. A sample stack is:page dumped because: VM_BUG_ON_PAGE(page_mapped(page)) kernel BUG at mm/filemap.c:169! ... RIP: 0010:unaccount_page_cache_page+0x1b8/0x200 ... Call Trace: __delete_from_page_cache+0x39/0x220 delete_from_page_cache+0x45/0x70 remove_inode_hugepages+0x13c/0x380 ? __add_to_page_cache_locked+0x162/0x380 hugetlbfs_fallocate+0x403/0x540 ? _cond_resched+0x15/0x30 ? __inode_security_revalidate+0x5d/0x70 ? selinux_file_permission+0x100/0x130 vfs_fallocate+0x13f/0x270 ksys_fallocate+0x3c/0x80 __x64_sys_fallocate+0x1a/0x20 do_syscall_64+0x5b/0x180 entry_SYSCALL_64_after_hwframe+0x44/0xa9There seems to be another potential COW issue/race with this approach of different private and shared keys as noted in commit
8382d914ebf7("mm, hugetlb: improve page-fault scalability").Since every hugetlb mapping (even anon and private) is actually a file mapping, just use the
address_spaceindex key for all mappings. This results in potentially more hash collisions. However, this should not be the common case.Fixes b5cec28d36f5 ("hugetlbfs: truncate_hugepages() takes a range of pages")Signed-off-by Mike Kravetz <[email protected]>--- fs/hugetlbfs/inode.c | 7 ++----- include/linux/hugetlb.h | 4 +--- mm/hugetlb.c | 19 +++++-------------- 3 files changed, 8 insertions(+), 22 deletions(-)fs/hugetlbfs/inode.c +1
-3@@ -414,9 +414,7 @@ static void remove_inode_hugepages(struct inode *inode, loff_t lstart,if (next >= end)break ; - hash =hugetlb_fault_mutex_hash (h, current->mm, - &pseudo_vma, - mapping, next,0 ); + hash =hugetlb_fault_mutex_hash (h, mapping, next,0 );mutex_lock (&hugetlb_fault_mutex_table[hash]);lock_page (page);
fs/hugetlbfs/inode.c static long hugetlbfs_fallocate(struct file *file, int mode, loff_t offset, · line 637
Quoted 9 lines
fs/hugetlbfs/inode.c +1
-2@@ -633,8 +631,7 @@ static long hugetlbfs_fallocate(struct file *file, int mode, loff_t offset, addr = index * hpage_size;/* mutex taken here, fault path and hole punch */ - hash =hugetlb_fault_mutex_hash (h, mm, &pseudo_vma, mapping, - index, addr); + hash =hugetlb_fault_mutex_hash (h, mapping, index, addr);mutex_lock (&hugetlb_fault_mutex_table[hash]);/* See if already present in mapping to avoid alloc/free */
Note, this backport causes this warning:fs/hugetlbfs/inode.c: In function hugetlbfs_fallocate:fs/hugetlbfs/inode.c:570:20: warning: unused variable mm [-Wunused-variable]
struct mm_struct *mm = current->mm;
^~So I'll go delete that line as well.
thanks,
greg k-h
Quoted 96 lines · Greg KH
Quoted 82 lines · Mike Kravetz
Quoted 5 lines · On 5/17/19 8:00 AM, [email protected] wrote:
The patch below does not apply to the 4.4-stable tree.
If someone wants it applied there, or to any other stable or longterm tree, then please email the backport, including the original git commit id to <[email protected]>.From: Mike Kravetz <[email protected]>
Date: Thu, 23 May 2019 13:52:15 -0700
Subject: [PATCH] hugetlb: use same fault hash key for shared and private
mappingscommit
1b426bac66e6cc83c9f2d92b96e4e72acf43419aupstream.hugetlb uses a fault mutex hash table to prevent page faults of the same pages concurrently. The key for shared and private mappings is different. Shared keys off
address_spaceand file index. Private keys off mm and virtual address. Consider a private mappings of a populated hugetlbfs file. A fault will map the page from the file and if needed do a COW to map a writable page.Hugetlbfs hole punch uses the fault mutex to prevent mappings of file pages. It uses the
address_spacefile index key. However, private mappings will use a different key and could race with this code to map the file page. This causes problems (BUG) for the page cache remove code as it expects the page to be unmapped. A sample stack is:page dumped because: VM_BUG_ON_PAGE(page_mapped(page)) kernel BUG at mm/filemap.c:169! ... RIP: 0010:unaccount_page_cache_page+0x1b8/0x200 ... Call Trace: __delete_from_page_cache+0x39/0x220 delete_from_page_cache+0x45/0x70 remove_inode_hugepages+0x13c/0x380 ? __add_to_page_cache_locked+0x162/0x380 hugetlbfs_fallocate+0x403/0x540 ? _cond_resched+0x15/0x30 ? __inode_security_revalidate+0x5d/0x70 ? selinux_file_permission+0x100/0x130 vfs_fallocate+0x13f/0x270 ksys_fallocate+0x3c/0x80 __x64_sys_fallocate+0x1a/0x20 do_syscall_64+0x5b/0x180 entry_SYSCALL_64_after_hwframe+0x44/0xa9There seems to be another potential COW issue/race with this approach of different private and shared keys as noted in commit
8382d914ebf7("mm, hugetlb: improve page-fault scalability").Since every hugetlb mapping (even anon and private) is actually a file mapping, just use the
address_spaceindex key for all mappings. This results in potentially more hash collisions. However, this should not be the common case.Fixes b5cec28d36f5 ("hugetlbfs: truncate_hugepages() takes a range of pages")Signed-off-by Mike Kravetz <[email protected]>--- fs/hugetlbfs/inode.c | 7 ++----- include/linux/hugetlb.h | 4 +--- mm/hugetlb.c | 19 +++++-------------- 3 files changed, 8 insertions(+), 22 deletions(-)fs/hugetlbfs/inode.c +1
-3@@ -414,9 +414,7 @@ static void remove_inode_hugepages(struct inode *inode, loff_t lstart,if (next >= end)break ; - hash =hugetlb_fault_mutex_hash (h, current->mm, - &pseudo_vma, - mapping, next,0 ); + hash =hugetlb_fault_mutex_hash (h, mapping, next,0 );mutex_lock (&hugetlb_fault_mutex_table[hash]);lock_page (page);fs/hugetlbfs/inode.c static long hugetlbfs_fallocate(struct file *file, int mode, loff_t offset, · line 637
Quoted 9 lines
fs/hugetlbfs/inode.c +1
-2@@ -633,8 +631,7 @@ static long hugetlbfs_fallocate(struct file *file, int mode, loff_t offset, addr = index * hpage_size;/* mutex taken here, fault path and hole punch */ - hash =hugetlb_fault_mutex_hash (h, mm, &pseudo_vma, mapping, - index, addr); + hash =hugetlb_fault_mutex_hash (h, mapping, index, addr);mutex_lock (&hugetlb_fault_mutex_table[hash]);/* See if already present in mapping to avoid alloc/free */ Note, this backport causes this warning:
fs/hugetlbfs/inode.c: In functionhugetlbfs_fallocate:fs/hugetlbfs/inode.c:570:20: warning: unused variable mm [-Wunused-variable]
Quoted 5 lines
struct mm_struct *mm = current->mm; ^~So I'll go delete that line as well.
Please do.
Sorry I missed that.
Signature · 1 line
Mike Kravetz