nbd: Respect max_part for all partition scans
[linux-2.6-microblaze.git] / mm / page_isolation.c
index 63a3db1..bddf788 100644 (file)
 
 static int set_migratetype_isolate(struct page *page, int migratetype, int isol_flags)
 {
-       struct page *unmovable = NULL;
-       struct zone *zone;
+       struct zone *zone = page_zone(page);
+       struct page *unmovable;
        unsigned long flags;
-       int ret = -EBUSY;
-
-       zone = page_zone(page);
 
        spin_lock_irqsave(&zone->lock, flags);
 
        /*
         * We assume the caller intended to SET migrate type to isolate.
         * If it is already set, then someone else must have raced and
-        * set it before us.  Return -EBUSY
+        * set it before us.
         */
-       if (is_migrate_isolate_page(page))
-               goto out;
+       if (is_migrate_isolate_page(page)) {
+               spin_unlock_irqrestore(&zone->lock, flags);
+               return -EBUSY;
+       }
 
        /*
         * FIXME: Now, memory hotplug doesn't call shrink_slab() by itself.
@@ -49,25 +48,20 @@ static int set_migratetype_isolate(struct page *page, int migratetype, int isol_
                                                                        NULL);
 
                __mod_zone_freepage_state(zone, -nr_pages, mt);
-               ret = 0;
+               spin_unlock_irqrestore(&zone->lock, flags);
+               return 0;
        }
 
-out:
        spin_unlock_irqrestore(&zone->lock, flags);
-       if (!ret) {
-               drain_all_pages(zone);
-       } else {
-               WARN_ON_ONCE(zone_idx(zone) == ZONE_MOVABLE);
-
-               if ((isol_flags & REPORT_FAILURE) && unmovable)
-                       /*
-                        * printk() with zone->lock held will likely trigger a
-                        * lockdep splat, so defer it here.
-                        */
-                       dump_page(unmovable, "unmovable page");
+       if (isol_flags & REPORT_FAILURE) {
+               /*
+                * printk() with zone->lock held will likely trigger a
+                * lockdep splat, so defer it here.
+                */
+               dump_page(unmovable, "unmovable page");
        }
 
-       return ret;
+       return -EBUSY;
 }
 
 static void unset_migratetype_isolate(struct page *page, unsigned migratetype)
@@ -93,8 +87,8 @@ static void unset_migratetype_isolate(struct page *page, unsigned migratetype)
         * these pages to be merged.
         */
        if (PageBuddy(page)) {
-               order = page_order(page);
-               if (order >= pageblock_order) {
+               order = buddy_order(page);
+               if (order >= pageblock_order && order < MAX_ORDER - 1) {
                        pfn = page_to_pfn(page);
                        buddy_pfn = __find_buddy_pfn(pfn, order);
                        buddy = page + (buddy_pfn - pfn);
@@ -111,6 +105,11 @@ static void unset_migratetype_isolate(struct page *page, unsigned migratetype)
         * If we isolate freepage with more than pageblock_order, there
         * should be no freepage in the range, so we could avoid costly
         * pageblock scanning for freepage moving.
+        *
+        * We didn't actually touch any of the isolated pages, so place them
+        * to the tail of the freelist. This is an optimization for memory
+        * onlining - just onlined memory won't immediately be considered for
+        * allocation.
         */
        if (!isolated_page) {
                nr_pages = move_freepages_block(zone, page, migratetype, NULL);
@@ -172,14 +171,14 @@ __first_valid_page(unsigned long pfn, unsigned long nr_pages)
  *
  * Please note that there is no strong synchronization with the page allocator
  * either. Pages might be freed while their page blocks are marked ISOLATED.
- * In some cases pages might still end up on pcp lists and that would allow
+ * A call to drain_all_pages() after isolation can flush most of them. However
+ * in some cases pages might still end up on pcp lists and that would allow
  * for their allocation even when they are in fact isolated already. Depending
- * on how strong of a guarantee the caller needs drain_all_pages might be needed
- * (e.g. __offline_pages will need to call it after check for isolated range for
- * a next retry).
+ * on how strong of a guarantee the caller needs, zone_pcp_disable/enable()
+ * might be used to flush and disable pcplist before isolation and enable after
+ * unisolation.
  *
- * Return: the number of isolated pageblocks on success and -EBUSY if any part
- * of range cannot be isolated.
+ * Return: 0 on success and -EBUSY if any part of range cannot be isolated.
  */
 int start_isolate_page_range(unsigned long start_pfn, unsigned long end_pfn,
                             unsigned migratetype, int flags)
@@ -187,7 +186,6 @@ int start_isolate_page_range(unsigned long start_pfn, unsigned long end_pfn,
        unsigned long pfn;
        unsigned long undo_pfn;
        struct page *page;
-       int nr_isolate_pageblock = 0;
 
        BUG_ON(!IS_ALIGNED(start_pfn, pageblock_nr_pages));
        BUG_ON(!IS_ALIGNED(end_pfn, pageblock_nr_pages));
@@ -201,10 +199,9 @@ int start_isolate_page_range(unsigned long start_pfn, unsigned long end_pfn,
                                undo_pfn = pfn;
                                goto undo;
                        }
-                       nr_isolate_pageblock++;
                }
        }
-       return nr_isolate_pageblock;
+       return 0;
 undo:
        for (pfn = start_pfn;
             pfn < undo_pfn;
@@ -264,7 +261,7 @@ __test_page_isolated_in_pageblock(unsigned long pfn, unsigned long end_pfn,
                         * the correct MIGRATE_ISOLATE freelist. There is no
                         * simple way to verify that as VM_BUG_ON(), though.
                         */
-                       pfn += 1 << page_order(page);
+                       pfn += 1 << buddy_order(page);
                else if ((flags & MEMORY_OFFLINE) && PageHWPoison(page))
                        /* A HWPoisoned page cannot be also PageBuddy */
                        pfn++;