]> err.no Git - linux-2.6/blobdiff - mm/swap.c
[PATCH] mm: never ClearPageLRU released pages
[linux-2.6] / mm / swap.c
index b524ea90bddb93554b7ace67af24af59fc657d17..3045a0f4c4519ac5052cbc052450dd0723056e2e 100644 (file)
--- a/mm/swap.c
+++ b/mm/swap.c
@@ -209,19 +209,18 @@ int lru_add_drain_all(void)
  */
 void fastcall __page_cache_release(struct page *page)
 {
-       unsigned long flags;
-       struct zone *zone = page_zone(page);
+       if (PageLRU(page)) {
+               unsigned long flags;
+               struct zone *zone = page_zone(page);
 
-       spin_lock_irqsave(&zone->lru_lock, flags);
-       if (TestClearPageLRU(page))
+               spin_lock_irqsave(&zone->lru_lock, flags);
+               if (!TestClearPageLRU(page))
+                       BUG();
                del_page_from_lru(zone, page);
-       if (page_count(page) != 0)
-               page = NULL;
-       spin_unlock_irqrestore(&zone->lru_lock, flags);
-       if (page)
-               free_hot_page(page);
+               spin_unlock_irqrestore(&zone->lru_lock, flags);
+       }
+       free_hot_page(page);
 }
-
 EXPORT_SYMBOL(__page_cache_release);
 
 /*
@@ -245,7 +244,6 @@ void release_pages(struct page **pages, int nr, int cold)
        pagevec_init(&pages_to_free, cold);
        for (i = 0; i < nr; i++) {
                struct page *page = pages[i];
-               struct zone *pagezone;
 
                if (unlikely(PageCompound(page))) {
                        if (zone) {
@@ -259,23 +257,27 @@ void release_pages(struct page **pages, int nr, int cold)
                if (!put_page_testzero(page))
                        continue;
 
-               pagezone = page_zone(page);
-               if (pagezone != zone) {
-                       if (zone)
-                               spin_unlock_irq(&zone->lru_lock);
-                       zone = pagezone;
-                       spin_lock_irq(&zone->lru_lock);
-               }
-               if (TestClearPageLRU(page))
+               if (PageLRU(page)) {
+                       struct zone *pagezone = page_zone(page);
+                       if (pagezone != zone) {
+                               if (zone)
+                                       spin_unlock_irq(&zone->lru_lock);
+                               zone = pagezone;
+                               spin_lock_irq(&zone->lru_lock);
+                       }
+                       if (!TestClearPageLRU(page))
+                               BUG();
                        del_page_from_lru(zone, page);
-               if (page_count(page) == 0) {
-                       if (!pagevec_add(&pages_to_free, page)) {
+               }
+
+               if (!pagevec_add(&pages_to_free, page)) {
+                       if (zone) {
                                spin_unlock_irq(&zone->lru_lock);
-                               __pagevec_free(&pages_to_free);
-                               pagevec_reinit(&pages_to_free);
-                               zone = NULL;    /* No lock is held */
+                               zone = NULL;
                        }
-               }
+                       __pagevec_free(&pages_to_free);
+                       pagevec_reinit(&pages_to_free);
+               }
        }
        if (zone)
                spin_unlock_irq(&zone->lru_lock);