]> git.proxmox.com Git - mirror_ubuntu-kernels.git/commitdiff
mm/thp: flush file for !is_shmem PageDirty() case in collapse_file()
authorSong Liu <songliubraving@fb.com>
Sun, 1 Dec 2019 01:57:19 +0000 (17:57 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Sun, 1 Dec 2019 20:59:09 +0000 (12:59 -0800)
For non-shmem file THPs, khugepaged only collapses read only .text
mapping (VM_DENYWRITE).  These pages should not be dirty except the case
where the file hasn't been flushed since first write.

Call filemap_flush() in collapse_file() to accelerate the write back in
such cases.

Link: http://lkml.kernel.org/r/20191106060930.2571389-3-songliubraving@fb.com
Signed-off-by: Song Liu <songliubraving@fb.com>
Cc: Kirill A. Shutemov <kirill.shutemov@linux.intel.com>
Cc: Hugh Dickins <hughd@google.com>
Cc: William Kucharski <william.kucharski@oracle.com>
Cc: Johannes Weiner <hannes@cmpxchg.org>
Cc: Matthew Wilcox <willy@infradead.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
mm/khugepaged.c

index a8a57bebb5fac3b72a48f187d878b6e257ddc479..b679908743cb207a8433673078a943e747ad5c65 100644 (file)
@@ -1602,6 +1602,24 @@ static void collapse_file(struct mm_struct *mm,
                                        result = SCAN_FAIL;
                                        goto xa_unlocked;
                                }
+                       } else if (PageDirty(page)) {
+                               /*
+                                * khugepaged only works on read-only fd,
+                                * so this page is dirty because it hasn't
+                                * been flushed since first write. There
+                                * won't be new dirty pages.
+                                *
+                                * Trigger async flush here and hope the
+                                * writeback is done when khugepaged
+                                * revisits this page.
+                                *
+                                * This is a one-off situation. We are not
+                                * forcing writeback in loop.
+                                */
+                               xas_unlock_irq(&xas);
+                               filemap_flush(mapping);
+                               result = SCAN_FAIL;
+                               goto xa_unlocked;
                        } else if (trylock_page(page)) {
                                get_page(page);
                                xas_unlock_irq(&xas);