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: Martin Schwidefsky <schwidefsky@de.ibm.com> Signed-off-by: Dominik Dingel <dingel@linux.vnet.ibm.com> Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
This commit is contained in:
committed by
Martin Schwidefsky
parent
1db9e0513d
commit
be39f1968e
@@ -1087,10 +1087,9 @@ again:
|
|||||||
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,
|
|||||||
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,
|
|||||||
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)
|
|||||||
/* 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;
|
||||||
|
Reference in New Issue
Block a user