diff mbox series

[2/2] thp, shmem: Fix conflict of above-47bit hint address and PMD alignment

Message ID 20191220142548.7118-3-kirill.shutemov@linux.intel.com (mailing list archive)
State New, archived
Headers show
Series Fix two above-47bit hint address vs. THP bugs | expand

Commit Message

Kirill A. Shutemov Dec. 20, 2019, 2:25 p.m. UTC
Shmem/tmpfs tries to provide THP-friendly mappings if huge pages are
enabled. But it doesn't work well with above-47bit hint address.

Normally, the kernel doesn't create userspace mappings above 47-bit,
even if the machine allows this (such as with 5-level paging on x86-64).
Not all user space is ready to handle wide addresses. It's known that
at least some JIT compilers use higher bits in pointers to encode their
information.

Userspace can ask for allocation from full address space by specifying
hint address (with or without MAP_FIXED) above 47-bits. If the
application doesn't need a particular address, but wants to allocate
from whole address space it can specify -1 as a hint address.

Unfortunately, this trick breaks THP alignment in shmem/tmp:
shmem_get_unmapped_area() would not try to allocate PMD-aligned area if
*any* hint address specified.

This can be fixed by requesting the aligned area if the we failed to
allocated at user-specified hint address. The request with inflated
length will also take the user-specified hint address. This way we will
not lose an allocation request from the full address space.

Signed-off-by: Kirill A. Shutemov <kirill.shutemov@linux.intel.com>
Fixes: b569bab78d8d ("x86/mm: Prepare to expose larger address space to userspace")
---
 mm/shmem.c | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

Comments

kernel test robot Dec. 28, 2019, 12:10 a.m. UTC | #1
Hi "Kirill,

Thank you for the patch! Perhaps something to improve:

