Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+13 −8
Original line number Diff line number Diff line
@@ -1087,10 +1087,9 @@ static unsigned long page_table_realloc_pmd(struct mmu_gather *tlb,
			continue;
		/* Allocate new page table with pgstes */
		new = page_table_alloc_pgste(mm, addr);
		if (!new) {
			mm->context.has_pgste = 0;
			continue;
		}
		if (!new)
			return -ENOMEM;

		spin_lock(&mm->page_table_lock);
		if (likely((unsigned long *) pmd_deref(*pmd) == table)) {
			/* Nuke pmd entry pointing to the "short" page table */
@@ -1128,12 +1127,14 @@ static unsigned long page_table_realloc_pud(struct mmu_gather *tlb,
		if (pud_none_or_clear_bad(pud))
			continue;
		next = page_table_realloc_pmd(tlb, mm, pud, addr, next);
		if (unlikely(IS_ERR_VALUE(next)))
			return next;
	} while (pud++, addr = next, addr != end);

	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 next;
@@ -1145,7 +1146,11 @@ static void page_table_realloc(struct mmu_gather *tlb, struct mm_struct *mm,
		if (pgd_none_or_clear_bad(pgd))
			continue;
		next = page_table_realloc_pud(tlb, mm, pgd, addr, next);
		if (unlikely(IS_ERR_VALUE(next)))
			return next;
	} 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 */
	thp_split_mm(mm);
	/* Reallocate the page tables with pgstes */
	mm->context.has_pgste = 1;
	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);
	up_write(&mm->mmap_sem);
	return mm->context.has_pgste ? 0 : -ENOMEM;