Commit be39f196 authored by Dominik Dingel's avatar Dominik Dingel Committed by Martin Schwidefsky

s390/mm: page_table_realloc returns failure

There is a possible race between setting has_pgste and reallocation of the
page_table, change the order to fix this.
Also page_table_alloc_pgste can fail, in that case we need to backpropagte this
as -ENOMEM to the caller of page_table_realloc.

Based on a patch by Christian Borntraeger <borntraeger@de.ibm.com>.
Reviewed-by: default avatarMartin Schwidefsky <schwidefsky@de.ibm.com>
Signed-off-by: default avatarDominik Dingel <dingel@linux.vnet.ibm.com>
Signed-off-by: default avatarMartin Schwidefsky <schwidefsky@de.ibm.com>
parent 1db9e051
...@@ -1087,10 +1087,9 @@ static unsigned long page_table_realloc_pmd(struct mmu_gather *tlb, ...@@ -1087,10 +1087,9 @@ static unsigned long page_table_realloc_pmd(struct mmu_gather *tlb,
continue; continue;
/* Allocate new page table with pgstes */ /* Allocate new page table with pgstes */
new = page_table_alloc_pgste(mm, addr); new = page_table_alloc_pgste(mm, addr);
if (!new) { if (!new)
mm->context.has_pgste = 0; return -ENOMEM;
continue;
}
spin_lock(&mm->page_table_lock); spin_lock(&mm->page_table_lock);
if (likely((unsigned long *) pmd_deref(*pmd) == table)) { if (likely((unsigned long *) pmd_deref(*pmd) == table)) {
/* Nuke pmd entry pointing to the "short" page table */ /* Nuke pmd entry pointing to the "short" page table */
...@@ -1128,13 +1127,15 @@ static unsigned long page_table_realloc_pud(struct mmu_gather *tlb, ...@@ -1128,13 +1127,15 @@ static unsigned long page_table_realloc_pud(struct mmu_gather *tlb,
if (pud_none_or_clear_bad(pud)) if (pud_none_or_clear_bad(pud))
continue; continue;
next = page_table_realloc_pmd(tlb, mm, pud, addr, next); next = page_table_realloc_pmd(tlb, mm, pud, addr, next);
if (unlikely(IS_ERR_VALUE(next)))
return next;
} while (pud++, addr = next, addr != end); } while (pud++, addr = next, addr != end);
return addr; return addr;
} }
static void page_table_realloc(struct mmu_gather *tlb, struct mm_struct *mm, static unsigned long page_table_realloc(struct mmu_gather *tlb, struct mm_struct *mm,
unsigned long addr, unsigned long end) unsigned long addr, unsigned long end)
{ {
unsigned long next; unsigned long next;
pgd_t *pgd; pgd_t *pgd;
...@@ -1145,7 +1146,11 @@ static void page_table_realloc(struct mmu_gather *tlb, struct mm_struct *mm, ...@@ -1145,7 +1146,11 @@ static void page_table_realloc(struct mmu_gather *tlb, struct mm_struct *mm,
if (pgd_none_or_clear_bad(pgd)) if (pgd_none_or_clear_bad(pgd))
continue; continue;
next = page_table_realloc_pud(tlb, mm, pgd, addr, next); next = page_table_realloc_pud(tlb, mm, pgd, addr, next);
if (unlikely(IS_ERR_VALUE(next)))
return next;
} while (pgd++, addr = next, addr != end); } while (pgd++, addr = next, addr != end);
return 0;
} }
/* /*
...@@ -1165,9 +1170,9 @@ int s390_enable_sie(void) ...@@ -1165,9 +1170,9 @@ int s390_enable_sie(void)
/* split thp mappings and disable thp for future mappings */ /* split thp mappings and disable thp for future mappings */
thp_split_mm(mm); thp_split_mm(mm);
/* Reallocate the page tables with pgstes */ /* Reallocate the page tables with pgstes */
mm->context.has_pgste = 1;
tlb_gather_mmu(&tlb, mm, 0, TASK_SIZE); tlb_gather_mmu(&tlb, mm, 0, TASK_SIZE);
page_table_realloc(&tlb, mm, 0, TASK_SIZE); if (!page_table_realloc(&tlb, mm, 0, TASK_SIZE))
mm->context.has_pgste = 1;
tlb_finish_mmu(&tlb, 0, TASK_SIZE); tlb_finish_mmu(&tlb, 0, TASK_SIZE);
up_write(&mm->mmap_sem); up_write(&mm->mmap_sem);
return mm->context.has_pgste ? 0 : -ENOMEM; return mm->context.has_pgste ? 0 : -ENOMEM;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment