On Fri, 2010-07-23 at 10:41 +1000, Benjamin Herrenschmidt wrote:
> There's a couple of nasty bugs lurking in our huge page hashing code.
> 
> First, we don't check the access permission atomically with setting
> the _PAGE_BUSY bit, which means that the PTE value we end up using
> for the hashing might be different than the one we have checked
> the access permissions for.
> 
> We've seen cases where that leads us to try to use an invalidated
> PTE for hashing, causing all sort of "interesting" issues.
> 
> Then, we also failed to set _PAGE_DIRTY on a write access.
> 
> This fixes both, while also simplifying the code a bit.

The changeset lacks a comment about a change to the return value
when hitting _PAGE_BUSY and ...

>       do {
>               old_pte = pte_val(*ptep);
> -             if (old_pte & _PAGE_BUSY)
> -                     goto out;
> +             /* If PTE busy, retry the access */
> +             if (unlikely(old_pte & _PAGE_BUSY))
> +                     return 0;
> +             /* If PTE permissions don't match, take page fault */
> +             if (unlikely(access & ~pte_val(*ptep)))
> +                     return 1;

old_pte will do just fine instead of reloading it

Thanks Michael !

I'll respin that one.

Cheers,
Ben.

> +             /* Try to lock the PTE, add ACCESSED and DIRTY if it was
> +              * a write access */
>               new_pte = old_pte | _PAGE_BUSY | _PAGE_ACCESSED;
> +             if (access & _PAGE_RW)
> +                     new_pte |= _PAGE_DIRTY;
>       } while(old_pte != __cmpxchg_u64((unsigned long *)ptep,
>                                        old_pte, new_pte));
>  
> @@ -127,8 +127,7 @@ repeat:
>                */
>               if (unlikely(slot == -2)) {
>                       *ptep = __pte(old_pte);
> -                     err = -1;
> -                     goto out;
> +                     return -1;
>               }
>  
>               new_pte |= (slot << 12) & (_PAGE_F_SECOND | _PAGE_F_GIX);
> @@ -138,9 +137,5 @@ repeat:
>        * No need to use ldarx/stdcx here
>        */
>       *ptep = __pte(new_pte & ~_PAGE_BUSY);
> -
> -     err = 0;
> -
> - out:
> -     return err;
> +     return 0;
>  }


_______________________________________________
Linuxppc-dev mailing list
Linuxppc-dev@lists.ozlabs.org
https://lists.ozlabs.org/listinfo/linuxppc-dev

Reply via email to