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

Commit 7888b4dd authored by Aneesh Kumar K.V's avatar Aneesh Kumar K.V Committed by Benjamin Herrenschmidt
Browse files

powerpc: Prevent gcc to re-read the pagetables



GCC is very likely to read the pagetables just once and cache them in
the local stack or in a register, but it is can also decide to re-read
the pagetables. The problem is that the pagetable in those places can
change from under gcc.

With THP/hugetlbfs the pmd (and pgd for hugetlbfs giga pages) can
change under gup_fast. The pages won't be freed untill we finish
gup fast because we have irq disabled and we free these pages via
rcu callback.

Signed-off-by: default avatarAneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
Signed-off-by: default avatarBenjamin Herrenschmidt <benh@kernel.crashing.org>
parent 0ac52dd7
Loading
Loading
Loading
Loading
+4 −4
Original line number Diff line number Diff line
@@ -34,7 +34,7 @@ static noinline int gup_pte_range(pmd_t pmd, unsigned long addr,

	ptep = pte_offset_kernel(&pmd, addr);
	do {
		pte_t pte = *ptep;
		pte_t pte = ACCESS_ONCE(*ptep);
		struct page *page;

		if ((pte_val(pte) & mask) != result)
@@ -63,7 +63,7 @@ static int gup_pmd_range(pud_t pud, unsigned long addr, unsigned long end,

	pmdp = pmd_offset(&pud, addr);
	do {
		pmd_t pmd = *pmdp;
		pmd_t pmd = ACCESS_ONCE(*pmdp);

		next = pmd_addr_end(addr, end);
		/*
@@ -97,7 +97,7 @@ static int gup_pud_range(pgd_t pgd, unsigned long addr, unsigned long end,

	pudp = pud_offset(&pgd, addr);
	do {
		pud_t pud = *pudp;
		pud_t pud = ACCESS_ONCE(*pudp);

		next = pud_addr_end(addr, end);
		if (pud_none(pud))
@@ -160,7 +160,7 @@ int get_user_pages_fast(unsigned long start, int nr_pages, int write,

	pgdp = pgd_offset(mm, addr);
	do {
		pgd_t pgd = *pgdp;
		pgd_t pgd = ACCESS_ONCE(*pgdp);

		pr_devel("  %016lx: normal pgd %p\n", addr,
			 (void *)pgd_val(pgd));
+1 −1
Original line number Diff line number Diff line
@@ -1024,7 +1024,7 @@ int gup_hugepte(pte_t *ptep, unsigned long sz, unsigned long addr,
	if (pte_end < end)
		end = pte_end;

	pte = *ptep;
	pte = ACCESS_ONCE(*ptep);
	mask = _PAGE_PRESENT | _PAGE_USER;
	if (write)
		mask |= _PAGE_RW;