• Michael Ellerman's avatar
    powerpc/64s: Fix possible corruption on big endian due to pgd/pud_present() · a5800762
    Michael Ellerman authored
    In v4.20 we changed our pgd/pud_present() to check for _PAGE_PRESENT
    rather than just checking that the value is non-zero, e.g.:
    
      static inline int pgd_present(pgd_t pgd)
      {
     -       return !pgd_none(pgd);
     +       return (pgd_raw(pgd) & cpu_to_be64(_PAGE_PRESENT));
      }
    
    Unfortunately this is broken on big endian, as the result of the
    bitwise & is truncated to int, which is always zero because
    _PAGE_PRESENT is 0x8000000000000000ul. This means pgd_present() and
    pud_present() are always false at compile time, and the compiler
    elides the subsequent code.
    
    Remarkably with that bug present we are still able to boot and run
    with few noticeable effects. However under some work loads we are able
    to trigger a warning in the ext4 code:
    
      WARNING: CPU: 11 PID: 29593 at fs/ext4/inode.c:3927 .ext4_set_page_dirty+0x70/0xb0
      CPU: 11 PID: 29593 Comm: debugedit Not tainted 4.20.0-rc1 #1
      ...
      NIP .ext4_set_page_dirty+0x70/0xb0
      LR  .set_page_dirty+0xa0/0x150
      Call Trace:
       .set_page_dirty+0xa0/0x150
       .unmap_page_range+0xbf0/0xe10
       .unmap_vmas+0x84/0x130
       .unmap_region+0xe8/0x190
       .__do_munmap+0x2f0/0x510
       .__vm_munmap+0x80/0x110
       .__se_sys_munmap+0x14/0x30
       system_call+0x5c/0x70
    
    The fix is simple, we need to convert the result of the bitwise & to
    an int before returning it.
    
    Thanks to Erhard, Jan Kara and Aneesh for help with debugging.
    
    Fixes: da7ad366 ("powerpc/mm/book3s: Update pmd_present to look at _PAGE_PRESENT bit")
    Cc: stable@vger.kernel.org # v4.20+
    Reported-by: default avatarErhard F. <erhard_f@mailbox.org>
    Reviewed-by: default avatarAneesh Kumar K.V <aneesh.kumar@linux.ibm.com>
    Signed-off-by: default avatarMichael Ellerman <mpe@ellerman.id.au>
    a5800762
pgtable.h 37.9 KB