[auto build test WARNING on linus/master]
[also build test WARNING on v5.5-rc3 next-20191220]
[if your patch is applied to the wrong git tree, please drop us a note to help
improve the system. BTW, we also suggest to use '--base' option to specify the
base tree in git format-patch, please see https://stackoverflow.com/a/37406982]

url:    https://github.com/0day-ci/linux/commits/Kirill-A-Shutemov/Fix-two-above-47bit-hint-address-vs-THP-bugs/20191223-221713
base:   https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git 46cf053efec6a3a5f343fead837777efe8252a46
reproduce:
        # apt-get install sparse
        # sparse version: v0.6.1-129-g341daf20-dirty
        make ARCH=x86_64 allmodconfig
        make C=1 CF='-fdiagnostic-prefix -D__CHECK_ENDIAN__'

If you fix the issue, kindly add following tag
Reported-by: kbuild test robot <lkp@intel.com>


sparse warnings: (new ones prefixed by >>)

>> mm/shmem.c:2147:34: sparse: sparse: incorrect type in argument 1 (different base types)
>> mm/shmem.c:2147:34: sparse:    expected struct file *
>> mm/shmem.c:2147:34: sparse:    got unsigned long uaddr

vim +2147 mm/shmem.c

  2073	
  2074	unsigned long shmem_get_unmapped_area(struct file *file,
  2075					      unsigned long uaddr, unsigned long len,
  2076					      unsigned long pgoff, unsigned long flags)
  2077	{
  2078		unsigned long (*get_area)(struct file *,
  2079			unsigned long, unsigned long, unsigned long, unsigned long);
  2080		unsigned long addr;
  2081		unsigned long offset;
  2082		unsigned long inflated_len;
  2083		unsigned long inflated_addr;
  2084		unsigned long inflated_offset;
  2085	
  2086		if (len > TASK_SIZE)
  2087			return -ENOMEM;
  2088	
  2089		get_area = current->mm->get_unmapped_area;
  2090		addr = get_area(file, uaddr, len, pgoff, flags);
  2091	
  2092		if (!IS_ENABLED(CONFIG_TRANSPARENT_HUGE_PAGECACHE))
  2093			return addr;
  2094		if (IS_ERR_VALUE(addr))
  2095			return addr;
  2096		if (addr & ~PAGE_MASK)
  2097			return addr;
  2098		if (addr > TASK_SIZE - len)
  2099			return addr;
  2100	
  2101		if (shmem_huge == SHMEM_HUGE_DENY)
  2102			return addr;
  2103		if (len < HPAGE_PMD_SIZE)
  2104			return addr;
  2105		if (flags & MAP_FIXED)
  2106			return addr;
  2107		/*
  2108		 * Our priority is to support MAP_SHARED mapped hugely;
  2109		 * and support MAP_PRIVATE mapped hugely too, until it is COWed.
  2110		 * But if caller specified an address hint and we allocated area there
  2111		 * successfully, respect that as before.
  2112		 */
  2113		if (uaddr == addr)
  2114			return addr;
  2115	
  2116		if (shmem_huge != SHMEM_HUGE_FORCE) {
  2117			struct super_block *sb;
  2118	
  2119			if (file) {
  2120				VM_BUG_ON(file->f_op != &shmem_file_operations);
  2121				sb = file_inode(file)->i_sb;
  2122			} else {
  2123				/*
  2124				 * Called directly from mm/mmap.c, or drivers/char/mem.c
  2125				 * for "/dev/zero", to create a shared anonymous object.
  2126				 */
  2127				if (IS_ERR(shm_mnt))
  2128					return addr;
  2129				sb = shm_mnt->mnt_sb;
  2130			}
  2131			if (SHMEM_SB(sb)->huge == SHMEM_HUGE_NEVER)
  2132				return addr;
  2133		}
  2134	
  2135		offset = (pgoff << PAGE_SHIFT) & (HPAGE_PMD_SIZE-1);
  2136		if (offset && offset + len < 2 * HPAGE_PMD_SIZE)
  2137			return addr;
  2138		if ((addr & (HPAGE_PMD_SIZE-1)) == offset)
  2139			return addr;
  2140	
  2141		inflated_len = len + HPAGE_PMD_SIZE - PAGE_SIZE;
  2142		if (inflated_len > TASK_SIZE)
  2143			return addr;
  2144		if (inflated_len < len)
  2145			return addr;
  2146	
> 2147		inflated_addr = get_area(uaddr, 0, inflated_len, 0, flags);
  2148		if (IS_ERR_VALUE(inflated_addr))
  2149			return addr;
  2150		if (inflated_addr & ~PAGE_MASK)
  2151			return addr;
  2152	
  2153		inflated_offset = inflated_addr & (HPAGE_PMD_SIZE-1);
  2154		inflated_addr += offset - inflated_offset;
  2155		if (inflated_offset > offset)
  2156			inflated_addr += HPAGE_PMD_SIZE;
  2157	
  2158		if (inflated_addr > TASK_SIZE - len)
  2159			return addr;
  2160		return inflated_addr;
  2161	}
  2162	

---
0-DAY kernel test infrastructure                 Open Source Technology Center
https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org Intel Corporation
diff mbox series

Patch

diff --git a/mm/shmem.c b/mm/shmem.c
index 165fa6332993..dc539482ce67 100644
--- a/mm/shmem.c
+++ b/mm/shmem.c
@@ -2107,9 +2107,10 @@  unsigned long shmem_get_unmapped_area(struct file *file,
 	/*
 	 * Our priority is to support MAP_SHARED mapped hugely;
 	 * and support MAP_PRIVATE mapped hugely too, until it is COWed.
-	 * But if caller specified an address hint, respect that as before.
+	 * But if caller specified an address hint and we allocated area there
+	 * successfully, respect that as before.
 	 */
-	if (uaddr)
+	if (uaddr == addr)
 		return addr;
 
 	if (shmem_huge != SHMEM_HUGE_FORCE) {
@@ -2143,7 +2144,7 @@  unsigned long shmem_get_unmapped_area(struct file *file,
 	if (inflated_len < len)
 		return addr;
 
-	inflated_addr = get_area(NULL, 0, inflated_len, 0, flags);
+	inflated_addr = get_area(uaddr, 0, inflated_len, 0, flags);
 	if (IS_ERR_VALUE(inflated_addr))
 		return addr;
 	if (inflated_addr & ~PAGE_MASK)