|
@@ -844,6 +844,51 @@ static unsigned long clear_active_flags(struct list_head *page_list)
|
|
|
return nr_active;
|
|
|
}
|
|
|
|
|
|
+/**
|
|
|
+ * isolate_lru_page - tries to isolate a page from its LRU list
|
|
|
+ * @page: page to isolate from its LRU list
|
|
|
+ *
|
|
|
+ * Isolates a @page from an LRU list, clears PageLRU and adjusts the
|
|
|
+ * vmstat statistic corresponding to whatever LRU list the page was on.
|
|
|
+ *
|
|
|
+ * Returns 0 if the page was removed from an LRU list.
|
|
|
+ * Returns -EBUSY if the page was not on an LRU list.
|
|
|
+ *
|
|
|
+ * The returned page will have PageLRU() cleared. If it was found on
|
|
|
+ * the active list, it will have PageActive set. That flag may need
|
|
|
+ * to be cleared by the caller before letting the page go.
|
|
|
+ *
|
|
|
+ * The vmstat statistic corresponding to the list on which the page was
|
|
|
+ * found will be decremented.
|
|
|
+ *
|
|
|
+ * Restrictions:
|
|
|
+ * (1) Must be called with an elevated refcount on the page. This is a
|
|
|
+ * fundamentnal difference from isolate_lru_pages (which is called
|
|
|
+ * without a stable reference).
|
|
|
+ * (2) the lru_lock must not be held.
|
|
|
+ * (3) interrupts must be enabled.
|
|
|
+ */
|
|
|
+int isolate_lru_page(struct page *page)
|
|
|
+{
|
|
|
+ int ret = -EBUSY;
|
|
|
+
|
|
|
+ if (PageLRU(page)) {
|
|
|
+ struct zone *zone = page_zone(page);
|
|
|
+
|
|
|
+ spin_lock_irq(&zone->lru_lock);
|
|
|
+ if (PageLRU(page) && get_page_unless_zero(page)) {
|
|
|
+ ret = 0;
|
|
|
+ ClearPageLRU(page);
|
|
|
+ if (PageActive(page))
|
|
|
+ del_page_from_active_list(zone, page);
|
|
|
+ else
|
|
|
+ del_page_from_inactive_list(zone, page);
|
|
|
+ }
|
|
|
+ spin_unlock_irq(&zone->lru_lock);
|
|
|
+ }
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+
|
|
|
/*
|
|
|
* shrink_inactive_list() is a helper for shrink_zone(). It returns the number
|
|
|
* of reclaimed pages
|