This version is much simpler as it just uses __count_immobile_pages()instead of using its own open coded version and it integrates changesfrom Minchan Kim (without page_count change as it doesn't seem correctand __count_immobile_pages() does the check in the standard way; if itstill is a problem I think that removing 1st phase check altogetherwould be better instead of adding more locking complexity).

The patch also adds compact_rescued_unmovable_blocks vmevent to vmstatsto make it possible to easily check if the code is working in practice.

When MIGRATE_UNMOVABLE pages are freed from MIGRATE_UNMOVABLEtype pageblock (and some MIGRATE_MOVABLE pages are left in it)waiting until an allocation takes ownership of the block maytake too long. The type of the pageblock remains unchangedso the pageblock cannot be used as a migration target duringcompaction.

Fix it by:

* Adding enum compact_mode (COMPACT_ASYNC_[MOVABLE,UNMOVABLE], and COMPACT_SYNC) and then converting sync field in struct compact_control to use it.

* Adding nr_pageblocks_skipped field to struct compact_control and tracking how many destination pageblocks were of MIGRATE_UNMOVABLE type. If COMPACT_ASYNC_MOVABLE mode compaction ran fully in try_to_compact_pages() (COMPACT_COMPLETE) it implies that there is not a suitable page for allocation. In this case then check how if there were enough MIGRATE_UNMOVABLE pageblocks to try a second pass in COMPACT_ASYNC_UNMOVABLE mode.

* Scanning the MIGRATE_UNMOVABLE pageblocks (during COMPACT_SYNC and COMPACT_ASYNC_UNMOVABLE compaction modes) and building a count based on finding PageBuddy pages, page_count(page) == 0 or PageLRU pages. If all pages within the MIGRATE_UNMOVABLE pageblock are in one of those three sets change the whole pageblock type to MIGRATE_MOVABLE.

NOTE: If we can make kswapd aware of order-0 request duringcompaction, we can enhance kswapd with changing mode toCOMPACT_ASYNC_FULL (COMPACT_ASYNC_MOVABLE + COMPACT_ASYNC_UNMOVABLE).Please see the following thread:

-/* Returns true if the page is within a block suitable for migration to */-static bool suitable_migration_target(struct page *page)+/*+ * Returns MIGRATE_TARGET if the page is within a block+ * suitable for migration to, UNMOVABLE_TARGET if the page+ * is within a MIGRATE_UNMOVABLE block, SKIP_TARGET otherwise.+ */+static enum smt_result suitable_migration_target(struct page *page,+ struct compact_control *cc) {