Re: [syzbot] [mm?] BUG: Bad page map (7)

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On 9/11/23 06:26, Matthew Wilcox wrote:
> @@ -231,7 +235,10 @@ static inline void set_ptes(struct mm_struct *mm, unsigned long addr,
>  		if (--nr == 0)
>  			break;
>  		ptep++;
> -		pte = __pte(pte_val(pte) + (1UL << PFN_PTE_SHIFT));
> +		if (__pte_needs_invert(pte_val(pte)))
> +			pte = __pte(pte_val(pte) - (1UL << PFN_PTE_SHIFT));
> +		else
> +			pte = __pte(pte_val(pte) + (1UL << PFN_PTE_SHIFT));
>  	}
>  	arch_leave_lazy_mmu_mode();
>  }

This is much better than a whole x86 fork of set_ptes().  But it's still
a bit wonky because it exposes the PTE inversion logic to generic code.

Could we do something like this instead?  It'll (probably) end up
repeating the PTE inversion logic each way though the loop, so it's less
efficient than what you have above.  But unless I buggered something, it
"just works" without exposing any of the inversion logic to generic code.

The trick is that pte_pfn() undoes the inversion and then pfn_pte()
re-does it on each trip through the loop.

static inline void set_ptes(struct mm_struct *mm, unsigned long addr,
                pte_t *ptep, pte_t pte, unsigned int nr)
{
	pgprot_t prot = pte_pgprot(x);
	unsigned long pfn = pte_pfn(pte);

        page_table_check_ptes_set(mm, ptep, pte, nr);

        arch_enter_lazy_mmu_mode();
        for (;;) {
                set_pte(ptep, pte);
                if (--nr == 0)
                        break;
                ptep++;
		pfn++;
                pte = pfn_pte(pfn, pgprot);
        }
        arch_leave_lazy_mmu_mode();
}

Obviously completely untested. :)




[Index of Archives]     [Linux ARM Kernel]     [Linux ARM]     [Linux Omap]     [Fedora ARM]     [IETF Annouce]     [Bugtraq]     [Linux OMAP]     [Linux MIPS]     [eCos]     [Asterisk Internet PBX]     [Linux API]

  Powered by Linux