mm: strictly require elevated page refcount in isolate_lru_page()
Konstantin Khlebnikov [Wed, 25 May 2011 00:12:21 +0000 (17:12 -0700)]
isolate_lru_page() must be called only with stable reference to the page,
this is what is written in the comment above it, this is reasonable.

current isolate_lru_page() users and its page extra reference sources:

  __collapse_huge_page_isolate() - reference from pte

  mem_cgroup_move_parent() - get_page_unless_zero()
  mem_cgroup_move_charge_pte_range() - reference from pte

  soft_offline_page() - fixed, reference from get_any_page()
  delete_from_lru_cache() - reference from caller or get_page_unless_zero()
[ seems like there bug, because __memory_failure() can call
  page_action() for hpages tail, but it is ok for
  isolate_lru_page(), tail getted and not in lru]

  do_migrate_range() - fixed, get_page_unless_zero()

  migrate_page_add() - reference from pte

  do_move_page_to_node_array() - reference from follow_page()

 mlock.c: - various external references

  putback_lru_page() - reference from isolate_lru_page()

It seems that all isolate_lru_page() users are ready now for this
restriction.  So, let's replace redundant get_page_unless_zero() with
get_page() and add page initial reference count check with VM_BUG_ON()

Signed-off-by: Konstantin Khlebnikov <>
Cc: Andi Kleen <>
Cc: KAMEZAWA Hiroyuki <>
Cc: KOSAKI Motohiro <>
Cc: Mel Gorman <>
Cc: Lee Schermerhorn <>
Cc: Rik van Riel <>
Signed-off-by: Andrew Morton <>
Signed-off-by: Linus Torvalds <>


index d303b60..890f541 100644 (file)
@@ -1207,13 +1207,16 @@ int isolate_lru_page(struct page *page)
        int ret = -EBUSY;
+       VM_BUG_ON(!page_count(page));
        if (PageLRU(page)) {
                struct zone *zone = page_zone(page);
-               if (PageLRU(page) && get_page_unless_zero(page)) {
+               if (PageLRU(page)) {
                        int lru = page_lru(page);
                        ret = 0;
+                       get_page(page);
                        del_page_from_lru_list(zone, page, lru);