diff options
author | Christian Borntraeger <borntraeger@de.ibm.com> | 2008-10-28 06:10:15 -0400 |
---|---|---|
committer | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2008-10-28 06:12:03 -0400 |
commit | 250cf776f74b5932a1977d0489cae9206e2351dd (patch) | |
tree | 71bb6778e65e8efbdd0cac09a64e4e1194b98c3f /arch/s390/mm/pgtable.c | |
parent | 2c78091405d6f54748b1fac78c45f2a799e3073a (diff) |
[S390] pgtables: Fix race in enable_sie vs. page table ops
The current enable_sie code sets the mm->context.pgstes bit to tell
dup_mm that the new mm should have extended page tables. This bit is also
used by the s390 specific page table primitives to decide about the page
table layout - which means context.pgstes has two meanings. This can cause
any kind of bugs. For example - e.g. shrink_zone can call
ptep_clear_flush_young while enable_sie is running. ptep_clear_flush_young
will test for context.pgstes. Since enable_sie changed that value of the old
struct mm without changing the page table layout ptep_clear_flush_young will
do the wrong thing.
The solution is to split pgstes into two bits
- one for the allocation
- one for the current state
Signed-off-by: Christian Borntraeger <borntraeger@de.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Diffstat (limited to 'arch/s390/mm/pgtable.c')
-rw-r--r-- | arch/s390/mm/pgtable.c | 16 |
1 files changed, 8 insertions, 8 deletions
diff --git a/arch/s390/mm/pgtable.c b/arch/s390/mm/pgtable.c index 3d98ba82ea67..ef3635b52fc0 100644 --- a/arch/s390/mm/pgtable.c +++ b/arch/s390/mm/pgtable.c | |||
@@ -169,7 +169,7 @@ unsigned long *page_table_alloc(struct mm_struct *mm) | |||
169 | unsigned long *table; | 169 | unsigned long *table; |
170 | unsigned long bits; | 170 | unsigned long bits; |
171 | 171 | ||
172 | bits = (mm->context.noexec || mm->context.pgstes) ? 3UL : 1UL; | 172 | bits = (mm->context.noexec || mm->context.has_pgste) ? 3UL : 1UL; |
173 | spin_lock(&mm->page_table_lock); | 173 | spin_lock(&mm->page_table_lock); |
174 | page = NULL; | 174 | page = NULL; |
175 | if (!list_empty(&mm->context.pgtable_list)) { | 175 | if (!list_empty(&mm->context.pgtable_list)) { |
@@ -186,7 +186,7 @@ unsigned long *page_table_alloc(struct mm_struct *mm) | |||
186 | pgtable_page_ctor(page); | 186 | pgtable_page_ctor(page); |
187 | page->flags &= ~FRAG_MASK; | 187 | page->flags &= ~FRAG_MASK; |
188 | table = (unsigned long *) page_to_phys(page); | 188 | table = (unsigned long *) page_to_phys(page); |
189 | if (mm->context.pgstes) | 189 | if (mm->context.has_pgste) |
190 | clear_table_pgstes(table); | 190 | clear_table_pgstes(table); |
191 | else | 191 | else |
192 | clear_table(table, _PAGE_TYPE_EMPTY, PAGE_SIZE); | 192 | clear_table(table, _PAGE_TYPE_EMPTY, PAGE_SIZE); |
@@ -210,7 +210,7 @@ void page_table_free(struct mm_struct *mm, unsigned long *table) | |||
210 | struct page *page; | 210 | struct page *page; |
211 | unsigned long bits; | 211 | unsigned long bits; |
212 | 212 | ||
213 | bits = (mm->context.noexec || mm->context.pgstes) ? 3UL : 1UL; | 213 | bits = (mm->context.noexec || mm->context.has_pgste) ? 3UL : 1UL; |
214 | bits <<= (__pa(table) & (PAGE_SIZE - 1)) / 256 / sizeof(unsigned long); | 214 | bits <<= (__pa(table) & (PAGE_SIZE - 1)) / 256 / sizeof(unsigned long); |
215 | page = pfn_to_page(__pa(table) >> PAGE_SHIFT); | 215 | page = pfn_to_page(__pa(table) >> PAGE_SHIFT); |
216 | spin_lock(&mm->page_table_lock); | 216 | spin_lock(&mm->page_table_lock); |
@@ -257,7 +257,7 @@ int s390_enable_sie(void) | |||
257 | struct mm_struct *mm, *old_mm; | 257 | struct mm_struct *mm, *old_mm; |
258 | 258 | ||
259 | /* Do we have pgstes? if yes, we are done */ | 259 | /* Do we have pgstes? if yes, we are done */ |
260 | if (tsk->mm->context.pgstes) | 260 | if (tsk->mm->context.has_pgste) |
261 | return 0; | 261 | return 0; |
262 | 262 | ||
263 | /* lets check if we are allowed to replace the mm */ | 263 | /* lets check if we are allowed to replace the mm */ |
@@ -269,14 +269,14 @@ int s390_enable_sie(void) | |||
269 | } | 269 | } |
270 | task_unlock(tsk); | 270 | task_unlock(tsk); |
271 | 271 | ||
272 | /* we copy the mm with pgstes enabled */ | 272 | /* we copy the mm and let dup_mm create the page tables with_pgstes */ |
273 | tsk->mm->context.pgstes = 1; | 273 | tsk->mm->context.alloc_pgste = 1; |
274 | mm = dup_mm(tsk); | 274 | mm = dup_mm(tsk); |
275 | tsk->mm->context.pgstes = 0; | 275 | tsk->mm->context.alloc_pgste = 0; |
276 | if (!mm) | 276 | if (!mm) |
277 | return -ENOMEM; | 277 | return -ENOMEM; |
278 | 278 | ||
279 | /* Now lets check again if somebody attached ptrace etc */ | 279 | /* Now lets check again if something happened */ |
280 | task_lock(tsk); | 280 | task_lock(tsk); |
281 | if (!tsk->mm || atomic_read(&tsk->mm->mm_users) > 1 || | 281 | if (!tsk->mm || atomic_read(&tsk->mm->mm_users) > 1 || |
282 | tsk->mm != tsk->active_mm || tsk->mm->ioctx_list) { | 282 | tsk->mm != tsk->active_mm || tsk->mm->ioctx_list) { |