]> git.proxmox.com Git - mirror_ubuntu-hirsute-kernel.git/blobdiff - mm/khugepaged.c
Merge tag 'mmc-v5.5-rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/ulfh/mmc
[mirror_ubuntu-hirsute-kernel.git] / mm / khugepaged.c
index f05d27b7183dcd9699427e19fdc1b8cd00642028..b679908743cb207a8433673078a943e747ad5c65 100644 (file)
@@ -1602,17 +1602,24 @@ static void collapse_file(struct mm_struct *mm,
                                        result = SCAN_FAIL;
                                        goto xa_unlocked;
                                }
-                       } else if (!PageUptodate(page)) {
-                               xas_unlock_irq(&xas);
-                               wait_on_page_locked(page);
-                               if (!trylock_page(page)) {
-                                       result = SCAN_PAGE_LOCK;
-                                       goto xa_unlocked;
-                               }
-                               get_page(page);
                        } 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_locked;
+                               goto xa_unlocked;
                        } else if (trylock_page(page)) {
                                get_page(page);
                                xas_unlock_irq(&xas);
@@ -1627,7 +1634,12 @@ static void collapse_file(struct mm_struct *mm,
                 * without racing with truncate.
                 */
                VM_BUG_ON_PAGE(!PageLocked(page), page);
-               VM_BUG_ON_PAGE(!PageUptodate(page), page);
+
+               /* make sure the page is up to date */
+               if (unlikely(!PageUptodate(page))) {
+                       result = SCAN_FAIL;
+                       goto out_unlock;
+               }
 
                /*
                 * If file was truncated then extended, or hole-punched, before
@@ -1643,6 +1655,16 @@ static void collapse_file(struct mm_struct *mm,
                        goto out_unlock;
                }
 
+               if (!is_shmem && PageDirty(page)) {
+                       /*
+                        * khugepaged only works on read-only fd, so this
+                        * page is dirty because it hasn't been flushed
+                        * since first write.
+                        */
+                       result = SCAN_FAIL;
+                       goto out_unlock;
+               }
+
                if (isolate_lru_page(page)) {
                        result = SCAN_DEL_PAGE_LRU;
                        goto out_unlock;