Merge branch 'work.misc' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs
[linux-2.6-microblaze.git] / mm / compaction.c
index 13cb7a9..e5acb97 100644 (file)
@@ -157,7 +157,7 @@ EXPORT_SYMBOL(__ClearPageMovable);
  * allocation success. 1 << compact_defer_shift, compactions are skipped up
  * to a limit of 1 << COMPACT_MAX_DEFER_SHIFT
  */
-void defer_compaction(struct zone *zone, int order)
+static void defer_compaction(struct zone *zone, int order)
 {
        zone->compact_considered = 0;
        zone->compact_defer_shift++;
@@ -172,7 +172,7 @@ void defer_compaction(struct zone *zone, int order)
 }
 
 /* Returns true if compaction should be skipped this time */
-bool compaction_deferred(struct zone *zone, int order)
+static bool compaction_deferred(struct zone *zone, int order)
 {
        unsigned long defer_limit = 1UL << zone->compact_defer_shift;
 
@@ -209,7 +209,7 @@ void compaction_defer_reset(struct zone *zone, int order,
 }
 
 /* Returns true if restarting compaction after many failures */
-bool compaction_restarting(struct zone *zone, int order)
+static bool compaction_restarting(struct zone *zone, int order)
 {
        if (order < zone->compact_order_failed)
                return false;
@@ -237,7 +237,7 @@ static void reset_cached_positions(struct zone *zone)
 }
 
 /*
- * Compound pages of >= pageblock_order should consistenly be skipped until
+ * Compound pages of >= pageblock_order should consistently be skipped until
  * released. It is always pointless to compact pages of such order (if they are
  * migratable), and the pageblocks they occupy cannot contain any free pages.
  */
@@ -804,7 +804,7 @@ isolate_migratepages_block(struct compact_control *cc, unsigned long low_pfn,
        unsigned long nr_scanned = 0, nr_isolated = 0;
        struct lruvec *lruvec;
        unsigned long flags = 0;
-       bool locked = false;
+       struct lruvec *locked = NULL;
        struct page *page = NULL, *valid_page = NULL;
        unsigned long start_pfn = low_pfn;
        bool skip_on_failure = false;
@@ -868,11 +868,20 @@ isolate_migratepages_block(struct compact_control *cc, unsigned long low_pfn,
                 * contention, to give chance to IRQs. Abort completely if
                 * a fatal signal is pending.
                 */
-               if (!(low_pfn % SWAP_CLUSTER_MAX)
-                   && compact_unlock_should_abort(&pgdat->lru_lock,
-                                           flags, &locked, cc)) {
-                       low_pfn = 0;
-                       goto fatal_pending;
+               if (!(low_pfn % SWAP_CLUSTER_MAX)) {
+                       if (locked) {
+                               unlock_page_lruvec_irqrestore(locked, flags);
+                               locked = NULL;
+                       }
+
+                       if (fatal_signal_pending(current)) {
+                               cc->contended = true;
+
+                               low_pfn = 0;
+                               goto fatal_pending;
+                       }
+
+                       cond_resched();
                }
 
                if (!pfn_valid_within(low_pfn))
@@ -890,6 +899,7 @@ isolate_migratepages_block(struct compact_control *cc, unsigned long low_pfn,
                if (!valid_page && IS_ALIGNED(low_pfn, pageblock_nr_pages)) {
                        if (!cc->ignore_skip_hint && get_pageblock_skip(page)) {
                                low_pfn = end_pfn;
+                               page = NULL;
                                goto isolate_abort;
                        }
                        valid_page = page;
@@ -943,9 +953,8 @@ isolate_migratepages_block(struct compact_control *cc, unsigned long low_pfn,
                        if (unlikely(__PageMovable(page)) &&
                                        !PageIsolated(page)) {
                                if (locked) {
-                                       spin_unlock_irqrestore(&pgdat->lru_lock,
-                                                                       flags);
-                                       locked = false;
+                                       unlock_page_lruvec_irqrestore(locked, flags);
+                                       locked = NULL;
                                }
 
                                if (!isolate_movable_page(page, isolate_mode))
@@ -971,10 +980,34 @@ isolate_migratepages_block(struct compact_control *cc, unsigned long low_pfn,
                if (!(cc->gfp_mask & __GFP_FS) && page_mapping(page))
                        goto isolate_fail;
 
+               /*
+                * Be careful not to clear PageLRU until after we're
+                * sure the page is not being freed elsewhere -- the
+                * page release code relies on it.
+                */
+               if (unlikely(!get_page_unless_zero(page)))
+                       goto isolate_fail;
+
+               if (__isolate_lru_page_prepare(page, isolate_mode) != 0)
+                       goto isolate_fail_put;
+
+               /* Try isolate the page */
+               if (!TestClearPageLRU(page))
+                       goto isolate_fail_put;
+
+               rcu_read_lock();
+               lruvec = mem_cgroup_page_lruvec(page, pgdat);
+
                /* If we already hold the lock, we can skip some rechecking */
-               if (!locked) {
-                       locked = compact_lock_irqsave(&pgdat->lru_lock,
-                                                               &flags, cc);
+               if (lruvec != locked) {
+                       if (locked)
+                               unlock_page_lruvec_irqrestore(locked, flags);
+
+                       compact_lock_irqsave(&lruvec->lru_lock, &flags, cc);
+                       locked = lruvec;
+                       rcu_read_unlock();
+
+                       lruvec_memcg_debug(lruvec, page);
 
                        /* Try get exclusive access under lock */
                        if (!skip_updated) {
@@ -983,10 +1016,6 @@ isolate_migratepages_block(struct compact_control *cc, unsigned long low_pfn,
                                        goto isolate_abort;
                        }
 
-                       /* Recheck PageLRU and PageCompound under lock */
-                       if (!PageLRU(page))
-                               goto isolate_fail;
-
                        /*
                         * Page become compound since the non-locked check,
                         * and it's on LRU. It can only be a THP so the order
@@ -994,15 +1023,11 @@ isolate_migratepages_block(struct compact_control *cc, unsigned long low_pfn,
                         */
                        if (unlikely(PageCompound(page) && !cc->alloc_contig)) {
                                low_pfn += compound_nr(page) - 1;
-                               goto isolate_fail;
+                               SetPageLRU(page);
+                               goto isolate_fail_put;
                        }
-               }
-
-               lruvec = mem_cgroup_page_lruvec(page, pgdat);
-
-               /* Try isolate the page */
-               if (__isolate_lru_page(page, isolate_mode) != 0)
-                       goto isolate_fail;
+               } else
+                       rcu_read_unlock();
 
                /* The whole page is taken off the LRU; skip the tail pages. */
                if (PageCompound(page))
@@ -1032,6 +1057,15 @@ isolate_success:
                }
 
                continue;
+
+isolate_fail_put:
+               /* Avoid potential deadlock in freeing page under lru_lock */
+               if (locked) {
+                       unlock_page_lruvec_irqrestore(locked, flags);
+                       locked = NULL;
+               }
+               put_page(page);
+
 isolate_fail:
                if (!skip_on_failure)
                        continue;
@@ -1043,8 +1077,8 @@ isolate_fail:
                 */
                if (nr_isolated) {
                        if (locked) {
-                               spin_unlock_irqrestore(&pgdat->lru_lock, flags);
-                               locked = false;
+                               unlock_page_lruvec_irqrestore(locked, flags);
+                               locked = NULL;
                        }
                        putback_movable_pages(&cc->migratepages);
                        cc->nr_migratepages = 0;
@@ -1068,9 +1102,15 @@ isolate_fail:
        if (unlikely(low_pfn > end_pfn))
                low_pfn = end_pfn;
 
+       page = NULL;
+
 isolate_abort:
        if (locked)
-               spin_unlock_irqrestore(&pgdat->lru_lock, flags);
+               unlock_page_lruvec_irqrestore(locked, flags);
+       if (page) {
+               SetPageLRU(page);
+               put_page(page);
+       }
 
        /*
         * Updated the cached scanner pfn once the pageblock has been scanned
@@ -2070,13 +2110,6 @@ static enum compact_result compact_finished(struct compact_control *cc)
        return ret;
 }
 
-/*
- * compaction_suitable: Is this suitable to run compaction on this zone now?
- * Returns
- *   COMPACT_SKIPPED  - If there are too few free pages for compaction
- *   COMPACT_SUCCESS  - If the allocation would succeed without compaction
- *   COMPACT_CONTINUE - If compaction should run now
- */
 static enum compact_result __compaction_suitable(struct zone *zone, int order,
                                        unsigned int alloc_flags,
                                        int highest_zoneidx,
@@ -2120,6 +2153,13 @@ static enum compact_result __compaction_suitable(struct zone *zone, int order,
        return COMPACT_CONTINUE;
 }
 
+/*
+ * compaction_suitable: Is this suitable to run compaction on this zone now?
+ * Returns
+ *   COMPACT_SKIPPED  - If there are too few free pages for compaction
+ *   COMPACT_SUCCESS  - If the allocation would succeed without compaction
+ *   COMPACT_CONTINUE - If compaction should run now
+ */
 enum compact_result compaction_suitable(struct zone *zone, int order,
                                        unsigned int alloc_flags,
                                        int highest_zoneidx)
@@ -2275,7 +2315,7 @@ compact_zone(struct compact_control *cc, struct capture_control *capc)
 
        while ((ret = compact_finished(cc)) == COMPACT_CONTINUE) {
                int err;
-               unsigned long start_pfn = cc->migrate_pfn;
+               unsigned long iteration_start_pfn = cc->migrate_pfn;
 
                /*
                 * Avoid multiple rescans which can happen if a page cannot be
@@ -2287,7 +2327,7 @@ compact_zone(struct compact_control *cc, struct capture_control *capc)
                 */
                cc->rescan = false;
                if (pageblock_start_pfn(last_migrated_pfn) ==
-                   pageblock_start_pfn(start_pfn)) {
+                   pageblock_start_pfn(iteration_start_pfn)) {
                        cc->rescan = true;
                }
 
@@ -2311,8 +2351,7 @@ compact_zone(struct compact_control *cc, struct capture_control *capc)
                        goto check_drain;
                case ISOLATE_SUCCESS:
                        update_cached = false;
-                       last_migrated_pfn = start_pfn;
-                       ;
+                       last_migrated_pfn = iteration_start_pfn;
                }
 
                err = migrate_pages(&cc->migratepages, compaction_alloc,