]> git.baikalelectronics.ru Git - kernel.git/commit
mm/huge_memory.c: __split_huge_page() use atomic ClearPageDirty()
authorHugh Dickins <hughd@google.com>
Fri, 1 Jun 2018 23:50:45 +0000 (16:50 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Sat, 2 Jun 2018 16:33:47 +0000 (09:33 -0700)
commitb61bc52831d92d255387d37ed35fb5016c671366
tree8d34f637439da9d593ad11e476e7e9d0bc20d893
parent505e52d49635f61f589d44cd3c122b08a35fb453
mm/huge_memory.c: __split_huge_page() use atomic ClearPageDirty()

Swapping load on huge=always tmpfs (with khugepaged tuned up to be very
eager, but I'm not sure that is relevant) soon hung uninterruptibly,
waiting for page lock in shmem_getpage_gfp()'s find_lock_entry(), most
often when "cp -a" was trying to write to a smallish file.  Debug showed
that the page in question was not locked, and page->mapping NULL by now,
but page->index consistent with having been in a huge page before.

Reproduced in minutes on a 4.15 kernel, even with 4.17's 4dda006e4a84
("mm/huge_memory.c: reorder operations in __split_huge_page_tail()") added
in; but took hours to reproduce on a 4.17 kernel (no idea why).

The culprit proved to be the __ClearPageDirty() on tails beyond i_size in
__split_huge_page(): the non-atomic __bitoperation may have been safe when
4.8's 4fc9f4387326 ("thp: file pages support for split_huge_page()")
introduced it, but liable to erase PageWaiters after 4.10's 297320b50ce4
("mm: add PageWaiters indicating tasks are waiting for a page bit").

Link: http://lkml.kernel.org/r/alpine.LSU.2.11.1805291841070.3197@eggly.anvils
Fixes: 297320b50ce4 ("mm: add PageWaiters indicating tasks are waiting for a page bit")
Signed-off-by: Hugh Dickins <hughd@google.com>
Acked-by: Kirill A. Shutemov <kirill.shutemov@linux.intel.com>
Cc: Konstantin Khlebnikov <khlebnikov@yandex-team.ru>
Cc: Nicholas Piggin <npiggin@gmail.com>
Cc: <stable@vger.kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
mm/huge_memory.c