Merge tag 'dmaengine-fix-6.8-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git...
[linux-2.6-block.git] / mm / compaction.c
index 27ada42924d59cdea7b06e0f55331280ff202398..4add68d40e8d99c72bd6af648510aadd587dddfc 100644 (file)
@@ -882,6 +882,7 @@ isolate_migratepages_block(struct compact_control *cc, unsigned long low_pfn,
 
        /* Time to isolate some pages for migration */
        for (; low_pfn < end_pfn; low_pfn++) {
+               bool is_dirty, is_unevictable;
 
                if (skip_on_failure && low_pfn >= next_skip_pfn) {
                        /*
@@ -1079,8 +1080,10 @@ isolate_migratepages_block(struct compact_control *cc, unsigned long low_pfn,
                if (!folio_test_lru(folio))
                        goto isolate_fail_put;
 
+               is_unevictable = folio_test_unevictable(folio);
+
                /* Compaction might skip unevictable pages but CMA takes them */
-               if (!(mode & ISOLATE_UNEVICTABLE) && folio_test_unevictable(folio))
+               if (!(mode & ISOLATE_UNEVICTABLE) && is_unevictable)
                        goto isolate_fail_put;
 
                /*
@@ -1092,26 +1095,42 @@ isolate_migratepages_block(struct compact_control *cc, unsigned long low_pfn,
                if ((mode & ISOLATE_ASYNC_MIGRATE) && folio_test_writeback(folio))
                        goto isolate_fail_put;
 
-               if ((mode & ISOLATE_ASYNC_MIGRATE) && folio_test_dirty(folio)) {
-                       bool migrate_dirty;
+               is_dirty = folio_test_dirty(folio);
+
+               if (((mode & ISOLATE_ASYNC_MIGRATE) && is_dirty) ||
+                   (mapping && is_unevictable)) {
+                       bool migrate_dirty = true;
+                       bool is_unmovable;
 
                        /*
                         * Only folios without mappings or that have
-                        * a ->migrate_folio callback are possible to
-                        * migrate without blocking.  However, we may
-                        * be racing with truncation, which can free
-                        * the mapping.  Truncation holds the folio lock
-                        * until after the folio is removed from the page
-                        * cache so holding it ourselves is sufficient.
+                        * a ->migrate_folio callback are possible to migrate
+                        * without blocking.
+                        *
+                        * Folios from unmovable mappings are not migratable.
+                        *
+                        * However, we can be racing with truncation, which can
+                        * free the mapping that we need to check. Truncation
+                        * holds the folio lock until after the folio is removed
+                        * from the page so holding it ourselves is sufficient.
+                        *
+                        * To avoid locking the folio just to check unmovable,
+                        * assume every unmovable folio is also unevictable,
+                        * which is a cheaper test.  If our assumption goes
+                        * wrong, it's not a correctness bug, just potentially
+                        * wasted cycles.
                         */
                        if (!folio_trylock(folio))
                                goto isolate_fail_put;
 
                        mapping = folio_mapping(folio);
-                       migrate_dirty = !mapping ||
-                                       mapping->a_ops->migrate_folio;
+                       if ((mode & ISOLATE_ASYNC_MIGRATE) && is_dirty) {
+                               migrate_dirty = !mapping ||
+                                               mapping->a_ops->migrate_folio;
+                       }
+                       is_unmovable = mapping && mapping_unmovable(mapping);
                        folio_unlock(folio);
-                       if (!migrate_dirty)
+                       if (!migrate_dirty || is_unmovable)
                                goto isolate_fail_put;
                }