Commit 0fb1d9bcbcf701a45835aa150c57ca54ea685bfa

Authored by Martin Schwidefsky
1 parent f481bfafd3

[S390] make page table upgrade work again

After TASK_SIZE now gives the current size of the address space the
upgrade of a 64 bit process from 3 to 4 levels of page table  needs
to use the arch_mmap_check hook to catch large mmap lengths. The
get_unmapped_area* functions need to check for -ENOMEM from the
arch_get_unmapped_area*, upgrade the page table and retry.

Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>

Showing 2 changed files with 35 additions and 14 deletions Side-by-side Diff

arch/s390/include/asm/mman.h
... ... @@ -22,5 +22,10 @@
22 22 #define MCL_CURRENT 1 /* lock all current mappings */
23 23 #define MCL_FUTURE 2 /* lock all future mappings */
24 24  
  25 +#if defined(__KERNEL__) && !defined(__ASSEMBLY__) && defined(CONFIG_64BIT)
  26 +int s390_mmap_check(unsigned long addr, unsigned long len);
  27 +#define arch_mmap_check(addr,len,flags) s390_mmap_check(addr,len)
  28 +#endif
  29 +
25 30 #endif /* __S390_MMAN_H__ */
... ... @@ -89,42 +89,58 @@
89 89  
90 90 #else
91 91  
  92 +int s390_mmap_check(unsigned long addr, unsigned long len)
  93 +{
  94 + if (!test_thread_flag(TIF_31BIT) &&
  95 + len >= TASK_SIZE && TASK_SIZE < (1UL << 53))
  96 + return crst_table_upgrade(current->mm, 1UL << 53);
  97 + return 0;
  98 +}
  99 +
92 100 static unsigned long
93 101 s390_get_unmapped_area(struct file *filp, unsigned long addr,
94 102 unsigned long len, unsigned long pgoff, unsigned long flags)
95 103 {
96 104 struct mm_struct *mm = current->mm;
  105 + unsigned long area;
97 106 int rc;
98 107  
99   - addr = arch_get_unmapped_area(filp, addr, len, pgoff, flags);
100   - if (addr & ~PAGE_MASK)
101   - return addr;
102   - if (unlikely(mm->context.asce_limit < addr + len)) {
103   - rc = crst_table_upgrade(mm, addr + len);
  108 + area = arch_get_unmapped_area(filp, addr, len, pgoff, flags);
  109 + if (!(area & ~PAGE_MASK))
  110 + return area;
  111 + if (area == -ENOMEM &&
  112 + !test_thread_flag(TIF_31BIT) && TASK_SIZE < (1UL << 53)) {
  113 + /* Upgrade the page table to 4 levels and retry. */
  114 + rc = crst_table_upgrade(mm, 1UL << 53);
104 115 if (rc)
105 116 return (unsigned long) rc;
  117 + area = arch_get_unmapped_area(filp, addr, len, pgoff, flags);
106 118 }
107   - return addr;
  119 + return area;
108 120 }
109 121  
110 122 static unsigned long
111   -s390_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0,
  123 +s390_get_unmapped_area_topdown(struct file *filp, const unsigned long addr,
112 124 const unsigned long len, const unsigned long pgoff,
113 125 const unsigned long flags)
114 126 {
115 127 struct mm_struct *mm = current->mm;
116   - unsigned long addr = addr0;
  128 + unsigned long area;
117 129 int rc;
118 130  
119   - addr = arch_get_unmapped_area_topdown(filp, addr, len, pgoff, flags);
120   - if (addr & ~PAGE_MASK)
121   - return addr;
122   - if (unlikely(mm->context.asce_limit < addr + len)) {
123   - rc = crst_table_upgrade(mm, addr + len);
  131 + area = arch_get_unmapped_area_topdown(filp, addr, len, pgoff, flags);
  132 + if (!(area & ~PAGE_MASK))
  133 + return area;
  134 + if (area == -ENOMEM &&
  135 + !test_thread_flag(TIF_31BIT) && TASK_SIZE < (1UL << 53)) {
  136 + /* Upgrade the page table to 4 levels and retry. */
  137 + rc = crst_table_upgrade(mm, 1UL << 53);
124 138 if (rc)
125 139 return (unsigned long) rc;
  140 + area = arch_get_unmapped_area_topdown(filp, addr, len,
  141 + pgoff, flags);
126 142 }
127   - return addr;
  143 + return area;
128 144 }
129 145 /*
130 146 * This function, called very early during the creation of a new